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
+7 -7
View File
@@ -440,9 +440,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %C.val: %C = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete]
@@ -485,9 +485,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -517,9 +517,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -549,10 +549,10 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %pattern_type.69f: type = pattern_type %C [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %C.val: %C = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.9ae: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.dbb: %T.as.Destroy.impl.Op.type.9ae = struct_value () [concrete]
@@ -617,9 +617,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %C.val: %C = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.b28: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.f48: %T.as.Destroy.impl.Op.type.b28 = struct_value () [concrete]
@@ -667,10 +667,10 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %O: type = class_type @O [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %C.val: %C = struct_value () [concrete]
// CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b8: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%O) [concrete]
@@ -788,9 +788,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %C.val: %C = struct_value () [concrete]
// CHECK:STDOUT: %C.bar.type: type = fn_type @C.bar [concrete]
// CHECK:STDOUT: %C.bar: %C.bar.type = struct_value () [concrete]
@@ -432,9 +432,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %S: type = class_type @S [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete]
@@ -477,9 +477,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %S: type = class_type @S [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -509,9 +509,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %S: type = class_type @S [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -541,10 +541,10 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %S: type = class_type @S [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %pattern_type.cd8: type = pattern_type %S [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.2b5: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.9b3: %T.as.Destroy.impl.Op.type.2b5 = struct_value () [concrete]
@@ -609,9 +609,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %S: type = class_type @S [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.17f: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.463: %T.as.Destroy.impl.Op.type.17f = struct_value () [concrete]
@@ -659,10 +659,10 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %O: type = class_type @O [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %S: type = class_type @S [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
// CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b8: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%O) [concrete]
@@ -780,9 +780,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %S: type = class_type @S [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
// CHECK:STDOUT: %S.bar.type: type = fn_type @S.bar [concrete]
// CHECK:STDOUT: %S.bar: %S.bar.type = struct_value () [concrete]
+7 -7
View File
@@ -465,9 +465,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %U: type = class_type @U [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %U.val: %U = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.0b7: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.2fa: %T.as.Destroy.impl.Op.type.0b7 = struct_value () [concrete]
@@ -510,9 +510,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %U: type = class_type @U [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -542,9 +542,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %U: type = class_type @U [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -574,10 +574,10 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %U: type = class_type @U [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %pattern_type.eb9: type = pattern_type %U [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %U.val: %U = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.2e1: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d5d: %T.as.Destroy.impl.Op.type.2e1 = struct_value () [concrete]
@@ -642,9 +642,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %U: type = class_type @U [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %U.val: %U = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.ee1: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.28c: %T.as.Destroy.impl.Op.type.ee1 = struct_value () [concrete]
@@ -692,10 +692,10 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %O: type = class_type @O [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %U: type = class_type @U [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %U.val: %U = struct_value () [concrete]
// CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b8: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%O) [concrete]
@@ -813,9 +813,9 @@ fn F() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %U: type = class_type @U [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %U.val: %U = struct_value () [concrete]
// CHECK:STDOUT: %U.bar.type: type = fn_type @U.bar [concrete]
// CHECK:STDOUT: %U.bar: %U.bar.type = struct_value () [concrete]