-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang][DebugInfo] Emit unified (Itanium) mangled name to structor declarations #154142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang][DebugInfo] Emit unified (Itanium) mangled name to structor declarations #154142
Conversation
@llvm/pr-subscribers-clang-driver @llvm/pr-subscribers-debuginfo Author: Michael Buch (Michael137) ChangesDepends on #154137 This patch is motivated by #149827, where we plan on using mangled names on structor declarations to find the exact structor definition that LLDB's expression evaluator should call. Given a This patch aligns Clang with GCC's DWARF output and allows us to implement the same lookup scheme in LLDB. Full diff: https://github.com/llvm/llvm-project/pull/154142.diff 9 Files Affected:
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 a7380a19e3607..484f1b12f3588 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -6014,6 +6014,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';
@@ -6024,6 +6026,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
case Ctor_Base:
Out << '2';
break;
+ case Ctor_Unified:
+ Out << '4';
+ break;
case Ctor_Comdat:
Out << '5';
break;
@@ -6041,6 +6046,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";
@@ -6051,6 +6058,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 241c7c35fcc83..fe188de81b20f 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"
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)
|
@llvm/pr-subscribers-clang Author: Michael Buch (Michael137) ChangesDepends on #154137 This patch is motivated by #149827, where we plan on using mangled names on structor declarations to find the exact structor definition that LLDB's expression evaluator should call. Given a This patch aligns Clang with GCC's DWARF output and allows us to implement the same lookup scheme in LLDB. Full diff: https://github.com/llvm/llvm-project/pull/154142.diff 9 Files Affected:
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 a7380a19e3607..484f1b12f3588 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -6014,6 +6014,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';
@@ -6024,6 +6026,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
case Ctor_Base:
Out << '2';
break;
+ case Ctor_Unified:
+ Out << '4';
+ break;
case Ctor_Comdat:
Out << '5';
break;
@@ -6041,6 +6046,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";
@@ -6051,6 +6058,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 241c7c35fcc83..fe188de81b20f 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"
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)
|
I provided some debug-info size numbers in #149827 but I'll regenerate them with this PR because the implementation changed slightly. |
a430cef
to
cf9f73b
Compare
Here is the debug-info increase when I run bloaty on all the Clang/LLDB/LLVM object files:
Google used an earlier version of this patch to check how their binaries are affected. The Also CCing @jmorse as a heads up for Sony in case you have any concerns. |
Test failure is an XPASS in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for adding the flag! I think this could've turned into a big fire drill for us if we had detected a 15% regression in .debug_str size during internal qualification later. 😥
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add DocBrief here to expand on what this flag does, see this example:
https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-frecord-command-line
This seems like a good place to mention that enabling the flag causes a significant increase (estimated 15%) in generated debug_str object size, that it's experimental, and that it enables a better interactive debugging experience, particularly in LLDB, because it enables calling constructors and destructors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops this must've been by accident
a9e9151
to
7491738
Compare
Similar thanks for the heads up, The change broadly LGTMs, although this isn't a zone of debug-info that I'm really familiar with. |
…een declaration and definition (cherry picked from commit 62641a7)
d6cb62e
to
91da739
Compare
I'll merge this with the LLDB test failure because it'll be fixed by the final PR in the patch series #149827 |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/162/builds/30695 Here is the relevant piece of the build log for the reference
|
#149827) Depends on * #148877 * #155483 * #155485 * #154137 * #154142 This patch is an implementation of [this discussion](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816/7) about handling ABI-tagged structors during expression evaluation. **Motivation** LLDB encodes the mangled name of a `DW_TAG_subprogram` into `AsmLabel`s on function and method Clang AST nodes. This means that when calls to these functions get lowered into IR (when running JITted expressions), the address resolver can locate the appropriate symbol by mangled name (and it is guaranteed to find the symbol because we got the mangled name from debug-info, instead of letting Clang mangle it based on AST structure). However, we don't do this for `CXXConstructorDecl`s/`CXXDestructorDecl`s because these structor declarations in DWARF don't have a linkage name. This is because there can be multiple variants of a structor, each with a distinct mangling in the Itanium ABI. Each structor variant has its own definition `DW_TAG_subprogram`. So LLDB doesn't know which mangled name to put into the `AsmLabel`. Currently this means using ABI-tagged structors in LLDB expressions won't work (see [this RFC](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816) for concrete examples). **Proposed Solution** The `FunctionCallLabel` encoding that we put into `AsmLabel`s already supports stuffing more info about a DIE into it. So this patch extends the `FunctionCallLabel` to contain an optional discriminator (a sequence of bytes) which the `SymbolFileDWARF` plugin interprets as the constructor/destructor variant of that DIE. So when searching for the definition DIE, LLDB will include the structor variant in its heuristic for determining a match. There's a few subtleties here: 1. At the point at which LLDB first constructs the label, it has no way of knowing (just by looking at the debug-info declaration), which structor variant the expression evaluator is supposed to call. That's something that gets decided when compiling the expression. So we let the Clang mangler inject the correct structor variant into the `AsmLabel` during JITing. I adjusted the `AsmLabelAttr` mangling for this in #155485. An option would've been to create a new Clang attribute which behaved like an `AsmLabel` but with these special semantics for LLDB. My main concern there is that we'd have to adjust all the `AsmLabelAttr` checks around Clang to also now account for this new attribute. 2. The compiler is free to omit the `C1` variant of a constructor if the `C2` variant is sufficient. In that case it may alias `C1` to `C2`, leaving us with only the `C2` `DW_TAG_subprogram` in the object file. Linux is one of the platforms where this occurs. For those cases I added a heuristic in `SymbolFileDWARF` where we pick `C2` if we asked for `C1` but it doesn't exist. This may not always be correct (e.g., if the compiler decided to drop `C1` for other reasons). 3. In #154142 Clang will emit `C4`/`D4` variants of ctors/dtors on declarations. When resolving the `FunctionCallLabel` we will now substitute the actual variant that Clang told us we need to call into the mangled name. We do this using LLDB's `ManglingSubstitutor`. That way we find the definition DIE exactly the same way we do for regular function calls. 4. In cases where declarations and definitions live in separate modules, the DIE ID encoded in the function call label may not be enough to find the definition DIE in the encoded module ID. For those cases we fall back to how LLDB used to work: look up in all images of the target. To make sure we don't use the unified mangled name for the fallback lookup, we change the lookup name to whatever mangled name the FunctionCallLabel resolved to. rdar://104968288
… call labels (#149827) Depends on * llvm/llvm-project#148877 * llvm/llvm-project#155483 * llvm/llvm-project#155485 * llvm/llvm-project#154137 * llvm/llvm-project#154142 This patch is an implementation of [this discussion](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816/7) about handling ABI-tagged structors during expression evaluation. **Motivation** LLDB encodes the mangled name of a `DW_TAG_subprogram` into `AsmLabel`s on function and method Clang AST nodes. This means that when calls to these functions get lowered into IR (when running JITted expressions), the address resolver can locate the appropriate symbol by mangled name (and it is guaranteed to find the symbol because we got the mangled name from debug-info, instead of letting Clang mangle it based on AST structure). However, we don't do this for `CXXConstructorDecl`s/`CXXDestructorDecl`s because these structor declarations in DWARF don't have a linkage name. This is because there can be multiple variants of a structor, each with a distinct mangling in the Itanium ABI. Each structor variant has its own definition `DW_TAG_subprogram`. So LLDB doesn't know which mangled name to put into the `AsmLabel`. Currently this means using ABI-tagged structors in LLDB expressions won't work (see [this RFC](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816) for concrete examples). **Proposed Solution** The `FunctionCallLabel` encoding that we put into `AsmLabel`s already supports stuffing more info about a DIE into it. So this patch extends the `FunctionCallLabel` to contain an optional discriminator (a sequence of bytes) which the `SymbolFileDWARF` plugin interprets as the constructor/destructor variant of that DIE. So when searching for the definition DIE, LLDB will include the structor variant in its heuristic for determining a match. There's a few subtleties here: 1. At the point at which LLDB first constructs the label, it has no way of knowing (just by looking at the debug-info declaration), which structor variant the expression evaluator is supposed to call. That's something that gets decided when compiling the expression. So we let the Clang mangler inject the correct structor variant into the `AsmLabel` during JITing. I adjusted the `AsmLabelAttr` mangling for this in llvm/llvm-project#155485. An option would've been to create a new Clang attribute which behaved like an `AsmLabel` but with these special semantics for LLDB. My main concern there is that we'd have to adjust all the `AsmLabelAttr` checks around Clang to also now account for this new attribute. 2. The compiler is free to omit the `C1` variant of a constructor if the `C2` variant is sufficient. In that case it may alias `C1` to `C2`, leaving us with only the `C2` `DW_TAG_subprogram` in the object file. Linux is one of the platforms where this occurs. For those cases I added a heuristic in `SymbolFileDWARF` where we pick `C2` if we asked for `C1` but it doesn't exist. This may not always be correct (e.g., if the compiler decided to drop `C1` for other reasons). 3. In llvm/llvm-project#154142 Clang will emit `C4`/`D4` variants of ctors/dtors on declarations. When resolving the `FunctionCallLabel` we will now substitute the actual variant that Clang told us we need to call into the mangled name. We do this using LLDB's `ManglingSubstitutor`. That way we find the definition DIE exactly the same way we do for regular function calls. 4. In cases where declarations and definitions live in separate modules, the DIE ID encoded in the function call label may not be enough to find the definition DIE in the encoded module ID. For those cases we fall back to how LLDB used to work: look up in all images of the target. To make sure we don't use the unified mangled name for the fallback lookup, we change the lookup name to whatever mangled name the FunctionCallLabel resolved to. rdar://104968288
…clarations (llvm#154142) Depends on llvm#154137 This patch is motivated by llvm#149827, where we plan on using mangled names on structor declarations to find the exact structor definition that LLDB's expression evaluator should call. Given a `DW_TAG_subprogram` for a function declaration, the most convenient way for a debugger to find the corresponding definition is to use the `DW_AT_linkage_name` (i.e., the mangled name). However, we currently can't do that for constructors/destructors because Clang doesn't attach linkage names to them. This is because, depending on ABI, there can be multiple definitions for a single constructor/destructor declaration. The way GCC works around this is by producing a `C4`/`D4` "unified" mangling for structor declarations (see [godbolt](https://godbolt.org/z/Wds6cja9K)). GDB uses this to locate the relevant definitions. This patch aligns Clang with GCC's DWARF output and allows us to implement the same lookup scheme in LLDB. (cherry picked from commit 06d202b)
llvm#149827) Depends on * llvm#148877 * llvm#155483 * llvm#155485 * llvm#154137 * llvm#154142 This patch is an implementation of [this discussion](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816/7) about handling ABI-tagged structors during expression evaluation. **Motivation** LLDB encodes the mangled name of a `DW_TAG_subprogram` into `AsmLabel`s on function and method Clang AST nodes. This means that when calls to these functions get lowered into IR (when running JITted expressions), the address resolver can locate the appropriate symbol by mangled name (and it is guaranteed to find the symbol because we got the mangled name from debug-info, instead of letting Clang mangle it based on AST structure). However, we don't do this for `CXXConstructorDecl`s/`CXXDestructorDecl`s because these structor declarations in DWARF don't have a linkage name. This is because there can be multiple variants of a structor, each with a distinct mangling in the Itanium ABI. Each structor variant has its own definition `DW_TAG_subprogram`. So LLDB doesn't know which mangled name to put into the `AsmLabel`. Currently this means using ABI-tagged structors in LLDB expressions won't work (see [this RFC](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816) for concrete examples). **Proposed Solution** The `FunctionCallLabel` encoding that we put into `AsmLabel`s already supports stuffing more info about a DIE into it. So this patch extends the `FunctionCallLabel` to contain an optional discriminator (a sequence of bytes) which the `SymbolFileDWARF` plugin interprets as the constructor/destructor variant of that DIE. So when searching for the definition DIE, LLDB will include the structor variant in its heuristic for determining a match. There's a few subtleties here: 1. At the point at which LLDB first constructs the label, it has no way of knowing (just by looking at the debug-info declaration), which structor variant the expression evaluator is supposed to call. That's something that gets decided when compiling the expression. So we let the Clang mangler inject the correct structor variant into the `AsmLabel` during JITing. I adjusted the `AsmLabelAttr` mangling for this in llvm#155485. An option would've been to create a new Clang attribute which behaved like an `AsmLabel` but with these special semantics for LLDB. My main concern there is that we'd have to adjust all the `AsmLabelAttr` checks around Clang to also now account for this new attribute. 2. The compiler is free to omit the `C1` variant of a constructor if the `C2` variant is sufficient. In that case it may alias `C1` to `C2`, leaving us with only the `C2` `DW_TAG_subprogram` in the object file. Linux is one of the platforms where this occurs. For those cases I added a heuristic in `SymbolFileDWARF` where we pick `C2` if we asked for `C1` but it doesn't exist. This may not always be correct (e.g., if the compiler decided to drop `C1` for other reasons). 3. In llvm#154142 Clang will emit `C4`/`D4` variants of ctors/dtors on declarations. When resolving the `FunctionCallLabel` we will now substitute the actual variant that Clang told us we need to call into the mangled name. We do this using LLDB's `ManglingSubstitutor`. That way we find the definition DIE exactly the same way we do for regular function calls. 4. In cases where declarations and definitions live in separate modules, the DIE ID encoded in the function call label may not be enough to find the definition DIE in the encoded module ID. For those cases we fall back to how LLDB used to work: look up in all images of the target. To make sure we don't use the unified mangled name for the fallback lookup, we change the lookup name to whatever mangled name the FunctionCallLabel resolved to. rdar://104968288 (cherry picked from commit 57a7907)
A recent change introduced a new dtor kind, which caused a build warning in the CIR code where this dtor kind wasn't handled in a switch. This fixes the problem.
Is it expected that |
I think it's a bug, I think it's just a consequence of the use of g_Group, and I'm filing an issue, maybe I can make a patch. |
Thanks for flagging! Yes that was unintentional. |
Depends on #154137
This patch is motivated by #149827, where we plan on using mangled names on structor declarations to find the exact structor definition that LLDB's expression evaluator should call.
Given a
DW_TAG_subprogram
for a function declaration, the most convenient way for a debugger to find the corresponding definition is to use theDW_AT_linkage_name
(i.e., the mangled name). However, we currently can't do that for constructors/destructors because Clang doesn't attach linkage names to them. This is because, depending on ABI, there can be multiple definitions for a single constructor/destructor declaration. The way GCC works around this is by producing aC4
/D4
"unified" mangling for structor declarations (see godbolt). GDB uses this to locate the relevant definitions.This patch aligns Clang with GCC's DWARF output and allows us to implement the same lookup scheme in LLDB.