Don't import a C++ class definition until the class is required to be complete. (#5865)

When importing a class definition, ask Clang to complete it first. This
causes class template specializations to get instantiated as needed when
the type-checking of Carbon requires a C++ class to be complete. It also
allows Clang to implement things like modules-aware definition
visibility checking.

Don't reject importing a class with a virtual base if it's never
required to be complete. Instead, defer diagnosing until the definition
is required.

This also removes the recursion from `MapType`, as mapping a class type
no longer maps its definition.

In order to get diagnostics from instantiation failures, fix a bug that
caused any Clang diagnostics produced after the initial building of the
`ASTUnit` to get discarded. This exposed some duplicate diagnostic
issues in `ImportNameFromCpp` which are fixed here too.
This commit is contained in:
Richard Smith
2025-07-30 23:34:18 +00:00
committed by GitHub
parent 14f51d70c2
commit ae16014df8
13 changed files with 353 additions and 82 deletions
+20 -7
View File
@@ -158,6 +158,19 @@ fn ConvertB(p: Cpp.C*) -> Cpp.B* {
struct A { int a; };
struct B : virtual A {};
void UseB(B * _Nonnull p);
// --- use_virtual_inheritance_incomplete.carbon
library "[[@TEST_NAME]]";
import Cpp library "virtual_inheritance.h";
fn Convert(p: Cpp.B*) {
// OK, doesn't require `Cpp.B` to be a complete type.
Cpp.UseB(p);
}
// --- fail_todo_use_virtual_inheritance.carbon
library "[[@TEST_NAME]]";
@@ -166,11 +179,11 @@ library "[[@TEST_NAME]]";
// CHECK:STDERR: ./virtual_inheritance.h:3: error: semantics TODO: `class with virtual bases` [SemanticsTodo]
import Cpp library "virtual_inheritance.h";
// CHECK:STDERR: fail_todo_use_virtual_inheritance.carbon:[[@LINE+4]]:15: note: in `Cpp` name lookup for `B` [InCppNameLookup]
// CHECK:STDERR: fn Convert(p: Cpp.B*) -> Cpp.A* {
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
fn Convert(p: Cpp.B*) -> Cpp.A* {
// CHECK:STDERR: fail_todo_use_virtual_inheritance.carbon:[[@LINE+11]]:3: note: while completing C++ class type `Cpp.B` [InCppTypeCompletion]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_use_virtual_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.B*` to `Cpp.A*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
@@ -221,9 +234,9 @@ class V {
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %ptr.ddb: type = ptr_type %Derived [concrete]
// CHECK:STDOUT: %pattern_type.5c8: type = pattern_type %ptr.ddb [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %ptr.fb2: type = ptr_type %Base [concrete]
// CHECK:STDOUT: %pattern_type.72a: type = pattern_type %ptr.fb2 [concrete]
// CHECK:STDOUT: %ConvertPtr.type: type = fn_type @ConvertPtr [concrete]
@@ -345,9 +358,9 @@ class V {
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %Base.elem: type = unbound_element_type %Base, %i32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -389,8 +402,8 @@ class V {
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %Base.f.type: type = fn_type @Base.f [concrete]
// CHECK:STDOUT: %Base.f: %Base.f.type = struct_value () [concrete]
// CHECK:STDOUT: %Base.g.type: type = fn_type @Base.g [concrete]