Skip to content

[DO-NOT-MERGE] Add unified mangled name to structor declarations in DWARF #153369

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions clang/include/clang/Basic/ABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ctor.
};

/// 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
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6056,6 +6056,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
case Ctor_Base:
Out << '2';
break;
case Ctor_Unified:
Out << '4';
break;
case Ctor_Comdat:
Out << '5';
break;
Expand Down Expand Up @@ -6083,6 +6086,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
case Dtor_Base:
Out << "D2";
break;
case Dtor_Unified:
Out << "D4";
break;
case Dtor_Comdat:
Out << "D5";
break;
Expand Down
33 changes: 32 additions & 1 deletion clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,33 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
return shouldMangleCXXName(D);
}

static llvm::StringRef g_lldb_func_call_label_prefix = "$__lldb_func:";

/// Given an LLDB function call label, this function prints the label
/// into \c Out, together with the structor type of \c GD (if the
/// decl is a constructor/destructor). LLDB knows how to handle mangled
/// names with this encoding.
///
/// Example input label:
/// $__lldb_func::123:456:~Foo
///
/// Example output:
/// $__lldb_func:D1:123:456:~Foo
///
static void emitLLDBAsmLabel(llvm::StringRef label, GlobalDecl GD,
llvm::raw_ostream &Out) {
assert(label.starts_with(g_lldb_func_call_label_prefix));

Out << g_lldb_func_call_label_prefix;

if (llvm::isa<clang::CXXConstructorDecl>(GD.getDecl()))
Out << "C" << GD.getCtorType();
else if (llvm::isa<clang::CXXDestructorDecl>(GD.getDecl()))
Out << "D" << GD.getDtorType();

Out << label.substr(g_lldb_func_call_label_prefix.size());
}

void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
const ASTContext &ASTContext = getASTContext();
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
Expand Down Expand Up @@ -185,7 +212,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (!UserLabelPrefix.empty())
Out << '\01'; // LLVM IR Marker for __asm("foo")

Out << ALA->getLabel();
if (ALA->getLabel().starts_with(g_lldb_func_call_label_prefix))
emitLLDBAsmLabel(ALA->getLabel(), GD, Out);
else
Out << ALA->getLabel();

return;
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1494,6 +1494,8 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// <operator-name> ::= ?_E # vector deleting destructor
// FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need
// it.
case Dtor_Unified:
llvm_unreachable("not expecting a unified dtor");
case Dtor_Comdat:
llvm_unreachable("not expecting a COMDAT");
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,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");

Expand Down
22 changes: 15 additions & 7 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
Expand Down Expand Up @@ -2177,22 +2178,29 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) {

llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
bool IsCtorOrDtor =
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(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.
const bool ShouldAddLinkageName =
(!isa<CXXConstructorDecl>(Method) && !isa<CXXDestructorDecl>(Method)) ||
CGM.getTarget().getCXXABI().isItaniumFamily();

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 (ShouldAddLinkageName && !isFunctionLocalClass(Method->getParent())) {
if (auto *Ctor = dyn_cast<CXXConstructorDecl>(Method))
MethodLinkageName =
CGM.getMangledName(GlobalDecl(Ctor, CXXCtorType::Ctor_Unified));
else if (auto *Dtor = dyn_cast<CXXDestructorDecl>(Method))
MethodLinkageName =
CGM.getMangledName(GlobalDecl(Dtor, CXXDtorType::Dtor_Unified));
else
MethodLinkageName = CGM.getMangledName(Method);
}

// Get the location for the method.
llvm::DIFile *MethodDefUnit = nullptr;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Diagnostic.h"
Expand Down Expand Up @@ -2150,7 +2151,8 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) {
if (!getTarget().getCXXABI().hasConstructorVariants()) {
CXXCtorType OrigCtorType = GD.getCtorType();
assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete);
assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete ||
OrigCtorType == Ctor_Unified);
if (OrigCtorType == Ctor_Base)
CanonicalGD = GlobalDecl(CD, Ctor_Complete);
}
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
case Dtor_Base:
return false;

case Dtor_Unified:
llvm_unreachable("unexpected unified dtor");

case Dtor_Comdat:
llvm_unreachable("emitting dtor comdat as function?");
}
Expand All @@ -102,6 +105,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
case Ctor_Base:
return false;

case Ctor_Unified:
llvm_unreachable("unexpected unified ctor");

case Ctor_CopyingClosure:
case Ctor_DefaultClosure:
llvm_unreachable("closure ctors in Itanium ABI?");
Expand Down
75 changes: 75 additions & 0 deletions clang/unittests/AST/DeclTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "clang/AST/Mangle.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/TargetInfo.h"
Expand Down Expand Up @@ -102,6 +103,80 @@ TEST(Decl, AsmLabelAttr) {
"foo");
}

TEST(Decl, AsmLabelAttr_LLDB) {
StringRef Code = R"(
struct S {
void f() {}
S() = default;
~S() = default;
};
)";
auto AST =
tooling::buildASTFromCodeWithArgs(Code, {"-target", "i386-apple-darwin"});
ASTContext &Ctx = AST->getASTContext();
assert(Ctx.getTargetInfo().getUserLabelPrefix() == StringRef("_") &&
"Expected target to have a global prefix");
DiagnosticsEngine &Diags = AST->getDiagnostics();

const auto *DeclS =
selectFirst<CXXRecordDecl>("d", match(cxxRecordDecl().bind("d"), Ctx));

auto *DeclF = *DeclS->method_begin();
auto *Ctor = *DeclS->ctor_begin();
auto *Dtor = DeclS->getDestructor();

ASSERT_TRUE(DeclF);
ASSERT_TRUE(Ctor);
ASSERT_TRUE(Dtor);

DeclF->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:_Z1fv"));
Ctor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:S"));
Dtor->addAttr(AsmLabelAttr::Create(Ctx, "$__lldb_func::123:123:~S"));

std::unique_ptr<ItaniumMangleContext> MC(
ItaniumMangleContext::create(Ctx, Diags));

{
std::string Mangled;
llvm::raw_string_ostream OS_Mangled(Mangled);
MC->mangleName(DeclF, OS_Mangled);

ASSERT_EQ(Mangled, "\x01$__lldb_func::123:123:_Z1fv");
};

{
std::string Mangled;
llvm::raw_string_ostream OS_Mangled(Mangled);
MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Complete), OS_Mangled);

ASSERT_EQ(Mangled, "\x01$__lldb_func:C0:123:123:S");
};

{
std::string Mangled;
llvm::raw_string_ostream OS_Mangled(Mangled);
MC->mangleName(GlobalDecl(Ctor, CXXCtorType::Ctor_Base), OS_Mangled);

ASSERT_EQ(Mangled, "\x01$__lldb_func:C1:123:123:S");
};

{
std::string Mangled;
llvm::raw_string_ostream OS_Mangled(Mangled);
MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Deleting), OS_Mangled);

ASSERT_EQ(Mangled, "\x01$__lldb_func:D0:123:123:~S");
};

{
std::string Mangled;
llvm::raw_string_ostream OS_Mangled(Mangled);
MC->mangleName(GlobalDecl(Dtor, CXXDtorType::Dtor_Base), OS_Mangled);

ASSERT_EQ(Mangled, "\x01$__lldb_func:D2:123:123:~S");
};
}

TEST(Decl, MangleDependentSizedArray) {
StringRef Code = R"(
template <int ...N>
Expand Down
28 changes: 17 additions & 11 deletions llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,17 +493,23 @@ void DwarfDebug::addSubprogramNames(
if (SP->getName() != "")
addAccelName(Unit, NameTableKind, SP->getName(), Die);

// We drop the mangling escape prefix when emitting the DW_AT_linkage_name. So
// ensure we don't include it when inserting into the accelerator tables.
llvm::StringRef LinkageName =
GlobalValue::dropLLVMManglingEscape(SP->getLinkageName());

// If the linkage name is different than the name, go ahead and output that as
// well into the name table. Only do that if we are going to actually emit
// that name.
if (LinkageName != "" && SP->getName() != LinkageName &&
(useAllLinkageNames() || InfoHolder.getAbstractScopeDIEs().lookup(SP)))
addAccelName(Unit, NameTableKind, LinkageName, Die);
auto AddLinkageName = [&](const DISubprogram *S) {
// We drop the mangling escape prefix when emitting the DW_AT_linkage_name.
// So ensure we don't include it when inserting into the accelerator tables.
llvm::StringRef LinkageName =
GlobalValue::dropLLVMManglingEscape(S->getLinkageName());

// If the linkage name is different than the name, go ahead and output that
// as well into the name table. Only do that if we are going to actually
// emit that name.
if (LinkageName != "" && S->getName() != LinkageName &&
(useAllLinkageNames() || InfoHolder.getAbstractScopeDIEs().lookup(S)))
addAccelName(Unit, NameTableKind, LinkageName, Die);
};

AddLinkageName(SP);
if (const DISubprogram *Spec = SP->getDeclaration())
AddLinkageName(Spec);

// If this is an Objective-C selector name add it to the ObjC accelerator
// too.
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1403,10 +1403,10 @@ 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() &&
// 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.
(DD->useAllLinkageNames() || DU->getAbstractScopeDIEs().lookup(SP)))
addLinkageName(SPDie, LinkageName);
Expand Down
Loading