Skip to content

Commit 868c4b7

Browse files
authored
C++ interop: Don't crash when looking up names inside an incomplete C++ class/struct/union (#6096)
Only do the lookup when the class is complete. Before this change we crash in `Sema::LookupQualifiedName()` on `Declaration context must already be complete!`.
1 parent d137cbe commit 868c4b7

File tree

5 files changed

+113
-0
lines changed

5 files changed

+113
-0
lines changed

toolchain/check/cpp/import.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,6 +2143,15 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id,
21432143
builder.Note(loc_id, InCppNameLookup, name_id);
21442144
});
21452145

2146+
if (auto class_decl = context.insts().TryGetAs<SemIR::ClassDecl>(
2147+
context.name_scopes().Get(scope_id).inst_id());
2148+
class_decl.has_value()) {
2149+
if (!context.types().IsComplete(
2150+
context.classes().Get(class_decl->class_id).self_type_id)) {
2151+
return SemIR::ScopeLookupResult::MakeError();
2152+
}
2153+
}
2154+
21462155
auto lookup = ClangLookupName(context, scope_id, name_id);
21472156
if (!lookup) {
21482157
SemIR::InstId builtin_inst_id =

toolchain/check/testdata/interop/cpp/class/constructor.carbon

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,32 @@ fn F() {
203203
//@dump-sem-ir-end
204204
}
205205

206+
// ============================================================================
207+
// Trying to call a constructor of an incomplete class
208+
// ============================================================================
209+
210+
// --- incomplete.h
211+
212+
class C;
213+
214+
// --- fail_import_incomplete.carbon
215+
216+
library "[[@TEST_NAME]]";
217+
218+
import Cpp library "incomplete.h";
219+
220+
fn F() {
221+
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:4: error: member access into incomplete class `Cpp.C` [QualifiedExprInIncompleteClassScope]
222+
// CHECK:STDERR: Cpp.C.C();
223+
// CHECK:STDERR: ^~~~~~~
224+
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
225+
// CHECK:STDERR: ./incomplete.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere]
226+
// CHECK:STDERR: class C;
227+
// CHECK:STDERR: ^
228+
// CHECK:STDERR:
229+
Cpp.C.C();
230+
}
231+
206232
// CHECK:STDOUT: --- import_default.carbon
207233
// CHECK:STDOUT:
208234
// CHECK:STDOUT: constants {

toolchain/check/testdata/interop/cpp/function/class.carbon

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,32 @@ fn F() {
341341
//@dump-sem-ir-end
342342
}
343343

344+
// ============================================================================
345+
// Incomplete class
346+
// ============================================================================
347+
348+
// --- incomplete.h
349+
350+
class Incomplete;
351+
352+
// --- fail_import_incomplete.carbon
353+
354+
library "[[@TEST_NAME]]";
355+
356+
import Cpp library "incomplete.h";
357+
358+
fn F() {
359+
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:3: error: member access into incomplete class `Cpp.Incomplete` [QualifiedExprInIncompleteClassScope]
360+
// CHECK:STDERR: Cpp.Incomplete.foo();
361+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
362+
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
363+
// CHECK:STDERR: ./incomplete.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere]
364+
// CHECK:STDERR: class Incomplete;
365+
// CHECK:STDERR: ^
366+
// CHECK:STDERR:
367+
Cpp.Incomplete.foo();
368+
}
369+
344370
// ============================================================================
345371
// Pointer to forward-declared class as parameter type
346372
// ============================================================================

toolchain/check/testdata/interop/cpp/function/struct.carbon

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,32 @@ fn F() {
339339
//@dump-sem-ir-end
340340
}
341341

342+
// ============================================================================
343+
// Incomplete struct
344+
// ============================================================================
345+
346+
// --- incomplete.h
347+
348+
struct Incomplete;
349+
350+
// --- fail_import_incomplete.carbon
351+
352+
library "[[@TEST_NAME]]";
353+
354+
import Cpp library "incomplete.h";
355+
356+
fn F() {
357+
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:3: error: member access into incomplete class `Cpp.Incomplete` [QualifiedExprInIncompleteClassScope]
358+
// CHECK:STDERR: Cpp.Incomplete.foo();
359+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
360+
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
361+
// CHECK:STDERR: ./incomplete.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere]
362+
// CHECK:STDERR: struct Incomplete;
363+
// CHECK:STDERR: ^
364+
// CHECK:STDERR:
365+
Cpp.Incomplete.foo();
366+
}
367+
342368
// ============================================================================
343369
// Pointer to forward-declared struct as parameter type
344370
// ============================================================================

toolchain/check/testdata/interop/cpp/function/union.carbon

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,32 @@ fn F() {
302302
//@dump-sem-ir-end
303303
}
304304

305+
// ============================================================================
306+
// Incomplete union
307+
// ============================================================================
308+
309+
// --- incomplete.h
310+
311+
union Incomplete;
312+
313+
// --- fail_import_incomplete.carbon
314+
315+
library "[[@TEST_NAME]]";
316+
317+
import Cpp library "incomplete.h";
318+
319+
fn F() {
320+
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:3: error: member access into incomplete class `Cpp.Incomplete` [QualifiedExprInIncompleteClassScope]
321+
// CHECK:STDERR: Cpp.Incomplete.foo();
322+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
323+
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
324+
// CHECK:STDERR: ./incomplete.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere]
325+
// CHECK:STDERR: union Incomplete;
326+
// CHECK:STDERR: ^
327+
// CHECK:STDERR:
328+
Cpp.Incomplete.foo();
329+
}
330+
305331
// ============================================================================
306332
// Pointer to forward-declared union as parameter type
307333
// ============================================================================

0 commit comments

Comments
 (0)