https://github.com/Michael137 updated 
https://github.com/llvm/llvm-project/pull/154142

>From d55e41fa03d09b2ddfc9484c4a70a7d21ed9a994 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 18 Aug 2025 15:12:45 +0100
Subject: [PATCH 01/10] [llvm][DebugInfo] Support DW_AT_linkage_names that are
 different between declaration and definition

(cherry picked from commit 62641a7cc6b439c747be0a9ae91b9b266d67816e)
---
 llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp     |  7 +-
 .../structor-declaration-linkage-names.ll     | 68 +++++++++++++++++++
 2 files changed, 70 insertions(+), 5 deletions(-)
 create mode 100644 
llvm/test/DebugInfo/Generic/structor-declaration-linkage-names.ll

diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp 
b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index b03fac2d22a52..4904ad03199c7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -1403,11 +1403,8 @@ bool 
DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP,
 
   // Add the linkage name if we have one and it isn't in the Decl.
   StringRef LinkageName = SP->getLinkageName();
-  assert(((LinkageName.empty() || DeclLinkageName.empty()) ||
-          LinkageName == DeclLinkageName) &&
-         "decl has a linkage name and it is different");
-  if (DeclLinkageName.empty() &&
-      // Always emit it for abstract subprograms.
+  // Always emit linkage name for abstract subprograms.
+  if (DeclLinkageName != LinkageName &&
       (DD->useAllLinkageNames() || DU->getAbstractScopeDIEs().lookup(SP)))
     addLinkageName(SPDie, LinkageName);
 
diff --git a/llvm/test/DebugInfo/Generic/structor-declaration-linkage-names.ll 
b/llvm/test/DebugInfo/Generic/structor-declaration-linkage-names.ll
new file mode 100644
index 0000000000000..9b1f2a5b2a186
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/structor-declaration-linkage-names.ll
@@ -0,0 +1,68 @@
+; RUN: %llc_dwarf < %s -filetype=obj | llvm-dwarfdump -debug-info - | 
FileCheck %s
+
+; Make sure we attach DW_AT_linkage_name on function declarations but only
+; attach it on definitions if the value is different than on the declaration.
+
+target triple = "arm64-apple-macosx"
+
+define void @_Z11SameLinkagev() !dbg !4 {
+entry:
+  ret void
+}
+
+; CHECK:     DW_AT_linkage_name ("_Z11SameLinkagev")
+; CHECK:     DW_AT_declaration (true)
+; CHECK-NOT: DW_AT_linkage_name ("_Z11SameLinkagev")
+
+define void @_Z11DiffLinkagev() !dbg !8 {
+entry:
+  ret void
+}
+
+; CHECK: DW_AT_linkage_name ("SomeName")
+; CHECK: DW_AT_declaration (true)
+; CHECK: DW_AT_linkage_name ("_Z11DiffLinkagev")
+
+define void @_Z15EmptyDefLinkagev() !dbg !10 {
+entry:
+  ret void
+}
+
+; CHECK:     DW_AT_linkage_name ("_Z15EmptyDefLinkagev")
+; CHECK:     DW_AT_declaration (true)
+; CHECK-NOT: DW_AT_linkage_name
+
+define void @_Z16EmptyDeclLinkagev() !dbg !12 {
+entry:
+  ret void
+}
+
+; CHECK: DW_AT_declaration (true)
+; CHECK: DW_AT_linkage_name ("_Z16EmptyDeclLinkagev")
+
+define void @_Z13EmptyLinkagesv() !dbg !14 {
+entry:
+  ret void
+}
+
+; CHECK-NOT: DW_AT_linkage_name
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, 
producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: 
FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
+!1 = !DIFile(filename: "foo.cpp", directory: "/tmp")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = distinct !DISubprogram(name: "SameLinkage", linkageName: 
"_Z11SameLinkagev", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, 
flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !7)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null}
+!7 = !DISubprogram(name: "SameLinkage", linkageName: "_Z11SameLinkagev", 
scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, 
spFlags: 0)
+!8 = distinct !DISubprogram(name: "DiffLinkage", linkageName: 
"_Z11DiffLinkagev", scope: !1, file: !1, line: 5, type: !5, scopeLine: 5, 
flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !9)
+!9 = !DISubprogram(name: "DiffLinkage", linkageName: "SomeName", scope: !1, 
file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: 0)
+!10 = distinct !DISubprogram(name: "EmptyDefLinkage", linkageName: "", scope: 
!1, file: !1, line: 5, type: !5, scopeLine: 5, flags: DIFlagPrototyped, 
spFlags: DISPFlagDefinition, unit: !0, declaration: !11)
+!11 = !DISubprogram(name: "EmptyDefLinkage", linkageName: 
"_Z15EmptyDefLinkagev", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, 
flags: DIFlagPrototyped, spFlags: 0)
+!12 = distinct !DISubprogram(name: "EmptyDeclLinkage", linkageName: 
"_Z16EmptyDeclLinkagev", scope: !1, file: !1, line: 5, type: !5, scopeLine: 5, 
flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: 
!13)
+!13 = !DISubprogram(name: "EmptyDeclLinkage", linkageName: "", scope: !1, 
file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: 0)
+!14 = distinct !DISubprogram(name: "EmptyLinkages", linkageName: "", scope: 
!1, file: !1, line: 5, type: !5, scopeLine: 5, flags: DIFlagPrototyped, 
spFlags: DISPFlagDefinition, unit: !0, declaration: !15)
+!15 = !DISubprogram(name: "EmptyLinkages", linkageName: "", scope: !1, file: 
!1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: 0)

>From 3ce391791dc7264791f75690d64ebd96a44c9c6b Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 18 Aug 2025 15:14:40 +0100
Subject: [PATCH 02/10] [clang][DebugInfo] Emit unified (Itanium) mangled name
 to structor declarations

---
 clang/include/clang/Basic/ABI.h               | 10 +--
 clang/lib/AST/ItaniumMangle.cpp               | 10 +++
 clang/lib/AST/MicrosoftMangle.cpp             |  2 +
 clang/lib/CodeGen/CGDebugInfo.cpp             | 32 +++++++--
 clang/lib/CodeGen/CGDebugInfo.h               |  4 ++
 clang/lib/CodeGen/MicrosoftCXXABI.cpp         |  4 ++
 .../debug-info-structor-linkage-names.cpp     | 72 +++++++++++++++++++
 7 files changed, 124 insertions(+), 10 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp

diff --git a/clang/include/clang/Basic/ABI.h b/clang/include/clang/Basic/ABI.h
index 231bad799a42c..8279529c316cf 100644
--- a/clang/include/clang/Basic/ABI.h
+++ b/clang/include/clang/Basic/ABI.h
@@ -27,14 +27,16 @@ enum CXXCtorType {
   Ctor_Comdat,         ///< The COMDAT used for ctors
   Ctor_CopyingClosure, ///< Copying closure variant of a ctor
   Ctor_DefaultClosure, ///< Default closure variant of a ctor
+  Ctor_Unified,        ///< GCC-style unified dtor
 };
 
 /// C++ destructor types.
 enum CXXDtorType {
-    Dtor_Deleting, ///< Deleting dtor
-    Dtor_Complete, ///< Complete object dtor
-    Dtor_Base,     ///< Base object dtor
-    Dtor_Comdat    ///< The COMDAT used for dtors
+  Dtor_Deleting, ///< Deleting dtor
+  Dtor_Complete, ///< Complete object dtor
+  Dtor_Base,     ///< Base object dtor
+  Dtor_Comdat,   ///< The COMDAT used for dtors
+  Dtor_Unified,  ///< GCC-style unified dtor
 };
 
 } // end namespace clang
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 112678fb2714a..f6ff9861508a2 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -6029,6 +6029,8 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
   //                  ::= CI2 <type> # base inheriting constructor
   //
   // In addition, C5 is a comdat name with C1 and C2 in it.
+  // C4 represents a ctor declaration and is used by debuggers to look up
+  // the various ctor variants.
   Out << 'C';
   if (InheritedFrom)
     Out << 'I';
@@ -6039,6 +6041,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
   case Ctor_Base:
     Out << '2';
     break;
+  case Ctor_Unified:
+    Out << '4';
+    break;
   case Ctor_Comdat:
     Out << '5';
     break;
@@ -6056,6 +6061,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
   //                  ::= D2  # base object destructor
   //
   // In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in it.
+  // D4 represents a dtor declaration and is used by debuggers to look up
+  // the various dtor variants.
   switch (T) {
   case Dtor_Deleting:
     Out << "D0";
@@ -6066,6 +6073,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
   case Dtor_Base:
     Out << "D2";
     break;
+  case Dtor_Unified:
+    Out << "D4";
+    break;
   case Dtor_Comdat:
     Out << "D5";
     break;
diff --git a/clang/lib/AST/MicrosoftMangle.cpp 
b/clang/lib/AST/MicrosoftMangle.cpp
index fc79ab1de24ff..d214db76e419b 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -1496,6 +1496,8 @@ void 
MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
   // it.
   case Dtor_Comdat:
     llvm_unreachable("not expecting a COMDAT");
+  case Dtor_Unified:
+    llvm_unreachable("not expecting a unified dtor type");
   }
   llvm_unreachable("Unsupported dtor type?");
 }
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 994bdbdae860f..f32e1e8185337 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2177,24 +2177,44 @@ static bool isFunctionLocalClass(const CXXRecordDecl 
*RD) {
   return false;
 }
 
-llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
-    const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
+llvm::StringRef
+CGDebugInfo::GetMethodLinkageName(const CXXMethodDecl *Method) const {
+  assert(Method);
+
   bool IsCtorOrDtor =
       isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
 
+  // In some ABIs (particularly Itanium) a single ctor/dtor
+  // corresponds to multiple functions. Attach a "unified"
+  // linkage name for those (which is the convention GCC uses).
+  // Otherwise, attach no linkage name.
+  if (IsCtorOrDtor && !CGM.getTarget().getCXXABI().hasConstructorVariants())
+    return {};
+
+  if (const auto *Ctor = llvm::dyn_cast<CXXConstructorDecl>(Method))
+    return CGM.getMangledName(GlobalDecl(Ctor, CXXCtorType::Ctor_Unified));
+
+  if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(Method))
+    return CGM.getMangledName(GlobalDecl(Dtor, CXXDtorType::Dtor_Unified));
+
+  return CGM.getMangledName(Method);
+}
+
+llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
+    const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
+  assert(Method);
+
   StringRef MethodName = getFunctionName(Method);
   llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit);
 
-  // Since a single ctor/dtor corresponds to multiple functions, it doesn't
-  // make sense to give a single ctor/dtor a linkage name.
   StringRef MethodLinkageName;
   // FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional
   // property to use here. It may've been intended to model "is non-external
   // type" but misses cases of non-function-local but non-external classes such
   // as those in anonymous namespaces as well as the reverse - external types
   // that are function local, such as those in (non-local) inline functions.
-  if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
-    MethodLinkageName = CGM.getMangledName(Method);
+  if (!isFunctionLocalClass(Method->getParent()))
+    MethodLinkageName = GetMethodLinkageName(Method);
 
   // Get the location for the method.
   llvm::DIFile *MethodDefUnit = nullptr;
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 497d3a6ab17b1..55c528031368d 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -899,6 +899,10 @@ class CGDebugInfo {
       std::memcpy(Data + A.size(), B.data(), B.size());
     return StringRef(Data, A.size() + B.size());
   }
+
+  /// If one exists, returns the linkage name of the specified \
+  /// (non-null) \c Method. Returns empty string otherwise.
+  llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
 };
 
 /// A scoped helper to set the current debug location to the specified
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp 
b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 88f0648660965..94190a149e859 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -77,6 +77,8 @@ class MicrosoftCXXABI : public CGCXXABI {
         return false;
 
       case Dtor_Comdat: llvm_unreachable("emitting dtor comdat as function?");
+      case Dtor_Unified:
+        llvm_unreachable("unexpected unified dtor type");
       }
       llvm_unreachable("bad dtor kind");
     }
@@ -1417,6 +1419,8 @@ llvm::GlobalValue::LinkageTypes 
MicrosoftCXXABI::getCXXDestructorLinkage(
     // and are emitted everywhere they are used. They are internal if the class
     // is internal.
     return llvm::GlobalValue::LinkOnceODRLinkage;
+  case Dtor_Unified:
+    llvm_unreachable("MS C++ ABI does not support unified dtors");
   case Dtor_Comdat:
     llvm_unreachable("MS C++ ABI does not support comdat dtors");
   }
diff --git a/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp 
b/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
new file mode 100644
index 0000000000000..88b4ee75d4565
--- /dev/null
+++ b/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
@@ -0,0 +1,72 @@
+// Tests that we emit unified constructor/destructor linkage names
+// for ABIs that support it.
+
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm 
-debug-info-kind=standalone %s -o - | FileCheck %s 
--check-prefixes=CHECK,ITANIUM
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm 
-debug-info-kind=standalone %s -o - | FileCheck %s --check-prefixes=CHECK,MSABI
+
+struct Base {
+  Base(int x);
+  ~Base();
+};
+
+Base::Base(int x) {}
+Base::~Base() {}
+
+// Check that we emit unified ctor/dtor (C4/D4) on Itanium but not for MS-ABI.
+
+// CHECK: ![[BASE_CTOR_DECL:[0-9]+]] = !DISubprogram(name: "Base"
+// MSABI-NOT:                                        linkageName:
+// ITANIUM-SAME:                                     linkageName: 
"_ZN4BaseC4Ei"
+// CHECK-SAME:                                       spFlags: 0
+
+// CHECK: ![[BASE_DTOR_DECL:[0-9]+]] = !DISubprogram(name: "~Base"
+// MSABI-NOT:                                        linkageName:
+// ITANIUM-SAME:                                     linkageName: 
"_ZN4BaseD4Ev"
+// CHECK-SAME:                                       spFlags: 0
+
+// Check that the ctor/dtor definitions have linkage names that aren't
+// the ones on the declaration.
+
+// CHECK: !DISubprogram(name: "Base"
+// MSABI-SAME:          linkageName:
+// ITANIUM-SAME:        linkageName: "_ZN4BaseC2Ei"
+// CHECK-SAME:          spFlags: DISPFlagDefinition
+// CHECK-SAME:          declaration: ![[BASE_CTOR_DECL]]
+
+// ITANIUM: !DISubprogram(name: "Base"
+// ITANIUM-SAME:          linkageName: "_ZN4BaseC1Ei"
+// ITANIUM-SAME:          spFlags: DISPFlagDefinition
+// ITANIUM-SAME:          declaration: ![[BASE_CTOR_DECL]]
+
+// CHECK: !DISubprogram(name: "~Base"
+// MSABI-SAME:          linkageName:
+// ITANIUM-SAME:        linkageName: "_ZN4BaseD2Ev"
+// CHECK-SAME:          spFlags: DISPFlagDefinition
+// CHECK-SAME:          declaration: ![[BASE_DTOR_DECL]]
+
+// ITANIUM: !DISubprogram(name: "~Base"
+// ITANIUM-SAME:          linkageName: "_ZN4BaseD1Ev"
+// ITANIUM-SAME:          spFlags: DISPFlagDefinition
+// ITANIUM-SAME:          declaration: ![[BASE_DTOR_DECL]]
+
+struct Derived : public Base {
+    using Base::Base;
+} d(5);
+
+// CHECK: !DISubprogram(name: "Base"
+// MSABI-SAME:          linkageName:
+// ITANIUM-SAME:        linkageName: "_ZN7DerivedCI14BaseEi"
+// CHECK-SAME:          spFlags: {{.*}}DISPFlagDefinition
+// CHECK-SAME:          declaration: ![[BASE_INHERIT_CTOR_DECL:[0-9]+]]
+
+// CHECK: [[BASE_INHERIT_CTOR_DECL]] = !DISubprogram(name: "Base"
+// MSABI-NOT:                                        linkageName:
+// ITANIUM-SAME:                                     linkageName: 
"_ZN7DerivedCI44BaseEi"
+// CHECK-SAME                                        spFlags: 0
+
+// ITANIUM: !DISubprogram(name: "Base"
+// ITANIUM-SAME:          linkageName: "_ZN7DerivedCI24BaseEi"
+// ITANIUM-SAME:          spFlags: DISPFlagDefinition
+// ITANIUM-SAME:          declaration: ![[BASE_INHERIT_CTOR_DECL:[0-9]+]]
+
+// MSABI: !DISubprogram(name: "~Derived"

>From 847afb07c6803dd642bed506b45a7b11a6c4c305 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 18 Aug 2025 17:07:42 +0100
Subject: [PATCH 03/10] fixup! switch-statement warnings

---
 clang/lib/CodeGen/CGClass.cpp       | 2 ++
 clang/lib/CodeGen/ItaniumCXXABI.cpp | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index e9a92ae0f01cb..ba587943384a6 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1502,6 +1502,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList 
&Args) {
   // we'd introduce *two* handler blocks.  In the Microsoft ABI, we
   // always delegate because we might not have a definition in this TU.
   switch (DtorType) {
+  case Dtor_Unified:
+    llvm_unreachable("not expecting a unified dtor");
   case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT");
   case Dtor_Deleting: llvm_unreachable("already handled deleting case");
 
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 4ed3775f156c9..4e6907ba68acf 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -91,6 +91,8 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
 
       case Dtor_Comdat:
         llvm_unreachable("emitting dtor comdat as function?");
+      case Dtor_Unified:
+        llvm_unreachable("emitting unified dtor as function?");
       }
       llvm_unreachable("bad dtor kind");
     }
@@ -108,6 +110,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
 
       case Ctor_Comdat:
         llvm_unreachable("emitting ctor comdat as function?");
+
+      case Ctor_Unified:
+        llvm_unreachable("emitting unified ctor as function?");
       }
       llvm_unreachable("bad dtor kind");
     }

>From f4a0dd86fe0888848d21d8a8525ccd50f0f4b7f0 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Wed, 20 Aug 2025 10:19:45 +0100
Subject: [PATCH 04/10] fixup! add clang driver option

---
 clang/include/clang/Basic/DebugOptions.def    |  5 ++++-
 clang/include/clang/Driver/Options.td         |  9 +++++++++
 clang/lib/CodeGen/CGDebugInfo.cpp             |  5 ++++-
 clang/lib/Driver/ToolChains/Clang.cpp         |  4 ++++
 .../debug-info-structor-linkage-names.cpp     | 20 +++++++++++++++++--
 5 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DebugOptions.def 
b/clang/include/clang/Basic/DebugOptions.def
index c6e736e92744c..c2fb705662c0c 100644
--- a/clang/include/clang/Basic/DebugOptions.def
+++ b/clang/include/clang/Basic/DebugOptions.def
@@ -125,8 +125,11 @@ DEBUGOPT(DebugNameTable, 2, 0, Compatible)
 /// Whether to use DWARF base address specifiers in .debug_ranges.
 DEBUGOPT(DebugRangesBaseAddress, 1, 0, Compatible)
 
+/// Whether to add linkage names to constructor/destructor declarations.
+DEBUGOPT(DebugStructorDeclLinkageNames, 1, 0, Benign)
+
 /// Whether to embed source in DWARF debug line section.
-DEBUGOPT(EmbedSource, 1, 0, Compatible)
+DEBUGOPT(EmbedSource, 1, 1, Compatible)
 
 #undef DEBUGOPT
 #undef ENUM_DEBUGOPT
diff --git a/clang/include/clang/Driver/Options.td 
b/clang/include/clang/Driver/Options.td
index 9cfb1bbcac5c3..ef0097f8ba334 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4767,6 +4767,15 @@ def gembed_source : Flag<["-"], "gembed-source">, 
Group<g_flags_Group>,
 def gno_embed_source : Flag<["-"], "gno-embed-source">, Group<g_flags_Group>,
     Flags<[NoXarchOption]>,
     HelpText<"Restore the default behavior of not embedding source text in 
DWARF debug sections">;
+defm structor_decl_linkage_names
+    : BoolGOption<"structor-decl-linkage-names",
+                  CodeGenOpts<"DebugStructorDeclLinkageNames">, DefaultTrue,
+                  NegFlag<SetFalse>,
+                  PosFlag<SetTrue, [], [],
+                          "Attach linkage names to C++ constructor/destructor "
+                          "declarations in DWARF."
+                          "Implies -g.">,
+                  BothFlags<[], [ClangOption, CLOption, CC1Option]>>;
 defm key_instructions : BoolGOption<"key-instructions",
     CodeGenOpts<"DebugKeyInstructions">, DefaultFalse,
     NegFlag<SetFalse>, PosFlag<SetTrue, [], [],
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index f32e1e8185337..2ad19e9581c12 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2181,9 +2181,12 @@ llvm::StringRef
 CGDebugInfo::GetMethodLinkageName(const CXXMethodDecl *Method) const {
   assert(Method);
 
-  bool IsCtorOrDtor =
+  const bool IsCtorOrDtor =
       isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
 
+  if (IsCtorOrDtor && !CGM.getCodeGenOpts().DebugStructorDeclLinkageNames)
+    return {};
+
   // In some ABIs (particularly Itanium) a single ctor/dtor
   // corresponds to multiple functions. Attach a "unified"
   // linkage name for those (which is the convention GCC uses).
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 29b7180df5cb5..10a00f268884e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4594,6 +4594,10 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, 
const llvm::Triple &T,
                    options::OPT_gno_key_instructions, false))
     CmdArgs.push_back("-gkey-instructions");
 
+  if (!Args.hasFlag(options::OPT_gstructor_decl_linkage_names,
+                    options::OPT_gno_structor_decl_linkage_names, true))
+    CmdArgs.push_back("-gno-structor-decl-linkage-names");
+
   if (EmitCodeView) {
     CmdArgs.push_back("-gcodeview");
 
diff --git a/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp 
b/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
index 88b4ee75d4565..72b0bf39e0bbb 100644
--- a/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
+++ b/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
@@ -1,8 +1,21 @@
 // Tests that we emit unified constructor/destructor linkage names
 // for ABIs that support it.
 
-// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm 
-debug-info-kind=standalone %s -o - | FileCheck %s 
--check-prefixes=CHECK,ITANIUM
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm 
-debug-info-kind=standalone %s -o - | FileCheck %s --check-prefixes=CHECK,MSABI
+// Check that -gstructor-decl-linkage-names is the default.
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm 
-debug-info-kind=standalone \
+// RUN:            %s -o - | FileCheck %s --check-prefixes=CHECK,ITANIUM
+//
+// Check with -gstructor-decl-linkage-names.
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm 
-debug-info-kind=standalone \
+// RUN:            -gstructor-decl-linkage-names %s -o - | FileCheck %s 
--check-prefixes=CHECK,ITANIUM
+//
+// Check with -gno-structor-decl-linkage-names.
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm 
-debug-info-kind=standalone \
+// RUN:            -gno-structor-decl-linkage-names %s -o - | FileCheck %s 
--check-prefixes=CHECK,DISABLE
+//
+// Check ABI without structor variants.
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm 
-debug-info-kind=standalone \
+// RUN:            -gstructor-decl-linkage-names %s -o - | FileCheck %s 
--check-prefixes=CHECK,MSABI
 
 struct Base {
   Base(int x);
@@ -16,11 +29,13 @@ Base::~Base() {}
 
 // CHECK: ![[BASE_CTOR_DECL:[0-9]+]] = !DISubprogram(name: "Base"
 // MSABI-NOT:                                        linkageName:
+// DISABLE-NOT:                                      linkageName:
 // ITANIUM-SAME:                                     linkageName: 
"_ZN4BaseC4Ei"
 // CHECK-SAME:                                       spFlags: 0
 
 // CHECK: ![[BASE_DTOR_DECL:[0-9]+]] = !DISubprogram(name: "~Base"
 // MSABI-NOT:                                        linkageName:
+// DISABLE-NOT:                                      linkageName:
 // ITANIUM-SAME:                                     linkageName: 
"_ZN4BaseD4Ev"
 // CHECK-SAME:                                       spFlags: 0
 
@@ -61,6 +76,7 @@ struct Derived : public Base {
 
 // CHECK: [[BASE_INHERIT_CTOR_DECL]] = !DISubprogram(name: "Base"
 // MSABI-NOT:                                        linkageName:
+// DISABLE-NOT:                                      linkageName:
 // ITANIUM-SAME:                                     linkageName: 
"_ZN7DerivedCI44BaseEi"
 // CHECK-SAME                                        spFlags: 0
 

>From f4b32c64425734db78c6751d8153600d2f0538c7 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Wed, 20 Aug 2025 14:23:06 +0100
Subject: [PATCH 05/10] fixup! fix test

---
 clang/test/DebugInfo/CXX/artificial-arg.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/test/DebugInfo/CXX/artificial-arg.cpp 
b/clang/test/DebugInfo/CXX/artificial-arg.cpp
index a0cf131f83e15..21b8d047b3456 100644
--- a/clang/test/DebugInfo/CXX/artificial-arg.cpp
+++ b/clang/test/DebugInfo/CXX/artificial-arg.cpp
@@ -25,7 +25,8 @@ int main(int argc, char **argv) {
 // CHECK: ![[CLASSTYPE:.*]] = distinct !DICompositeType(tag: 
DW_TAG_class_type, name: "A",
 // CHECK-SAME:                                 identifier: "_ZTS1A"
 // CHECK: ![[ARTARG:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: 
![[CLASSTYPE]],{{.*}} DIFlagArtificial
-// CHECK: !DISubprogram(name: "A", scope: ![[CLASSTYPE]]
+// CHECK: !DISubprogram(name: "A"
+// CHECK-SAME:          scope: ![[CLASSTYPE]]
 // CHECK-SAME:          line: 12
 // CHECK-SAME:          DIFlagPublic
 // CHECK: !DISubroutineType(types: [[FUNCTYPE:![0-9]*]])

>From fd5ca533deaec0c7f5567605b260787b08b52a74 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Wed, 20 Aug 2025 14:25:26 +0100
Subject: [PATCH 06/10] fixup! fix test

---
 clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp 
b/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
index 72b0bf39e0bbb..b7aac198c5180 100644
--- a/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
+++ b/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
@@ -85,4 +85,5 @@ struct Derived : public Base {
 // ITANIUM-SAME:          spFlags: DISPFlagDefinition
 // ITANIUM-SAME:          declaration: ![[BASE_INHERIT_CTOR_DECL:[0-9]+]]
 
-// MSABI: !DISubprogram(name: "~Derived"
+// MSABI:   !DISubprogram(name: "~Derived"
+// DISABLE: !DISubprogram(name: "~Derived"

>From 9ef0564b477c8209986991382e0148951c7e8ce8 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Thu, 21 Aug 2025 08:54:57 +0100
Subject: [PATCH 07/10] fixup! add comment

---
 clang/include/clang/Basic/DebugOptions.def | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DebugOptions.def 
b/clang/include/clang/Basic/DebugOptions.def
index c2fb705662c0c..a768b12fa4e0d 100644
--- a/clang/include/clang/Basic/DebugOptions.def
+++ b/clang/include/clang/Basic/DebugOptions.def
@@ -126,10 +126,13 @@ DEBUGOPT(DebugNameTable, 2, 0, Compatible)
 DEBUGOPT(DebugRangesBaseAddress, 1, 0, Compatible)
 
 /// Whether to add linkage names to constructor/destructor declarations.
+/// This is an escape hatch for cases where attaching the additional linkage
+/// names would increase debug-info size (particularly the .debug_str section)
+/// too much.
 DEBUGOPT(DebugStructorDeclLinkageNames, 1, 0, Benign)
 
 /// Whether to embed source in DWARF debug line section.
-DEBUGOPT(EmbedSource, 1, 1, Compatible)
+DEBUGOPT(EmbedSource, 1, 0, Compatible)
 
 #undef DEBUGOPT
 #undef ENUM_DEBUGOPT

>From 5926a49f235b67ef966426c4e61ade4b016c9cf3 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Thu, 21 Aug 2025 09:22:33 +0100
Subject: [PATCH 08/10] fixup! add DocBrief

---
 clang/include/clang/Driver/Options.td | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Driver/Options.td 
b/clang/include/clang/Driver/Options.td
index ef0097f8ba334..f701c4d9e485f 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4775,7 +4775,10 @@ defm structor_decl_linkage_names
                           "Attach linkage names to C++ constructor/destructor "
                           "declarations in DWARF."
                           "Implies -g.">,
-                  BothFlags<[], [ClangOption, CLOption, CC1Option]>>;
+                  BothFlags<[], [ClangOption, CLOption, CC1Option]>>,
+                  DocBrief<[{On some ABIs (e.g., Itanium), constructors and 
destructors may have multiple variants. Historically, when generating DWARF, 
Clang did not attach ``DW_AT_linkage_name``s to structor DIEs because there 
were multiple possible manglings (depending on the structor variant) that could 
be used. With ``-gstructor-decl-linkage-names``, for ABIs with structor 
variants, we attach a "unified" mangled name to structor declarations DIEs 
which debuggers can use to look up all the definitions for a structor 
declaration. E.g., a "unified" mangled name ``_ZN3FooC4Ev`` may have multiple 
definitions associated with it such as ``_ZN3FooC1Ev`` and ``_ZN3FooC2Ev``.
+
+Enabling this flag results in a better interactive debugging experience (both 
GDB and LLDB have support for understanding these "unified" linkage names). 
However, it comes with a significant increase in debug-info size (particularly 
the `.debug_str` section). As an escape hatch, users can disable this feature 
using ``-gno-structor-decl-linkage-names``.}]>;
 defm key_instructions : BoolGOption<"key-instructions",
     CodeGenOpts<"DebugKeyInstructions">, DefaultFalse,
     NegFlag<SetFalse>, PosFlag<SetTrue, [], [],

>From 74917380ec7c2808857292d2521d02a88eb378f8 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Thu, 21 Aug 2025 09:27:46 +0100
Subject: [PATCH 09/10] fixup! move test

---
 .../CXX}/debug-info-structor-linkage-names.cpp                    | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename clang/test/{CodeGenCXX => 
DebugInfo/CXX}/debug-info-structor-linkage-names.cpp (100%)

diff --git a/clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp 
b/clang/test/DebugInfo/CXX/debug-info-structor-linkage-names.cpp
similarity index 100%
rename from clang/test/CodeGenCXX/debug-info-structor-linkage-names.cpp
rename to clang/test/DebugInfo/CXX/debug-info-structor-linkage-names.cpp

>From d6cb62eeac0c27f2068a182e225151746b0666dc Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Thu, 21 Aug 2025 16:12:41 +0100
Subject: [PATCH 10/10] fixup! fix test

---
 clang/test/CodeGenObjCXX/debug-info-cyclic.mm | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGenObjCXX/debug-info-cyclic.mm 
b/clang/test/CodeGenObjCXX/debug-info-cyclic.mm
index 2fb1611c904d0..a062b6ad50612 100644
--- a/clang/test/CodeGenObjCXX/debug-info-cyclic.mm
+++ b/clang/test/CodeGenObjCXX/debug-info-cyclic.mm
@@ -10,8 +10,9 @@
 // CHECK-SAME:                             identifier:
 // CHECK: ![[BMEMBERS]] = !{![[BB:[0-9]+]]}
   B(struct A *);
-// CHECK: ![[BB]] = !DISubprogram(name: "B", scope: ![[B]]
-// CHECK-SAME:                    line: [[@LINE-2]],
+// CHECK: ![[BB]] = !DISubprogram(name: "B",
+// CHECK-SAME:                    scope: ![[B]]
+// CHECK-SAME:                    line: [[@LINE-3]],
 // CHECK-SAME:                    type: ![[TY:[0-9]+]],
 // CHECK: ![[TY]] = !DISubroutineType(types: ![[ARGS:[0-9]+]])
 // CHECK: ![[ARGS]] = !{null, ![[THIS:[0-9]+]], !{{[^,]+}}}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to