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,123 @@ +; Checks that DW_AT_decl_file attribute is correctly set 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 { +; template T tmpfn() { return T(42); } +; }; +; +; // File: inc2.h +; struct S2 { int dummy; }; +; +; // File: foo.cpp +; #include "inc1.h" +; S s_foo; +; extern int bar(); +; int main() {return bar(); } +; +; // File: bar.cpp +; #include "inc2.h" +; #include "inc1.h" +; struct S gs_bar; +; struct S2 gs2_bar; +; int bar() { +; return gs_bar.tmpfn(); +; } + +; RUN: llc -filetype=obj %s -o %t +; RUN: llvm-dwarfdump %t -o - | FileCheck %s + +; CHECK: DW_AT_linkage_name ("_ZN1S5tmpfnIiEET_v") +; CHECK-NEXT: DW_AT_name ("tmpfn") +; CHECK-NEXT: DW_AT_decl_file ("{{.*}}inc1.h") +; CHECK-NEXT: DW_AT_decl_line (2) + +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.0 = type { i8 } + +$_ZN1S5tmpfnIiEET_v = comdat any + +@gs_bar = internal global %struct.S.0 zeroinitializer, align 1, !dbg !0 + +; Function Attrs: noinline norecurse optnone uwtable +define dso_local i32 @main() !dbg !27 { + %1 = alloca i32, align 4 + store i32 0, i32* %1, align 4 + %2 = call i32 @_Z3barv(), !dbg !29 + ret i32 %2, !dbg !30 +} + +; Function Attrs: noinline optnone uwtable +define internal i32 @_Z3barv() !dbg !31 { + %1 = call i32 @_ZN1S5tmpfnIiEET_v(%struct.S.0* @gs_bar), !dbg !32 + ret i32 %1, !dbg !33 +} + +; Function Attrs: noinline nounwind optnone uwtable +define internal i32 @_ZN1S5tmpfnIiEET_v(%struct.S.0*) comdat align 2 !dbg !34 { + %2 = alloca %struct.S.0*, align 8 + store %struct.S.0* %0, %struct.S.0** %2, align 8 + call void @llvm.dbg.declare(metadata %struct.S.0** %2, metadata !41, metadata !DIExpression()), !dbg !43 + %3 = load %struct.S.0*, %struct.S.0** %2, align 8 + ret i32 42, !dbg !44 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) +!llvm.dbg.cu = !{!16, !2} +!llvm.ident = !{!21, !21} +!llvm.module.flags = !{!22, !23, !24, !25, !26} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "gs_bar", scope: !2, file: !3, line: 4, type: !14, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (trunk 354767)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !7, nameTableKind: None) +!3 = !DIFile(filename: "bar.cpp", directory: "/home/evgeny/work/cpp_lexer/sample2") +!4 = !{} +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{!0, !8} +!8 = !DIGlobalVariableExpression(var: !9, expr: !DIExpression()) +!9 = distinct !DIGlobalVariable(name: "gs2_bar", scope: !2, file: !3, line: 5, type: !10, isLocal: false, isDefinition: true) +!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S2", file: !11, line: 1, size: 32, flags: DIFlagTypePassByValue | DIFlagTrivial, elements: !12, identifier: "_ZTS2S2") +!11 = !DIFile(filename: "./inc2.h", directory: "/home/evgeny/work/cpp_lexer/sample2") +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "dummy", scope: !10, file: !11, line: 2, baseType: !6, size: 32) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !15, line: 1, size: 8, flags: DIFlagTypePassByValue | DIFlagTrivial, elements: !4, identifier: "_ZTS1S") +!15 = !DIFile(filename: "./inc1.h", directory: "/home/evgeny/work/cpp_lexer/sample2") +!16 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !17, producer: "clang version 9.0.0 (trunk 354767)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !18, nameTableKind: None) +!17 = !DIFile(filename: "foo.cpp", directory: "/home/evgeny/work/cpp_lexer/sample2") +!18 = !{!19} +!19 = !DIGlobalVariableExpression(var: !20, expr: !DIExpression()) +!20 = distinct !DIGlobalVariable(name: "s_foo", scope: !16, file: !17, line: 3, type: !14, isLocal: false, isDefinition: true) +!21 = !{!"clang version 9.0.0 (trunk 354767)"} +!22 = !{i32 2, !"Dwarf Version", i32 4} +!23 = !{i32 2, !"Debug Info Version", i32 3} +!24 = !{i32 1, !"wchar_size", i32 4} +!25 = !{i32 1, !"ThinLTO", i32 0} +!26 = !{i32 1, !"EnableSplitLTOUnit", i32 0} +!27 = distinct !DISubprogram(name: "main", scope: !17, file: !17, line: 6, type: !28, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !16, retainedNodes: !4) +!28 = !DISubroutineType(types: !5) +!29 = !DILocation(line: 7, column: 10, scope: !27) +!30 = !DILocation(line: 7, column: 3, scope: !27) +!31 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !3, file: !3, line: 7, type: !28, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) +!32 = !DILocation(line: 8, column: 17, scope: !31) +!33 = !DILocation(line: 8, column: 3, scope: !31) +!34 = distinct !DISubprogram(name: "tmpfn", linkageName: "_ZN1S5tmpfnIiEET_v", scope: !14, file: !15, line: 2, type: !35, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, templateParams: !39, declaration: !38, retainedNodes: !4) +!35 = !DISubroutineType(types: !36) +!36 = !{!6, !37} +!37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!38 = !DISubprogram(name: "tmpfn", linkageName: "_ZN1S5tmpfnIiEET_v", scope: !14, file: !15, line: 2, type: !35, scopeLine: 2, flags: DIFlagPrototyped, spFlags: 0, templateParams: !39) +!39 = !{!40} +!40 = !DITemplateTypeParameter(name: "T", type: !6) +!41 = !DILocalVariable(name: "this", arg: 1, scope: !34, type: !42, flags: DIFlagArtificial | DIFlagObjectPointer) +!42 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!43 = !DILocation(line: 0, scope: !34) +!44 = !DILocation(line: 2, column: 34, scope: !34)