https://github.com/HaohaiWen updated https://github.com/llvm/llvm-project/pull/189794
>From e2151dd480216fabcf562cc4f44dec648422b5d2 Mon Sep 17 00:00:00 2001 From: "Wen, Haohai" <[email protected]> Date: Wed, 1 Apr 2026 10:19:16 +0800 Subject: [PATCH 1/2] [clang] Set linkage name for atexit destructor debug info Compiler-generated atexit destructors for global variables were missing DW_AT_linkage_name in their DWARF debug info. Different template instantiations of the same variable all shared the same unmangled name, making them indistinguishable in the debug info. Set LinkageName to Fn->getName() (the mangled IR function name) for the VarDecl/DynamicInitKind case, matching what other compiler-generated functions already do. --- clang/lib/CodeGen/CGDebugInfo.cpp | 1 + .../debug-info-atexit-linkage-name.cpp | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 clang/test/CodeGenCXX/debug-info-atexit-linkage-name.cpp diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 0fd17b98570fc..05e7d4b0a025b 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -4907,6 +4907,7 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, // This is a global initializer or atexit destructor for a global variable. Name = getDynamicInitializerName(cast<VarDecl>(D), GD.getDynamicInitKind(), Fn); + LinkageName = Fn->getName(); } else { Name = Fn->getName(); diff --git a/clang/test/CodeGenCXX/debug-info-atexit-linkage-name.cpp b/clang/test/CodeGenCXX/debug-info-atexit-linkage-name.cpp new file mode 100644 index 0000000000000..5c89dc4300a26 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-atexit-linkage-name.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple x86_64-windows-msvc -debug-info-kind=limited -emit-llvm %s -o - | \ +// RUN: FileCheck %s + +// Verify that compiler-generated atexit destructors for global variables have +// a non-empty linkageName in their DISubprogram. Without this, different +// template instantiations would be indistinguishable in the debug info. + +struct Foo { + ~Foo(); +}; + +template <typename T> +struct Bar { + static Foo &get() { + static Foo instance; + return instance; + } +}; + +void use() { + Bar<int>::get(); + Bar<float>::get(); +} + +// Both atexit destructors should have distinct linkageNames. +// CHECK-DAG: distinct !DISubprogram({{.*}}linkageName: "??__Finstance@?2??get@?$Bar@H@@SAAEAUFoo@@XZ@YAXXZ" +// CHECK-DAG: distinct !DISubprogram({{.*}}linkageName: "??__Finstance@?2??get@?$Bar@M@@SAAEAUFoo@@XZ@YAXXZ" >From 3a285727c6f87c6ff7349e41587cc9818259fa3d Mon Sep 17 00:00:00 2001 From: "Wen, Haohai" <[email protected]> Date: Thu, 2 Apr 2026 17:38:09 +0800 Subject: [PATCH 2/2] [clang][DebugInfo] Set linkage name for dynamic initializer/destructor debug info Compiler-generated dynamic initializers and atexit destructors for global variables were missing DW_AT_linkage_name in their DWARF debug info. For CodeView targets, different template instantiations of the same variable all shared the same human-readable name, making them indistinguishable in the debug info. Set LinkageName to Fn->getName() (the mangled IR function name) for the VarDecl/DynamicInitKind case, matching what other compiler-generated functions already do. --- .../debug-info-atexit-linkage-name.cpp | 27 ------------------ clang/test/DebugInfo/CXX/aix-static-init.cpp | 4 +-- clang/test/DebugInfo/CXX/atexit-stub.cpp | 2 +- clang/test/DebugInfo/CXX/global-ctor-dtor.cpp | 28 +++++++++---------- 4 files changed, 17 insertions(+), 44 deletions(-) delete mode 100644 clang/test/CodeGenCXX/debug-info-atexit-linkage-name.cpp diff --git a/clang/test/CodeGenCXX/debug-info-atexit-linkage-name.cpp b/clang/test/CodeGenCXX/debug-info-atexit-linkage-name.cpp deleted file mode 100644 index 5c89dc4300a26..0000000000000 --- a/clang/test/CodeGenCXX/debug-info-atexit-linkage-name.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-windows-msvc -debug-info-kind=limited -emit-llvm %s -o - | \ -// RUN: FileCheck %s - -// Verify that compiler-generated atexit destructors for global variables have -// a non-empty linkageName in their DISubprogram. Without this, different -// template instantiations would be indistinguishable in the debug info. - -struct Foo { - ~Foo(); -}; - -template <typename T> -struct Bar { - static Foo &get() { - static Foo instance; - return instance; - } -}; - -void use() { - Bar<int>::get(); - Bar<float>::get(); -} - -// Both atexit destructors should have distinct linkageNames. -// CHECK-DAG: distinct !DISubprogram({{.*}}linkageName: "??__Finstance@?2??get@?$Bar@H@@SAAEAUFoo@@XZ@YAXXZ" -// CHECK-DAG: distinct !DISubprogram({{.*}}linkageName: "??__Finstance@?2??get@?$Bar@M@@SAAEAUFoo@@XZ@YAXXZ" diff --git a/clang/test/DebugInfo/CXX/aix-static-init.cpp b/clang/test/DebugInfo/CXX/aix-static-init.cpp index 6453e4379ae9a..b42602372041e 100644 --- a/clang/test/DebugInfo/CXX/aix-static-init.cpp +++ b/clang/test/DebugInfo/CXX/aix-static-init.cpp @@ -52,10 +52,10 @@ X v; // CHECK: ret void // CHECK: } -// CHECK: ![[DBGVAR16]] = distinct !DISubprogram(name: "__cxx_global_var_init", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, type: !{{[0-9]+}}, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}) +// CHECK: ![[DBGVAR16]] = distinct !DISubprogram(name: "__cxx_global_var_init", linkageName: "__cxx_global_var_init", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, type: !{{[0-9]+}}, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}) // CHECK: ![[DBGVAR19]] = !DILocation(line: 14, column: 3, scope: ![[DBGVAR16]]) // CHECK: ![[DBGVAR19b]] = !DILocation(line: 0, scope: ![[DBGVAR16]]) -// CHECK: ![[DBGVAR20]] = distinct !DISubprogram(name: "__dtor_v", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 14, type: !{{[0-9]+}}, scopeLine: 14, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}) +// CHECK: ![[DBGVAR20]] = distinct !DISubprogram(name: "__dtor_v", linkageName: "__dtor_v", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 14, type: !{{[0-9]+}}, scopeLine: 14, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}) // CHECK: ![[DBGVAR21b]] = !DILocation(line: 0, scope: ![[DBGVAR20]]) // CHECK: ![[DBGVAR21]] = !DILocation(line: 14, column: 3, scope: ![[DBGVAR20]]) // CHECK: ![[DBGVAR22]] = distinct !DISubprogram(linkageName: "__finalize_v", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 14, type: !{{[0-9]+}}, scopeLine: 14, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}) diff --git a/clang/test/DebugInfo/CXX/atexit-stub.cpp b/clang/test/DebugInfo/CXX/atexit-stub.cpp index ca9bc3a13a1e4..838f70179fb08 100644 --- a/clang/test/DebugInfo/CXX/atexit-stub.cpp +++ b/clang/test/DebugInfo/CXX/atexit-stub.cpp @@ -17,6 +17,6 @@ c<B> *d() { // CHECK: define internal void @"??__Ff@?1??d@@YAPEAU?$c@UB@@@@XZ@YAXXZ"() // CHECK-SAME: !dbg ![[SUBPROGRAM:[0-9]+]] { // CHECK: call void @"??1?$c@UB@@@@QEAA@XZ"(ptr @"?f@?1??d@@YAPEAU?$c@UB@@@@XZ@4U2@A"), !dbg ![[LOCATION:[0-9]+]] -// CHECK: ![[SUBPROGRAM]] = distinct !DISubprogram(name: "`dynamic atexit destructor for 'f'" +// CHECK: ![[SUBPROGRAM]] = distinct !DISubprogram(name: "`dynamic atexit destructor for 'f'", linkageName: "??__Ff@?1??d@@YAPEAU?$c@UB@@@@XZ@YAXXZ" // CHECK-SAME: flags: DIFlagArtificial // CHECK: ![[LOCATION]] = !DILocation(line: 0, scope: ![[SUBPROGRAM]]) diff --git a/clang/test/DebugInfo/CXX/global-ctor-dtor.cpp b/clang/test/DebugInfo/CXX/global-ctor-dtor.cpp index 62647615a3dd6..a988a28aeae7f 100644 --- a/clang/test/DebugInfo/CXX/global-ctor-dtor.cpp +++ b/clang/test/DebugInfo/CXX/global-ctor-dtor.cpp @@ -29,25 +29,25 @@ template <typename U> A FooTpl<T>::sdm_tpl(sizeof(U) + sizeof(T)); template A FooTpl<int>::sdm_tpl<int>; -// CHECK-NOKEXT: !DISubprogram(name: "__cxx_global_var_init",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-NOKEXT: !DISubprogram(name: "__dtor_glob",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-NOKEXT: !DISubprogram(name: "__cxx_global_var_init.1",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-NOKEXT: !DISubprogram(name: "__cxx_global_array_dtor",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-NOKEXT: !DISubprogram(name: "__dtor_array",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-NOKEXT: !DISubprogram(name: "__dtor__ZZ3foovE4stat",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-NOKEXT: !DISubprogram(name: "__cxx_global_var_init", linkageName: "__cxx_global_var_init",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-NOKEXT: !DISubprogram(name: "__dtor_glob", linkageName: "__dtor_glob",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-NOKEXT: !DISubprogram(name: "__cxx_global_var_init.1", linkageName: "__cxx_global_var_init.1",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-NOKEXT: !DISubprogram(name: "__cxx_global_array_dtor", linkageName: "__cxx_global_array_dtor",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-NOKEXT: !DISubprogram(name: "__dtor_array", linkageName: "__dtor_array",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-NOKEXT: !DISubprogram(name: "__dtor__ZZ3foovE4stat", linkageName: "__dtor__ZZ3foovE4stat",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition // CHECK-NOKEXT: !DISubprogram({{.*}} DISPFlagLocalToUnit | DISPFlagDefinition // CHECK-KEXT: !DISubprogram({{.*}} DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-MSVC: !DISubprogram(name: "`dynamic initializer for 'glob'",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-MSVC: !DISubprogram(name: "`dynamic atexit destructor for 'glob'",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-MSVC: !DISubprogram(name: "`dynamic initializer for 'array'",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-MSVC: !DISubprogram(name: "__cxx_global_array_dtor",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-MSVC: !DISubprogram(name: "`dynamic atexit destructor for 'array'",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-MSVC: !DISubprogram(name: "`dynamic atexit destructor for 'stat'",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-MSVC: !DISubprogram(name: "`dynamic initializer for 'glob'", linkageName: "??__Eglob@@YAXXZ",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-MSVC: !DISubprogram(name: "`dynamic atexit destructor for 'glob'", linkageName: "??__Fglob@@YAXXZ",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-MSVC: !DISubprogram(name: "`dynamic initializer for 'array'", linkageName: "??__Earray@@YAXXZ",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-MSVC: !DISubprogram(name: "__cxx_global_array_dtor", linkageName: "__cxx_global_array_dtor",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-MSVC: !DISubprogram(name: "`dynamic atexit destructor for 'array'", linkageName: "??__Farray@@YAXXZ",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-MSVC: !DISubprogram(name: "`dynamic atexit destructor for 'stat'", linkageName: "??__Fstat@?1??foo@@YAXXZ@YAXXZ",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition // MSVC does weird stuff when templates are involved, so we don't match exactly, // but these names are reasonable. // FIXME: These should not be marked DISPFlagLocalToUnit. -// CHECK-MSVC: !DISubprogram(name: "FooTpl<int>::`dynamic initializer for 'sdm_tpl<int>'",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK-MSVC: !DISubprogram(name: "FooTpl<int>::`dynamic atexit destructor for 'sdm_tpl<int>'",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-MSVC: !DISubprogram(name: "FooTpl<int>::`dynamic initializer for 'sdm_tpl<int>'", linkageName: "??__E??$sdm_tpl@H@?$FooTpl@H@@2VA@@A@@YAXXZ",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK-MSVC: !DISubprogram(name: "FooTpl<int>::`dynamic atexit destructor for 'sdm_tpl<int>'", linkageName: "??__F??$sdm_tpl@H@?$FooTpl@H@@2VA@@A@@YAXXZ",{{.*}} flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
