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 1/9] [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 2/9] [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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits