diff --git a/toolchain/lower/function_context.cpp b/toolchain/lower/function_context.cpp index 7f23e9199215..ce7e0ad1229a 100644 --- a/toolchain/lower/function_context.cpp +++ b/toolchain/lower/function_context.cpp @@ -153,9 +153,16 @@ auto FunctionContext::GetDebugLoc(SemIR::InstId inst_id) -> llvm::DebugLoc { return llvm::DebugLoc(); } auto loc = file_context_->GetLocForDI(inst_id); - CARBON_CHECK(loc.filename == di_subprogram_->getFile()->getFilename(), - "Instructions located in a different file from their " - "enclosing function aren't handled yet"); + if (loc.filename != di_subprogram_->getFile()->getFilename()) { + // Location is from a different file. We can't represent that directly + // within the scope of this function's subprogram, and we don't want to + // generate a new subprogram, so just discard the location information. This + // happens for thunks when emitting the portion of the thunk that is + // duplicated from the original signature. + // + // TODO: Handle this case better. + return llvm::DebugLoc(); + } return llvm::DILocation::get(builder_.getContext(), loc.line_number, loc.column_number, di_subprogram_); } diff --git a/toolchain/lower/testdata/impl/import_thunk.carbon b/toolchain/lower/testdata/impl/import_thunk.carbon index e4eb51ccdcdd..4cf5e6a97841 100644 --- a/toolchain/lower/testdata/impl/import_thunk.carbon +++ b/toolchain/lower/testdata/impl/import_thunk.carbon @@ -31,7 +31,7 @@ impl () as I { fn F(b: B) -> B { return {.b = b.b}; } } -// --- call.carbon +// --- call_thunk.carbon library "[[@TEST_NAME]]"; @@ -41,6 +41,29 @@ fn Test(a: A) -> C { return ().(I.F)(a); } +// --- thunk_for_imported_interface.carbon + +library "[[@TEST_NAME]]"; + +import library "thunk"; + +class X {} + +impl X as I { + fn F(b: B) -> B { return {.b = b.b}; } +} + +// --- call_thunk_for_imported_interface.carbon + +library "[[@TEST_NAME]]"; + +import library "thunk"; +import library "thunk_for_imported_interface"; + +fn Test(a: A) -> C { + return X.(I.F)(a); +} + // CHECK:STDOUT: ; ModuleID = 'thunk.carbon' // CHECK:STDOUT: source_filename = "thunk.carbon" // CHECK:STDOUT: @@ -106,8 +129,8 @@ fn Test(a: A) -> C { // CHECK:STDOUT: !18 = distinct !DISubprogram(name: "F", linkageName: "_CF:thunk.61ea2aba74ab3bf1:I.Main", scope: null, file: !3, line: 20, type: !5, spFlags: DISPFlagDefinition, unit: !2) // CHECK:STDOUT: !19 = !DILocation(line: 20, column: 3, scope: !18) // CHECK:STDOUT: !20 = !DILocation(line: 16, column: 8, scope: !18) -// CHECK:STDOUT: ; ModuleID = 'call.carbon' -// CHECK:STDOUT: source_filename = "call.carbon" +// CHECK:STDOUT: ; ModuleID = 'call_thunk.carbon' +// CHECK:STDOUT: source_filename = "call_thunk.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define void @_CTest.Main(ptr sret({ i32 }) %return, ptr %a) !dbg !4 { // CHECK:STDOUT: entry: @@ -123,9 +146,74 @@ fn Test(a: A) -> C { // CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} // CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} // CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) -// CHECK:STDOUT: !3 = !DIFile(filename: "call.carbon", directory: "") +// CHECK:STDOUT: !3 = !DIFile(filename: "call_thunk.carbon", directory: "") // CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Test", linkageName: "_CTest.Main", scope: null, file: !3, line: 6, type: !5, spFlags: DISPFlagDefinition, unit: !2) // CHECK:STDOUT: !5 = !DISubroutineType(types: !6) // CHECK:STDOUT: !6 = !{} // CHECK:STDOUT: !7 = !DILocation(line: 7, column: 10, scope: !4) // CHECK:STDOUT: !8 = !DILocation(line: 7, column: 3, scope: !4) +// CHECK:STDOUT: ; ModuleID = 'thunk_for_imported_interface.carbon' +// CHECK:STDOUT: source_filename = "thunk_for_imported_interface.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define void @"_CF.X.Main:I.Main"(ptr sret({ i32 }) %return, ptr %b) !dbg !4 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc9_35.1.b = getelementptr inbounds nuw { i32 }, ptr %b, i32 0, i32 0, !dbg !7 +// CHECK:STDOUT: %.loc9_35.2 = load i32, ptr %.loc9_35.1.b, align 4, !dbg !7 +// CHECK:STDOUT: %.loc9_37.2.b = getelementptr inbounds nuw { i32 }, ptr %return, i32 0, i32 0, !dbg !8 +// CHECK:STDOUT: store i32 %.loc9_35.2, ptr %.loc9_37.2.b, align 4, !dbg !8 +// CHECK:STDOUT: ret void, !dbg !9 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define void @"_CF:thunk.X.Main:I.Main"(ptr sret({ i32 }) %return, ptr %a) !dbg !10 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc9_19.1.temp = alloca { i32 }, align 8, !dbg !11 +// CHECK:STDOUT: %.2.temp = alloca { i32 }, align 8 +// CHECK:STDOUT: call void @"_CConvert.A.Main:ImplicitAs.Core"(ptr %.2.temp, ptr %a) +// CHECK:STDOUT: call void @"_CF.X.Main:I.Main"(ptr %.loc9_19.1.temp, ptr %.2.temp), !dbg !11 +// CHECK:STDOUT: %.loc9_19.2.temp = alloca { i32 }, align 8, !dbg !11 +// CHECK:STDOUT: call void @"_CConvert.B.Main:ImplicitAs.Core"(ptr %.loc9_19.2.temp, ptr %.loc9_19.1.temp), !dbg !11 +// CHECK:STDOUT: ret void, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @"_CConvert.A.Main:ImplicitAs.Core"(ptr sret({ i32 }), ptr) +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @"_CConvert.B.Main:ImplicitAs.Core"(ptr sret({ i32 }), ptr) +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1} +// CHECK:STDOUT: !llvm.dbg.cu = !{!2} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !3 = !DIFile(filename: "thunk_for_imported_interface.carbon", directory: "") +// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "F", linkageName: "_CF.X.Main:I.Main", scope: null, file: !3, line: 9, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !5 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !6 = !{} +// CHECK:STDOUT: !7 = !DILocation(line: 9, column: 34, scope: !4) +// CHECK:STDOUT: !8 = !DILocation(line: 9, column: 28, scope: !4) +// CHECK:STDOUT: !9 = !DILocation(line: 9, column: 21, scope: !4) +// CHECK:STDOUT: !10 = distinct !DISubprogram(name: "F", linkageName: "_CF:thunk.X.Main:I.Main", scope: null, file: !3, line: 9, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !11 = !DILocation(line: 9, column: 3, scope: !10) +// CHECK:STDOUT: ; ModuleID = 'call_thunk_for_imported_interface.carbon' +// CHECK:STDOUT: source_filename = "call_thunk_for_imported_interface.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CTest.Main(ptr sret({ i32 }) %return, ptr %a) !dbg !4 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_CF:thunk.X.Main:I.Main"(ptr %return, ptr %a), !dbg !7 +// CHECK:STDOUT: ret void, !dbg !8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @"_CF:thunk.X.Main:I.Main"(ptr sret({ i32 }), ptr) +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1} +// CHECK:STDOUT: !llvm.dbg.cu = !{!2} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !3 = !DIFile(filename: "call_thunk_for_imported_interface.carbon", directory: "") +// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Test", linkageName: "_CTest.Main", scope: null, file: !3, line: 7, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !5 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !6 = !{} +// CHECK:STDOUT: !7 = !DILocation(line: 8, column: 10, scope: !4) +// CHECK:STDOUT: !8 = !DILocation(line: 8, column: 3, scope: !4)