diff options
author | Michael Buch <michaelbuch12@gmail.com> | 2023-11-28 21:24:19 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-28 21:24:19 +0000 |
commit | 4d5079c4dc0ce30ba36315a7c822255cd1eeb9fb (patch) | |
tree | 1b6ed53f5760ab4be92132454581b73b0b259687 /libcxxabi | |
parent | ec76d3975c42cb4906fe6e2b555f720d097cc49f (diff) | |
download | llvm-4d5079c4dc0ce30ba36315a7c822255cd1eeb9fb.zip llvm-4d5079c4dc0ce30ba36315a7c822255cd1eeb9fb.tar.gz llvm-4d5079c4dc0ce30ba36315a7c822255cd1eeb9fb.tar.bz2 |
[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.
Diffstat (limited to 'libcxxabi')
-rw-r--r-- | libcxxabi/src/demangle/ItaniumDemangle.h | 61 | ||||
-rw-r--r-- | libcxxabi/src/demangle/ItaniumNodes.def | 1 | ||||
-rw-r--r-- | libcxxabi/test/test_demangle.pass.cpp | 10 |
3 files changed, 64 insertions, 8 deletions
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index 0ebfc0e..90f2551 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -889,6 +889,32 @@ public: } }; +/// 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 e27c111..18f5d52 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 ff56d87..67d5208 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 |