mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 08:44:41 +01:00
Export Carbon classes as base / final / abstract. (#7191)
* For Carbon `base class C`, export as a regular C++ class. * For Carbon `class C`, export with the C++ `final` keyword attribute. * For Carbon `abstract C`, mark the destructor as pure virtual in cases where no member function is abstract, or emit an error if the destructor is not virtual. To support the final point, mark the destructor of an exported class as virtual if it overrides a virtual destructor from the base class. In passing, fix a crash exporting fields if the class has an invalid base type.
This commit is contained in:
+108
-3
@@ -49,8 +49,113 @@ void Qualified() {
|
||||
}
|
||||
|
||||
void MemberAccess(Carbon::A *a, Carbon::B *b) {
|
||||
// TODO: These cause a crash.
|
||||
// b->F();
|
||||
// b->G();
|
||||
b->F();
|
||||
b->G();
|
||||
}
|
||||
''';
|
||||
|
||||
// --- fail_derive_from_final.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
class Final {}
|
||||
|
||||
inline Cpp '''
|
||||
// CHECK:STDERR: fail_derive_from_final.carbon:[[@LINE+5]]:12: error: base 'Final' is marked 'final' [CppInteropParseError]
|
||||
// CHECK:STDERR: 13 | struct A : Carbon::Final {};
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: note: 'Final' declared here [CppInteropParseNote]
|
||||
// CHECK:STDERR:
|
||||
struct A : Carbon::Final {};
|
||||
''';
|
||||
|
||||
// --- fail_abstract.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
// TODO: Add a way to give a class a virtual destructor without C++ interop.
|
||||
inline Cpp '''
|
||||
struct VirtualDestructor {
|
||||
virtual ~VirtualDestructor() {}
|
||||
};
|
||||
''';
|
||||
|
||||
// CHECK:STDERR: fail_abstract.carbon:[[@LINE+4]]:1: error: cannot access member of interface `Core.Destroy` in type `Abstract` that does not implement that interface [MissingImplInMemberAccess]
|
||||
// CHECK:STDERR: abstract class Abstract {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
abstract class Abstract {
|
||||
extend base: Cpp.VirtualDestructor;
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
// CHECK:STDERR: fail_abstract.carbon:[[@LINE+5]]:18: error: variable type 'Carbon::Abstract' is an abstract class [CppInteropParseError]
|
||||
// CHECK:STDERR: 26 | Carbon::Abstract x;
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: note: unimplemented pure virtual method '~Abstract' in 'Abstract' [CppInteropParseNote]
|
||||
// CHECK:STDERR:
|
||||
Carbon::Abstract x;
|
||||
''';
|
||||
|
||||
// --- fail_todo_abstract_nonvirtual_dtor.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
// TODO: Find a way to export this to C++ as an abstract class, despite not
|
||||
// having a vptr.
|
||||
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor.carbon:[[@LINE+8]]:1: error: semantics TODO: `exporting abstract class with no abstract methods and non-virtual destructor to C++` [SemanticsTodo]
|
||||
// CHECK:STDERR: abstract class Abstract {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor.carbon:[[@LINE+4]]:1: error: cannot access member of interface `Core.Destroy` in type `Abstract` that does not implement that interface [MissingImplInMemberAccess]
|
||||
// CHECK:STDERR: abstract class Abstract {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
abstract class Abstract {}
|
||||
|
||||
inline Cpp '''
|
||||
class Derived : public Carbon::Abstract {};
|
||||
''';
|
||||
|
||||
// --- fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
// TODO: We should support generating a base subobject destructor for an
|
||||
// abstract class, even though we refuse to generate a complete object
|
||||
// destructor.
|
||||
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon:[[@LINE+4]]:1: error: cannot access member of interface `Core.Destroy` in type `Abstract` that does not implement that interface [MissingImplInMemberAccess]
|
||||
// CHECK:STDERR: abstract class Abstract {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
abstract class Abstract {
|
||||
abstract fn F[self: Self]();
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
class Derived : public Carbon::Abstract {
|
||||
};
|
||||
''';
|
||||
|
||||
// --- override_virtual_dtor.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp;
|
||||
|
||||
inline Cpp '''
|
||||
struct A {
|
||||
virtual ~A() = 0;
|
||||
};
|
||||
''';
|
||||
|
||||
class B {
|
||||
extend base: Cpp.A;
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
Carbon::B b;
|
||||
''';
|
||||
|
||||
@@ -121,3 +121,20 @@ void F() {
|
||||
a.x = 12;
|
||||
}
|
||||
''';
|
||||
|
||||
// --- fail_invalid.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
import Cpp;
|
||||
|
||||
// This should not cause a crash.
|
||||
class A {
|
||||
// CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:16: error: name `Whoops` not found [NameNotFound]
|
||||
// CHECK:STDERR: extend base: Whoops;
|
||||
// CHECK:STDERR: ^~~~~~
|
||||
// CHECK:STDERR:
|
||||
extend base: Whoops;
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
Carbon::A x;
|
||||
''';
|
||||
|
||||
Reference in New Issue
Block a user