//===--- ItaniumDemangle.h -----------*- mode:c++;eval:(read-only-mode) -*-===// // Do not edit! See README.txt. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-FileCopyrightText: Part of the LLVM Project // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Generic itanium demangler library. // There are two copies of this file in the source tree. The one under // libcxxabi is the original and the one under llvm is the copy. Use // cp-to-llvm.sh to update the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// #ifndef DEMANGLE_ITANIUMDEMANGLE_H #define DEMANGLE_ITANIUMDEMANGLE_H #include "DemangleConfig.h" #include "StringViewExtras.h" #include "Utility.h" #include #include #include #include #include #include #include #include #include #include #include DEMANGLE_NAMESPACE_BEGIN template class PODSmallVector { static_assert(std::is_pod::value, "T is required to be a plain old data type"); T *First = nullptr; T *Last = nullptr; T *Cap = nullptr; T Inline[N] = {0}; bool isInline() const { return First == Inline; } void clearInline() { First = Inline; Last = Inline; Cap = Inline + N; } void reserve(size_t NewCap) { size_t S = size(); if (isInline()) { auto *Tmp = static_cast(std::malloc(NewCap * sizeof(T))); if (Tmp == nullptr) std::terminate(); std::copy(First, Last, Tmp); First = Tmp; } else { First = static_cast(std::realloc(First, NewCap * sizeof(T))); if (First == nullptr) std::terminate(); } Last = First + S; Cap = First + NewCap; } public: PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} PODSmallVector(const PODSmallVector &) = delete; PODSmallVector &operator=(const PODSmallVector &) = delete; PODSmallVector(PODSmallVector &&Other) : PODSmallVector() { if (Other.isInline()) { std::copy(Other.begin(), Other.end(), First); Last = First + Other.size(); Other.clear(); return; } First = Other.First; Last = Other.Last; Cap = Other.Cap; Other.clearInline(); } PODSmallVector &operator=(PODSmallVector &&Other) { if (Other.isInline()) { if (!isInline()) { std::free(First); clearInline(); } std::copy(Other.begin(), Other.end(), First); Last = First + Other.size(); Other.clear(); return *this; } if (isInline()) { First = Other.First; Last = Other.Last; Cap = Other.Cap; Other.clearInline(); return *this; } std::swap(First, Other.First); std::swap(Last, Other.Last); std::swap(Cap, Other.Cap); Other.clear(); return *this; } // NOLINTNEXTLINE(readability-identifier-naming) void push_back(const T &Elem) { if (Last == Cap) reserve(size() * 2); *Last++ = Elem; } // NOLINTNEXTLINE(readability-identifier-naming) void pop_back() { assert(Last != First && "Popping empty vector!"); --Last; } void dropBack(size_t Index) { assert(Index <= size() && "dropBack() can't expand!"); Last = First + Index; } T *begin() { return First; } T *end() { return Last; } bool empty() const { return First == Last; } size_t size() const { return static_cast(Last - First); } T &back() { assert(Last != First && "Calling back() on empty vector!"); return *(Last - 1); } T &operator[](size_t Index) { assert(Index < size() && "Invalid access!"); return *(begin() + Index); } void clear() { Last = First; } ~PODSmallVector() { if (!isInline()) std::free(First); } }; // Base class of all AST nodes. The AST is built by the parser, then is // traversed by the printLeft/Right functions to produce a demangled string. class Node { public: enum Kind : unsigned char { #define NODE(NodeKind) K##NodeKind, #include "ItaniumNodes.def" }; /// Three-way bool to track a cached value. Unknown is possible if this node /// has an unexpanded parameter pack below it that may affect this cache. enum class Cache : unsigned char { Yes, No, Unknown, }; /// Operator precedence for expression nodes. Used to determine required /// parens in expression emission. enum class Prec { Primary, Postfix, Unary, Cast, PtrMem, Multiplicative, Additive, Shift, Spaceship, Relational, Equality, And, Xor, Ior, AndIf, OrIf, Conditional, Assign, Comma, Default, }; private: Kind K; Prec Precedence : 6; // FIXME: Make these protected. public: /// Tracks if this node has a component on its right side, in which case we /// need to call printRight. Cache RHSComponentCache : 2; /// Track if this node is a (possibly qualified) array type. This can affect /// how we format the output string. Cache ArrayCache : 2; /// Track if this node is a (possibly qualified) function type. This can /// affect how we format the output string. Cache FunctionCache : 2; public: Node(Kind K_, Prec Precedence_ = Prec::Primary, Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) : K(K_), Precedence(Precedence_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), FunctionCache(FunctionCache_) {} Node(Kind K_, Cache RHSComponentCache_, Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) : Node(K_, Prec::Primary, RHSComponentCache_, ArrayCache_, FunctionCache_) {} /// Visit the most-derived object corresponding to this object. template void visit(Fn F) const; // The following function is provided by all derived classes: // // Call F with arguments that, when passed to the constructor of this node, // would construct an equivalent node. //template void match(Fn F) const; bool hasRHSComponent(OutputBuffer &OB) const { if (RHSComponentCache != Cache::Unknown) return RHSComponentCache == Cache::Yes; return hasRHSComponentSlow(OB); } bool hasArray(OutputBuffer &OB) const { if (ArrayCache != Cache::Unknown) return ArrayCache == Cache::Yes; return hasArraySlow(OB); } bool hasFunction(OutputBuffer &OB) const { if (FunctionCache != Cache::Unknown) return FunctionCache == Cache::Yes; return hasFunctionSlow(OB); } Kind getKind() const { return K; } Prec getPrecedence() const { return Precedence; } virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; } virtual bool hasArraySlow(OutputBuffer &) const { return false; } virtual bool hasFunctionSlow(OutputBuffer &) const { return false; } // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to // get at a node that actually represents some concrete syntax. virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; } // Print this node as an expression operand, surrounding it in parentheses if // its precedence is [Strictly] weaker than P. void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default, bool StrictlyWorse = false) const { bool Paren = unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse); if (Paren) OB.printOpen(); print(OB); if (Paren) OB.printClose(); } void print(OutputBuffer &OB) const { printLeft(OB); if (RHSComponentCache != Cache::No) printRight(OB); } // Print the "left" side of this Node into OutputBuffer. virtual void printLeft(OutputBuffer &) const = 0; // Print the "right". This distinction is necessary to represent C++ types // that appear on the RHS of their subtype, such as arrays or functions. // Since most types don't have such a component, provide a default // implementation. virtual void printRight(OutputBuffer &) const {} virtual std::string_view getBaseName() const { return {}; } // Silence compiler warnings, this dtor will never be called. virtual ~Node() = default; #ifndef NDEBUG DEMANGLE_DUMP_METHOD void dump() const; #endif }; class NodeArray { Node **Elements; size_t NumElements; public: NodeArray() : Elements(nullptr), NumElements(0) {} NodeArray(Node **Elements_, size_t NumElements_) : Elements(Elements_), NumElements(NumElements_) {} bool empty() const { return NumElements == 0; } size_t size() const { return NumElements; } Node **begin() const { return Elements; } Node **end() const { return Elements + NumElements; } Node *operator[](size_t Idx) const { return Elements[Idx]; } void printWithComma(OutputBuffer &OB) const { bool FirstElement = true; for (size_t Idx = 0; Idx != NumElements; ++Idx) { size_t BeforeComma = OB.getCurrentPosition(); if (!FirstElement) OB += ", "; size_t AfterComma = OB.getCurrentPosition(); Elements[Idx]->printAsOperand(OB, Node::Prec::Comma); // Elements[Idx] is an empty parameter pack expansion, we should erase the // comma we just printed. if (AfterComma == OB.getCurrentPosition()) { OB.setCurrentPosition(BeforeComma); continue; } FirstElement = false; } } }; struct NodeArrayNode : Node { NodeArray Array; NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} template void match(Fn F) const { F(Array); } void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); } }; class DotSuffix final : public Node { const Node *Prefix; const std::string_view Suffix; public: DotSuffix(const Node *Prefix_, std::string_view Suffix_) : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} template void match(Fn F) const { F(Prefix, Suffix); } void printLeft(OutputBuffer &OB) const override { Prefix->print(OB); OB += " ("; OB += Suffix; OB += ")"; } }; class VendorExtQualType final : public Node { const Node *Ty; std::string_view Ext; const Node *TA; public: VendorExtQualType(const Node *Ty_, std::string_view Ext_, const Node *TA_) : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} const Node *getTy() const { return Ty; } std::string_view getExt() const { return Ext; } const Node *getTA() const { return TA; } template void match(Fn F) const { F(Ty, Ext, TA); } void printLeft(OutputBuffer &OB) const override { Ty->print(OB); OB += " "; OB += Ext; if (TA != nullptr) TA->print(OB); } }; enum FunctionRefQual : unsigned char { FrefQualNone, FrefQualLValue, FrefQualRValue, }; enum Qualifiers { QualNone = 0, QualConst = 0x1, QualVolatile = 0x2, QualRestrict = 0x4, }; inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) { return Q1 = static_cast(Q1 | Q2); } class QualType final : public Node { protected: const Qualifiers Quals; const Node *Child; void printQuals(OutputBuffer &OB) const { if (Quals & QualConst) OB += " const"; if (Quals & QualVolatile) OB += " volatile"; if (Quals & QualRestrict) OB += " restrict"; } public: QualType(const Node *Child_, Qualifiers Quals_) : Node(KQualType, Child_->RHSComponentCache, Child_->ArrayCache, Child_->FunctionCache), Quals(Quals_), Child(Child_) {} Qualifiers getQuals() const { return Quals; } const Node *getChild() const { return Child; } template void match(Fn F) const { F(Child, Quals); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { return Child->hasRHSComponent(OB); } bool hasArraySlow(OutputBuffer &OB) const override { return Child->hasArray(OB); } bool hasFunctionSlow(OutputBuffer &OB) const override { return Child->hasFunction(OB); } void printLeft(OutputBuffer &OB) const override { Child->printLeft(OB); printQuals(OB); } void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } }; class ConversionOperatorType final : public Node { const Node *Ty; public: ConversionOperatorType(const Node *Ty_) : Node(KConversionOperatorType), Ty(Ty_) {} template void match(Fn F) const { F(Ty); } void printLeft(OutputBuffer &OB) const override { OB += "operator "; Ty->print(OB); } }; class PostfixQualifiedType final : public Node { const Node *Ty; const std::string_view Postfix; public: PostfixQualifiedType(const Node *Ty_, std::string_view Postfix_) : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} template void match(Fn F) const { F(Ty, Postfix); } void printLeft(OutputBuffer &OB) const override { Ty->printLeft(OB); OB += Postfix; } }; class NameType final : public Node { const std::string_view Name; public: NameType(std::string_view Name_) : Node(KNameType), Name(Name_) {} template void match(Fn F) const { F(Name); } std::string_view getName() const { return Name; } std::string_view getBaseName() const override { return Name; } void printLeft(OutputBuffer &OB) const override { OB += Name; } }; class BitIntType final : public Node { const Node *Size; bool Signed; public: BitIntType(const Node *Size_, bool Signed_) : Node(KBitIntType), Size(Size_), Signed(Signed_) {} template void match(Fn F) const { F(Size, Signed); } void printLeft(OutputBuffer &OB) const override { if (!Signed) OB += "unsigned "; OB += "_BitInt"; OB.printOpen(); Size->printAsOperand(OB); OB.printClose(); } }; class ElaboratedTypeSpefType : public Node { std::string_view Kind; Node *Child; public: ElaboratedTypeSpefType(std::string_view Kind_, Node *Child_) : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} template void match(Fn F) const { F(Kind, Child); } void printLeft(OutputBuffer &OB) const override { OB += Kind; OB += ' '; Child->print(OB); } }; struct AbiTagAttr : Node { Node *Base; std::string_view Tag; AbiTagAttr(Node *Base_, std::string_view Tag_) : Node(KAbiTagAttr, Base_->RHSComponentCache, Base_->ArrayCache, Base_->FunctionCache), Base(Base_), Tag(Tag_) {} template void match(Fn F) const { F(Base, Tag); } std::string_view getBaseName() const override { return Base->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); OB += "[abi:"; OB += Tag; OB += "]"; } }; class EnableIfAttr : public Node { NodeArray Conditions; public: EnableIfAttr(NodeArray Conditions_) : Node(KEnableIfAttr), Conditions(Conditions_) {} template void match(Fn F) const { F(Conditions); } void printLeft(OutputBuffer &OB) const override { OB += " [enable_if:"; Conditions.printWithComma(OB); OB += ']'; } }; class ObjCProtoName : public Node { const Node *Ty; std::string_view Protocol; friend class PointerType; public: ObjCProtoName(const Node *Ty_, std::string_view Protocol_) : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} template void match(Fn F) const { F(Ty, Protocol); } bool isObjCObject() const { return Ty->getKind() == KNameType && static_cast(Ty)->getName() == "objc_object"; } void printLeft(OutputBuffer &OB) const override { Ty->print(OB); OB += "<"; OB += Protocol; OB += ">"; } }; class PointerType final : public Node { const Node *Pointee; public: PointerType(const Node *Pointee_) : Node(KPointerType, Pointee_->RHSComponentCache), Pointee(Pointee_) {} const Node *getPointee() const { return Pointee; } template void match(Fn F) const { F(Pointee); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { return Pointee->hasRHSComponent(OB); } void printLeft(OutputBuffer &OB) const override { // We rewrite objc_object* into id. if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { Pointee->printLeft(OB); if (Pointee->hasArray(OB)) OB += " "; if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) OB += "("; OB += "*"; } else { const auto *objcProto = static_cast(Pointee); OB += "id<"; OB += objcProto->Protocol; OB += ">"; } } void printRight(OutputBuffer &OB) const override { if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) OB += ")"; Pointee->printRight(OB); } } }; enum class ReferenceKind { LValue, RValue, }; // Represents either a LValue or an RValue reference type. class ReferenceType : public Node { const Node *Pointee; ReferenceKind RK; mutable bool Printing = false; // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any // other combination collapses to a lvalue ref. // // A combination of a TemplateForwardReference and a back-ref Substitution // from an ill-formed string may have created a cycle; use cycle detection to // avoid looping forever. std::pair collapse(OutputBuffer &OB) const { auto SoFar = std::make_pair(RK, Pointee); // Track the chain of nodes for the Floyd's 'tortoise and hare' // cycle-detection algorithm, since getSyntaxNode(S) is impure PODSmallVector Prev; for (;;) { const Node *SN = SoFar.second->getSyntaxNode(OB); if (SN->getKind() != KReferenceType) break; auto *RT = static_cast(SN); SoFar.second = RT->Pointee; SoFar.first = std::min(SoFar.first, RT->RK); // The middle of Prev is the 'slow' pointer moving at half speed Prev.push_back(SoFar.second); if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) { // Cycle detected SoFar.second = nullptr; break; } } return SoFar; } public: ReferenceType(const Node *Pointee_, ReferenceKind RK_) : Node(KReferenceType, Pointee_->RHSComponentCache), Pointee(Pointee_), RK(RK_) {} template void match(Fn F) const { F(Pointee, RK); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { return Pointee->hasRHSComponent(OB); } void printLeft(OutputBuffer &OB) const override { if (Printing) return; ScopedOverride SavePrinting(Printing, true); std::pair Collapsed = collapse(OB); if (!Collapsed.second) return; Collapsed.second->printLeft(OB); if (Collapsed.second->hasArray(OB)) OB += " "; if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) OB += "("; OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); } void printRight(OutputBuffer &OB) const override { if (Printing) return; ScopedOverride SavePrinting(Printing, true); std::pair Collapsed = collapse(OB); if (!Collapsed.second) return; if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) OB += ")"; Collapsed.second->printRight(OB); } }; class PointerToMemberType final : public Node { const Node *ClassType; const Node *MemberType; public: PointerToMemberType(const Node *ClassType_, const Node *MemberType_) : Node(KPointerToMemberType, MemberType_->RHSComponentCache), ClassType(ClassType_), MemberType(MemberType_) {} template void match(Fn F) const { F(ClassType, MemberType); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { return MemberType->hasRHSComponent(OB); } void printLeft(OutputBuffer &OB) const override { MemberType->printLeft(OB); if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) OB += "("; else OB += " "; ClassType->print(OB); OB += "::*"; } void printRight(OutputBuffer &OB) const override { if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) OB += ")"; MemberType->printRight(OB); } }; class ArrayType final : public Node { const Node *Base; Node *Dimension; public: ArrayType(const Node *Base_, Node *Dimension_) : Node(KArrayType, /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::Yes), Base(Base_), Dimension(Dimension_) {} template void match(Fn F) const { F(Base, Dimension); } bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } bool hasArraySlow(OutputBuffer &) const override { return true; } void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); } void printRight(OutputBuffer &OB) const override { if (OB.back() != ']') OB += " "; OB += "["; if (Dimension) Dimension->print(OB); OB += "]"; Base->printRight(OB); } }; class FunctionType final : public Node { const Node *Ret; NodeArray Params; Qualifiers CVQuals; FunctionRefQual RefQual; const Node *ExceptionSpec; public: FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, FunctionRefQual RefQual_, const Node *ExceptionSpec_) : Node(KFunctionType, /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, /*FunctionCache=*/Cache::Yes), Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), ExceptionSpec(ExceptionSpec_) {} template void match(Fn F) const { F(Ret, Params, CVQuals, RefQual, ExceptionSpec); } bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } bool hasFunctionSlow(OutputBuffer &) const override { return true; } // Handle C++'s ... quirky decl grammar by using the left & right // distinction. Consider: // int (*f(float))(char) {} // f is a function that takes a float and returns a pointer to a function // that takes a char and returns an int. If we're trying to print f, start // by printing out the return types's left, then print our parameters, then // finally print right of the return type. void printLeft(OutputBuffer &OB) const override { Ret->printLeft(OB); OB += " "; } void printRight(OutputBuffer &OB) const override { OB.printOpen(); Params.printWithComma(OB); OB.printClose(); Ret->printRight(OB); if (CVQuals & QualConst) OB += " const"; if (CVQuals & QualVolatile) OB += " volatile"; if (CVQuals & QualRestrict) OB += " restrict"; if (RefQual == FrefQualLValue) OB += " &"; else if (RefQual == FrefQualRValue) OB += " &&"; if (ExceptionSpec != nullptr) { OB += ' '; ExceptionSpec->print(OB); } } }; class NoexceptSpec : public Node { const Node *E; public: NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {} template void match(Fn F) const { F(E); } void printLeft(OutputBuffer &OB) const override { OB += "noexcept"; OB.printOpen(); E->printAsOperand(OB); OB.printClose(); } }; class DynamicExceptionSpec : public Node { NodeArray Types; public: DynamicExceptionSpec(NodeArray Types_) : Node(KDynamicExceptionSpec), Types(Types_) {} template void match(Fn F) const { F(Types); } void printLeft(OutputBuffer &OB) const override { OB += "throw"; OB.printOpen(); Types.printWithComma(OB); OB.printClose(); } }; class FunctionEncoding final : public Node { const Node *Ret; const Node *Name; NodeArray Params; const Node *Attrs; Qualifiers CVQuals; FunctionRefQual RefQual; public: FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_, const Node *Attrs_, Qualifiers CVQuals_, FunctionRefQual RefQual_) : Node(KFunctionEncoding, /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, /*FunctionCache=*/Cache::Yes), Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), CVQuals(CVQuals_), RefQual(RefQual_) {} template void match(Fn F) const { F(Ret, Name, Params, Attrs, CVQuals, RefQual); } Qualifiers getCVQuals() const { return CVQuals; } FunctionRefQual getRefQual() const { return RefQual; } NodeArray getParams() const { return Params; } const Node *getReturnType() const { return Ret; } bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } bool hasFunctionSlow(OutputBuffer &) const override { return true; } const Node *getName() const { return Name; } void printLeft(OutputBuffer &OB) const override { if (Ret) { Ret->printLeft(OB); if (!Ret->hasRHSComponent(OB)) OB += " "; } Name->print(OB); } void printRight(OutputBuffer &OB) const override { OB.printOpen(); Params.printWithComma(OB); OB.printClose(); if (Ret) Ret->printRight(OB); if (CVQuals & QualConst) OB += " const"; if (CVQuals & QualVolatile) OB += " volatile"; if (CVQuals & QualRestrict) OB += " restrict"; if (RefQual == FrefQualLValue) OB += " &"; else if (RefQual == FrefQualRValue) OB += " &&"; if (Attrs != nullptr) Attrs->print(OB); } }; class LiteralOperator : public Node { const Node *OpName; public: LiteralOperator(const Node *OpName_) : Node(KLiteralOperator), OpName(OpName_) {} template void match(Fn F) const { F(OpName); } void printLeft(OutputBuffer &OB) const override { OB += "operator\"\" "; OpName->print(OB); } }; class SpecialName final : public Node { const std::string_view Special; const Node *Child; public: SpecialName(std::string_view Special_, const Node *Child_) : Node(KSpecialName), Special(Special_), Child(Child_) {} template void match(Fn F) const { F(Special, Child); } void printLeft(OutputBuffer &OB) const override { OB += Special; Child->print(OB); } }; class CtorVtableSpecialName final : public Node { const Node *FirstType; const Node *SecondType; public: CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_) : Node(KCtorVtableSpecialName), FirstType(FirstType_), SecondType(SecondType_) {} template void match(Fn F) const { F(FirstType, SecondType); } void printLeft(OutputBuffer &OB) const override { OB += "construction vtable for "; FirstType->print(OB); OB += "-in-"; SecondType->print(OB); } }; struct NestedName : Node { Node *Qual; Node *Name; NestedName(Node *Qual_, Node *Name_) : Node(KNestedName), Qual(Qual_), Name(Name_) {} template void match(Fn F) const { F(Qual, Name); } std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Qual->print(OB); OB += "::"; Name->print(OB); } }; struct ModuleName : Node { ModuleName *Parent; Node *Name; bool IsPartition; ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false) : Node(KModuleName), Parent(Parent_), Name(Name_), IsPartition(IsPartition_) {} template void match(Fn F) const { F(Parent, Name, IsPartition); } void printLeft(OutputBuffer &OB) const override { if (Parent) Parent->print(OB); if (Parent || IsPartition) OB += IsPartition ? ':' : '.'; Name->print(OB); } }; struct ModuleEntity : Node { ModuleName *Module; Node *Name; ModuleEntity(ModuleName *Module_, Node *Name_) : Node(KModuleEntity), Module(Module_), Name(Name_) {} template void match(Fn F) const { F(Module, Name); } std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Name->print(OB); OB += '@'; Module->print(OB); } }; struct LocalName : Node { Node *Encoding; Node *Entity; LocalName(Node *Encoding_, Node *Entity_) : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} template void match(Fn F) const { F(Encoding, Entity); } void printLeft(OutputBuffer &OB) const override { Encoding->print(OB); OB += "::"; Entity->print(OB); } }; class QualifiedName final : public Node { // qualifier::name const Node *Qualifier; const Node *Name; public: QualifiedName(const Node *Qualifier_, const Node *Name_) : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} template void match(Fn F) const { F(Qualifier, Name); } std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Qualifier->print(OB); OB += "::"; Name->print(OB); } }; class VectorType final : public Node { const Node *BaseType; const Node *Dimension; public: VectorType(const Node *BaseType_, const Node *Dimension_) : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} const Node *getBaseType() const { return BaseType; } const Node *getDimension() const { return Dimension; } template void match(Fn F) const { F(BaseType, Dimension); } void printLeft(OutputBuffer &OB) const override { BaseType->print(OB); OB += " vector["; if (Dimension) Dimension->print(OB); OB += "]"; } }; class PixelVectorType final : public Node { const Node *Dimension; public: PixelVectorType(const Node *Dimension_) : Node(KPixelVectorType), Dimension(Dimension_) {} template void match(Fn F) const { F(Dimension); } void printLeft(OutputBuffer &OB) const override { // FIXME: This should demangle as "vector pixel". OB += "pixel vector["; Dimension->print(OB); OB += "]"; } }; class BinaryFPType final : public Node { const Node *Dimension; public: BinaryFPType(const Node *Dimension_) : Node(KBinaryFPType), Dimension(Dimension_) {} template void match(Fn F) const { F(Dimension); } void printLeft(OutputBuffer &OB) const override { OB += "_Float"; Dimension->print(OB); } }; enum class TemplateParamKind { Type, NonType, Template }; /// An invented name for a template parameter for which we don't have a /// corresponding template argument. /// /// This node is created when parsing the for a lambda with /// explicit template arguments, which might be referenced in the parameter /// types appearing later in the . class SyntheticTemplateParamName final : public Node { TemplateParamKind Kind; unsigned Index; public: SyntheticTemplateParamName(TemplateParamKind Kind_, unsigned Index_) : Node(KSyntheticTemplateParamName), Kind(Kind_), Index(Index_) {} template void match(Fn F) const { F(Kind, Index); } void printLeft(OutputBuffer &OB) const override { switch (Kind) { case TemplateParamKind::Type: OB += "$T"; break; case TemplateParamKind::NonType: OB += "$N"; break; case TemplateParamKind::Template: OB += "$TT"; break; } if (Index > 0) OB << Index - 1; } }; /// A template type parameter declaration, 'typename T'. class TypeTemplateParamDecl final : public Node { Node *Name; public: TypeTemplateParamDecl(Node *Name_) : Node(KTypeTemplateParamDecl, Cache::Yes), Name(Name_) {} template void match(Fn F) const { F(Name); } void printLeft(OutputBuffer &OB) const override { OB += "typename "; } void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A non-type template parameter declaration, 'int N'. class NonTypeTemplateParamDecl final : public Node { Node *Name; Node *Type; public: NonTypeTemplateParamDecl(Node *Name_, Node *Type_) : Node(KNonTypeTemplateParamDecl, Cache::Yes), Name(Name_), Type(Type_) {} template void match(Fn F) const { F(Name, Type); } void printLeft(OutputBuffer &OB) const override { Type->printLeft(OB); if (!Type->hasRHSComponent(OB)) OB += " "; } void printRight(OutputBuffer &OB) const override { Name->print(OB); Type->printRight(OB); } }; /// A template template parameter declaration, /// 'template typename N'. class TemplateTemplateParamDecl final : public Node { Node *Name; NodeArray Params; public: TemplateTemplateParamDecl(Node *Name_, NodeArray Params_) : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_), Params(Params_) {} template void match(Fn F) const { F(Name, Params); } void printLeft(OutputBuffer &OB) const override { ScopedOverride LT(OB.GtIsGt, 0); OB += "template<"; Params.printWithComma(OB); OB += "> typename "; } void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A template parameter pack declaration, 'typename ...T'. class TemplateParamPackDecl final : public Node { Node *Param; public: TemplateParamPackDecl(Node *Param_) : Node(KTemplateParamPackDecl, Cache::Yes), Param(Param_) {} template void match(Fn F) const { F(Param); } void printLeft(OutputBuffer &OB) const override { Param->printLeft(OB); OB += "..."; } void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } }; /// An unexpanded parameter pack (either in the expression or type context). If /// this AST is correct, this node will have a ParameterPackExpansion node above /// it. /// /// This node is created when some are found that apply to an /// , and is stored in the TemplateParams table. In order for this to /// appear in the final AST, it has to referenced via a (ie, /// T_). class ParameterPack final : public Node { NodeArray Data; // Setup OutputBuffer for a pack expansion, unless we're already expanding // one. void initializePackExpansion(OutputBuffer &OB) const { if (OB.CurrentPackMax == std::numeric_limits::max()) { OB.CurrentPackMax = static_cast(Data.size()); OB.CurrentPackIndex = 0; } } public: ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) { ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown; if (std::all_of(Data.begin(), Data.end(), [](Node* P) { return P->ArrayCache == Cache::No; })) ArrayCache = Cache::No; if (std::all_of(Data.begin(), Data.end(), [](Node* P) { return P->FunctionCache == Cache::No; })) FunctionCache = Cache::No; if (std::all_of(Data.begin(), Data.end(), [](Node* P) { return P->RHSComponentCache == Cache::No; })) RHSComponentCache = Cache::No; } template void match(Fn F) const { F(Data); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { initializePackExpansion(OB); size_t Idx = OB.CurrentPackIndex; return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB); } bool hasArraySlow(OutputBuffer &OB) const override { initializePackExpansion(OB); size_t Idx = OB.CurrentPackIndex; return Idx < Data.size() && Data[Idx]->hasArray(OB); } bool hasFunctionSlow(OutputBuffer &OB) const override { initializePackExpansion(OB); size_t Idx = OB.CurrentPackIndex; return Idx < Data.size() && Data[Idx]->hasFunction(OB); } const Node *getSyntaxNode(OutputBuffer &OB) const override { initializePackExpansion(OB); size_t Idx = OB.CurrentPackIndex; return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this; } void printLeft(OutputBuffer &OB) const override { initializePackExpansion(OB); size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) Data[Idx]->printLeft(OB); } void printRight(OutputBuffer &OB) const override { initializePackExpansion(OB); size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) Data[Idx]->printRight(OB); } }; /// A variadic template argument. This node represents an occurrence of /// JE in some . It isn't itself unexpanded, unless /// one of it's Elements is. The parser inserts a ParameterPack into the /// TemplateParams table if the this pack belongs to apply to an /// . class TemplateArgumentPack final : public Node { NodeArray Elements; public: TemplateArgumentPack(NodeArray Elements_) : Node(KTemplateArgumentPack), Elements(Elements_) {} template void match(Fn F) const { F(Elements); } NodeArray getElements() const { return Elements; } void printLeft(OutputBuffer &OB) const override { Elements.printWithComma(OB); } }; /// A pack expansion. Below this node, there are some unexpanded ParameterPacks /// which each have Child->ParameterPackSize elements. class ParameterPackExpansion final : public Node { const Node *Child; public: ParameterPackExpansion(const Node *Child_) : Node(KParameterPackExpansion), Child(Child_) {} template void match(Fn F) const { F(Child); } const Node *getChild() const { return Child; } void printLeft(OutputBuffer &OB) const override { constexpr unsigned Max = std::numeric_limits::max(); ScopedOverride SavePackIdx(OB.CurrentPackIndex, Max); ScopedOverride SavePackMax(OB.CurrentPackMax, Max); size_t StreamPos = OB.getCurrentPosition(); // Print the first element in the pack. If Child contains a ParameterPack, // it will set up S.CurrentPackMax and print the first element. Child->print(OB); // No ParameterPack was found in Child. This can occur if we've found a pack // expansion on a . if (OB.CurrentPackMax == Max) { OB += "..."; return; } // We found a ParameterPack, but it has no elements. Erase whatever we may // of printed. if (OB.CurrentPackMax == 0) { OB.setCurrentPosition(StreamPos); return; } // Else, iterate through the rest of the elements in the pack. for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) { OB += ", "; OB.CurrentPackIndex = I; Child->print(OB); } } }; class TemplateArgs final : public Node { NodeArray Params; public: TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} template void match(Fn F) const { F(Params); } NodeArray getParams() { return Params; } void printLeft(OutputBuffer &OB) const override { ScopedOverride LT(OB.GtIsGt, 0); OB += "<"; Params.printWithComma(OB); OB += ">"; } }; /// A forward-reference to a template argument that was not known at the point /// where the template parameter name was parsed in a mangling. /// /// This is created when demangling the name of a specialization of a /// conversion function template: /// /// \code /// struct A { /// template operator T*(); /// }; /// \endcode /// /// When demangling a specialization of the conversion function template, we /// encounter the name of the template (including the \c T) before we reach /// the template argument list, so we cannot substitute the parameter name /// for the corresponding argument while parsing. Instead, we create a /// \c ForwardTemplateReference node that is resolved after we parse the /// template arguments. struct ForwardTemplateReference : Node { size_t Index; Node *Ref = nullptr; // If we're currently printing this node. It is possible (though invalid) for // a forward template reference to refer to itself via a substitution. This // creates a cyclic AST, which will stack overflow printing. To fix this, bail // out if more than one print* function is active. mutable bool Printing = false; ForwardTemplateReference(size_t Index_) : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, Cache::Unknown), Index(Index_) {} // We don't provide a matcher for these, because the value of the node is // not determined by its construction parameters, and it generally needs // special handling. template void match(Fn F) const = delete; bool hasRHSComponentSlow(OutputBuffer &OB) const override { if (Printing) return false; ScopedOverride SavePrinting(Printing, true); return Ref->hasRHSComponent(OB); } bool hasArraySlow(OutputBuffer &OB) const override { if (Printing) return false; ScopedOverride SavePrinting(Printing, true); return Ref->hasArray(OB); } bool hasFunctionSlow(OutputBuffer &OB) const override { if (Printing) return false; ScopedOverride SavePrinting(Printing, true); return Ref->hasFunction(OB); } const Node *getSyntaxNode(OutputBuffer &OB) const override { if (Printing) return this; ScopedOverride SavePrinting(Printing, true); return Ref->getSyntaxNode(OB); } void printLeft(OutputBuffer &OB) const override { if (Printing) return; ScopedOverride SavePrinting(Printing, true); Ref->printLeft(OB); } void printRight(OutputBuffer &OB) const override { if (Printing) return; ScopedOverride SavePrinting(Printing, true); Ref->printRight(OB); } }; struct NameWithTemplateArgs : Node { // name Node *Name; Node *TemplateArgs; NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} template void match(Fn F) const { F(Name, TemplateArgs); } std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Name->print(OB); TemplateArgs->print(OB); } }; class GlobalQualifiedName final : public Node { Node *Child; public: GlobalQualifiedName(Node* Child_) : Node(KGlobalQualifiedName), Child(Child_) {} template void match(Fn F) const { F(Child); } std::string_view getBaseName() const override { return Child->getBaseName(); } void printLeft(OutputBuffer &OB) const override { OB += "::"; Child->print(OB); } }; enum class SpecialSubKind { allocator, basic_string, string, istream, ostream, iostream, }; class SpecialSubstitution; class ExpandedSpecialSubstitution : public Node { protected: SpecialSubKind SSK; ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_) : Node(K_), SSK(SSK_) {} public: ExpandedSpecialSubstitution(SpecialSubKind SSK_) : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {} inline ExpandedSpecialSubstitution(SpecialSubstitution const *); template void match(Fn F) const { F(SSK); } protected: bool isInstantiation() const { return unsigned(SSK) >= unsigned(SpecialSubKind::string); } std::string_view getBaseName() const override { switch (SSK) { case SpecialSubKind::allocator: return {"allocator"}; case SpecialSubKind::basic_string: return {"basic_string"}; case SpecialSubKind::string: return {"basic_string"}; case SpecialSubKind::istream: return {"basic_istream"}; case SpecialSubKind::ostream: return {"basic_ostream"}; case SpecialSubKind::iostream: return {"basic_iostream"}; } DEMANGLE_UNREACHABLE; } private: void printLeft(OutputBuffer &OB) const override { OB << "std::" << getBaseName(); if (isInstantiation()) { OB << ""; if (SSK == SpecialSubKind::string) OB << ", std::allocator"; OB << ">"; } } }; class SpecialSubstitution final : public ExpandedSpecialSubstitution { public: SpecialSubstitution(SpecialSubKind SSK_) : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {} template void match(Fn F) const { F(SSK); } std::string_view getBaseName() const override { std::string_view SV = ExpandedSpecialSubstitution::getBaseName(); if (isInstantiation()) { // The instantiations are typedefs that drop the "basic_" prefix. assert(llvm::itanium_demangle::starts_with(SV, "basic_")); SV.remove_prefix(sizeof("basic_") - 1); } return SV; } void printLeft(OutputBuffer &OB) const override { OB << "std::" << getBaseName(); } }; inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution( SpecialSubstitution const *SS) : ExpandedSpecialSubstitution(SS->SSK) {} class CtorDtorName final : public Node { const Node *Basename; const bool IsDtor; const int Variant; public: CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_) : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_), Variant(Variant_) {} template void match(Fn F) const { F(Basename, IsDtor, Variant); } void printLeft(OutputBuffer &OB) const override { if (IsDtor) OB += "~"; OB += Basename->getBaseName(); } }; class DtorName : public Node { const Node *Base; public: DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {} template void match(Fn F) const { F(Base); } void printLeft(OutputBuffer &OB) const override { OB += "~"; Base->printLeft(OB); } }; class UnnamedTypeName : public Node { const std::string_view Count; public: UnnamedTypeName(std::string_view Count_) : Node(KUnnamedTypeName), Count(Count_) {} template void match(Fn F) const { F(Count); } void printLeft(OutputBuffer &OB) const override { OB += "'unnamed"; OB += Count; OB += "\'"; } }; class ClosureTypeName : public Node { NodeArray TemplateParams; NodeArray Params; std::string_view Count; public: ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, std::string_view Count_) : Node(KClosureTypeName), TemplateParams(TemplateParams_), Params(Params_), Count(Count_) {} template void match(Fn F) const { F(TemplateParams, Params, Count); } void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { ScopedOverride LT(OB.GtIsGt, 0); OB += "<"; TemplateParams.printWithComma(OB); OB += ">"; } OB.printOpen(); Params.printWithComma(OB); OB.printClose(); } void printLeft(OutputBuffer &OB) const override { OB += "\'lambda"; OB += Count; OB += "\'"; printDeclarator(OB); } }; class StructuredBindingName : public Node { NodeArray Bindings; public: StructuredBindingName(NodeArray Bindings_) : Node(KStructuredBindingName), Bindings(Bindings_) {} template void match(Fn F) const { F(Bindings); } void printLeft(OutputBuffer &OB) const override { OB.printOpen('['); Bindings.printWithComma(OB); OB.printClose(']'); } }; // -- Expression Nodes -- class BinaryExpr : public Node { const Node *LHS; const std::string_view InfixOperator; const Node *RHS; public: BinaryExpr(const Node *LHS_, std::string_view InfixOperator_, const Node *RHS_, Prec Prec_) : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {} template void match(Fn F) const { F(LHS, InfixOperator, RHS, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { bool ParenAll = OB.isGtInsideTemplateArgs() && (InfixOperator == ">" || InfixOperator == ">>"); if (ParenAll) OB.printOpen(); // Assignment is right associative, with special LHS precedence. bool IsAssign = getPrecedence() == Prec::Assign; LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign); // No space before comma operator if (!(InfixOperator == ",")) OB += " "; OB += InfixOperator; OB += " "; RHS->printAsOperand(OB, getPrecedence(), IsAssign); if (ParenAll) OB.printClose(); } }; class ArraySubscriptExpr : public Node { const Node *Op1; const Node *Op2; public: ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_) : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {} template void match(Fn F) const { F(Op1, Op2, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { Op1->printAsOperand(OB, getPrecedence()); OB.printOpen('['); Op2->printAsOperand(OB); OB.printClose(']'); } }; class PostfixExpr : public Node { const Node *Child; const std::string_view Operator; public: PostfixExpr(const Node *Child_, std::string_view Operator_, Prec Prec_) : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {} template void match(Fn F) const { F(Child, Operator, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { Child->printAsOperand(OB, getPrecedence(), true); OB += Operator; } }; class ConditionalExpr : public Node { const Node *Cond; const Node *Then; const Node *Else; public: ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_, Prec Prec_) : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {} template void match(Fn F) const { F(Cond, Then, Else, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { Cond->printAsOperand(OB, getPrecedence()); OB += " ? "; Then->printAsOperand(OB); OB += " : "; Else->printAsOperand(OB, Prec::Assign, true); } }; class MemberExpr : public Node { const Node *LHS; const std::string_view Kind; const Node *RHS; public: MemberExpr(const Node *LHS_, std::string_view Kind_, const Node *RHS_, Prec Prec_) : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} template void match(Fn F) const { F(LHS, Kind, RHS, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { LHS->printAsOperand(OB, getPrecedence(), true); OB += Kind; RHS->printAsOperand(OB, getPrecedence(), false); } }; class SubobjectExpr : public Node { const Node *Type; const Node *SubExpr; std::string_view Offset; NodeArray UnionSelectors; bool OnePastTheEnd; public: SubobjectExpr(const Node *Type_, const Node *SubExpr_, std::string_view Offset_, NodeArray UnionSelectors_, bool OnePastTheEnd_) : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_), UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {} template void match(Fn F) const { F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); } void printLeft(OutputBuffer &OB) const override { SubExpr->print(OB); OB += ".<"; Type->print(OB); OB += " at offset "; if (Offset.empty()) { OB += "0"; } else if (Offset[0] == 'n') { OB += "-"; OB += std::string_view(Offset.data() + 1, Offset.size() - 1); } else { OB += Offset; } OB += ">"; } }; class EnclosingExpr : public Node { const std::string_view Prefix; const Node *Infix; const std::string_view Postfix; public: EnclosingExpr(std::string_view Prefix_, const Node *Infix_, Prec Prec_ = Prec::Primary) : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {} template void match(Fn F) const { F(Prefix, Infix, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { OB += Prefix; OB.printOpen(); Infix->print(OB); OB.printClose(); OB += Postfix; } }; class CastExpr : public Node { // cast_kind(from) const std::string_view CastKind; const Node *To; const Node *From; public: CastExpr(std::string_view CastKind_, const Node *To_, const Node *From_, Prec Prec_) : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {} template void match(Fn F) const { F(CastKind, To, From, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { OB += CastKind; { ScopedOverride LT(OB.GtIsGt, 0); OB += "<"; To->printLeft(OB); OB += ">"; } OB.printOpen(); From->printAsOperand(OB); OB.printClose(); } }; class SizeofParamPackExpr : public Node { const Node *Pack; public: SizeofParamPackExpr(const Node *Pack_) : Node(KSizeofParamPackExpr), Pack(Pack_) {} template void match(Fn F) const { F(Pack); } void printLeft(OutputBuffer &OB) const override { OB += "sizeof..."; OB.printOpen(); ParameterPackExpansion PPE(Pack); PPE.printLeft(OB); OB.printClose(); } }; class CallExpr : public Node { const Node *Callee; NodeArray Args; public: CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_) : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {} template void match(Fn F) const { F(Callee, Args, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { Callee->print(OB); OB.printOpen(); Args.printWithComma(OB); OB.printClose(); } }; class NewExpr : public Node { // new (expr_list) type(init_list) NodeArray ExprList; Node *Type; NodeArray InitList; bool IsGlobal; // ::operator new ? bool IsArray; // new[] ? public: NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, bool IsArray_, Prec Prec_) : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_), InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} template void match(Fn F) const { F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { if (IsGlobal) OB += "::"; OB += "new"; if (IsArray) OB += "[]"; if (!ExprList.empty()) { OB.printOpen(); ExprList.printWithComma(OB); OB.printClose(); } OB += " "; Type->print(OB); if (!InitList.empty()) { OB.printOpen(); InitList.printWithComma(OB); OB.printClose(); } } }; class DeleteExpr : public Node { Node *Op; bool IsGlobal; bool IsArray; public: DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_) : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} template void match(Fn F) const { F(Op, IsGlobal, IsArray, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { if (IsGlobal) OB += "::"; OB += "delete"; if (IsArray) OB += "[]"; OB += ' '; Op->print(OB); } }; class PrefixExpr : public Node { std::string_view Prefix; Node *Child; public: PrefixExpr(std::string_view Prefix_, Node *Child_, Prec Prec_) : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {} template void match(Fn F) const { F(Prefix, Child, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { OB += Prefix; Child->printAsOperand(OB, getPrecedence()); } }; class FunctionParam : public Node { std::string_view Number; public: FunctionParam(std::string_view Number_) : Node(KFunctionParam), Number(Number_) {} template void match(Fn F) const { F(Number); } void printLeft(OutputBuffer &OB) const override { OB += "fp"; OB += Number; } }; class ConversionExpr : public Node { const Node *Type; NodeArray Expressions; public: ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_) : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {} template void match(Fn F) const { F(Type, Expressions, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { OB.printOpen(); Type->print(OB); OB.printClose(); OB.printOpen(); Expressions.printWithComma(OB); OB.printClose(); } }; class PointerToMemberConversionExpr : public Node { const Node *Type; const Node *SubExpr; std::string_view Offset; public: PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, std::string_view Offset_, Prec Prec_) : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_), SubExpr(SubExpr_), Offset(Offset_) {} template void match(Fn F) const { F(Type, SubExpr, Offset, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { OB.printOpen(); Type->print(OB); OB.printClose(); OB.printOpen(); SubExpr->print(OB); OB.printClose(); } }; class InitListExpr : public Node { const Node *Ty; NodeArray Inits; public: InitListExpr(const Node *Ty_, NodeArray Inits_) : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {} template void match(Fn F) const { F(Ty, Inits); } void printLeft(OutputBuffer &OB) const override { if (Ty) Ty->print(OB); OB += '{'; Inits.printWithComma(OB); OB += '}'; } }; class BracedExpr : public Node { const Node *Elem; const Node *Init; bool IsArray; public: BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_) : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {} template void match(Fn F) const { F(Elem, Init, IsArray); } void printLeft(OutputBuffer &OB) const override { if (IsArray) { OB += '['; Elem->print(OB); OB += ']'; } else { OB += '.'; Elem->print(OB); } if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) OB += " = "; Init->print(OB); } }; class BracedRangeExpr : public Node { const Node *First; const Node *Last; const Node *Init; public: BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_) : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {} template void match(Fn F) const { F(First, Last, Init); } void printLeft(OutputBuffer &OB) const override { OB += '['; First->print(OB); OB += " ... "; Last->print(OB); OB += ']'; if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) OB += " = "; Init->print(OB); } }; class FoldExpr : public Node { const Node *Pack, *Init; std::string_view OperatorName; bool IsLeftFold; public: FoldExpr(bool IsLeftFold_, std::string_view OperatorName_, const Node *Pack_, const Node *Init_) : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), IsLeftFold(IsLeftFold_) {} template void match(Fn F) const { F(IsLeftFold, OperatorName, Pack, Init); } void printLeft(OutputBuffer &OB) const override { auto PrintPack = [&] { OB.printOpen(); ParameterPackExpansion(Pack).print(OB); OB.printClose(); }; OB.printOpen(); // Either '[init op ]... op pack' or 'pack op ...[ op init]' // Refactored to '[(init|pack) op ]...[ op (pack|init)]' // Fold expr operands are cast-expressions if (!IsLeftFold || Init != nullptr) { // '(init|pack) op ' if (IsLeftFold) Init->printAsOperand(OB, Prec::Cast, true); else PrintPack(); OB << " " << OperatorName << " "; } OB << "..."; if (IsLeftFold || Init != nullptr) { // ' op (init|pack)' OB << " " << OperatorName << " "; if (IsLeftFold) PrintPack(); else Init->printAsOperand(OB, Prec::Cast, true); } OB.printClose(); } }; class ThrowExpr : public Node { const Node *Op; public: ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {} template void match(Fn F) const { F(Op); } void printLeft(OutputBuffer &OB) const override { OB += "throw "; Op->print(OB); } }; class BoolExpr : public Node { bool Value; public: BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {} template void match(Fn F) const { F(Value); } void printLeft(OutputBuffer &OB) const override { OB += Value ? std::string_view("true") : std::string_view("false"); } }; class StringLiteral : public Node { const Node *Type; public: StringLiteral(const Node *Type_) : Node(KStringLiteral), Type(Type_) {} template void match(Fn F) const { F(Type); } void printLeft(OutputBuffer &OB) const override { OB += "\"<"; Type->print(OB); OB += ">\""; } }; class LambdaExpr : public Node { const Node *Type; public: LambdaExpr(const Node *Type_) : Node(KLambdaExpr), Type(Type_) {} template void match(Fn F) const { F(Type); } void printLeft(OutputBuffer &OB) const override { OB += "[]"; if (Type->getKind() == KClosureTypeName) static_cast(Type)->printDeclarator(OB); OB += "{...}"; } }; class EnumLiteral : public Node { // ty(integer) const Node *Ty; std::string_view Integer; public: EnumLiteral(const Node *Ty_, std::string_view Integer_) : Node(KEnumLiteral), Ty(Ty_), Integer(Integer_) {} template void match(Fn F) const { F(Ty, Integer); } void printLeft(OutputBuffer &OB) const override { OB.printOpen(); Ty->print(OB); OB.printClose(); if (Integer[0] == 'n') OB << '-' << std::string_view(Integer.data() + 1, Integer.size() - 1); else OB << Integer; } }; class IntegerLiteral : public Node { std::string_view Type; std::string_view Value; public: IntegerLiteral(std::string_view Type_, std::string_view Value_) : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} template void match(Fn F) const { F(Type, Value); } void printLeft(OutputBuffer &OB) const override { if (Type.size() > 3) { OB.printOpen(); OB += Type; OB.printClose(); } if (Value[0] == 'n') OB << '-' << std::string_view(Value.data() + 1, Value.size() - 1); else OB += Value; if (Type.size() <= 3) OB += Type; } }; template struct FloatData; namespace float_literal_impl { constexpr Node::Kind getFloatLiteralKind(float *) { return Node::KFloatLiteral; } constexpr Node::Kind getFloatLiteralKind(double *) { return Node::KDoubleLiteral; } constexpr Node::Kind getFloatLiteralKind(long double *) { return Node::KLongDoubleLiteral; } } template class FloatLiteralImpl : public Node { const std::string_view Contents; static constexpr Kind KindForClass = float_literal_impl::getFloatLiteralKind((Float *)nullptr); public: FloatLiteralImpl(std::string_view Contents_) : Node(KindForClass), Contents(Contents_) {} template void match(Fn F) const { F(Contents); } void printLeft(OutputBuffer &OB) const override { const size_t N = FloatData::mangled_size; if (Contents.size() >= N) { union { Float value; char buf[sizeof(Float)]; }; const char *t = Contents.data(); const char *last = t + N; char *e = buf; for (; t != last; ++t, ++e) { unsigned d1 = isdigit(*t) ? static_cast(*t - '0') : static_cast(*t - 'a' + 10); ++t; unsigned d0 = isdigit(*t) ? static_cast(*t - '0') : static_cast(*t - 'a' + 10); *e = static_cast((d1 << 4) + d0); } #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ std::reverse(buf, e); #endif char num[FloatData::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData::spec, value); OB += std::string_view(num, n); } } }; using FloatLiteral = FloatLiteralImpl; using DoubleLiteral = FloatLiteralImpl; using LongDoubleLiteral = FloatLiteralImpl; /// Visit the node. Calls \c F(P), where \c P is the node cast to the /// appropriate derived class. template void Node::visit(Fn F) const { switch (K) { #define NODE(X) \ case K##X: \ return F(static_cast(this)); #include "ItaniumNodes.def" } assert(0 && "unknown mangling node kind"); } /// Determine the kind of a node from its type. template struct NodeKind; #define NODE(X) \ template <> struct NodeKind { \ static constexpr Node::Kind Kind = Node::K##X; \ static constexpr const char *name() { return #X; } \ }; #include "ItaniumNodes.def" template struct AbstractManglingParser { const char *First; const char *Last; // Name stack, this is used by the parser to hold temporary names that were // parsed. The parser collapses multiple names into new nodes to construct // the AST. Once the parser is finished, names.size() == 1. PODSmallVector Names; // Substitution table. Itanium supports name substitutions as a means of // compression. The string "S42_" refers to the 44nd entry (base-36) in this // table. PODSmallVector Subs; using TemplateParamList = PODSmallVector; class ScopedTemplateParamList { AbstractManglingParser *Parser; size_t OldNumTemplateParamLists; TemplateParamList Params; public: ScopedTemplateParamList(AbstractManglingParser *TheParser) : Parser(TheParser), OldNumTemplateParamLists(TheParser->TemplateParams.size()) { Parser->TemplateParams.push_back(&Params); } ~ScopedTemplateParamList() { assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists); Parser->TemplateParams.dropBack(OldNumTemplateParamLists); } }; // Template parameter table. Like the above, but referenced like "T42_". // This has a smaller size compared to Subs and Names because it can be // stored on the stack. TemplateParamList OuterTemplateParams; // Lists of template parameters indexed by template parameter depth, // referenced like "TL2_4_". If nonempty, element 0 is always // OuterTemplateParams; inner elements are always template parameter lists of // lambda expressions. For a generic lambda with no explicit template // parameter list, the corresponding parameter list pointer will be null. PODSmallVector TemplateParams; // Set of unresolved forward references. These can occur in a // conversion operator's type, and are resolved in the enclosing . PODSmallVector ForwardTemplateRefs; bool TryToParseTemplateArgs = true; bool PermitForwardTemplateReferences = false; size_t ParsingLambdaParamsAtLevel = (size_t)-1; unsigned NumSyntheticTemplateParameters[3] = {}; Alloc ASTAllocator; AbstractManglingParser(const char *First_, const char *Last_) : First(First_), Last(Last_) {} Derived &getDerived() { return static_cast(*this); } void reset(const char *First_, const char *Last_) { First = First_; Last = Last_; Names.clear(); Subs.clear(); TemplateParams.clear(); ParsingLambdaParamsAtLevel = (size_t)-1; TryToParseTemplateArgs = true; PermitForwardTemplateReferences = false; for (int I = 0; I != 3; ++I) NumSyntheticTemplateParameters[I] = 0; ASTAllocator.reset(); } template Node *make(Args &&... args) { return ASTAllocator.template makeNode(std::forward(args)...); } template NodeArray makeNodeArray(It begin, It end) { size_t sz = static_cast(end - begin); void *mem = ASTAllocator.allocateNodeArray(sz); Node **data = new (mem) Node *[sz]; std::copy(begin, end, data); return NodeArray(data, sz); } NodeArray popTrailingNodeArray(size_t FromPosition) { assert(FromPosition <= Names.size()); NodeArray res = makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); Names.dropBack(FromPosition); return res; } bool consumeIf(std::string_view S) { if (llvm::itanium_demangle::starts_with( std::string_view(First, Last - First), S)) { First += S.size(); return true; } return false; } bool consumeIf(char C) { if (First != Last && *First == C) { ++First; return true; } return false; } char consume() { return First != Last ? *First++ : '\0'; } char look(unsigned Lookahead = 0) const { if (static_cast(Last - First) <= Lookahead) return '\0'; return First[Lookahead]; } size_t numLeft() const { return static_cast(Last - First); } std::string_view parseNumber(bool AllowNegative = false); Qualifiers parseCVQualifiers(); bool parsePositiveInteger(size_t *Out); std::string_view parseBareSourceName(); bool parseSeqId(size_t *Out); Node *parseSubstitution(); Node *parseTemplateParam(); Node *parseTemplateParamDecl(); Node *parseTemplateArgs(bool TagTemplates = false); Node *parseTemplateArg(); /// Parse the production. Node *parseExpr(); Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec); Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec); Node *parseIntegerLiteral(std::string_view Lit); Node *parseExprPrimary(); template Node *parseFloatingLiteral(); Node *parseFunctionParam(); Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); Node *parsePointerToMemberConversionExpr(Node::Prec Prec); Node *parseSubobjectExpr(); /// Parse the production. Node *parseType(); Node *parseFunctionType(); Node *parseVectorType(); Node *parseDecltype(); Node *parseArrayType(); Node *parsePointerToMemberType(); Node *parseClassEnumType(); Node *parseQualifiedType(); Node *parseEncoding(); bool parseCallOffset(); Node *parseSpecialName(); /// Holds some extra information about a that is being parsed. This /// information is only pertinent if the refers to an . struct NameState { bool CtorDtorConversion = false; bool EndsWithTemplateArgs = false; Qualifiers CVQualifiers = QualNone; FunctionRefQual ReferenceQualifier = FrefQualNone; size_t ForwardTemplateRefsBegin; NameState(AbstractManglingParser *Enclosing) : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} }; bool resolveForwardTemplateRefs(NameState &State) { size_t I = State.ForwardTemplateRefsBegin; size_t E = ForwardTemplateRefs.size(); for (; I < E; ++I) { size_t Idx = ForwardTemplateRefs[I]->Index; if (TemplateParams.empty() || !TemplateParams[0] || Idx >= TemplateParams[0]->size()) return true; ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx]; } ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); return false; } /// Parse the production> Node *parseName(NameState *State = nullptr); Node *parseLocalName(NameState *State); Node *parseOperatorName(NameState *State); bool parseModuleNameOpt(ModuleName *&Module); Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module); Node *parseUnnamedTypeName(NameState *State); Node *parseSourceName(NameState *State); Node *parseUnscopedName(NameState *State, bool *isSubstName); Node *parseNestedName(NameState *State); Node *parseCtorDtorName(Node *&SoFar, NameState *State); Node *parseAbiTags(Node *N); struct OperatorInfo { enum OIKind : unsigned char { Prefix, // Prefix unary: @ expr Postfix, // Postfix unary: expr @ Binary, // Binary: lhs @ rhs Array, // Array index: lhs [ rhs ] Member, // Member access: lhs @ rhs New, // New Del, // Delete Call, // Function call: expr (expr*) CCast, // C cast: (type)expr Conditional, // Conditional: expr ? expr : expr NameOnly, // Overload only, not allowed in expression. // Below do not have operator names NamedCast, // Named cast, @(expr) OfIdOp, // alignof, sizeof, typeid Unnameable = NamedCast, }; char Enc[2]; // Encoding OIKind Kind; // Kind of operator bool Flag : 1; // Entry-specific flag Node::Prec Prec : 7; // Precedence const char *Name; // Spelling public: constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P, const char *N) : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {} public: bool operator<(const OperatorInfo &Other) const { return *this < Other.Enc; } bool operator<(const char *Peek) const { return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]); } bool operator==(const char *Peek) const { return Enc[0] == Peek[0] && Enc[1] == Peek[1]; } bool operator!=(const char *Peek) const { return !this->operator==(Peek); } public: std::string_view getSymbol() const { std::string_view Res = Name; if (Kind < Unnameable) { assert(llvm::itanium_demangle::starts_with(Res, "operator") && "operator name does not start with 'operator'"); Res.remove_prefix(sizeof("operator") - 1); if (llvm::itanium_demangle::starts_with(Res, ' ')) Res.remove_prefix(1); } return Res; } std::string_view getName() const { return Name; } OIKind getKind() const { return Kind; } bool getFlag() const { return Flag; } Node::Prec getPrecedence() const { return Prec; } }; static const OperatorInfo Ops[]; static const size_t NumOps; const OperatorInfo *parseOperatorEncoding(); /// Parse the production. Node *parseUnresolvedName(bool Global); Node *parseSimpleId(); Node *parseBaseUnresolvedName(); Node *parseUnresolvedType(); Node *parseDestructorName(); /// Top-level entry point into the parser. Node *parse(); }; const char* parse_discriminator(const char* first, const char* last); // ::= // N // ::= # See Scope Encoding below // Z // ::= // ::= // // ::= // ::= template Node *AbstractManglingParser::parseName(NameState *State) { if (look() == 'N') return getDerived().parseNestedName(State); if (look() == 'Z') return getDerived().parseLocalName(State); Node *Result = nullptr; bool IsSubst = false; Result = getDerived().parseUnscopedName(State, &IsSubst); if (!Result) return nullptr; if (look() == 'I') { // ::= if (!IsSubst) // An unscoped-template-name is substitutable. Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; if (State) State->EndsWithTemplateArgs = true; Result = make(Result, TA); } else if (IsSubst) { // The substitution case must be followed by . return nullptr; } return Result; } // := Z E [] // := Z E s [] // := Z Ed [ ] _ template Node *AbstractManglingParser::parseLocalName(NameState *State) { if (!consumeIf('Z')) return nullptr; Node *Encoding = getDerived().parseEncoding(); if (Encoding == nullptr || !consumeIf('E')) return nullptr; if (consumeIf('s')) { First = parse_discriminator(First, Last); auto *StringLitName = make("string literal"); if (!StringLitName) return nullptr; return make(Encoding, StringLitName); } if (consumeIf('d')) { parseNumber(true); if (!consumeIf('_')) return nullptr; Node *N = getDerived().parseName(State); if (N == nullptr) return nullptr; return make(Encoding, N); } Node *Entity = getDerived().parseName(State); if (Entity == nullptr) return nullptr; First = parse_discriminator(First, Last); return make(Encoding, Entity); } // ::= // ::= St # ::std:: // [*] extension template Node * AbstractManglingParser::parseUnscopedName(NameState *State, bool *IsSubst) { Node *Std = nullptr; if (consumeIf("St")) { Std = make("std"); if (Std == nullptr) return nullptr; } Node *Res = nullptr; ModuleName *Module = nullptr; if (look() == 'S') { Node *S = getDerived().parseSubstitution(); if (!S) return nullptr; if (S->getKind() == Node::KModuleName) Module = static_cast(S); else if (IsSubst && Std == nullptr) { Res = S; *IsSubst = true; } else { return nullptr; } } if (Res == nullptr || Std != nullptr) { Res = getDerived().parseUnqualifiedName(State, Std, Module); } return Res; } // ::= [] L? [] // ::= [] [] // ::= [] L? [] // ::= [] L? [] // # structured binding declaration // ::= [] L? DC + E template Node *AbstractManglingParser::parseUnqualifiedName( NameState *State, Node *Scope, ModuleName *Module) { if (getDerived().parseModuleNameOpt(Module)) return nullptr; consumeIf('L'); Node *Result; if (look() >= '1' && look() <= '9') { Result = getDerived().parseSourceName(State); } else if (look() == 'U') { Result = getDerived().parseUnnamedTypeName(State); } else if (consumeIf("DC")) { // Structured binding size_t BindingsBegin = Names.size(); do { Node *Binding = getDerived().parseSourceName(State); if (Binding == nullptr) return nullptr; Names.push_back(Binding); } while (!consumeIf('E')); Result = make(popTrailingNodeArray(BindingsBegin)); } else if (look() == 'C' || look() == 'D') { // A . if (Scope == nullptr || Module != nullptr) return nullptr; Result = getDerived().parseCtorDtorName(Scope, State); } else { Result = getDerived().parseOperatorName(State); } if (Result != nullptr && Module != nullptr) Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); if (Result != nullptr && Scope != nullptr) Result = make(Scope, Result); return Result; } // ::= // ::= // ::= # passed in by caller // ::= W // ::= W P template bool AbstractManglingParser::parseModuleNameOpt( ModuleName *&Module) { while (consumeIf('W')) { bool IsPartition = consumeIf('P'); Node *Sub = getDerived().parseSourceName(nullptr); if (!Sub) return true; Module = static_cast(make(Module, Sub, IsPartition)); Subs.push_back(Module); } return false; } // ::= Ut [] _ // ::= // // ::= Ul E [ ] _ // // ::= + # Parameter types or "v" if the lambda has no parameters template Node * AbstractManglingParser::parseUnnamedTypeName(NameState *State) { // refer to the innermost . Clear out any // outer args that we may have inserted into TemplateParams. if (State != nullptr) TemplateParams.clear(); if (consumeIf("Ut")) { std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; return make(Count); } if (consumeIf("Ul")) { ScopedOverride SwapParams(ParsingLambdaParamsAtLevel, TemplateParams.size()); ScopedTemplateParamList LambdaTemplateParams(this); size_t ParamsBegin = Names.size(); while (look() == 'T' && std::string_view("yptn").find(look(1)) != std::string_view::npos) { Node *T = parseTemplateParamDecl(); if (!T) return nullptr; Names.push_back(T); } NodeArray TempParams = popTrailingNodeArray(ParamsBegin); // FIXME: If TempParams is empty and none of the function parameters // includes 'auto', we should remove LambdaTemplateParams from the // TemplateParams list. Unfortunately, we don't find out whether there are // any 'auto' parameters until too late in an example such as: // // template void f( // decltype([](decltype([](T v) {}), // auto) {})) {} // template void f( // decltype([](decltype([](T w) {}), // int) {})) {} // // Here, the type of v is at level 2 but the type of w is at level 1. We // don't find this out until we encounter the type of the next parameter. // // However, compilers can't actually cope with the former example in // practice, and it's likely to be made ill-formed in future, so we don't // need to support it here. // // If we encounter an 'auto' in the function parameter types, we will // recreate a template parameter scope for it, but any intervening lambdas // will be parsed in the 'wrong' template parameter depth. if (TempParams.empty()) TemplateParams.pop_back(); if (!consumeIf("vE")) { do { Node *P = getDerived().parseType(); if (P == nullptr) return nullptr; Names.push_back(P); } while (!consumeIf('E')); } NodeArray Params = popTrailingNodeArray(ParamsBegin); std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; return make(TempParams, Params, Count); } if (consumeIf("Ub")) { (void)parseNumber(); if (!consumeIf('_')) return nullptr; return make("'block-literal'"); } return nullptr; } // ::= template Node *AbstractManglingParser::parseSourceName(NameState *) { size_t Length = 0; if (parsePositiveInteger(&Length)) return nullptr; if (numLeft() < Length || Length == 0) return nullptr; std::string_view Name(First, Length); First += Length; if (llvm::itanium_demangle::starts_with(Name, "_GLOBAL__N")) return make("(anonymous namespace)"); return make(Name); } // Operator encodings template const typename AbstractManglingParser< Derived, Alloc>::OperatorInfo AbstractManglingParser::Ops[] = { // Keep ordered by encoding {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="}, {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="}, {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"}, {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"}, {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"}, {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "}, {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary, "operator co_await"}, {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "}, {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"}, {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"}, {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"}, {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"}, {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="}, {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary, "operator delete[]"}, {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"}, {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"}, {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary, "operator delete"}, {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, "operator.*"}, {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix, "operator."}, {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"}, {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="}, {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"}, {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="}, {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="}, {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"}, {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"}, {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="}, {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="}, {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"}, {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"}, {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="}, {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="}, {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"}, {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative, "operator*"}, {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"}, {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary, "operator new[]"}, {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="}, {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"}, {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"}, {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"}, {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="}, {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"}, {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"}, {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="}, {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"}, {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, "operator->*"}, {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"}, {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"}, {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix, "operator->"}, {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional, "operator?"}, {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="}, {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="}, {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "reinterpret_cast"}, {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative, "operator%"}, {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"}, {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"}, {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"}, {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "}, {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "}, {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix, "typeid "}, {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "}, }; template const size_t AbstractManglingParser::NumOps = sizeof(Ops) / sizeof(Ops[0]); // If the next 2 chars are an operator encoding, consume them and return their // OperatorInfo. Otherwise return nullptr. template const typename AbstractManglingParser::OperatorInfo * AbstractManglingParser::parseOperatorEncoding() { if (numLeft() < 2) return nullptr; // We can't use lower_bound as that can link to symbols in the C++ library, // and this must remain independant of that. size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds. while (upper != lower) { size_t middle = (upper + lower) / 2; if (Ops[middle] < First) lower = middle + 1; else upper = middle; } if (Ops[lower] != First) return nullptr; First += 2; return &Ops[lower]; } // ::= See parseOperatorEncoding() // ::= li # operator "" // ::= v # vendor extended operator template Node * AbstractManglingParser::parseOperatorName(NameState *State) { if (const auto *Op = parseOperatorEncoding()) { if (Op->getKind() == OperatorInfo::CCast) { // ::= cv # (cast) ScopedOverride SaveTemplate(TryToParseTemplateArgs, false); // If we're parsing an encoding, State != nullptr and the conversion // operators' could have a that refers to some // s further ahead in the mangled name. ScopedOverride SavePermit(PermitForwardTemplateReferences, PermitForwardTemplateReferences || State != nullptr); Node *Ty = getDerived().parseType(); if (Ty == nullptr) return nullptr; if (State) State->CtorDtorConversion = true; return make(Ty); } if (Op->getKind() >= OperatorInfo::Unnameable) /* Not a nameable operator. */ return nullptr; if (Op->getKind() == OperatorInfo::Member && !Op->getFlag()) /* Not a nameable MemberExpr */ return nullptr; return make(Op->getName()); } if (consumeIf("li")) { // ::= li # operator "" Node *SN = getDerived().parseSourceName(State); if (SN == nullptr) return nullptr; return make(SN); } if (consumeIf('v')) { // ::= v # vendor extended operator if (look() >= '0' && look() <= '9') { First++; Node *SN = getDerived().parseSourceName(State); if (SN == nullptr) return nullptr; return make(SN); } return nullptr; } return nullptr; } // ::= C1 # complete object constructor // ::= C2 # base object constructor // ::= C3 # complete object allocating constructor // extension ::= C4 # gcc old-style "[unified]" constructor // extension ::= C5 # the COMDAT used for ctors // ::= D0 # deleting destructor // ::= D1 # complete object destructor // ::= D2 # base object destructor // extension ::= D4 # gcc old-style "[unified]" destructor // extension ::= D5 # the COMDAT used for dtors template Node * AbstractManglingParser::parseCtorDtorName(Node *&SoFar, NameState *State) { if (SoFar->getKind() == Node::KSpecialSubstitution) { // Expand the special substitution. SoFar = make( static_cast(SoFar)); if (!SoFar) return nullptr; } if (consumeIf('C')) { bool IsInherited = consumeIf('I'); if (look() != '1' && look() != '2' && look() != '3' && look() != '4' && look() != '5') return nullptr; int Variant = look() - '0'; ++First; if (State) State->CtorDtorConversion = true; if (IsInherited) { if (getDerived().parseName(State) == nullptr) return nullptr; } return make(SoFar, /*IsDtor=*/false, Variant); } if (look() == 'D' && (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '4' || look(1) == '5')) { int Variant = look(1) - '0'; First += 2; if (State) State->CtorDtorConversion = true; return make(SoFar, /*IsDtor=*/true, Variant); } return nullptr; } // ::= N [] [] // E // ::= N [] [] // E // // ::= // ::= // ::= // ::= // ::= # empty // ::= // ::= // [*] extension // // := [] M // // ::=