From 2a059366a7a32c226a575cc6ab9f4ad85e284805 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 24 Apr 2026 12:30:02 -0700 Subject: [PATCH] Require imported C++ types to be complete before creating a Core.Copy witness (#7112) Fixes a crash that would occur due to `scope_id` of the class being unset. Relands #7106 that was reverted by #7103 due to a github infrastructure bug. Co-authored-by: David Blaikie --- toolchain/check/cpp/impl_lookup.cpp | 12 ++++++++ .../interop/cpp/class/import/class.carbon | 28 +++++++++++++++++++ toolchain/diagnostics/kind.def | 1 + 3 files changed, 41 insertions(+) diff --git a/toolchain/check/cpp/impl_lookup.cpp b/toolchain/check/cpp/impl_lookup.cpp index 1eb6761bab8c..f319bb1c184e 100644 --- a/toolchain/check/cpp/impl_lookup.cpp +++ b/toolchain/check/cpp/impl_lookup.cpp @@ -15,6 +15,7 @@ #include "toolchain/check/import_ref.h" #include "toolchain/check/inst.h" #include "toolchain/check/type.h" +#include "toolchain/check/type_completion.h" #include "toolchain/sem_ir/builtin_function_kind.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/typed_insts.h" @@ -113,6 +114,17 @@ static auto BuildCopyWitness( return SemIR::InstId::None; } if (auto* class_decl = dyn_cast(tag_decl)) { + auto class_type_id = SemIR::TypeId::ForTypeConstant(query_self_const_id); + if (!Check::RequireCompleteType( + context, class_type_id, SemIR::LocId::None, [&](auto& builder) { + CARBON_DIAGNOSTIC(IncompleteTypeInCopyWitness, Context, + "argument to C++ call has incomplete type {0}", + SemIR::TypeId); + builder.Context(loc_id, IncompleteTypeInCopyWitness, + class_type_id); + })) { + return SemIR::ErrorInst::InstId; + } auto decl_info = DeclInfo{.decl = clang_sema.LookupCopyingConstructor( class_decl, clang::Qualifiers::Const), .signature = {.num_params = 1}}; diff --git a/toolchain/check/testdata/interop/cpp/class/import/class.carbon b/toolchain/check/testdata/interop/cpp/class/import/class.carbon index 213b3d18976e..70d4b5ca136c 100644 --- a/toolchain/check/testdata/interop/cpp/class/import/class.carbon +++ b/toolchain/check/testdata/interop/cpp/class/import/class.carbon @@ -224,6 +224,34 @@ import Cpp library "template.h"; fn MyF(bar: Cpp.Bar(Cpp.X)*); //@dump-sem-ir-end +// --- fail_copy_witness_of_incomplete_class.carbon + +library "[[@TEST_NAME]]"; + +import Cpp inline ''' +class Class1; +'''; + +class Generic(x:! Core.Copy) { +} + +// CHECK:STDERR: fail_copy_witness_of_incomplete_class.carbon:[[@LINE+14]]:19: error: argument to C++ call has incomplete type `Cpp.Class1` [IncompleteTypeInCopyWitness] +// CHECK:STDERR: fn GenericUse(p2: Generic(Cpp.Class1)) { +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_copy_witness_of_incomplete_class.carbon:[[@LINE-9]]:7: note: class was forward declared here [ClassForwardDeclaredHere] +// CHECK:STDERR: class Class1; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_copy_witness_of_incomplete_class.carbon:[[@LINE-9]]:15: note: initializing generic parameter `x` declared here [InitializingGenericParam] +// CHECK:STDERR: class Generic(x:! Core.Copy) { +// CHECK:STDERR: ^~~~~~~~~~~~~ +// CHECK:STDERR: +// CHECK:STDERR: fail_copy_witness_of_incomplete_class.carbon:[[@LINE+4]]:15: warning: binding `p2` unused [UnusedBinding] +// CHECK:STDERR: fn GenericUse(p2: Generic(Cpp.Class1)) { +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn GenericUse(p2: Generic(Cpp.Class1)) { +} + // CHECK:STDOUT: --- import_declaration.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/diagnostics/kind.def b/toolchain/diagnostics/kind.def index 0a0d879e08c4..9e4f1cf11158 100644 --- a/toolchain/diagnostics/kind.def +++ b/toolchain/diagnostics/kind.def @@ -455,6 +455,7 @@ CARBON_DIAGNOSTIC_KIND(IncompleteTypeInAdaptDecl) CARBON_DIAGNOSTIC_KIND(IncompleteTypeInBaseDecl) CARBON_DIAGNOSTIC_KIND(IncompleteTypeInBindingDecl) CARBON_DIAGNOSTIC_KIND(IncompleteTypeInConversion) +CARBON_DIAGNOSTIC_KIND(IncompleteTypeInCopyWitness) CARBON_DIAGNOSTIC_KIND(IncompleteTypeInFieldDecl) CARBON_DIAGNOSTIC_KIND(IncompleteTypeInFunctionParam) CARBON_DIAGNOSTIC_KIND(IncompleteTypeInFunctionReturnType)