[clang] [lldb] [llvm] [WIP][lldb][Expression] More reliable function call resolution (PR #114529)
Michael Buch via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 5 04:28:50 PST 2024
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/114529
>From 9337e170d920eaabe2b59a25622f0c554ca5afcf Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Sun, 20 Oct 2024 11:35:15 +0100
Subject: [PATCH 1/2] [WIP][lldb][Expression] More reliable function call
resolution
Implements all the parts of following RFC:
https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816
Main changes:
1. Instead of relying on linkage names to resolve function symbols,
encode the exact function DIE and module in the `AsmLabelAttr`
2. Teach the LLDB symbol resolve about (1)
3. Introduce new Clang attribute to allow specifying multiple `asm`
labels for ctors/dtors (one for each variant)
4. Attach the new attribute in (3), where the mangled names use the
format from (1). To determine which variant a DIE corresponds to we
add a new API to the `ItaniumPartialDemangler` (though could be made
into a DWARF attribute for quicker determination).
---
clang/include/clang/Basic/Attr.td | 8 ++
clang/include/clang/Basic/AttrDocs.td | 5 ++
clang/lib/AST/Mangle.cpp | 69 +++++++++++++++-
clang/lib/Sema/SemaDeclAttr.cpp | 22 +++++
lldb/source/Expression/IRExecutionUnit.cpp | 36 +++++++++
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 80 +++++++++++++++----
.../TypeSystem/Clang/TypeSystemClang.cpp | 15 +++-
.../TypeSystem/Clang/TypeSystemClang.h | 3 +-
lldb/test/Shell/Expr/TestAbiTagCtorsDtors.cpp | 28 +++++++
llvm/include/llvm/Demangle/Demangle.h | 3 +
llvm/include/llvm/Demangle/ItaniumDemangle.h | 2 +
llvm/lib/Demangle/ItaniumDemangle.cpp | 18 +++--
12 files changed, 264 insertions(+), 25 deletions(-)
create mode 100644 lldb/test/Shell/Expr/TestAbiTagCtorsDtors.cpp
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 70fad60d4edbb5..407eece2a728a2 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -784,6 +784,14 @@ def AbiTag : Attr {
let Documentation = [AbiTagsDocs];
}
+def StructorMangledNames : Attr {
+ let Spellings = [Clang<"structor_names">];
+ let Args = [VariadicStringArgument<"MangledNames">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [StructorMangledNamesDocs];
+}
+
+
def AddressSpace : TypeAttr {
let Spellings = [Clang<"address_space">];
let Args = [IntArgument<"AddressSpace">];
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 546e5100b79dd9..2b886aecd193de 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -3568,6 +3568,11 @@ manipulating bits of the enumerator when issuing warnings.
}];
}
+def StructorMangledNamesDocs : Documentation {
+ let Category = DocCatDecl;
+ let Content = [{ TODO }];
+}
+
def AsmLabelDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 4875e8537b3c11..9b304d28113625 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -9,19 +9,20 @@
// Implements generic name mangling support for blocks and Objective-C.
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/Attr.h"
+#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/Mangle.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Mangler.h"
#include "llvm/Support/ErrorHandling.h"
@@ -126,7 +127,7 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
// Any decl can be declared with __asm("foo") on it, and this takes precedence
// over all other naming in the .o file.
- if (D->hasAttr<AsmLabelAttr>())
+ if (D->hasAttr<AsmLabelAttr>() || D->hasAttr<StructorMangledNamesAttr>())
return true;
// Declarations that don't have identifier names always need to be mangled.
@@ -140,6 +141,68 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
const ASTContext &ASTContext = getASTContext();
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
+ if (const StructorMangledNamesAttr *SMA =
+ D->getAttr<StructorMangledNamesAttr>()) {
+ CXXConstructorDecl const *Ctor = dyn_cast<CXXConstructorDecl>(D);
+ CXXDestructorDecl const *Dtor = dyn_cast<CXXDestructorDecl>(D);
+ assert(Ctor || Dtor);
+ enum CtorDtor {
+ None = -1,
+ Deleting = 0,
+ Base,
+ Complete,
+ Allocating
+ } CtorDtorVariant = None;
+
+ // Map ctor/dtor variant to a the variant that LLDB encoded in the
+ // special identifier. I.e., a number between [0-3].
+ if (Dtor) {
+ switch (GD.getDtorType()) {
+ case Dtor_Complete:
+ CtorDtorVariant = Complete;
+ break;
+ case Dtor_Base:
+ CtorDtorVariant = Base;
+ break;
+ case Dtor_Deleting:
+ case Dtor_Comdat:
+ llvm_unreachable("");
+ }
+ } else if (Ctor) {
+ switch (GD.getCtorType()) {
+ case Ctor_Complete:
+ CtorDtorVariant = Complete;
+ break;
+ case Ctor_Base:
+ CtorDtorVariant = Base;
+ break;
+ case Ctor_DefaultClosure:
+ case Ctor_CopyingClosure:
+ case Ctor_Comdat:
+ llvm_unreachable("");
+ }
+ }
+
+ // Parse the LLDB [variant -> special name] mappings.
+ llvm::DenseMap<CtorDtor, llvm::StringRef> names;
+ for (auto name : SMA->mangledNames()) {
+ auto [structor_variant, mangled_name] = name.split(':');
+ auto variant = llvm::StringSwitch<CtorDtor>(structor_variant)
+ .Case("0", CtorDtor::Deleting)
+ .Case("1", CtorDtor::Base)
+ .Case("2", CtorDtor::Complete)
+ .Case("3", CtorDtor::Complete)
+ .Default(CtorDtor::None);
+ names[variant] = mangled_name;
+ }
+
+ assert(CtorDtorVariant != CtorDtor::None);
+
+ // Pick the mapping
+ Out << names[CtorDtorVariant];
+ return;
+ }
+
// Any decl can be declared with __asm("foo") on it, and this takes precedence
// over all other naming in the .o file.
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 14cc51cf89665a..fdf66be8ac3987 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5539,6 +5539,25 @@ static void handleMSConstexprAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL));
}
+static void handleStructorNamesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ SmallVector<StringRef, 4> Tags;
+ for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
+ StringRef Tag;
+ if (!S.checkStringLiteralArgumentAttr(AL, I, Tag))
+ return;
+ Tags.push_back(Tag);
+ }
+
+ if (!AL.checkAtLeastNumArgs(S, 1))
+ return;
+
+ // Store tags without duplicates.
+ Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
+
+ D->addAttr(::new (S.Context) StructorMangledNamesAttr(
+ S.Context, AL, Tags.data(), Tags.size()));
+}
+
static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
SmallVector<StringRef, 4> Tags;
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
@@ -6983,6 +7002,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
S.HLSL().handleParamModifierAttr(D, AL);
break;
+ case ParsedAttr::AT_StructorMangledNames:
+ handleStructorNamesAttr(S, D, AL);
+ break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
break;
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 15ca2ddbbae046..b11085d921c419 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -16,6 +16,8 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
+#include "Plugins/SymbolFile/DWARF/DWARFBaseDIE.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
@@ -37,6 +39,8 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
+#include <cstddef>
+#include <cstdint>
#include <optional>
using namespace lldb_private;
@@ -781,6 +785,38 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
function_options.include_inlines = false;
for (const ConstString &name : names) {
+ auto ref = name.GetStringRef();
+ if (ref.consume_front("$__lldb_func_")) {
+ uintptr_t module_ptr;
+ if (ref.consumeInteger(0, module_ptr))
+ return LLDB_INVALID_ADDRESS;
+
+ auto *mod = (lldb_private::Module *)module_ptr;
+ auto *sym = mod->GetSymbolFile();
+ assert(mod && sym);
+
+ if (!ref.consume_front(":"))
+ return LLDB_INVALID_ADDRESS;
+
+ lldb::user_id_t die_id;
+ if (ref.consumeInteger(10, die_id))
+ return LLDB_INVALID_ADDRESS;
+
+ auto *dwarf = llvm::dyn_cast<plugin::dwarf::SymbolFileDWARF>(sym);
+ if (!dwarf)
+ return LLDB_INVALID_ADDRESS;
+
+ auto die = dwarf->GetDIE(die_id);
+ Module::LookupInfo lookup_info(
+ ConstString(die.GetMangledName()),
+ lldb::FunctionNameType::eFunctionNameTypeAny,
+ lldb::LanguageType::eLanguageTypeC_plus_plus);
+ SymbolContextList sc_list;
+ dwarf->FindFunctions(lookup_info, {}, false, sc_list);
+ if (auto load_addr = resolver.Resolve(sc_list))
+ return *load_addr;
+ }
+
if (sc.module_sp) {
SymbolContextList sc_list;
sc.module_sp->FindFunctions(name, CompilerDeclContext(),
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 70540fe7fada68..ea86ef352800ec 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -45,6 +45,7 @@
#include "clang/AST/Type.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/FormatVariadic.h"
#include <map>
#include <memory>
@@ -1040,6 +1041,62 @@ bool DWARFASTParserClang::ParseObjCMethod(
return true;
}
+static bool IsStructorDIE(DWARFDIE const &die, DWARFDIE const &parent_die) {
+ llvm::StringRef name = die.GetName();
+ llvm::StringRef parent_name = parent_die.GetName();
+
+ name.consume_front("~");
+ parent_name = parent_name.substr(0, parent_name.find('<'));
+
+ return name == parent_name;
+}
+
+/// Given a DIE with an external definition (and thus no linkage name)
+/// find the definitions by lookup into the DWARF name index.
+/// We check the DW_AT_specification for each DIE in the index with
+/// the same name as the specified 'die' until we find one that references
+/// 'die'. Then return that linkage name. If no such DIE is found in the index,
+/// returns nullptr.
+static std::vector<std::string> FindStructorNames(DWARFDIE die) {
+ auto *dwarf = die.GetDWARF();
+ assert(dwarf);
+
+ ConstString func_name(die.GetName());
+ assert(func_name);
+
+ SymbolContextList sc_list;
+ Module::LookupInfo lookup_info(func_name,
+ FunctionNameType::eFunctionNameTypeMethod |
+ FunctionNameType::eFunctionNameTypeFull,
+ LanguageType::eLanguageTypeUnknown);
+ dwarf->FindFunctions(lookup_info, {}, true, sc_list);
+
+ std::vector<std::string> structor_names;
+ for (auto const &sc : sc_list.SymbolContexts()) {
+ if (auto *func = sc.function) {
+ auto func_die = dwarf->GetDIE(func->GetID());
+ if (!func_die.IsValid())
+ continue;
+
+ auto spec_die =
+ func_die.GetAttributeValueAsReferenceDIE(DW_AT_specification);
+ if (spec_die.IsValid() && spec_die == die) {
+ llvm::ItaniumPartialDemangler D;
+ const bool success = !D.partialDemangle(func_die.GetMangledName());
+ assert(success);
+ const auto maybe_structor_kind = D.getCtorDtorVariant();
+ assert(maybe_structor_kind);
+
+ structor_names.push_back(
+ llvm::formatv("{0}:$__lldb_func_{1}:{2}", *maybe_structor_kind,
+ func_die.GetModule().get(), func_die.GetID()));
+ }
+ }
+ }
+
+ return structor_names;
+}
+
std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
const DWARFDIE &die, CompilerType clang_type,
const ParsedDWARFTypeAttributes &attrs, const DWARFDIE &decl_ctx_die,
@@ -1140,11 +1197,15 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
const auto accessibility =
attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility;
+ std::vector<std::string> structor_names;
+ if (IsStructorDIE(die, decl_ctx_die))
+ structor_names = FindStructorNames(die);
+
clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
- attrs.is_artificial);
+ attrs.is_artificial, structor_names);
if (cxx_method_decl) {
LinkDeclContextToDIE(cxx_method_decl, die);
@@ -1330,19 +1391,10 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
lldbassert(function_decl);
if (function_decl) {
- // Attach an asm(<mangled_name>) label to the FunctionDecl.
- // This ensures that clang::CodeGen emits function calls
- // using symbols that are mangled according to the DW_AT_linkage_name.
- // If we didn't do this, the external symbols wouldn't exactly
- // match the mangled name LLDB knows about and the IRExecutionUnit
- // would have to fall back to searching object files for
- // approximately matching function names. The motivating
- // example is generating calls to ABI-tagged template functions.
- // This is done separately for member functions in
- // AddMethodToCXXRecordType.
- if (attrs.mangled_name)
- function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
- m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false));
+ auto ident = llvm::formatv("$__lldb_func_{0}:{1}",
+ die.GetModule().get(), die.GetID());
+ function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
+ m_ast.getASTContext(), ident.str(), /*literal=*/false));
LinkDeclContextToDIE(function_decl, die);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index b0f49ebf2d2cbb..549b810490a590 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/FormatVariadic.h"
@@ -7735,7 +7736,8 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
lldb::opaque_compiler_type_t type, llvm::StringRef name,
const char *mangled_name, const CompilerType &method_clang_type,
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
- bool is_explicit, bool is_attr_used, bool is_artificial) {
+ bool is_explicit, bool is_attr_used, bool is_artificial,
+ std::vector<std::string> const &structor_names) {
if (!type || !method_clang_type.IsValid() || name.empty())
return nullptr;
@@ -7788,6 +7790,11 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
cxx_dtor_decl->setImplicit(is_artificial);
cxx_dtor_decl->setInlineSpecified(is_inline);
cxx_dtor_decl->setConstexprKind(ConstexprSpecKind::Unspecified);
+ if (!structor_names.empty()) {
+ auto names = llvm::to_vector_of<llvm::StringRef>(structor_names);
+ cxx_dtor_decl->addAttr(clang::StructorMangledNamesAttr::CreateImplicit(
+ getASTContext(), names.data(), names.size()));
+ }
cxx_method_decl = cxx_dtor_decl;
} else if (decl_name == cxx_record_decl->getDeclName()) {
cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized(
@@ -7802,6 +7809,12 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
cxx_ctor_decl->setConstexprKind(ConstexprSpecKind::Unspecified);
cxx_ctor_decl->setNumCtorInitializers(0);
cxx_ctor_decl->setExplicitSpecifier(explicit_spec);
+ if (!structor_names.empty()) {
+ auto names = llvm::to_vector_of<llvm::StringRef>(structor_names);
+ cxx_ctor_decl->addAttr(clang::StructorMangledNamesAttr::CreateImplicit(
+ getASTContext(), names.data(), names.size()));
+ }
+
cxx_method_decl = cxx_ctor_decl;
} else {
clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index e39aedec7e3902..f5ab4dde8ed58c 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -980,7 +980,8 @@ class TypeSystemClang : public TypeSystem {
lldb::opaque_compiler_type_t type, llvm::StringRef name,
const char *mangled_name, const CompilerType &method_type,
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
- bool is_explicit, bool is_attr_used, bool is_artificial);
+ bool is_explicit, bool is_attr_used, bool is_artificial,
+ std::vector<std::string> const &structor_names = {});
void AddMethodOverridesForCXXRecordType(lldb::opaque_compiler_type_t type);
diff --git a/lldb/test/Shell/Expr/TestAbiTagCtorsDtors.cpp b/lldb/test/Shell/Expr/TestAbiTagCtorsDtors.cpp
new file mode 100644
index 00000000000000..49de90ee64dea6
--- /dev/null
+++ b/lldb/test/Shell/Expr/TestAbiTagCtorsDtors.cpp
@@ -0,0 +1,28 @@
+// Tests that we can call abi-tagged constructors/destructors.
+
+// RUN: %build %s -o %t
+// RUN: %lldb %t -o run \
+// RUN: -o "expression sinkTagged(getTagged())" \
+// RUN: -o "expression Tagged()" \
+// RUN: -o exit | FileCheck %s
+
+// CHECK: expression sinkTagged(getTagged())
+// CHECK: expression Tagged()
+
+struct Tagged {
+ [[gnu::abi_tag("Test", "CtorTag")]] [[gnu::abi_tag("v1")]] Tagged() = default;
+ [[gnu::abi_tag("Test", "DtorTag")]] [[gnu::abi_tag("v1")]] ~Tagged() {}
+
+ int mem = 15;
+};
+
+Tagged getTagged() { return Tagged(); }
+void sinkTagged(Tagged t) {}
+
+int main() {
+ Tagged t;
+
+ // TODO: is there a more reliable way of triggering destructor call?
+ sinkTagged(getTagged());
+ __builtin_debugtrap();
+}
diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h
index fe129603c0785d..103b60d6c343ce 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -10,6 +10,7 @@
#define LLVM_DEMANGLE_DEMANGLE_H
#include <cstddef>
+#include <optional>
#include <string>
#include <string_view>
@@ -108,6 +109,8 @@ struct ItaniumPartialDemangler {
/// the function is a non-static member function.
bool hasFunctionQualifiers() const;
+ std::optional<int> getCtorDtorVariant() const;
+
/// If this symbol describes a constructor or destructor.
bool isCtorOrDtor() const;
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 0af0224bc83fa8..39389132430ab0 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -1728,6 +1728,8 @@ class CtorDtorName final : public Node {
template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
+ int getVariant() const { return Variant; }
+
void printLeft(OutputBuffer &OB) const override {
if (IsDtor)
OB += "~";
diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp
index 5c21b06a1d0955..786985a141b022 100644
--- a/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -20,6 +20,7 @@
#include <cstring>
#include <exception>
#include <functional>
+#include <optional>
#include <utility>
using namespace llvm;
@@ -548,15 +549,16 @@ bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
}
-bool ItaniumPartialDemangler::isCtorOrDtor() const {
+std::optional<int> ItaniumPartialDemangler::getCtorDtorVariant() const {
const Node *N = static_cast<const Node *>(RootNode);
while (N) {
switch (N->getKind()) {
default:
- return false;
- case Node::KCtorDtorName:
- return true;
-
+ return std::nullopt;
+ case Node::KCtorDtorName: {
+ auto const *StructorNode = static_cast<const CtorDtorName *>(N);
+ return StructorNode->getVariant();
+ }
case Node::KAbiTagAttr:
N = static_cast<const AbiTagAttr *>(N)->Base;
break;
@@ -577,7 +579,11 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
break;
}
}
- return false;
+ return std::nullopt;
+}
+
+bool ItaniumPartialDemangler::isCtorOrDtor() const {
+ return getCtorDtorVariant().has_value();
}
bool ItaniumPartialDemangler::isFunction() const {
>From 752676b9921e424b10fc2dafbdf4410938a092c2 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 5 Nov 2024 11:34:12 +0000
Subject: [PATCH 2/2] fixup! handle case of aliased constructor variant
---
clang/lib/AST/Mangle.cpp | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 9b304d28113625..fcb1c6ecf42987 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -183,21 +183,37 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
}
}
+ // TODO: if only 1 variant is specified (i.e., C1 or C2)
+ // and we're looking for C1 or C2, pick the single one.
+ // Will that always do the right thing? What if C1 was
+ // optimized out because it was actually never called
+ // in the source. But then we tried to call it in expression
+ // evaluator? Maybe that's a sacrifice we have to make?
+ //
// Parse the LLDB [variant -> special name] mappings.
llvm::DenseMap<CtorDtor, llvm::StringRef> names;
for (auto name : SMA->mangledNames()) {
auto [structor_variant, mangled_name] = name.split(':');
auto variant = llvm::StringSwitch<CtorDtor>(structor_variant)
.Case("0", CtorDtor::Deleting)
- .Case("1", CtorDtor::Base)
- .Case("2", CtorDtor::Complete)
- .Case("3", CtorDtor::Complete)
+ .Case("1", CtorDtor::Complete)
+ .Case("2", CtorDtor::Base)
.Default(CtorDtor::None);
names[variant] = mangled_name;
}
assert(CtorDtorVariant != CtorDtor::None);
+ // If there is no definition for a completing structor variant but
+ // Clang is calling it lets take call the base variant since the
+ // definitions should (?) be the same.
+ if (!names.contains(CtorDtorVariant)
+ && names.size() == 1
+ && CtorDtorVariant == CtorDtor::Complete) {
+ CtorDtorVariant = CtorDtor::Base;
+ assert(names.contains(CtorDtorVariant));
+ }
+
// Pick the mapping
Out << names[CtorDtorVariant];
return;
More information about the cfe-commits
mailing list