diff --git a/toolchain/check/cpp/import.cpp b/toolchain/check/cpp/import.cpp index 9047b445ef56..0de21db25606 100644 --- a/toolchain/check/cpp/import.cpp +++ b/toolchain/check/cpp/import.cpp @@ -2143,6 +2143,15 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, builder.Note(loc_id, InCppNameLookup, name_id); }); + if (auto class_decl = context.insts().TryGetAs( + context.name_scopes().Get(scope_id).inst_id()); + class_decl.has_value()) { + if (!context.types().IsComplete( + context.classes().Get(class_decl->class_id).self_type_id)) { + return SemIR::ScopeLookupResult::MakeError(); + } + } + auto lookup = ClangLookupName(context, scope_id, name_id); if (!lookup) { SemIR::InstId builtin_inst_id = diff --git a/toolchain/check/testdata/interop/cpp/class/constructor.carbon b/toolchain/check/testdata/interop/cpp/class/constructor.carbon index 52eeeb5b8b70..30d1da90fc1c 100644 --- a/toolchain/check/testdata/interop/cpp/class/constructor.carbon +++ b/toolchain/check/testdata/interop/cpp/class/constructor.carbon @@ -203,6 +203,32 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// Trying to call a constructor of an incomplete class +// ============================================================================ + +// --- incomplete.h + +class C; + +// --- fail_import_incomplete.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "incomplete.h"; + +fn F() { + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:4: error: member access into incomplete class `Cpp.C` [QualifiedExprInIncompleteClassScope] + // CHECK:STDERR: Cpp.C.C(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./incomplete.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class C; + // CHECK:STDERR: ^ + // CHECK:STDERR: + Cpp.C.C(); +} + // CHECK:STDOUT: --- import_default.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/testdata/interop/cpp/function/class.carbon b/toolchain/check/testdata/interop/cpp/function/class.carbon index a65333bfe403..8808f557e63b 100644 --- a/toolchain/check/testdata/interop/cpp/function/class.carbon +++ b/toolchain/check/testdata/interop/cpp/function/class.carbon @@ -341,6 +341,32 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// Incomplete class +// ============================================================================ + +// --- incomplete.h + +class Incomplete; + +// --- fail_import_incomplete.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "incomplete.h"; + +fn F() { + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:3: error: member access into incomplete class `Cpp.Incomplete` [QualifiedExprInIncompleteClassScope] + // CHECK:STDERR: Cpp.Incomplete.foo(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./incomplete.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class Incomplete; + // CHECK:STDERR: ^ + // CHECK:STDERR: + Cpp.Incomplete.foo(); +} + // ============================================================================ // Pointer to forward-declared class as parameter type // ============================================================================ diff --git a/toolchain/check/testdata/interop/cpp/function/struct.carbon b/toolchain/check/testdata/interop/cpp/function/struct.carbon index 5276346fee7f..0787e332602f 100644 --- a/toolchain/check/testdata/interop/cpp/function/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/function/struct.carbon @@ -339,6 +339,32 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// Incomplete struct +// ============================================================================ + +// --- incomplete.h + +struct Incomplete; + +// --- fail_import_incomplete.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "incomplete.h"; + +fn F() { + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:3: error: member access into incomplete class `Cpp.Incomplete` [QualifiedExprInIncompleteClassScope] + // CHECK:STDERR: Cpp.Incomplete.foo(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./incomplete.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: struct Incomplete; + // CHECK:STDERR: ^ + // CHECK:STDERR: + Cpp.Incomplete.foo(); +} + // ============================================================================ // Pointer to forward-declared struct as parameter type // ============================================================================ diff --git a/toolchain/check/testdata/interop/cpp/function/union.carbon b/toolchain/check/testdata/interop/cpp/function/union.carbon index 7d62ae9bb298..7ee76770a426 100644 --- a/toolchain/check/testdata/interop/cpp/function/union.carbon +++ b/toolchain/check/testdata/interop/cpp/function/union.carbon @@ -302,6 +302,32 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// Incomplete union +// ============================================================================ + +// --- incomplete.h + +union Incomplete; + +// --- fail_import_incomplete.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "incomplete.h"; + +fn F() { + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:3: error: member access into incomplete class `Cpp.Incomplete` [QualifiedExprInIncompleteClassScope] + // CHECK:STDERR: Cpp.Incomplete.foo(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./incomplete.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: union Incomplete; + // CHECK:STDERR: ^ + // CHECK:STDERR: + Cpp.Incomplete.foo(); +} + // ============================================================================ // Pointer to forward-declared union as parameter type // ============================================================================