[clang] [clang][Mangle] Inject structor type into mangled name when mangling for LLDB JIT expressions (PR #155485)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 26 12:53:46 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Michael Buch (Michael137)
<details>
<summary>Changes</summary>
Part of https://github.com/llvm/llvm-project/pull/149827
This patch adds special handling for `AsmLabel`s created by LLDB. LLDB uses `AsmLabel`s to encode information about a function declaration to make it easier to locate function symbols when JITing C++ expressions. For constructors/destructors LLDB doesn't know at the time of creating the `AsmLabelAttr` which structor variant the expression evaluator will need to call (this is decided when compiling the expression). So we make the Clang mangler inject this information into our custom label when we're JITting the expression.
---
Full diff: https://github.com/llvm/llvm-project/pull/155485.diff
2 Files Affected:
- (modified) clang/lib/AST/Mangle.cpp (+32-1)
- (modified) clang/unittests/AST/DeclTest.cpp (+75)
``````````diff
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 0bfb51c11f0a5..1131477fa7200 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -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());
@@ -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;
}
diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp
index 6b443918ec137..4bd7886ef9b35 100644
--- a/clang/unittests/AST/DeclTest.cpp
+++ b/clang/unittests/AST/DeclTest.cpp
@@ -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"
@@ -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>
``````````
</details>
https://github.com/llvm/llvm-project/pull/155485
More information about the cfe-commits
mailing list