[llvm] 4d5079c - [libcxxabi][ItaniumDemangle] Demangle explicitly named object parameters (#72881)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 28 13:24:24 PST 2023
Author: Michael Buch
Date: 2023-11-28T21:24:19Z
New Revision: 4d5079c4dc0ce30ba36315a7c822255cd1eeb9fb
URL: https://github.com/llvm/llvm-project/commit/4d5079c4dc0ce30ba36315a7c822255cd1eeb9fb
DIFF: https://github.com/llvm/llvm-project/commit/4d5079c4dc0ce30ba36315a7c822255cd1eeb9fb.diff
LOG: [libcxxabi][ItaniumDemangle] Demangle explicitly named object parameters (#72881)
The mangling for an explicitly named object was introduced in
https://reviews.llvm.org/D140828
See following discussion for why a new mangling had to be introduced:
https://github.com/itanium-cxx-abi/cxx-abi/issues/148
Since clang started emitting names with the new mangling, this patch
implements support for demangling such names.
The approach this patch takes is to add a new `ExplicitObjectParameter`
node that will print the first parameter of a function declaration with
a `this ` prefix, to reflect what was spelled out in source.
Example:
```
void MyClass::func(this MyClass const& self); // _ZNH7MyClass4funcERKS_
```
With this patch, the above demangles to:
```
_ZNH7MyClass4funcERKS_ -> MyClass::func(this MyClass const&)
```
Note that `func` is not marked as `const &`, since the
function-qualifiers are now encoded as part of the explicit `this`. C++
doesn't allow specifying the function-qualifiers in the presence of an
explicit object parameter, so this demangling is consistent with the
source spelling.
Added:
Modified:
libcxxabi/src/demangle/ItaniumDemangle.h
libcxxabi/src/demangle/ItaniumNodes.def
libcxxabi/test/test_demangle.pass.cpp
llvm/include/llvm/Demangle/ItaniumDemangle.h
llvm/include/llvm/Demangle/ItaniumNodes.def
Removed:
################################################################################
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 0ebfc0ecb74d8e1..90f25519fad1c8d 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -889,6 +889,32 @@ class DynamicExceptionSpec : public Node {
}
};
+/// Represents the explicitly named object parameter.
+/// E.g.,
+/// \code{.cpp}
+/// struct Foo {
+/// void bar(this Foo && self);
+/// };
+/// \endcode
+class ExplicitObjectParameter final : public Node {
+ Node *Base;
+
+public:
+ ExplicitObjectParameter(Node *Base_)
+ : Node(KExplicitObjectParameter), Base(Base_) {
+ DEMANGLE_ASSERT(
+ Base != nullptr,
+ "Creating an ExplicitObjectParameter without a valid Base Node.");
+ }
+
+ template <typename Fn> void match(Fn F) const { F(Base); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "this ";
+ Base->print(OB);
+ }
+};
+
class FunctionEncoding final : public Node {
const Node *Ret;
const Node *Name;
@@ -2780,6 +2806,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Qualifiers CVQualifiers = QualNone;
FunctionRefQual ReferenceQualifier = FrefQualNone;
size_t ForwardTemplateRefsBegin;
+ bool HasExplicitObjectParameter = false;
NameState(AbstractManglingParser *Enclosing)
: ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}
@@ -3438,15 +3465,25 @@ AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
if (!consumeIf('N'))
return nullptr;
- Qualifiers CVTmp = parseCVQualifiers();
- if (State) State->CVQualifiers = CVTmp;
+ // 'H' specifies that the encoding that follows
+ // has an explicit object parameter.
+ if (!consumeIf('H')) {
+ Qualifiers CVTmp = parseCVQualifiers();
+ if (State)
+ State->CVQualifiers = CVTmp;
- if (consumeIf('O')) {
- if (State) State->ReferenceQualifier = FrefQualRValue;
- } else if (consumeIf('R')) {
- if (State) State->ReferenceQualifier = FrefQualLValue;
- } else {
- if (State) State->ReferenceQualifier = FrefQualNone;
+ if (consumeIf('O')) {
+ if (State)
+ State->ReferenceQualifier = FrefQualRValue;
+ } else if (consumeIf('R')) {
+ if (State)
+ State->ReferenceQualifier = FrefQualLValue;
+ } else {
+ if (State)
+ State->ReferenceQualifier = FrefQualNone;
+ }
+ } else if (State) {
+ State->HasExplicitObjectParameter = true;
}
Node *SoFar = nullptr;
@@ -5422,6 +5459,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return nullptr;
+
+ const bool IsFirstParam = ParamsBegin == Names.size();
+ if (NameInfo.HasExplicitObjectParameter && IsFirstParam)
+ Ty = make<ExplicitObjectParameter>(Ty);
+
+ if (Ty == nullptr)
+ return nullptr;
+
Names.push_back(Ty);
} while (!IsEndOfEncoding() && look() != 'Q');
Params = popTrailingNodeArray(ParamsBegin);
diff --git a/libcxxabi/src/demangle/ItaniumNodes.def b/libcxxabi/src/demangle/ItaniumNodes.def
index e27c111de3389c5..18f5d52b47e9113 100644
--- a/libcxxabi/src/demangle/ItaniumNodes.def
+++ b/libcxxabi/src/demangle/ItaniumNodes.def
@@ -99,5 +99,6 @@ NODE(RequiresExpr)
NODE(ExprRequirement)
NODE(TypeRequirement)
NODE(NestedRequirement)
+NODE(ExplicitObjectParameter)
#undef NODE
diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index ff56d8772869c19..67d52088a9e7c9a 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -30175,6 +30175,16 @@ const char* cases[][2] =
{"_Z2f5IKiEvu14__remove_constIT_E", "void f5<int const>(__remove_const(int const))"},
{"_Z2f5IPiEvu16__remove_pointerIT_E", "void f5<int*>(__remove_pointer(int*))"},
{"_Z2f5IiEvu14__remove_cvrefIT_E", "void f5<int>(__remove_cvref(int))"},
+
+ // C++23 explicit object parameter
+ {"_ZNH3Foo3fooES_i", "Foo::foo(this Foo, int)"},
+ {"_ZNH3Foo3fooERKS_i", "Foo::foo(this Foo const&, int)"},
+ {"_ZNH1X3fooIRS_EEvOT_i", "void X::foo<X&>(this X&, int)"},
+ {"_ZZNH2ns3Foo3fooES0_iENH4Foo24foo2EOKS1_", "ns::Foo::foo(this ns::Foo, int)::Foo2::foo2(this Foo2 const&&)" },
+ {"_ZNH2ns3FooB7Foo_tag3fooB7foo_tagERKS0_i", "ns::Foo[abi:Foo_tag]::foo[abi:foo_tag](this ns::Foo[abi:Foo_tag] const&, int)" },
+ {"_ZZN3Foo3fooEiENH4Foo24foo2EOKS0_", "Foo::foo(int)::Foo2::foo2(this Foo2 const&&)"},
+ {"_ZZNH3Foo3fooES_iENK4Foo24foo2Ev", "Foo::foo(this Foo, int)::Foo2::foo2() const" },
+ {"_ZNH3FooclERKS_", "Foo::operator()(this Foo const&)"},
};
// clang-format on
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index a3558d2cfd5be83..e0ff035d47cfb4f 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -888,6 +888,32 @@ class DynamicExceptionSpec : public Node {
}
};
+/// Represents the explicitly named object parameter.
+/// E.g.,
+/// \code{.cpp}
+/// struct Foo {
+/// void bar(this Foo && self);
+/// };
+/// \endcode
+class ExplicitObjectParameter final : public Node {
+ Node *Base;
+
+public:
+ ExplicitObjectParameter(Node *Base_)
+ : Node(KExplicitObjectParameter), Base(Base_) {
+ DEMANGLE_ASSERT(
+ Base != nullptr,
+ "Creating an ExplicitObjectParameter without a valid Base Node.");
+ }
+
+ template <typename Fn> void match(Fn F) const { F(Base); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "this ";
+ Base->print(OB);
+ }
+};
+
class FunctionEncoding final : public Node {
const Node *Ret;
const Node *Name;
@@ -2779,6 +2805,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Qualifiers CVQualifiers = QualNone;
FunctionRefQual ReferenceQualifier = FrefQualNone;
size_t ForwardTemplateRefsBegin;
+ bool HasExplicitObjectParameter = false;
NameState(AbstractManglingParser *Enclosing)
: ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}
@@ -3437,15 +3464,25 @@ AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
if (!consumeIf('N'))
return nullptr;
- Qualifiers CVTmp = parseCVQualifiers();
- if (State) State->CVQualifiers = CVTmp;
+ // 'H' specifies that the encoding that follows
+ // has an explicit object parameter.
+ if (!consumeIf('H')) {
+ Qualifiers CVTmp = parseCVQualifiers();
+ if (State)
+ State->CVQualifiers = CVTmp;
- if (consumeIf('O')) {
- if (State) State->ReferenceQualifier = FrefQualRValue;
- } else if (consumeIf('R')) {
- if (State) State->ReferenceQualifier = FrefQualLValue;
- } else {
- if (State) State->ReferenceQualifier = FrefQualNone;
+ if (consumeIf('O')) {
+ if (State)
+ State->ReferenceQualifier = FrefQualRValue;
+ } else if (consumeIf('R')) {
+ if (State)
+ State->ReferenceQualifier = FrefQualLValue;
+ } else {
+ if (State)
+ State->ReferenceQualifier = FrefQualNone;
+ }
+ } else if (State) {
+ State->HasExplicitObjectParameter = true;
}
Node *SoFar = nullptr;
@@ -5421,6 +5458,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return nullptr;
+
+ const bool IsFirstParam = ParamsBegin == Names.size();
+ if (NameInfo.HasExplicitObjectParameter && IsFirstParam)
+ Ty = make<ExplicitObjectParameter>(Ty);
+
+ if (Ty == nullptr)
+ return nullptr;
+
Names.push_back(Ty);
} while (!IsEndOfEncoding() && look() != 'Q');
Params = popTrailingNodeArray(ParamsBegin);
diff --git a/llvm/include/llvm/Demangle/ItaniumNodes.def b/llvm/include/llvm/Demangle/ItaniumNodes.def
index 30a93eccaee37e9..330552663ee658d 100644
--- a/llvm/include/llvm/Demangle/ItaniumNodes.def
+++ b/llvm/include/llvm/Demangle/ItaniumNodes.def
@@ -99,5 +99,6 @@ NODE(RequiresExpr)
NODE(ExprRequirement)
NODE(TypeRequirement)
NODE(NestedRequirement)
+NODE(ExplicitObjectParameter)
#undef NODE
More information about the llvm-commits
mailing list