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

Reply via email to