Skip to content

[libcxxabi][ItaniumDemangle] Demangle explicitly named object parameters #72881

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

Merged
Merged
61 changes: 53 additions & 8 deletions libcxxabi/src/demangle/ItaniumDemangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()) {}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions libcxxabi/src/demangle/ItaniumNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,6 @@ NODE(RequiresExpr)
NODE(ExprRequirement)
NODE(TypeRequirement)
NODE(NestedRequirement)
NODE(ExplicitObjectParameter)

#undef NODE
10 changes: 10 additions & 0 deletions libcxxabi/test/test_demangle.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
61 changes: 53 additions & 8 deletions llvm/include/llvm/Demangle/ItaniumDemangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()) {}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Demangle/ItaniumNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,6 @@ NODE(RequiresExpr)
NODE(ExprRequirement)
NODE(TypeRequirement)
NODE(NestedRequirement)
NODE(ExplicitObjectParameter)

#undef NODE