Index: include/llvm/CodeGen/DIE.h =================================================================== --- include/llvm/CodeGen/DIE.h +++ include/llvm/CodeGen/DIE.h @@ -759,7 +759,7 @@ /// /// \returns the DIEUnit that represents the compile or type unit that owns /// this DIE, or NULL if this DIE hasn't been added to a unit DIE. - const DIEUnit *getUnit() const; + DIEUnit *getUnit() const; void setOffset(unsigned O) { Offset = O; } void setSize(unsigned S) { Size = S; } Index: lib/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIE.cpp +++ lib/CodeGen/AsmPrinter/DIE.cpp @@ -211,7 +211,7 @@ return nullptr; } -const DIEUnit *DIE::getUnit() const { +DIEUnit *DIE::getUnit() const { const DIE *UnitDie = getUnitDie(); if (UnitDie) return UnitDie->Owner.dyn_cast(); Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1106,7 +1106,8 @@ if (SP->isDefinition()) return &SPDie; - applySubprogramAttributes(SP, SPDie); + static_cast(SPDie.getUnit()) + ->applySubprogramAttributes(SP, SPDie); return &SPDie; } Index: test/DebugInfo/X86/template_function_decl.ll =================================================================== --- test/DebugInfo/X86/template_function_decl.ll +++ test/DebugInfo/X86/template_function_decl.ll @@ -0,0 +1,153 @@ +; Checks that we correctly set DW_AT_decl_file attribute for +; template function declaration. When using full LTO we likely +; end up having multiple CUs in a single DWARF file, and it is +; possible that we add template function declaration DIE from +; CU#1 to structure type DIE from CU#2. In such case we should +; add source line attributes on behalf of CU#2, not CU#1 + +; Example source code used to generate this sample (C++) +; // File: inc1.h +; struct S { +; int foo; +; template T squared(T val) { return val * val; } +; }; +; +; // File: inc2.h +; struct S2 { int q, v; }; +; +; // File: foo.cpp +; #include "inc1.h" +; S s_foo; +; extern int bar(int); +; int main() { +; return bar(s_foo.foo); +; } +; +; // File: bar.cpp +; #include "inc2.h" +; #include "inc1.h" +; struct S gs_bar; +; struct S2 gs2_bar; +; int bar(int v) { +; return gs_bar.squared(v); +; } + +; RUN: llc -filetype=obj %s -o %t +; RUN: llvm-dwarfdump %t -o - | FileCheck %s + +; CHECK: DW_AT_linkage_name ("_ZN1S7squaredIiEET_S1_") +; CHECK-NEXT: DW_AT_name ("squared") +; CHECK-NEXT: DW_AT_decl_file ("{{.*}}inc1.h") +; CHECK-NEXT: DW_AT_decl_line (3) + +source_filename = "ld-temp.o" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.S = type { i32 } + +$_ZN1S7squaredIiEET_S1_ = comdat any + +@s_foo = internal global %struct.S zeroinitializer, align 4, !dbg !0 +@gs_bar = internal global %struct.S zeroinitializer, align 4, !dbg !11 + +; Function Attrs: noinline norecurse optnone uwtable +define dso_local i32 @main() !dbg !29 { + %1 = alloca i32, align 4 + store i32 0, i32* %1, align 4 + %2 = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s_foo, i32 0, i32 0), align 4, !dbg !32 + %3 = call i32 @_Z3bari(i32 %2), !dbg !33 + ret i32 %3, !dbg !34 +} + +; Function Attrs: noinline optnone uwtable +define internal i32 @_Z3bari(i32) !dbg !35 { + %2 = alloca i32, align 4 + store i32 %0, i32* %2, align 4 + call void @llvm.dbg.declare(metadata i32* %2, metadata !38, metadata !DIExpression()), !dbg !39 + %3 = load i32, i32* %2, align 4, !dbg !40 + %4 = call i32 @_ZN1S7squaredIiEET_S1_(%struct.S* @gs_bar, i32 %3), !dbg !41 + ret i32 %4, !dbg !42 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +; Function Attrs: noinline nounwind optnone uwtable +define internal i32 @_ZN1S7squaredIiEET_S1_(%struct.S*, i32) comdat align 2 !dbg !43 { + %3 = alloca %struct.S*, align 8 + %4 = alloca i32, align 4 + store %struct.S* %0, %struct.S** %3, align 8 + call void @llvm.dbg.declare(metadata %struct.S** %3, metadata !50, metadata !DIExpression()), !dbg !52 + store i32 %1, i32* %4, align 4 + call void @llvm.dbg.declare(metadata i32* %4, metadata !53, metadata !DIExpression()), !dbg !54 + %5 = load %struct.S*, %struct.S** %3, align 8 + %6 = load i32, i32* %4, align 4, !dbg !55 + %7 = load i32, i32* %4, align 4, !dbg !56 + %8 = mul nsw i32 %6, %7, !dbg !57 + ret i32 %8, !dbg !58 +} + +!llvm.dbg.cu = !{!2, !13} +!llvm.ident = !{!23, !23} +!llvm.module.flags = !{!24, !25, !26, !27, !28} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "s_foo", scope: !2, file: !3, line: 3, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (trunk 353925)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "foo.cpp", directory: "/home/evgeny/work/cpp_lexer/sample2") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !7, line: 1, size: 32, flags: DIFlagTypePassByValue | DIFlagTrivial, elements: !8, identifier: "_ZTS1S") +!7 = !DIFile(filename: "./inc1.h", directory: "/home/evgeny/work/cpp_lexer/sample2") +!8 = !{!9} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "foo", scope: !6, file: !7, line: 2, baseType: !10, size: 32) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression()) +!12 = distinct !DIGlobalVariable(name: "gs_bar", scope: !13, file: !14, line: 4, type: !6, isLocal: false, isDefinition: true) +!13 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !14, producer: "clang version 9.0.0 (trunk 353925)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !15, nameTableKind: None) +!14 = !DIFile(filename: "bar.cpp", directory: "/home/evgeny/work/cpp_lexer/sample2") +!15 = !{!11, !16} +!16 = !DIGlobalVariableExpression(var: !17, expr: !DIExpression()) +!17 = distinct !DIGlobalVariable(name: "gs2_bar", scope: !13, file: !14, line: 5, type: !18, isLocal: false, isDefinition: true) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S2", file: !19, line: 1, size: 64, flags: DIFlagTypePassByValue | DIFlagTrivial, elements: !20, identifier: "_ZTS2S2") +!19 = !DIFile(filename: "./inc2.h", directory: "/home/evgeny/work/cpp_lexer/sample2") +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "q", scope: !18, file: !19, line: 2, baseType: !10, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "v", scope: !18, file: !19, line: 2, baseType: !10, size: 32, offset: 32) +!23 = !{!"clang version 9.0.0 (trunk 353925)"} +!24 = !{i32 2, !"Dwarf Version", i32 4} +!25 = !{i32 2, !"Debug Info Version", i32 3} +!26 = !{i32 1, !"wchar_size", i32 4} +!27 = !{i32 1, !"ThinLTO", i32 0} +!28 = !{i32 1, !"EnableSplitLTOUnit", i32 0} +!29 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 6, type: !30, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) +!30 = !DISubroutineType(types: !31) +!31 = !{!10} +!32 = !DILocation(line: 7, column: 20, scope: !29) +!33 = !DILocation(line: 7, column: 10, scope: !29) +!34 = !DILocation(line: 7, column: 3, scope: !29) +!35 = distinct !DISubprogram(name: "bar", linkageName: "_Z3bari", scope: !14, file: !14, line: 7, type: !36, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !13, retainedNodes: !4) +!36 = !DISubroutineType(types: !37) +!37 = !{!10, !10} +!38 = !DILocalVariable(name: "v", arg: 1, scope: !35, file: !14, line: 7, type: !10) +!39 = !DILocation(line: 7, column: 13, scope: !35) +!40 = !DILocation(line: 8, column: 25, scope: !35) +!41 = !DILocation(line: 8, column: 17, scope: !35) +!42 = !DILocation(line: 8, column: 3, scope: !35) +!43 = distinct !DISubprogram(name: "squared", linkageName: "_ZN1S7squaredIiEET_S1_", scope: !6, file: !7, line: 3, type: !44, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !13, templateParams: !48, declaration: !47, retainedNodes: !4) +!44 = !DISubroutineType(types: !45) +!45 = !{!10, !46, !10} +!46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!47 = !DISubprogram(name: "squared", linkageName: "_ZN1S7squaredIiEET_S1_", scope: !6, file: !7, line: 3, type: !44, scopeLine: 3, flags: DIFlagPrototyped, spFlags: 0, templateParams: !48) +!48 = !{!49} +!49 = !DITemplateTypeParameter(name: "T", type: !10) +!50 = !DILocalVariable(name: "this", arg: 1, scope: !43, type: !51, flags: DIFlagArtificial | DIFlagObjectPointer) +!51 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) +!52 = !DILocation(line: 0, scope: !43) +!53 = !DILocalVariable(name: "val", arg: 2, scope: !43, file: !7, line: 3, type: !10) +!54 = !DILocation(line: 3, column: 34, scope: !43) +!55 = !DILocation(line: 3, column: 48, scope: !43) +!56 = !DILocation(line: 3, column: 54, scope: !43) +!57 = !DILocation(line: 3, column: 52, scope: !43) +!58 = !DILocation(line: 3, column: 41, scope: !43)