diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
commit | d8e91e46262bc44006913e6796843909f1ac7bcd (patch) | |
tree | 7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/Demangle/ItaniumDemangle.cpp | |
parent | b7eb8e35e481a74962664b63dfb09483b200209a (diff) | |
download | src-d8e91e46262bc44006913e6796843909f1ac7bcd.tar.gz src-d8e91e46262bc44006913e6796843909f1ac7bcd.zip |
Vendor import of llvm trunk r351319 (just before the release_80 branchvendor/llvm/llvm-trunk-r351319
Notes
Notes:
svn path=/vendor/llvm/dist/; revision=343171
svn path=/vendor/llvm/llvm-trunk-r351319/; revision=343172; tag=vendor/llvm/llvm-trunk-r351319
Diffstat (limited to 'lib/Demangle/ItaniumDemangle.cpp')
-rw-r--r-- | lib/Demangle/ItaniumDemangle.cpp | 5052 |
1 files changed, 211 insertions, 4841 deletions
diff --git a/lib/Demangle/ItaniumDemangle.cpp b/lib/Demangle/ItaniumDemangle.cpp index 72e4b56c05e3..b2de0be2b70c 100644 --- a/lib/Demangle/ItaniumDemangle.cpp +++ b/lib/Demangle/ItaniumDemangle.cpp @@ -11,1761 +11,239 @@ // file does not yet support: // - C++ modules TS -#include "Compiler.h" -#include "StringView.h" -#include "Utility.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/ItaniumDemangle.h" #include <cassert> #include <cctype> #include <cstdio> #include <cstdlib> #include <cstring> +#include <functional> #include <numeric> #include <utility> #include <vector> -namespace { -// 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 { - KNodeArrayNode, - KDotSuffix, - KVendorExtQualType, - KQualType, - KConversionOperatorType, - KPostfixQualifiedType, - KElaboratedTypeSpefType, - KNameType, - KAbiTagAttr, - KEnableIfAttr, - KObjCProtoName, - KPointerType, - KReferenceType, - KPointerToMemberType, - KArrayType, - KFunctionType, - KNoexceptSpec, - KDynamicExceptionSpec, - KFunctionEncoding, - KLiteralOperator, - KSpecialName, - KCtorVtableSpecialName, - KQualifiedName, - KNestedName, - KLocalName, - KVectorType, - KParameterPack, - KTemplateArgumentPack, - KParameterPackExpansion, - KTemplateArgs, - KForwardTemplateReference, - KNameWithTemplateArgs, - KGlobalQualifiedName, - KStdQualifiedName, - KExpandedSpecialSubstitution, - KSpecialSubstitution, - KCtorDtorName, - KDtorName, - KUnnamedTypeName, - KClosureTypeName, - KStructuredBindingName, - KExpr, - KBracedExpr, - KBracedRangeExpr, - }; - - Kind K; - - /// 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, }; - - /// Tracks if this node has a component on its right side, in which case we - /// need to call printRight. - Cache RHSComponentCache; - - /// Track if this node is a (possibly qualified) array type. This can affect - /// how we format the output string. - Cache ArrayCache; - - /// Track if this node is a (possibly qualified) function type. This can - /// affect how we format the output string. - Cache FunctionCache; - - Node(Kind K_, Cache RHSComponentCache_ = Cache::No, - Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) - : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), - FunctionCache(FunctionCache_) {} - - bool hasRHSComponent(OutputStream &S) const { - if (RHSComponentCache != Cache::Unknown) - return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); - } - - bool hasArray(OutputStream &S) const { - if (ArrayCache != Cache::Unknown) - return ArrayCache == Cache::Yes; - return hasArraySlow(S); - } - - bool hasFunction(OutputStream &S) const { - if (FunctionCache != Cache::Unknown) - return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); - } - - Kind getKind() const { return K; } - - virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } - virtual bool hasArraySlow(OutputStream &) const { return false; } - virtual bool hasFunctionSlow(OutputStream &) 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(OutputStream &) const { - return this; - } +using namespace llvm; +using namespace llvm::itanium_demangle; - void print(OutputStream &S) const { - printLeft(S); - if (RHSComponentCache != Cache::No) - printRight(S); - } - - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) 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(OutputStream &) const {} - - virtual StringView getBaseName() const { return StringView(); } - - // Silence compiler warnings, this dtor will never be called. - virtual ~Node() = default; +constexpr const char *itanium_demangle::FloatData<float>::spec; +constexpr const char *itanium_demangle::FloatData<double>::spec; +constexpr const char *itanium_demangle::FloatData<long double>::spec; -#ifndef NDEBUG - LLVM_DUMP_METHOD void dump() const { - char *Buffer = static_cast<char*>(std::malloc(1024)); - OutputStream S(Buffer, 1024); - print(S); - S += '\0'; - printf("Symbol dump for %p: %s\n", (const void*)this, S.getBuffer()); - std::free(S.getBuffer()); - } -#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(OutputStream &S) const { - bool FirstElement = true; - for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); - if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); - - // Elements[Idx] is an empty parameter pack expansion, we should erase the - // comma we just printed. - if (AfterComma == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); - continue; +// <discriminator> := _ <non-negative number> # when number < 10 +// := __ <non-negative number> _ # when number >= 10 +// extension := decimal-digit+ # at the end of string +const char *itanium_demangle::parse_discriminator(const char *first, + const char *last) { + // parse but ignore discriminator + if (first != last) { + if (*first == '_') { + const char *t1 = first + 1; + if (t1 != last) { + if (std::isdigit(*t1)) + first = t1 + 1; + else if (*t1 == '_') { + for (++t1; t1 != last && std::isdigit(*t1); ++t1) + ; + if (t1 != last && *t1 == '_') + first = t1 + 1; + } } - - FirstElement = false; + } else if (std::isdigit(*first)) { + const char *t1 = first + 1; + for (; t1 != last && std::isdigit(*t1); ++t1) + ; + if (t1 == last) + first = last; } } -}; - -struct NodeArrayNode : Node { - NodeArray Array; - NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} - void printLeft(OutputStream &S) const override { - Array.printWithComma(S); - } -}; - -class DotSuffix final : public Node { - const Node *Prefix; - const StringView Suffix; - -public: - DotSuffix(Node *Prefix_, StringView Suffix_) - : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} - - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; - } -}; - -class VendorExtQualType final : public Node { - const Node *Ty; - StringView Ext; - -public: - VendorExtQualType(Node *Ty_, StringView Ext_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} - - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; - } -}; - -enum FunctionRefQual : unsigned char { - FrefQualNone, - FrefQualLValue, - FrefQualRValue, -}; - -enum Qualifiers { - QualNone = 0, - QualConst = 0x1, - QualVolatile = 0x2, - QualRestrict = 0x4, -}; - -void addQualifiers(Qualifiers &Q1, Qualifiers Q2) { - Q1 = static_cast<Qualifiers>(Q1 | Q2); + return first; } -class QualType : public Node { -protected: - const Qualifiers Quals; - const Node *Child; - - void printQuals(OutputStream &S) const { - if (Quals & QualConst) - S += " const"; - if (Quals & QualVolatile) - S += " volatile"; - if (Quals & QualRestrict) - S += " restrict"; - } - -public: - QualType(Node *Child_, Qualifiers Quals_) - : Node(KQualType, Child_->RHSComponentCache, - Child_->ArrayCache, Child_->FunctionCache), - Quals(Quals_), Child(Child_) {} - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); - } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); - } - - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); - } - - void printRight(OutputStream &S) const override { Child->printRight(S); } -}; - -class ConversionOperatorType final : public Node { - const Node *Ty; - -public: - ConversionOperatorType(Node *Ty_) - : Node(KConversionOperatorType), Ty(Ty_) {} - - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); - } -}; - -class PostfixQualifiedType final : public Node { - const Node *Ty; - const StringView Postfix; - -public: - PostfixQualifiedType(Node *Ty_, StringView Postfix_) - : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} - - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; - } -}; - -class NameType final : public Node { - const StringView Name; - -public: - NameType(StringView Name_) : Node(KNameType), Name(Name_) {} - - StringView getName() const { return Name; } - StringView getBaseName() const override { return Name; } - - void printLeft(OutputStream &s) const override { s += Name; } -}; - -class ElaboratedTypeSpefType : public Node { - StringView Kind; - Node *Child; -public: - ElaboratedTypeSpefType(StringView Kind_, Node *Child_) - : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} - - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); - } -}; - -struct AbiTagAttr : Node { - Node *Base; - StringView Tag; - - AbiTagAttr(Node* Base_, StringView Tag_) - : Node(KAbiTagAttr, Base_->RHSComponentCache, - Base_->ArrayCache, Base_->FunctionCache), - Base(Base_), Tag(Tag_) {} - - void printLeft(OutputStream &S) const override { - Base->printLeft(S); - S += "[abi:"; - S += Tag; - S += "]"; - } -}; - -class EnableIfAttr : public Node { - NodeArray Conditions; -public: - EnableIfAttr(NodeArray Conditions_) - : Node(KEnableIfAttr), Conditions(Conditions_) {} - - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; - } -}; - -class ObjCProtoName : public Node { - Node *Ty; - StringView Protocol; - - friend class PointerType; - -public: - ObjCProtoName(Node *Ty_, StringView Protocol_) - : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} - - bool isObjCObject() const { - return Ty->getKind() == KNameType && - static_cast<NameType *>(Ty)->getName() == "objc_object"; - } - - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; - } -}; - -class PointerType final : public Node { - const Node *Pointee; - -public: - PointerType(Node *Pointee_) - : Node(KPointerType, Pointee_->RHSComponentCache), - Pointee(Pointee_) {} - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) const override { - // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>. - if (Pointee->getKind() != KObjCProtoName || - !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; - } else { - const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; - } - } - - void printRight(OutputStream &s) const override { - if (Pointee->getKind() != KObjCProtoName || - !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); - } - } -}; - -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; +#ifndef NDEBUG +namespace { +struct DumpVisitor { + unsigned Depth = 0; + bool PendingNewline = 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. - std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const { - auto SoFar = std::make_pair(RK, Pointee); - for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(S); - if (SN->getKind() != KReferenceType) - break; - auto *RT = static_cast<const ReferenceType *>(SN); - SoFar.second = RT->Pointee; - SoFar.first = std::min(SoFar.first, RT->RK); - } - return SoFar; + template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) { + return true; } + static bool wantsNewline(NodeArray A) { return !A.empty(); } + static constexpr bool wantsNewline(...) { return false; } -public: - ReferenceType(Node *Pointee_, ReferenceKind RK_) - : Node(KReferenceType, Pointee_->RHSComponentCache), - Pointee(Pointee_), RK(RK_) {} - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) { + for (bool B : {wantsNewline(Vs)...}) + if (B) + return true; + return false; } - void printLeft(OutputStream &s) const override { - if (Printing) - return; - SwapAndRestore<bool> SavePrinting(Printing, true); - std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); - Collapsed.second->printLeft(s); - if (Collapsed.second->hasArray(s)) - s += " "; - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += "("; - - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + void printStr(const char *S) { fprintf(stderr, "%s", S); } + void print(StringView SV) { + fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); } - void printRight(OutputStream &s) const override { - if (Printing) - return; - SwapAndRestore<bool> SavePrinting(Printing, true); - std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += ")"; - Collapsed.second->printRight(s); - } -}; - -class PointerToMemberType final : public Node { - const Node *ClassType; - const Node *MemberType; - -public: - PointerToMemberType(Node *ClassType_, Node *MemberType_) - : Node(KPointerToMemberType, MemberType_->RHSComponentCache), - ClassType(ClassType_), MemberType(MemberType_) {} - - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; + void print(const Node *N) { + if (N) + N->visit(std::ref(*this)); else - s += " "; - ClassType->print(s); - s += "::*"; - } - - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); - } -}; - -class NodeOrString { - const void *First; - const void *Second; - -public: - /* implicit */ NodeOrString(StringView Str) { - const char *FirstChar = Str.begin(); - const char *SecondChar = Str.end(); - if (SecondChar == nullptr) { - assert(FirstChar == SecondChar); - ++FirstChar, ++SecondChar; - } - First = static_cast<const void *>(FirstChar); - Second = static_cast<const void *>(SecondChar); - } - - /* implicit */ NodeOrString(Node *N) - : First(static_cast<const void *>(N)), Second(nullptr) {} - NodeOrString() : First(nullptr), Second(nullptr) {} - - bool isString() const { return Second && First; } - bool isNode() const { return First && !Second; } - bool isEmpty() const { return !First && !Second; } - - StringView asString() const { - assert(isString()); - return StringView(static_cast<const char *>(First), - static_cast<const char *>(Second)); - } - - const Node *asNode() const { - assert(isNode()); - return static_cast<const Node *>(First); - } -}; - -class ArrayType final : public Node { - Node *Base; - NodeOrString Dimension; - -public: - ArrayType(Node *Base_, NodeOrString Dimension_) - : Node(KArrayType, - /*RHSComponentCache=*/Cache::Yes, - /*ArrayCache=*/Cache::Yes), - Base(Base_), Dimension(Dimension_) {} - - // Incomplete array type. - ArrayType(Node *Base_) - : Node(KArrayType, - /*RHSComponentCache=*/Cache::Yes, - /*ArrayCache=*/Cache::Yes), - Base(Base_) {} - - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } - - void printLeft(OutputStream &S) const override { Base->printLeft(S); } - - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; - if (Dimension.isString()) - S += Dimension.asString(); - else if (Dimension.isNode()) - Dimension.asNode()->print(S); - S += "]"; - Base->printRight(S); - } -}; - -class FunctionType final : public Node { - Node *Ret; - NodeArray Params; - Qualifiers CVQuals; - FunctionRefQual RefQual; - Node *ExceptionSpec; - -public: - FunctionType(Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, - FunctionRefQual RefQual_, Node *ExceptionSpec_) - : Node(KFunctionType, - /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, - /*FunctionCache=*/Cache::Yes), - Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), - ExceptionSpec(ExceptionSpec_) {} - - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) 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(OutputStream &S) const override { - Ret->printLeft(S); - S += " "; - } - - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); - - if (CVQuals & QualConst) - S += " const"; - if (CVQuals & QualVolatile) - S += " volatile"; - if (CVQuals & QualRestrict) - S += " restrict"; - - if (RefQual == FrefQualLValue) - S += " &"; - else if (RefQual == FrefQualRValue) - S += " &&"; - - if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); - } - } -}; - -class NoexceptSpec : public Node { - Node *E; -public: - NoexceptSpec(Node *E_) : Node(KNoexceptSpec), E(E_) {} - - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; + printStr("<null>"); } -}; - -class DynamicExceptionSpec : public Node { - NodeArray Types; -public: - DynamicExceptionSpec(NodeArray Types_) - : Node(KDynamicExceptionSpec), Types(Types_) {} - - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; - } -}; - -class FunctionEncoding final : public Node { - Node *Ret; - Node *Name; - NodeArray Params; - Node *Attrs; - Qualifiers CVQuals; - FunctionRefQual RefQual; - -public: - FunctionEncoding(Node *Ret_, Node *Name_, NodeArray Params_, - 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_) {} - - Qualifiers getCVQuals() const { return CVQuals; } - FunctionRefQual getRefQual() const { return RefQual; } - NodeArray getParams() const { return Params; } - Node *getReturnType() const { return Ret; } - - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } - - Node *getName() { return const_cast<Node *>(Name); } - - void printLeft(OutputStream &S) const override { - if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; + void print(NodeOrString NS) { + if (NS.isNode()) + print(NS.asNode()); + else if (NS.isString()) + print(NS.asString()); + else + printStr("NodeOrString()"); + } + void print(NodeArray A) { + ++Depth; + printStr("{"); + bool First = true; + for (const Node *N : A) { + if (First) + print(N); + else + printWithComma(N); + First = false; } - Name->print(S); - } - - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - if (Ret) - Ret->printRight(S); - - if (CVQuals & QualConst) - S += " const"; - if (CVQuals & QualVolatile) - S += " volatile"; - if (CVQuals & QualRestrict) - S += " restrict"; - - if (RefQual == FrefQualLValue) - S += " &"; - else if (RefQual == FrefQualRValue) - S += " &&"; - - if (Attrs != nullptr) - Attrs->print(S); - } -}; - -class LiteralOperator : public Node { - const Node *OpName; - -public: - LiteralOperator(Node *OpName_) : Node(KLiteralOperator), OpName(OpName_) {} - - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); - } -}; - -class SpecialName final : public Node { - const StringView Special; - const Node *Child; - -public: - SpecialName(StringView Special_, Node* Child_) - : Node(KSpecialName), Special(Special_), Child(Child_) {} - - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); + printStr("}"); + --Depth; } -}; -class CtorVtableSpecialName final : public Node { - const Node *FirstType; - const Node *SecondType; + // Overload used when T is exactly 'bool', not merely convertible to 'bool'. + void print(bool B) { printStr(B ? "true" : "false"); } -public: - CtorVtableSpecialName(Node *FirstType_, Node *SecondType_) - : Node(KCtorVtableSpecialName), - FirstType(FirstType_), SecondType(SecondType_) {} - - void printLeft(OutputStream &S) const override { - S += "construction vtable for "; - FirstType->print(S); - S += "-in-"; - SecondType->print(S); + template <class T> + typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) { + fprintf(stderr, "%llu", (unsigned long long)N); } -}; -struct NestedName : Node { - Node *Qual; - Node *Name; - - NestedName(Node *Qual_, Node *Name_) - : Node(KNestedName), Qual(Qual_), Name(Name_) {} - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Qual->print(S); - S += "::"; - Name->print(S); + template <class T> + typename std::enable_if<std::is_signed<T>::value>::type print(T N) { + fprintf(stderr, "%lld", (long long)N); } -}; - -struct LocalName : Node { - Node *Encoding; - Node *Entity; - - LocalName(Node *Encoding_, Node *Entity_) - : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} - - void printLeft(OutputStream &S) const override { - Encoding->print(S); - S += "::"; - Entity->print(S); - } -}; - -class QualifiedName final : public Node { - // qualifier::name - const Node *Qualifier; - const Node *Name; - -public: - QualifiedName(Node* Qualifier_, Node* Name_) - : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); - } -}; - -class VectorType final : public Node { - const Node *BaseType; - const NodeOrString Dimension; - const bool IsPixel; - -public: - VectorType(NodeOrString Dimension_) - : Node(KVectorType), BaseType(nullptr), Dimension(Dimension_), - IsPixel(true) {} - VectorType(Node *BaseType_, NodeOrString Dimension_) - : Node(KVectorType), BaseType(BaseType_), - Dimension(Dimension_), IsPixel(false) {} - - void printLeft(OutputStream &S) const override { - if (IsPixel) { - S += "pixel vector["; - S += Dimension.asString(); - S += "]"; - } else { - BaseType->print(S); - S += " vector["; - if (Dimension.isNode()) - Dimension.asNode()->print(S); - else if (Dimension.isString()) - S += Dimension.asString(); - S += "]"; + void print(ReferenceKind RK) { + switch (RK) { + case ReferenceKind::LValue: + return printStr("ReferenceKind::LValue"); + case ReferenceKind::RValue: + return printStr("ReferenceKind::RValue"); } } -}; - -/// 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 <template-args> are found that apply to an -/// <encoding>, and is stored in the TemplateParams table. In order for this to -/// appear in the final AST, it has to referenced via a <template-param> (ie, -/// T_). -class ParameterPack final : public Node { - NodeArray Data; - - // Setup OutputStream for a pack expansion unless we're already expanding one. - void initializePackExpansion(OutputStream &S) const { - if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) { - S.CurrentPackMax = static_cast<unsigned>(Data.size()); - S.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; - } - - bool hasRHSComponentSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); - } - bool hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); - } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; - } - - void printLeft(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - if (Idx < Data.size()) - Data[Idx]->printLeft(S); - } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - if (Idx < Data.size()) - Data[Idx]->printRight(S); - } -}; - -/// A variadic template argument. This node represents an occurrence of -/// J<something>E in some <template-args>. It isn't itself unexpanded, unless -/// one of it's Elements is. The parser inserts a ParameterPack into the -/// TemplateParams table if the <template-args> this pack belongs to apply to an -/// <encoding>. -class TemplateArgumentPack final : public Node { - NodeArray Elements; -public: - TemplateArgumentPack(NodeArray Elements_) - : Node(KTemplateArgumentPack), Elements(Elements_) {} - - NodeArray getElements() const { return Elements; } - - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); - } -}; - -/// 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(Node* Child_) - : Node(KParameterPackExpansion), Child(Child_) {} - - const Node *getChild() const { return Child; } - - void printLeft(OutputStream &S) const override { - constexpr unsigned Max = std::numeric_limits<unsigned>::max(); - SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.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(S); - - // No ParameterPack was found in Child. This can occur if we've found a pack - // expansion on a <function-param>. - if (S.CurrentPackMax == Max) { - S += "..."; - return; + void print(FunctionRefQual RQ) { + switch (RQ) { + case FunctionRefQual::FrefQualNone: + return printStr("FunctionRefQual::FrefQualNone"); + case FunctionRefQual::FrefQualLValue: + return printStr("FunctionRefQual::FrefQualLValue"); + case FunctionRefQual::FrefQualRValue: + return printStr("FunctionRefQual::FrefQualRValue"); } - - // We found a ParameterPack, but it has no elements. Erase whatever we may - // of printed. - if (S.CurrentPackMax == 0) { - S.setCurrentPosition(StreamPos); - return; - } - - // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { - S += ", "; - S.CurrentPackIndex = I; - Child->print(S); - } - } -}; - -class TemplateArgs final : public Node { - NodeArray Params; - -public: - TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} - - NodeArray getParams() { return Params; } - - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; } -}; - -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_) {} - - bool hasRHSComponentSlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); - } - bool hasArraySlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasFunction(S); - } - const Node *getSyntaxNode(OutputStream &S) const override { - if (Printing) - return this; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); - } - - void printLeft(OutputStream &S) const override { - if (Printing) - return; - SwapAndRestore<bool> SavePrinting(Printing, true); - Ref->printLeft(S); - } - void printRight(OutputStream &S) const override { - if (Printing) - return; - SwapAndRestore<bool> SavePrinting(Printing, true); - Ref->printRight(S); - } -}; - -struct NameWithTemplateArgs : Node { - // name<template_args> - Node *Name; - Node *TemplateArgs; - - NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) - : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Name->print(S); - TemplateArgs->print(S); - } -}; - -class GlobalQualifiedName final : public Node { - Node *Child; - -public: - GlobalQualifiedName(Node* Child_) - : Node(KGlobalQualifiedName), Child(Child_) {} - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); - } -}; - -struct StdQualifiedName : Node { - Node *Child; - - StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "std::"; - Child->print(S); - } -}; - -enum class SpecialSubKind { - allocator, - basic_string, - string, - istream, - ostream, - iostream, -}; - -class ExpandedSpecialSubstitution final : public Node { - SpecialSubKind SSK; - -public: - ExpandedSpecialSubstitution(SpecialSubKind SSK_) - : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} - - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("basic_string"); - case SpecialSubKind::istream: - return StringView("basic_istream"); - case SpecialSubKind::ostream: - return StringView("basic_ostream"); - case SpecialSubKind::iostream: - return StringView("basic_iostream"); - } - LLVM_BUILTIN_UNREACHABLE; - } - - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::basic_string<char, std::char_traits<char>, " - "std::allocator<char> >"; - break; - case SpecialSubKind::basic_string: - case SpecialSubKind::string: - S += "std::basic_string<char, std::char_traits<char>, " - "std::allocator<char> >"; - break; - case SpecialSubKind::istream: - S += "std::basic_istream<char, std::char_traits<char> >"; - break; - case SpecialSubKind::ostream: - S += "std::basic_ostream<char, std::char_traits<char> >"; - break; - case SpecialSubKind::iostream: - S += "std::basic_iostream<char, std::char_traits<char> >"; - break; - } - } -}; - -class SpecialSubstitution final : public Node { -public: - SpecialSubKind SSK; - - SpecialSubstitution(SpecialSubKind SSK_) - : Node(KSpecialSubstitution), SSK(SSK_) {} - - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("string"); - case SpecialSubKind::istream: - return StringView("istream"); - case SpecialSubKind::ostream: - return StringView("ostream"); - case SpecialSubKind::iostream: - return StringView("iostream"); + void print(Qualifiers Qs) { + if (!Qs) return printStr("QualNone"); + struct QualName { Qualifiers Q; const char *Name; } Names[] = { + {QualConst, "QualConst"}, + {QualVolatile, "QualVolatile"}, + {QualRestrict, "QualRestrict"}, + }; + for (QualName Name : Names) { + if (Qs & Name.Q) { + printStr(Name.Name); + Qs = Qualifiers(Qs & ~Name.Q); + if (Qs) printStr(" | "); + } } - LLVM_BUILTIN_UNREACHABLE; } - - void printLeft(OutputStream &S) const override { + void print(SpecialSubKind SSK) { switch (SSK) { case SpecialSubKind::allocator: - S += "std::allocator"; - break; + return printStr("SpecialSubKind::allocator"); case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; + return printStr("SpecialSubKind::basic_string"); case SpecialSubKind::string: - S += "std::string"; - break; + return printStr("SpecialSubKind::string"); case SpecialSubKind::istream: - S += "std::istream"; - break; + return printStr("SpecialSubKind::istream"); case SpecialSubKind::ostream: - S += "std::ostream"; - break; + return printStr("SpecialSubKind::ostream"); case SpecialSubKind::iostream: - S += "std::iostream"; - break; - } - } -}; - -class CtorDtorName final : public Node { - const Node *Basename; - const bool IsDtor; - -public: - CtorDtorName(Node *Basename_, bool IsDtor_) - : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_) {} - - void printLeft(OutputStream &S) const override { - if (IsDtor) - S += "~"; - S += Basename->getBaseName(); - } -}; - -class DtorName : public Node { - const Node *Base; - -public: - DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {} - - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); - } -}; - -class UnnamedTypeName : public Node { - const StringView Count; - -public: - UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} - - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; - } -}; - -class ClosureTypeName : public Node { - NodeArray Params; - StringView Count; - -public: - ClosureTypeName(NodeArray Params_, StringView Count_) - : Node(KClosureTypeName), Params(Params_), Count(Count_) {} - - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'("; - Params.printWithComma(S); - S += ")"; - } -}; - -class StructuredBindingName : public Node { - NodeArray Bindings; -public: - StructuredBindingName(NodeArray Bindings_) - : Node(KStructuredBindingName), Bindings(Bindings_) {} - - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; - } -}; - -// -- Expression Nodes -- - -struct Expr : public Node { - Expr(Kind K = KExpr) : Node(K) {} -}; - -class BinaryExpr : public Expr { - const Node *LHS; - const StringView InfixOperator; - const Node *RHS; - -public: - BinaryExpr(Node *LHS_, StringView InfixOperator_, Node *RHS_) - : LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {} - - void printLeft(OutputStream &S) const override { - // might be a template argument expression, then we need to disambiguate - // with parens. - if (InfixOperator == ">") - S += "("; - - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; - - if (InfixOperator == ">") - S += ")"; - } -}; - -class ArraySubscriptExpr : public Expr { - const Node *Op1; - const Node *Op2; - -public: - ArraySubscriptExpr(Node *Op1_, Node *Op2_) : Op1(Op1_), Op2(Op2_) {} - - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; - } -}; - -class PostfixExpr : public Expr { - const Node *Child; - const StringView Operand; - -public: - PostfixExpr(Node *Child_, StringView Operand_) - : Child(Child_), Operand(Operand_) {} - - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operand; - } -}; - -class ConditionalExpr : public Expr { - const Node *Cond; - const Node *Then; - const Node *Else; - -public: - ConditionalExpr(Node *Cond_, Node *Then_, Node *Else_) - : Cond(Cond_), Then(Then_), Else(Else_) {} - - void printLeft(OutputStream &S) const override { - S += "("; - Cond->print(S); - S += ") ? ("; - Then->print(S); - S += ") : ("; - Else->print(S); - S += ")"; - } -}; - -class MemberExpr : public Expr { - const Node *LHS; - const StringView Kind; - const Node *RHS; - -public: - MemberExpr(Node *LHS_, StringView Kind_, Node *RHS_) - : LHS(LHS_), Kind(Kind_), RHS(RHS_) {} - - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); - } -}; - -class EnclosingExpr : public Expr { - const StringView Prefix; - const Node *Infix; - const StringView Postfix; - -public: - EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) - : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {} - - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; - } -}; - -class CastExpr : public Expr { - // cast_kind<to>(from) - const StringView CastKind; - const Node *To; - const Node *From; - -public: - CastExpr(StringView CastKind_, Node *To_, Node *From_) - : CastKind(CastKind_), To(To_), From(From_) {} - - void printLeft(OutputStream &S) const override { - S += CastKind; - S += "<"; - To->printLeft(S); - S += ">("; - From->printLeft(S); - S += ")"; - } -}; - -class SizeofParamPackExpr : public Expr { - Node *Pack; - -public: - SizeofParamPackExpr(Node *Pack_) : Pack(Pack_) {} - - void printLeft(OutputStream &S) const override { - S += "sizeof...("; - ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; - } -}; - -class CallExpr : public Expr { - const Node *Callee; - NodeArray Args; - -public: - CallExpr(Node *Callee_, NodeArray Args_) : Callee(Callee_), Args(Args_) {} - - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; - } -}; - -class NewExpr : public Expr { - // 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_) - : ExprList(ExprList_), Type(Type_), InitList(InitList_), - IsGlobal(IsGlobal_), IsArray(IsArray_) {} - - void printLeft(OutputStream &S) const override { - if (IsGlobal) - S += "::operator "; - S += "new"; - if (IsArray) - S += "[]"; - S += ' '; - if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; + return printStr("SpecialSubKind::iostream"); } - Type->print(S); - if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; - } - - } -}; - -class DeleteExpr : public Expr { - Node *Op; - bool IsGlobal; - bool IsArray; - -public: - DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) - : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} - - void printLeft(OutputStream &S) const override { - if (IsGlobal) - S += "::"; - S += "delete"; - if (IsArray) - S += "[] "; - Op->print(S); - } -}; - -class PrefixExpr : public Expr { - StringView Prefix; - Node *Child; - -public: - PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {} - - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; } -}; - -class FunctionParam : public Expr { - StringView Number; -public: - FunctionParam(StringView Number_) : Number(Number_) {} - - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; + void newLine() { + printStr("\n"); + for (unsigned I = 0; I != Depth; ++I) + printStr(" "); + PendingNewline = false; } -}; -class ConversionExpr : public Expr { - const Node *Type; - NodeArray Expressions; - -public: - ConversionExpr(const Node *Type_, NodeArray Expressions_) - : Type(Type_), Expressions(Expressions_) {} - - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; + template<typename T> void printWithPendingNewline(T V) { + print(V); + if (wantsNewline(V)) + PendingNewline = true; } -}; - -class InitListExpr : public Expr { - Node *Ty; - NodeArray Inits; -public: - InitListExpr(Node *Ty_, NodeArray Inits_) : Ty(Ty_), Inits(Inits_) {} - - void printLeft(OutputStream &S) const override { - if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; - } -}; -class BracedExpr : public Expr { - Node *Elem; - Node *Init; - bool IsArray; -public: - BracedExpr(Node *Elem_, Node *Init_, bool IsArray_) - : Expr(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {} - - void printLeft(OutputStream &S) const override { - if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; + template<typename T> void printWithComma(T V) { + if (PendingNewline || wantsNewline(V)) { + printStr(","); + newLine(); } else { - S += '.'; - Elem->print(S); + printStr(", "); } - if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); - } -}; -class BracedRangeExpr : public Expr { - Node *First; - Node *Last; - Node *Init; -public: - BracedRangeExpr(Node *First_, Node *Last_, Node *Init_) - : Expr(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {} - - void printLeft(OutputStream &S) const override { - S += '['; - First->print(S); - S += " ... "; - Last->print(S); - S += ']'; - if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + printWithPendingNewline(V); } -}; - -struct FoldExpr : Expr { - Node *Pack, *Init; - StringView OperatorName; - bool IsLeftFold; - - FoldExpr(bool IsLeftFold_, StringView OperatorName_, Node *Pack_, Node *Init_) - : Pack(Pack_), Init(Init_), OperatorName(OperatorName_), - IsLeftFold(IsLeftFold_) {} - void printLeft(OutputStream &S) const override { - auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; - }; - - S += '('; + struct CtorArgPrinter { + DumpVisitor &Visitor; - if (IsLeftFold) { - // init op ... op pack - if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; - } - // ... op pack - S += "... "; - S += OperatorName; - S += ' '; - PrintPack(); - } else { // !IsLeftFold - // pack op ... - PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; - // pack op ... op init - if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); - } + template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) { + if (Visitor.anyWantNewline(V, Vs...)) + Visitor.newLine(); + Visitor.printWithPendingNewline(V); + int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 }; + (void)PrintInOrder; } - S += ')'; - } -}; - -class ThrowExpr : public Expr { - const Node *Op; - -public: - ThrowExpr(Node *Op_) : Op(Op_) {} - - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); - } -}; - -class BoolExpr : public Expr { - bool Value; - -public: - BoolExpr(bool Value_) : Value(Value_) {} - - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); - } -}; - -class IntegerCastExpr : public Expr { - // ty(integer) - Node *Ty; - StringView Integer; - -public: - IntegerCastExpr(Node *Ty_, StringView Integer_) - : Ty(Ty_), Integer(Integer_) {} - - void printLeft(OutputStream &S) const override { - S += "("; - Ty->print(S); - S += ")"; - S += Integer; - } -}; - -class IntegerExpr : public Expr { - StringView Type; - StringView Value; - -public: - IntegerExpr(StringView Type_, StringView Value_) : Type(Type_), Value(Value_) {} + }; - void printLeft(OutputStream &S) const override { - if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; + template<typename NodeT> void operator()(const NodeT *Node) { + Depth += 2; + fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name()); + Node->match(CtorArgPrinter{*this}); + fprintf(stderr, ")"); + Depth -= 2; + } + + void operator()(const ForwardTemplateReference *Node) { + Depth += 2; + fprintf(stderr, "ForwardTemplateReference("); + if (Node->Ref && !Node->Printing) { + Node->Printing = true; + CtorArgPrinter{*this}(Node->Ref); + Node->Printing = false; + } else { + CtorArgPrinter{*this}(Node->Index); } - - if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); - } else - S += Value; - - if (Type.size() <= 3) - S += Type; + fprintf(stderr, ")"); + Depth -= 2; } }; +} -template <class Float> struct FloatData; - -template <class Float> class FloatExpr : public Expr { - const StringView Contents; - -public: - FloatExpr(StringView Contents_) : Contents(Contents_) {} - - void printLeft(OutputStream &s) const override { - const char *first = Contents.begin(); - const char *last = Contents.end() + 1; - - const size_t N = FloatData<Float>::mangled_size; - if (static_cast<std::size_t>(last - first) > N) { - last = first + N; - union { - Float value; - char buf[sizeof(Float)]; - }; - const char *t = first; - char *e = buf; - for (; t != last; ++t, ++e) { - unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') - : static_cast<unsigned>(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') - : static_cast<unsigned>(*t - 'a' + 10); - *e = static_cast<char>((d1 << 4) + d0); - } -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::reverse(buf, e); +void itanium_demangle::Node::dump() const { + DumpVisitor V; + visit(std::ref(V)); + V.newLine(); +} #endif - char num[FloatData<Float>::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); - s += StringView(num, num + n); - } - } -}; +namespace { class BumpPointerAllocator { struct BlockMeta { BlockMeta* Next; @@ -1823,3134 +301,28 @@ public: ~BumpPointerAllocator() { reset(); } }; -template <class T, size_t N> -class PODSmallVector { - static_assert(std::is_pod<T>::value, - "T is required to be a plain old data type"); - - T* First; - T* Last; - T* Cap; - T Inline[N]; - - 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<T*>(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T))); - if (First == nullptr) - std::terminate(); - } - Last = First + S; - Cap = First + NewCap; - } +class DefaultAllocator { + BumpPointerAllocator Alloc; 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; - } - - void push_back(const T& Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - 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<size_t>(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); - } -}; - -struct Db { - 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<Node *, 32> 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<Node *, 32> Subs; - - // 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. - PODSmallVector<Node *, 8> TemplateParams; - - // Set of unresolved forward <template-param> references. These can occur in a - // conversion operator's type, and are resolved in the enclosing <encoding>. - PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs; - - bool TryToParseTemplateArgs = true; - bool PermitForwardTemplateReferences = false; - bool ParsingLambdaParams = false; - - BumpPointerAllocator ASTAllocator; + void reset() { Alloc.reset(); } - Db(const char *First_, const char *Last_) : First(First_), Last(Last_) {} - - void reset(const char *First_, const char *Last_) { - First = First_; - Last = Last_; - Names.clear(); - Subs.clear(); - TemplateParams.clear(); - ParsingLambdaParams = false; - TryToParseTemplateArgs = true; - PermitForwardTemplateReferences = false; - ASTAllocator.reset(); - } - - template <class T, class... Args> T *make(Args &&... args) { - return new (ASTAllocator.allocate(sizeof(T))) + template<typename T, typename ...Args> T *makeNode(Args &&...args) { + return new (Alloc.allocate(sizeof(T))) T(std::forward<Args>(args)...); } - template <class It> NodeArray makeNodeArray(It begin, It end) { - size_t sz = static_cast<size_t>(end - begin); - void *mem = ASTAllocator.allocate(sizeof(Node *) * 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(StringView S) { - if (StringView(First, Last).startsWith(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) { - if (static_cast<size_t>(Last - First) <= Lookahead) - return '\0'; - return First[Lookahead]; - } - - size_t numLeft() const { return static_cast<size_t>(Last - First); } - - StringView parseNumber(bool AllowNegative = false); - Qualifiers parseCVQualifiers(); - bool parsePositiveInteger(size_t *Out); - StringView parseBareSourceName(); - - bool parseSeqId(size_t *Out); - Node *parseSubstitution(); - Node *parseTemplateParam(); - Node *parseTemplateArgs(bool TagTemplates = false); - Node *parseTemplateArg(); - - /// Parse the <expr> production. - Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind); - Node *parseBinaryExpr(StringView Kind); - Node *parseIntegerLiteral(StringView Lit); - Node *parseExprPrimary(); - template <class Float> Node *parseFloatingLiteral(); - Node *parseFunctionParam(); - Node *parseNewExpr(); - Node *parseConversionExpr(); - Node *parseBracedExpr(); - Node *parseFoldExpr(); - - /// Parse the <type> 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 <name> that is being parsed. This - /// information is only pertinent if the <name> refers to an <encoding>. - struct NameState { - bool CtorDtorConversion = false; - bool EndsWithTemplateArgs = false; - Qualifiers CVQualifiers = QualNone; - FunctionRefQual ReferenceQualifier = FrefQualNone; - size_t ForwardTemplateRefsBegin; - - NameState(Db *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 (Idx >= TemplateParams.size()) - return true; - ForwardTemplateRefs[I]->Ref = TemplateParams[Idx]; - } - ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); - return false; + void *allocateNodeArray(size_t sz) { + return Alloc.allocate(sizeof(Node *) * sz); } - - /// Parse the <name> production> - Node *parseName(NameState *State = nullptr); - Node *parseLocalName(NameState *State); - Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(NameState *State); - Node *parseUnnamedTypeName(NameState *State); - Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State); - Node *parseNestedName(NameState *State); - Node *parseCtorDtorName(Node *&SoFar, NameState *State); - - Node *parseAbiTags(Node *N); - - /// Parse the <unresolved-name> production. - Node *parseUnresolvedName(); - Node *parseSimpleId(); - Node *parseBaseUnresolvedName(); - Node *parseUnresolvedType(); - Node *parseDestructorName(); - - /// Top-level entry point into the parser. - Node *parse(); }; +} // unnamed namespace -const char* parse_discriminator(const char* first, const char* last); - -// <name> ::= <nested-name> // N -// ::= <local-name> # See Scope Encoding below // Z -// ::= <unscoped-template-name> <template-args> -// ::= <unscoped-name> -// -// <unscoped-template-name> ::= <unscoped-name> -// ::= <substitution> -Node *Db::parseName(NameState *State) { - consumeIf('L'); // extension - - if (look() == 'N') - return parseNestedName(State); - if (look() == 'Z') - return parseLocalName(State); - - // ::= <unscoped-template-name> <template-args> - if (look() == 'S' && look(1) != 't') { - Node *S = parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; - Node *TA = parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make<NameWithTemplateArgs>(S, TA); - } - - Node *N = parseUnscopedName(State); - if (N == nullptr) - return nullptr; - // ::= <unscoped-template-name> <template-args> - if (look() == 'I') { - Subs.push_back(N); - Node *TA = parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make<NameWithTemplateArgs>(N, TA); - } - // ::= <unscoped-name> - return N; -} - -// <local-name> := Z <function encoding> E <entity name> [<discriminator>] -// := Z <function encoding> E s [<discriminator>] -// := Z <function encoding> Ed [ <parameter number> ] _ <entity name> -Node *Db::parseLocalName(NameState *State) { - if (!consumeIf('Z')) - return nullptr; - Node *Encoding = parseEncoding(); - if (Encoding == nullptr || !consumeIf('E')) - return nullptr; - - if (consumeIf('s')) { - First = parse_discriminator(First, Last); - return make<LocalName>(Encoding, make<NameType>("string literal")); - } - - if (consumeIf('d')) { - parseNumber(true); - if (!consumeIf('_')) - return nullptr; - Node *N = parseName(State); - if (N == nullptr) - return nullptr; - return make<LocalName>(Encoding, N); - } - - Node *Entity = parseName(State); - if (Entity == nullptr) - return nullptr; - First = parse_discriminator(First, Last); - return make<LocalName>(Encoding, Entity); -} - -// <unscoped-name> ::= <unqualified-name> -// ::= St <unqualified-name> # ::std:: -// extension ::= StL<unqualified-name> -Node *Db::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = parseUnqualifiedName(State); - if (R == nullptr) - return nullptr; - return make<StdQualifiedName>(R); - } - return parseUnqualifiedName(State); -} - -// <unqualified-name> ::= <operator-name> [abi-tags] -// ::= <ctor-dtor-name> -// ::= <source-name> -// ::= <unnamed-type-name> -// ::= DC <source-name>+ E # structured binding declaration -Node *Db::parseUnqualifiedName(NameState *State) { - // <ctor-dtor-name>s are special-cased in parseNestedName(). - Node *Result; - if (look() == 'U') - Result = parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') - Result = parseSourceName(State); - else if (consumeIf("DC")) { - size_t BindingsBegin = Names.size(); - do { - Node *Binding = parseSourceName(State); - if (Binding == nullptr) - return nullptr; - Names.push_back(Binding); - } while (!consumeIf('E')); - Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin)); - } else - Result = parseOperatorName(State); - if (Result != nullptr) - Result = parseAbiTags(Result); - return Result; -} - -// <unnamed-type-name> ::= Ut [<nonnegative number>] _ -// ::= <closure-type-name> -// -// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ -// -// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters -Node *Db::parseUnnamedTypeName(NameState *) { - if (consumeIf("Ut")) { - StringView Count = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<UnnamedTypeName>(Count); - } - if (consumeIf("Ul")) { - NodeArray Params; - SwapAndRestore<bool> SwapParams(ParsingLambdaParams, true); - if (!consumeIf("vE")) { - size_t ParamsBegin = Names.size(); - do { - Node *P = parseType(); - if (P == nullptr) - return nullptr; - Names.push_back(P); - } while (!consumeIf('E')); - Params = popTrailingNodeArray(ParamsBegin); - } - StringView Count = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<ClosureTypeName>(Params, Count); - } - return nullptr; -} - -// <source-name> ::= <positive length number> <identifier> -Node *Db::parseSourceName(NameState *) { - size_t Length = 0; - if (parsePositiveInteger(&Length)) - return nullptr; - if (numLeft() < Length || Length == 0) - return nullptr; - StringView Name(First, First + Length); - First += Length; - if (Name.startsWith("_GLOBAL__N")) - return make<NameType>("(anonymous namespace)"); - return make<NameType>(Name); -} - -// <operator-name> ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv <type> # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= -// ::= li <source-name> # operator "" -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in <expression> context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in <expression> context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= ss # <=> C++2a -// ::= v <digit> <source-name> # vendor extended operator -Node *Db::parseOperatorName(NameState *State) { - switch (look()) { - case 'a': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator&&"); - case 'd': - case 'n': - First += 2; - return make<NameType>("operator&"); - case 'N': - First += 2; - return make<NameType>("operator&="); - case 'S': - First += 2; - return make<NameType>("operator="); - } - return nullptr; - case 'c': - switch (look(1)) { - case 'l': - First += 2; - return make<NameType>("operator()"); - case 'm': - First += 2; - return make<NameType>("operator,"); - case 'o': - First += 2; - return make<NameType>("operator~"); - // ::= cv <type> # (cast) - case 'v': { - First += 2; - SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false); - // If we're parsing an encoding, State != nullptr and the conversion - // operators' <type> could have a <template-param> that refers to some - // <template-arg>s further ahead in the mangled name. - SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences, - PermitForwardTemplateReferences || - State != nullptr); - Node* Ty = parseType(); - if (Ty == nullptr) - return nullptr; - if (State) State->CtorDtorConversion = true; - return make<ConversionOperatorType>(Ty); - } - } - return nullptr; - case 'd': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator delete[]"); - case 'e': - First += 2; - return make<NameType>("operator*"); - case 'l': - First += 2; - return make<NameType>("operator delete"); - case 'v': - First += 2; - return make<NameType>("operator/"); - case 'V': - First += 2; - return make<NameType>("operator/="); - } - return nullptr; - case 'e': - switch (look(1)) { - case 'o': - First += 2; - return make<NameType>("operator^"); - case 'O': - First += 2; - return make<NameType>("operator^="); - case 'q': - First += 2; - return make<NameType>("operator=="); - } - return nullptr; - case 'g': - switch (look(1)) { - case 'e': - First += 2; - return make<NameType>("operator>="); - case 't': - First += 2; - return make<NameType>("operator>"); - } - return nullptr; - case 'i': - if (look(1) == 'x') { - First += 2; - return make<NameType>("operator[]"); - } - return nullptr; - case 'l': - switch (look(1)) { - case 'e': - First += 2; - return make<NameType>("operator<="); - // ::= li <source-name> # operator "" - case 'i': { - First += 2; - Node *SN = parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make<LiteralOperator>(SN); - } - case 's': - First += 2; - return make<NameType>("operator<<"); - case 'S': - First += 2; - return make<NameType>("operator<<="); - case 't': - First += 2; - return make<NameType>("operator<"); - } - return nullptr; - case 'm': - switch (look(1)) { - case 'i': - First += 2; - return make<NameType>("operator-"); - case 'I': - First += 2; - return make<NameType>("operator-="); - case 'l': - First += 2; - return make<NameType>("operator*"); - case 'L': - First += 2; - return make<NameType>("operator*="); - case 'm': - First += 2; - return make<NameType>("operator--"); - } - return nullptr; - case 'n': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator new[]"); - case 'e': - First += 2; - return make<NameType>("operator!="); - case 'g': - First += 2; - return make<NameType>("operator-"); - case 't': - First += 2; - return make<NameType>("operator!"); - case 'w': - First += 2; - return make<NameType>("operator new"); - } - return nullptr; - case 'o': - switch (look(1)) { - case 'o': - First += 2; - return make<NameType>("operator||"); - case 'r': - First += 2; - return make<NameType>("operator|"); - case 'R': - First += 2; - return make<NameType>("operator|="); - } - return nullptr; - case 'p': - switch (look(1)) { - case 'm': - First += 2; - return make<NameType>("operator->*"); - case 'l': - First += 2; - return make<NameType>("operator+"); - case 'L': - First += 2; - return make<NameType>("operator+="); - case 'p': - First += 2; - return make<NameType>("operator++"); - case 's': - First += 2; - return make<NameType>("operator+"); - case 't': - First += 2; - return make<NameType>("operator->"); - } - return nullptr; - case 'q': - if (look(1) == 'u') { - First += 2; - return make<NameType>("operator?"); - } - return nullptr; - case 'r': - switch (look(1)) { - case 'm': - First += 2; - return make<NameType>("operator%"); - case 'M': - First += 2; - return make<NameType>("operator%="); - case 's': - First += 2; - return make<NameType>("operator>>"); - case 'S': - First += 2; - return make<NameType>("operator>>="); - } - return nullptr; - case 's': - if (look(1) == 's') { - First += 2; - return make<NameType>("operator<=>"); - } - return nullptr; - // ::= v <digit> <source-name> # vendor extended operator - case 'v': - if (std::isdigit(look(1))) { - First += 2; - Node *SN = parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make<ConversionOperatorType>(SN); - } - return nullptr; - } - return nullptr; -} - -// <ctor-dtor-name> ::= C1 # complete object constructor -// ::= C2 # base object constructor -// ::= C3 # complete object allocating constructor -// extension ::= C5 # ? -// ::= D0 # deleting destructor -// ::= D1 # complete object destructor -// ::= D2 # base object destructor -// extension ::= D5 # ? -Node *Db::parseCtorDtorName(Node *&SoFar, NameState *State) { - if (SoFar->K == Node::KSpecialSubstitution) { - auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK; - switch (SSK) { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - SoFar = make<ExpandedSpecialSubstitution>(SSK); - default: - break; - } - } - - if (consumeIf('C')) { - bool IsInherited = consumeIf('I'); - if (look() != '1' && look() != '2' && look() != '3' && look() != '5') - return nullptr; - ++First; - if (State) State->CtorDtorConversion = true; - if (IsInherited) { - if (parseName(State) == nullptr) - return nullptr; - } - return make<CtorDtorName>(SoFar, false); - } - - if (look() == 'D' && - (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) { - First += 2; - if (State) State->CtorDtorConversion = true; - return make<CtorDtorName>(SoFar, true); - } - - return nullptr; -} - -// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E -// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E -// -// <prefix> ::= <prefix> <unqualified-name> -// ::= <template-prefix> <template-args> -// ::= <template-param> -// ::= <decltype> -// ::= # empty -// ::= <substitution> -// ::= <prefix> <data-member-prefix> -// extension ::= L -// -// <data-member-prefix> := <member source-name> [<template-args>] M -// -// <template-prefix> ::= <prefix> <template unqualified-name> -// ::= <template-param> -// ::= <substitution> -Node *Db::parseNestedName(NameState *State) { - if (!consumeIf('N')) - return nullptr; - - 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; - - Node *SoFar = nullptr; - auto PushComponent = [&](Node *Comp) { - if (SoFar) SoFar = make<NestedName>(SoFar, Comp); - else SoFar = Comp; - if (State) State->EndsWithTemplateArgs = false; - }; - - if (consumeIf("St")) - SoFar = make<NameType>("std"); - - while (!consumeIf('E')) { - consumeIf('L'); // extension - - // <data-member-prefix> := <member source-name> [<template-args>] M - if (consumeIf('M')) { - if (SoFar == nullptr) - return nullptr; - continue; - } - - // ::= <template-param> - if (look() == 'T') { - Node *TP = parseTemplateParam(); - if (TP == nullptr) - return nullptr; - PushComponent(TP); - Subs.push_back(SoFar); - continue; - } - - // ::= <template-prefix> <template-args> - if (look() == 'I') { - Node *TA = parseTemplateArgs(State != nullptr); - if (TA == nullptr || SoFar == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - if (State) State->EndsWithTemplateArgs = true; - Subs.push_back(SoFar); - continue; - } - - // ::= <decltype> - if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - Node *DT = parseDecltype(); - if (DT == nullptr) - return nullptr; - PushComponent(DT); - Subs.push_back(SoFar); - continue; - } - - // ::= <substitution> - if (look() == 'S' && look(1) != 't') { - Node *S = parseSubstitution(); - if (S == nullptr) - return nullptr; - PushComponent(S); - if (SoFar != S) - Subs.push_back(S); - continue; - } - - // Parse an <unqualified-name> thats actually a <ctor-dtor-name>. - if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { - if (SoFar == nullptr) - return nullptr; - Node *CtorDtor = parseCtorDtorName(SoFar, State); - if (CtorDtor == nullptr) - return nullptr; - PushComponent(CtorDtor); - SoFar = parseAbiTags(SoFar); - if (SoFar == nullptr) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= <prefix> <unqualified-name> - Node *N = parseUnqualifiedName(State); - if (N == nullptr) - return nullptr; - PushComponent(N); - Subs.push_back(SoFar); - } - - if (SoFar == nullptr || Subs.empty()) - return nullptr; - - Subs.pop_back(); - return SoFar; -} - -// <simple-id> ::= <source-name> [ <template-args> ] -Node *Db::parseSimpleId() { - Node *SN = parseSourceName(/*NameState=*/nullptr); - if (SN == nullptr) - return nullptr; - if (look() == 'I') { - Node *TA = parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - return make<NameWithTemplateArgs>(SN, TA); - } - return SN; -} - -// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) -// ::= <simple-id> # e.g., ~A<2*N> -Node *Db::parseDestructorName() { - Node *Result; - if (std::isdigit(look())) - Result = parseSimpleId(); - else - Result = parseUnresolvedType(); - if (Result == nullptr) - return nullptr; - return make<DtorName>(Result); -} - -// <unresolved-type> ::= <template-param> -// ::= <decltype> -// ::= <substitution> -Node *Db::parseUnresolvedType() { - if (look() == 'T') { - Node *TP = parseTemplateParam(); - if (TP == nullptr) - return nullptr; - Subs.push_back(TP); - return TP; - } - if (look() == 'D') { - Node *DT = parseDecltype(); - if (DT == nullptr) - return nullptr; - Subs.push_back(DT); - return DT; - } - return parseSubstitution(); -} - -// <base-unresolved-name> ::= <simple-id> # unresolved name -// extension ::= <operator-name> # unresolved operator-function-id -// extension ::= <operator-name> <template-args> # unresolved operator template-id -// ::= on <operator-name> # unresolved operator-function-id -// ::= on <operator-name> <template-args> # unresolved operator template-id -// ::= dn <destructor-name> # destructor or pseudo-destructor; -// # e.g. ~X or ~X<N-1> -Node *Db::parseBaseUnresolvedName() { - if (std::isdigit(look())) - return parseSimpleId(); - - if (consumeIf("dn")) - return parseDestructorName(); - - consumeIf("on"); - - Node *Oper = parseOperatorName(/*NameState=*/nullptr); - if (Oper == nullptr) - return nullptr; - if (look() == 'I') { - Node *TA = parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - return make<NameWithTemplateArgs>(Oper, TA); - } - return Oper; -} - -// <unresolved-name> -// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> -// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x -// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> -// # A::x, N::y, A<T>::z; "gs" means leading "::" -// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x -// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> -// # T::N::x /decltype(p)::N::x -// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> -// -// <unresolved-qualifier-level> ::= <simple-id> -Node *Db::parseUnresolvedName() { - Node *SoFar = nullptr; - - // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> - // srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> - if (consumeIf("srN")) { - SoFar = parseUnresolvedType(); - if (SoFar == nullptr) - return nullptr; - - if (look() == 'I') { - Node *TA = parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - } - - while (!consumeIf('E')) { - Node *Qual = parseSimpleId(); - if (Qual == nullptr) - return nullptr; - SoFar = make<QualifiedName>(SoFar, Qual); - } - - Node *Base = parseBaseUnresolvedName(); - if (Base == nullptr) - return nullptr; - return make<QualifiedName>(SoFar, Base); - } - - bool Global = consumeIf("gs"); - - // [gs] <base-unresolved-name> # x or (with "gs") ::x - if (!consumeIf("sr")) { - SoFar = parseBaseUnresolvedName(); - if (SoFar == nullptr) - return nullptr; - if (Global) - SoFar = make<GlobalQualifiedName>(SoFar); - return SoFar; - } - - // [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> - if (std::isdigit(look())) { - do { - Node *Qual = parseSimpleId(); - if (Qual == nullptr) - return nullptr; - if (SoFar) - SoFar = make<QualifiedName>(SoFar, Qual); - else if (Global) - SoFar = make<GlobalQualifiedName>(Qual); - else - SoFar = Qual; - } while (!consumeIf('E')); - } - // sr <unresolved-type> <base-unresolved-name> - // sr <unresolved-type> <template-args> <base-unresolved-name> - else { - SoFar = parseUnresolvedType(); - if (SoFar == nullptr) - return nullptr; - - if (look() == 'I') { - Node *TA = parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - } - } - - assert(SoFar != nullptr); - - Node *Base = parseBaseUnresolvedName(); - if (Base == nullptr) - return nullptr; - return make<QualifiedName>(SoFar, Base); -} - -// <abi-tags> ::= <abi-tag> [<abi-tags>] -// <abi-tag> ::= B <source-name> -Node *Db::parseAbiTags(Node *N) { - while (consumeIf('B')) { - StringView SN = parseBareSourceName(); - if (SN.empty()) - return nullptr; - N = make<AbiTagAttr>(N, SN); - } - return N; -} - -// <number> ::= [n] <non-negative decimal integer> -StringView Db::parseNumber(bool AllowNegative) { - const char *Tmp = First; - if (AllowNegative) - consumeIf('n'); - if (numLeft() == 0 || !std::isdigit(*First)) - return StringView(); - while (numLeft() != 0 && std::isdigit(*First)) - ++First; - return StringView(Tmp, First); -} - -// <positive length number> ::= [0-9]* -bool Db::parsePositiveInteger(size_t *Out) { - *Out = 0; - if (look() < '0' || look() > '9') - return true; - while (look() >= '0' && look() <= '9') { - *Out *= 10; - *Out += static_cast<size_t>(consume() - '0'); - } - return false; -} - -StringView Db::parseBareSourceName() { - size_t Int = 0; - if (parsePositiveInteger(&Int) || numLeft() < Int) - return StringView(); - StringView R(First, First + Int); - First += Int; - return R; -} - -// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E -// -// <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw()) -// ::= DO <expression> E # computed (instantiation-dependent) noexcept -// ::= Dw <type>+ E # dynamic exception specification with instantiation-dependent types -// -// <ref-qualifier> ::= R # & ref-qualifier -// <ref-qualifier> ::= O # && ref-qualifier -Node *Db::parseFunctionType() { - Qualifiers CVQuals = parseCVQualifiers(); - - Node *ExceptionSpec = nullptr; - if (consumeIf("Do")) { - ExceptionSpec = make<NameType>("noexcept"); - } else if (consumeIf("DO")) { - Node *E = parseExpr(); - if (E == nullptr || !consumeIf('E')) - return nullptr; - ExceptionSpec = make<NoexceptSpec>(E); - } else if (consumeIf("Dw")) { - size_t SpecsBegin = Names.size(); - while (!consumeIf('E')) { - Node *T = parseType(); - if (T == nullptr) - return nullptr; - Names.push_back(T); - } - ExceptionSpec = - make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin)); - } - - consumeIf("Dx"); // transaction safe - - if (!consumeIf('F')) - return nullptr; - consumeIf('Y'); // extern "C" - Node *ReturnType = parseType(); - if (ReturnType == nullptr) - return nullptr; - - FunctionRefQual ReferenceQualifier = FrefQualNone; - size_t ParamsBegin = Names.size(); - while (true) { - if (consumeIf('E')) - break; - if (consumeIf('v')) - continue; - if (consumeIf("RE")) { - ReferenceQualifier = FrefQualLValue; - break; - } - if (consumeIf("OE")) { - ReferenceQualifier = FrefQualRValue; - break; - } - Node *T = parseType(); - if (T == nullptr) - return nullptr; - Names.push_back(T); - } - - NodeArray Params = popTrailingNodeArray(ParamsBegin); - return make<FunctionType>(ReturnType, Params, CVQuals, - ReferenceQualifier, ExceptionSpec); -} - -// extension: -// <vector-type> ::= Dv <positive dimension number> _ <extended element type> -// ::= Dv [<dimension expression>] _ <element type> -// <extended element type> ::= <element type> -// ::= p # AltiVec vector pixel -Node *Db::parseVectorType() { - if (!consumeIf("Dv")) - return nullptr; - if (look() >= '1' && look() <= '9') { - StringView DimensionNumber = parseNumber(); - if (!consumeIf('_')) - return nullptr; - if (consumeIf('p')) - return make<VectorType>(DimensionNumber); - Node *ElemType = parseType(); - if (ElemType == nullptr) - return nullptr; - return make<VectorType>(ElemType, DimensionNumber); - } - - if (!consumeIf('_')) { - Node *DimExpr = parseExpr(); - if (!DimExpr) - return nullptr; - if (!consumeIf('_')) - return nullptr; - Node *ElemType = parseType(); - if (!ElemType) - return nullptr; - return make<VectorType>(ElemType, DimExpr); - } - Node *ElemType = parseType(); - if (!ElemType) - return nullptr; - return make<VectorType>(ElemType, StringView()); -} - -// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) -// ::= DT <expression> E # decltype of an expression (C++0x) -Node *Db::parseDecltype() { - if (!consumeIf('D')) - return nullptr; - if (!consumeIf('t') && !consumeIf('T')) - return nullptr; - Node *E = parseExpr(); - if (E == nullptr) - return nullptr; - if (!consumeIf('E')) - return nullptr; - return make<EnclosingExpr>("decltype(", E, ")"); -} - -// <array-type> ::= A <positive dimension number> _ <element type> -// ::= A [<dimension expression>] _ <element type> -Node *Db::parseArrayType() { - if (!consumeIf('A')) - return nullptr; - - if (std::isdigit(look())) { - StringView Dimension = parseNumber(); - if (!consumeIf('_')) - return nullptr; - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - return make<ArrayType>(Ty, Dimension); - } - - if (!consumeIf('_')) { - Node *DimExpr = parseExpr(); - if (DimExpr == nullptr) - return nullptr; - if (!consumeIf('_')) - return nullptr; - Node *ElementType = parseType(); - if (ElementType == nullptr) - return nullptr; - return make<ArrayType>(ElementType, DimExpr); - } - - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - return make<ArrayType>(Ty); -} - -// <pointer-to-member-type> ::= M <class type> <member type> -Node *Db::parsePointerToMemberType() { - if (!consumeIf('M')) - return nullptr; - Node *ClassType = parseType(); - if (ClassType == nullptr) - return nullptr; - Node *MemberType = parseType(); - if (MemberType == nullptr) - return nullptr; - return make<PointerToMemberType>(ClassType, MemberType); -} - -// <class-enum-type> ::= <name> # non-dependent type name, dependent type name, or dependent typename-specifier -// ::= Ts <name> # dependent elaborated type specifier using 'struct' or 'class' -// ::= Tu <name> # dependent elaborated type specifier using 'union' -// ::= Te <name> # dependent elaborated type specifier using 'enum' -Node *Db::parseClassEnumType() { - StringView ElabSpef; - if (consumeIf("Ts")) - ElabSpef = "struct"; - else if (consumeIf("Tu")) - ElabSpef = "union"; - else if (consumeIf("Te")) - ElabSpef = "enum"; - - Node *Name = parseName(); - if (Name == nullptr) - return nullptr; - - if (!ElabSpef.empty()) - return make<ElaboratedTypeSpefType>(ElabSpef, Name); - - return Name; -} - -// <qualified-type> ::= <qualifiers> <type> -// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers> -// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier -Node *Db::parseQualifiedType() { - if (consumeIf('U')) { - StringView Qual = parseBareSourceName(); - if (Qual.empty()) - return nullptr; - - // FIXME parse the optional <template-args> here! - - // extension ::= U <objc-name> <objc-type> # objc-type<identifier> - if (Qual.startsWith("objcproto")) { - StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); - StringView Proto; - { - SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); - Proto = parseBareSourceName(); - } - if (Proto.empty()) - return nullptr; - Node *Child = parseQualifiedType(); - if (Child == nullptr) - return nullptr; - return make<ObjCProtoName>(Child, Proto); - } - - Node *Child = parseQualifiedType(); - if (Child == nullptr) - return nullptr; - return make<VendorExtQualType>(Child, Qual); - } - - Qualifiers Quals = parseCVQualifiers(); - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - if (Quals != QualNone) - Ty = make<QualType>(Ty, Quals); - return Ty; -} - -// <type> ::= <builtin-type> -// ::= <qualified-type> -// ::= <function-type> -// ::= <class-enum-type> -// ::= <array-type> -// ::= <pointer-to-member-type> -// ::= <template-param> -// ::= <template-template-param> <template-args> -// ::= <decltype> -// ::= P <type> # pointer -// ::= R <type> # l-value reference -// ::= O <type> # r-value reference (C++11) -// ::= C <type> # complex pair (C99) -// ::= G <type> # imaginary (C99) -// ::= <substitution> # See Compression below -// extension ::= U <objc-name> <objc-type> # objc-type<identifier> -// extension ::= <vector-type> # <vector-type> starts with Dv -// -// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1 -// <objc-type> ::= <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name> -Node *Db::parseType() { - Node *Result = nullptr; - - switch (look()) { - // ::= <qualified-type> - case 'r': - case 'V': - case 'K': { - unsigned AfterQuals = 0; - if (look(AfterQuals) == 'r') ++AfterQuals; - if (look(AfterQuals) == 'V') ++AfterQuals; - if (look(AfterQuals) == 'K') ++AfterQuals; - - if (look(AfterQuals) == 'F' || - (look(AfterQuals) == 'D' && - (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' || - look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) { - Result = parseFunctionType(); - break; - } - LLVM_FALLTHROUGH; - } - case 'U': { - Result = parseQualifiedType(); - break; - } - // <builtin-type> ::= v # void - case 'v': - ++First; - return make<NameType>("void"); - // ::= w # wchar_t - case 'w': - ++First; - return make<NameType>("wchar_t"); - // ::= b # bool - case 'b': - ++First; - return make<NameType>("bool"); - // ::= c # char - case 'c': - ++First; - return make<NameType>("char"); - // ::= a # signed char - case 'a': - ++First; - return make<NameType>("signed char"); - // ::= h # unsigned char - case 'h': - ++First; - return make<NameType>("unsigned char"); - // ::= s # short - case 's': - ++First; - return make<NameType>("short"); - // ::= t # unsigned short - case 't': - ++First; - return make<NameType>("unsigned short"); - // ::= i # int - case 'i': - ++First; - return make<NameType>("int"); - // ::= j # unsigned int - case 'j': - ++First; - return make<NameType>("unsigned int"); - // ::= l # long - case 'l': - ++First; - return make<NameType>("long"); - // ::= m # unsigned long - case 'm': - ++First; - return make<NameType>("unsigned long"); - // ::= x # long long, __int64 - case 'x': - ++First; - return make<NameType>("long long"); - // ::= y # unsigned long long, __int64 - case 'y': - ++First; - return make<NameType>("unsigned long long"); - // ::= n # __int128 - case 'n': - ++First; - return make<NameType>("__int128"); - // ::= o # unsigned __int128 - case 'o': - ++First; - return make<NameType>("unsigned __int128"); - // ::= f # float - case 'f': - ++First; - return make<NameType>("float"); - // ::= d # double - case 'd': - ++First; - return make<NameType>("double"); - // ::= e # long double, __float80 - case 'e': - ++First; - return make<NameType>("long double"); - // ::= g # __float128 - case 'g': - ++First; - return make<NameType>("__float128"); - // ::= z # ellipsis - case 'z': - ++First; - return make<NameType>("..."); - - // <builtin-type> ::= u <source-name> # vendor extended type - case 'u': { - ++First; - StringView Res = parseBareSourceName(); - if (Res.empty()) - return nullptr; - return make<NameType>(Res); - } - case 'D': - switch (look(1)) { - // ::= Dd # IEEE 754r decimal floating point (64 bits) - case 'd': - First += 2; - return make<NameType>("decimal64"); - // ::= De # IEEE 754r decimal floating point (128 bits) - case 'e': - First += 2; - return make<NameType>("decimal128"); - // ::= Df # IEEE 754r decimal floating point (32 bits) - case 'f': - First += 2; - return make<NameType>("decimal32"); - // ::= Dh # IEEE 754r half-precision floating point (16 bits) - case 'h': - First += 2; - return make<NameType>("decimal16"); - // ::= Di # char32_t - case 'i': - First += 2; - return make<NameType>("char32_t"); - // ::= Ds # char16_t - case 's': - First += 2; - return make<NameType>("char16_t"); - // ::= Da # auto (in dependent new-expressions) - case 'a': - First += 2; - return make<NameType>("auto"); - // ::= Dc # decltype(auto) - case 'c': - First += 2; - return make<NameType>("decltype(auto)"); - // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) - case 'n': - First += 2; - return make<NameType>("std::nullptr_t"); - - // ::= <decltype> - case 't': - case 'T': { - Result = parseDecltype(); - break; - } - // extension ::= <vector-type> # <vector-type> starts with Dv - case 'v': { - Result = parseVectorType(); - break; - } - // ::= Dp <type> # pack expansion (C++0x) - case 'p': { - First += 2; - Node *Child = parseType(); - if (!Child) - return nullptr; - Result = make<ParameterPackExpansion>(Child); - break; - } - // Exception specifier on a function type. - case 'o': - case 'O': - case 'w': - // Transaction safe function type. - case 'x': - Result = parseFunctionType(); - break; - } - break; - // ::= <function-type> - case 'F': { - Result = parseFunctionType(); - break; - } - // ::= <array-type> - case 'A': { - Result = parseArrayType(); - break; - } - // ::= <pointer-to-member-type> - case 'M': { - Result = parsePointerToMemberType(); - break; - } - // ::= <template-param> - case 'T': { - // This could be an elaborate type specifier on a <class-enum-type>. - if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') { - Result = parseClassEnumType(); - break; - } - - Result = parseTemplateParam(); - if (Result == nullptr) - return nullptr; - - // Result could be either of: - // <type> ::= <template-param> - // <type> ::= <template-template-param> <template-args> - // - // <template-template-param> ::= <template-param> - // ::= <substitution> - // - // If this is followed by some <template-args>, and we're permitted to - // parse them, take the second production. - - if (TryToParseTemplateArgs && look() == 'I') { - Node *TA = parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - Result = make<NameWithTemplateArgs>(Result, TA); - } - break; - } - // ::= P <type> # pointer - case 'P': { - ++First; - Node *Ptr = parseType(); - if (Ptr == nullptr) - return nullptr; - Result = make<PointerType>(Ptr); - break; - } - // ::= R <type> # l-value reference - case 'R': { - ++First; - Node *Ref = parseType(); - if (Ref == nullptr) - return nullptr; - Result = make<ReferenceType>(Ref, ReferenceKind::LValue); - break; - } - // ::= O <type> # r-value reference (C++11) - case 'O': { - ++First; - Node *Ref = parseType(); - if (Ref == nullptr) - return nullptr; - Result = make<ReferenceType>(Ref, ReferenceKind::RValue); - break; - } - // ::= C <type> # complex pair (C99) - case 'C': { - ++First; - Node *P = parseType(); - if (P == nullptr) - return nullptr; - Result = make<PostfixQualifiedType>(P, " complex"); - break; - } - // ::= G <type> # imaginary (C99) - case 'G': { - ++First; - Node *P = parseType(); - if (P == nullptr) - return P; - Result = make<PostfixQualifiedType>(P, " imaginary"); - break; - } - // ::= <substitution> # See Compression below - case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = parseSubstitution(); - if (Sub == nullptr) - return nullptr; - - // Sub could be either of: - // <type> ::= <substitution> - // <type> ::= <template-template-param> <template-args> - // - // <template-template-param> ::= <template-param> - // ::= <substitution> - // - // If this is followed by some <template-args>, and we're permitted to - // parse them, take the second production. - - if (TryToParseTemplateArgs && look() == 'I') { - Node *TA = parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - Result = make<NameWithTemplateArgs>(Sub, TA); - break; - } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; - } - LLVM_FALLTHROUGH; - } - // ::= <class-enum-type> - default: { - Result = parseClassEnumType(); - break; - } - } - - // If we parsed a type, insert it into the substitution table. Note that all - // <builtin-type>s and <substitution>s have already bailed out, because they - // don't get substitutions. - if (Result != nullptr) - Subs.push_back(Result); - return Result; -} - -Node *Db::parsePrefixExpr(StringView Kind) { - Node *E = parseExpr(); - if (E == nullptr) - return nullptr; - return make<PrefixExpr>(Kind, E); -} - -Node *Db::parseBinaryExpr(StringView Kind) { - Node *LHS = parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<BinaryExpr>(LHS, Kind, RHS); -} - -Node *Db::parseIntegerLiteral(StringView Lit) { - StringView Tmp = parseNumber(true); - if (!Tmp.empty() && consumeIf('E')) - return make<IntegerExpr>(Lit, Tmp); - return nullptr; -} - -// <CV-Qualifiers> ::= [r] [V] [K] -Qualifiers Db::parseCVQualifiers() { - Qualifiers CVR = QualNone; - if (consumeIf('r')) - addQualifiers(CVR, QualRestrict); - if (consumeIf('V')) - addQualifiers(CVR, QualVolatile); - if (consumeIf('K')) - addQualifiers(CVR, QualConst); - return CVR; -} - -// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter -// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters -// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter -// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters -Node *Db::parseFunctionParam() { - if (consumeIf("fp")) { - parseCVQualifiers(); - StringView Num = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<FunctionParam>(Num); - } - if (consumeIf("fL")) { - if (parseNumber().empty()) - return nullptr; - if (!consumeIf('p')) - return nullptr; - parseCVQualifiers(); - StringView Num = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<FunctionParam>(Num); - } - return nullptr; -} - -// [gs] nw <expression>* _ <type> E # new (expr-list) type -// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// [gs] na <expression>* _ <type> E # new[] (expr-list) type -// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// <initializer> ::= pi <expression>* E # parenthesized initialization -Node *Db::parseNewExpr() { - bool Global = consumeIf("gs"); - bool IsArray = look(1) == 'a'; - if (!consumeIf("nw") && !consumeIf("na")) - return nullptr; - size_t Exprs = Names.size(); - while (!consumeIf('_')) { - Node *Ex = parseExpr(); - if (Ex == nullptr) - return nullptr; - Names.push_back(Ex); - } - NodeArray ExprList = popTrailingNodeArray(Exprs); - Node *Ty = parseType(); - if (Ty == nullptr) - return Ty; - if (consumeIf("pi")) { - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Init = parseExpr(); - if (Init == nullptr) - return Init; - Names.push_back(Init); - } - NodeArray Inits = popTrailingNodeArray(InitsBegin); - return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray); - } else if (!consumeIf('E')) - return nullptr; - return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray); -} - -// cv <type> <expression> # conversion with one argument -// cv <type> _ <expression>* E # conversion with a different number of arguments -Node *Db::parseConversionExpr() { - if (!consumeIf("cv")) - return nullptr; - Node *Ty; - { - SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false); - Ty = parseType(); - } - - if (Ty == nullptr) - return nullptr; - - if (consumeIf('_')) { - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - } - NodeArray Exprs = popTrailingNodeArray(ExprsBegin); - return make<ConversionExpr>(Ty, Exprs); - } - - Node *E[1] = {parseExpr()}; - if (E[0] == nullptr) - return nullptr; - return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1)); -} - -// <expr-primary> ::= L <type> <value number> E # integer literal -// ::= L <type> <value float> E # floating literal -// ::= L <string type> E # string literal -// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") -// FIXME: ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) -// ::= L <mangled-name> E # external name -Node *Db::parseExprPrimary() { - if (!consumeIf('L')) - return nullptr; - switch (look()) { - case 'w': - ++First; - return parseIntegerLiteral("wchar_t"); - case 'b': - if (consumeIf("b0E")) - return make<BoolExpr>(0); - if (consumeIf("b1E")) - return make<BoolExpr>(1); - return nullptr; - case 'c': - ++First; - return parseIntegerLiteral("char"); - case 'a': - ++First; - return parseIntegerLiteral("signed char"); - case 'h': - ++First; - return parseIntegerLiteral("unsigned char"); - case 's': - ++First; - return parseIntegerLiteral("short"); - case 't': - ++First; - return parseIntegerLiteral("unsigned short"); - case 'i': - ++First; - return parseIntegerLiteral(""); - case 'j': - ++First; - return parseIntegerLiteral("u"); - case 'l': - ++First; - return parseIntegerLiteral("l"); - case 'm': - ++First; - return parseIntegerLiteral("ul"); - case 'x': - ++First; - return parseIntegerLiteral("ll"); - case 'y': - ++First; - return parseIntegerLiteral("ull"); - case 'n': - ++First; - return parseIntegerLiteral("__int128"); - case 'o': - ++First; - return parseIntegerLiteral("unsigned __int128"); - case 'f': - ++First; - return parseFloatingLiteral<float>(); - case 'd': - ++First; - return parseFloatingLiteral<double>(); - case 'e': - ++First; - return parseFloatingLiteral<long double>(); - case '_': - if (consumeIf("_Z")) { - Node *R = parseEncoding(); - if (R != nullptr && consumeIf('E')) - return R; - } - return nullptr; - case 'T': - // Invalid mangled name per - // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html - return nullptr; - default: { - // might be named type - Node *T = parseType(); - if (T == nullptr) - return nullptr; - StringView N = parseNumber(); - if (!N.empty()) { - if (!consumeIf('E')) - return nullptr; - return make<IntegerCastExpr>(T, N); - } - if (consumeIf('E')) - return T; - return nullptr; - } - } -} - -// <braced-expression> ::= <expression> -// ::= di <field source-name> <braced-expression> # .name = expr -// ::= dx <index expression> <braced-expression> # [expr] = expr -// ::= dX <range begin expression> <range end expression> <braced-expression> -Node *Db::parseBracedExpr() { - if (look() == 'd') { - switch (look(1)) { - case 'i': { - First += 2; - Node *Field = parseSourceName(/*NameState=*/nullptr); - if (Field == nullptr) - return nullptr; - Node *Init = parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedExpr>(Field, Init, /*isArray=*/false); - } - case 'x': { - First += 2; - Node *Index = parseExpr(); - if (Index == nullptr) - return nullptr; - Node *Init = parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedExpr>(Index, Init, /*isArray=*/true); - } - case 'X': { - First += 2; - Node *RangeBegin = parseExpr(); - if (RangeBegin == nullptr) - return nullptr; - Node *RangeEnd = parseExpr(); - if (RangeEnd == nullptr) - return nullptr; - Node *Init = parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init); - } - } - } - return parseExpr(); -} - -// (not yet in the spec) -// <fold-expr> ::= fL <binary-operator-name> <expression> <expression> -// ::= fR <binary-operator-name> <expression> <expression> -// ::= fl <binary-operator-name> <expression> -// ::= fr <binary-operator-name> <expression> -Node *Db::parseFoldExpr() { - if (!consumeIf('f')) - return nullptr; - - char FoldKind = look(); - bool IsLeftFold, HasInitializer; - HasInitializer = FoldKind == 'L' || FoldKind == 'R'; - if (FoldKind == 'l' || FoldKind == 'L') - IsLeftFold = true; - else if (FoldKind == 'r' || FoldKind == 'R') - IsLeftFold = false; - else - return nullptr; - ++First; - - // FIXME: This map is duplicated in parseOperatorName and parseExpr. - StringView OperatorName; - if (consumeIf("aa")) OperatorName = "&&"; - else if (consumeIf("an")) OperatorName = "&"; - else if (consumeIf("aN")) OperatorName = "&="; - else if (consumeIf("aS")) OperatorName = "="; - else if (consumeIf("cm")) OperatorName = ","; - else if (consumeIf("ds")) OperatorName = ".*"; - else if (consumeIf("dv")) OperatorName = "/"; - else if (consumeIf("dV")) OperatorName = "/="; - else if (consumeIf("eo")) OperatorName = "^"; - else if (consumeIf("eO")) OperatorName = "^="; - else if (consumeIf("eq")) OperatorName = "=="; - else if (consumeIf("ge")) OperatorName = ">="; - else if (consumeIf("gt")) OperatorName = ">"; - else if (consumeIf("le")) OperatorName = "<="; - else if (consumeIf("ls")) OperatorName = "<<"; - else if (consumeIf("lS")) OperatorName = "<<="; - else if (consumeIf("lt")) OperatorName = "<"; - else if (consumeIf("mi")) OperatorName = "-"; - else if (consumeIf("mI")) OperatorName = "-="; - else if (consumeIf("ml")) OperatorName = "*"; - else if (consumeIf("mL")) OperatorName = "*="; - else if (consumeIf("ne")) OperatorName = "!="; - else if (consumeIf("oo")) OperatorName = "||"; - else if (consumeIf("or")) OperatorName = "|"; - else if (consumeIf("oR")) OperatorName = "|="; - else if (consumeIf("pl")) OperatorName = "+"; - else if (consumeIf("pL")) OperatorName = "+="; - else if (consumeIf("rm")) OperatorName = "%"; - else if (consumeIf("rM")) OperatorName = "%="; - else if (consumeIf("rs")) OperatorName = ">>"; - else if (consumeIf("rS")) OperatorName = ">>="; - else return nullptr; - - Node *Pack = parseExpr(), *Init = nullptr; - if (Pack == nullptr) - return nullptr; - if (HasInitializer) { - Init = parseExpr(); - if (Init == nullptr) - return nullptr; - } - - if (IsLeftFold && Init) - std::swap(Pack, Init); - - return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init); -} - -// <expression> ::= <unary operator-name> <expression> -// ::= <binary operator-name> <expression> <expression> -// ::= <ternary operator-name> <expression> <expression> <expression> -// ::= cl <expression>+ E # call -// ::= cv <type> <expression> # conversion with one argument -// ::= cv <type> _ <expression>* E # conversion with a different number of arguments -// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type -// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type -// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// ::= [gs] dl <expression> # delete expression -// ::= [gs] da <expression> # delete[] expression -// ::= pp_ <expression> # prefix ++ -// ::= mm_ <expression> # prefix -- -// ::= ti <type> # typeid (type) -// ::= te <expression> # typeid (expression) -// ::= dc <type> <expression> # dynamic_cast<type> (expression) -// ::= sc <type> <expression> # static_cast<type> (expression) -// ::= cc <type> <expression> # const_cast<type> (expression) -// ::= rc <type> <expression> # reinterpret_cast<type> (expression) -// ::= st <type> # sizeof (a type) -// ::= sz <expression> # sizeof (an expression) -// ::= at <type> # alignof (a type) -// ::= az <expression> # alignof (an expression) -// ::= nx <expression> # noexcept (expression) -// ::= <template-param> -// ::= <function-param> -// ::= dt <expression> <unresolved-name> # expr.name -// ::= pt <expression> <unresolved-name> # expr->name -// ::= ds <expression> <expression> # expr.*expr -// ::= sZ <template-param> # size of a parameter pack -// ::= sZ <function-param> # size of a function parameter pack -// ::= sP <template-arg>* E # sizeof...(T), size of a captured template parameter pack from an alias template -// ::= sp <expression> # pack expansion -// ::= tw <expression> # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= <unresolved-name> # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= fL <binary-operator-name> <expression> <expression> -// ::= fR <binary-operator-name> <expression> <expression> -// ::= fl <binary-operator-name> <expression> -// ::= fr <binary-operator-name> <expression> -// ::= <expr-primary> -Node *Db::parseExpr() { - bool Global = consumeIf("gs"); - if (numLeft() < 2) - return nullptr; - - switch (*First) { - case 'L': - return parseExprPrimary(); - case 'T': - return parseTemplateParam(); - case 'f': { - // Disambiguate a fold expression from a <function-param>. - if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) - return parseFunctionParam(); - return parseFoldExpr(); - } - case 'a': - switch (First[1]) { - case 'a': - First += 2; - return parseBinaryExpr("&&"); - case 'd': - First += 2; - return parsePrefixExpr("&"); - case 'n': - First += 2; - return parseBinaryExpr("&"); - case 'N': - First += 2; - return parseBinaryExpr("&="); - case 'S': - First += 2; - return parseBinaryExpr("="); - case 't': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - return make<EnclosingExpr>("alignof (", Ty, ")"); - } - case 'z': { - First += 2; - Node *Ty = parseExpr(); - if (Ty == nullptr) - return nullptr; - return make<EnclosingExpr>("alignof (", Ty, ")"); - } - } - return nullptr; - case 'c': - switch (First[1]) { - // cc <type> <expression> # const_cast<type>(expression) - case 'c': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return Ty; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("const_cast", Ty, Ex); - } - // cl <expression>+ E # call - case 'l': { - First += 2; - Node *Callee = parseExpr(); - if (Callee == nullptr) - return Callee; - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - } - return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin)); - } - case 'm': - First += 2; - return parseBinaryExpr(","); - case 'o': - First += 2; - return parsePrefixExpr("~"); - case 'v': - return parseConversionExpr(); - } - return nullptr; - case 'd': - switch (First[1]) { - case 'a': { - First += 2; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<DeleteExpr>(Ex, Global, /*is_array=*/true); - } - case 'c': { - First += 2; - Node *T = parseType(); - if (T == nullptr) - return T; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("dynamic_cast", T, Ex); - } - case 'e': - First += 2; - return parsePrefixExpr("*"); - case 'l': { - First += 2; - Node *E = parseExpr(); - if (E == nullptr) - return E; - return make<DeleteExpr>(E, Global, /*is_array=*/false); - } - case 'n': - return parseUnresolvedName(); - case 's': { - First += 2; - Node *LHS = parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<MemberExpr>(LHS, ".*", RHS); - } - case 't': { - First += 2; - Node *LHS = parseExpr(); - if (LHS == nullptr) - return LHS; - Node *RHS = parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<MemberExpr>(LHS, ".", RHS); - } - case 'v': - First += 2; - return parseBinaryExpr("/"); - case 'V': - First += 2; - return parseBinaryExpr("/="); - } - return nullptr; - case 'e': - switch (First[1]) { - case 'o': - First += 2; - return parseBinaryExpr("^"); - case 'O': - First += 2; - return parseBinaryExpr("^="); - case 'q': - First += 2; - return parseBinaryExpr("=="); - } - return nullptr; - case 'g': - switch (First[1]) { - case 'e': - First += 2; - return parseBinaryExpr(">="); - case 't': - First += 2; - return parseBinaryExpr(">"); - } - return nullptr; - case 'i': - switch (First[1]) { - case 'x': { - First += 2; - Node *Base = parseExpr(); - if (Base == nullptr) - return nullptr; - Node *Index = parseExpr(); - if (Index == nullptr) - return Index; - return make<ArraySubscriptExpr>(Base, Index); - } - case 'l': { - First += 2; - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin)); - } - } - return nullptr; - case 'l': - switch (First[1]) { - case 'e': - First += 2; - return parseBinaryExpr("<="); - case 's': - First += 2; - return parseBinaryExpr("<<"); - case 'S': - First += 2; - return parseBinaryExpr("<<="); - case 't': - First += 2; - return parseBinaryExpr("<"); - } - return nullptr; - case 'm': - switch (First[1]) { - case 'i': - First += 2; - return parseBinaryExpr("-"); - case 'I': - First += 2; - return parseBinaryExpr("-="); - case 'l': - First += 2; - return parseBinaryExpr("*"); - case 'L': - First += 2; - return parseBinaryExpr("*="); - case 'm': - First += 2; - if (consumeIf('_')) - return parsePrefixExpr("--"); - Node *Ex = parseExpr(); - if (Ex == nullptr) - return nullptr; - return make<PostfixExpr>(Ex, "--"); - } - return nullptr; - case 'n': - switch (First[1]) { - case 'a': - case 'w': - return parseNewExpr(); - case 'e': - First += 2; - return parseBinaryExpr("!="); - case 'g': - First += 2; - return parsePrefixExpr("-"); - case 't': - First += 2; - return parsePrefixExpr("!"); - case 'x': - First += 2; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("noexcept (", Ex, ")"); - } - return nullptr; - case 'o': - switch (First[1]) { - case 'n': - return parseUnresolvedName(); - case 'o': - First += 2; - return parseBinaryExpr("||"); - case 'r': - First += 2; - return parseBinaryExpr("|"); - case 'R': - First += 2; - return parseBinaryExpr("|="); - } - return nullptr; - case 'p': - switch (First[1]) { - case 'm': - First += 2; - return parseBinaryExpr("->*"); - case 'l': - First += 2; - return parseBinaryExpr("+"); - case 'L': - First += 2; - return parseBinaryExpr("+="); - case 'p': { - First += 2; - if (consumeIf('_')) - return parsePrefixExpr("++"); - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<PostfixExpr>(Ex, "++"); - } - case 's': - First += 2; - return parsePrefixExpr("+"); - case 't': { - First += 2; - Node *L = parseExpr(); - if (L == nullptr) - return nullptr; - Node *R = parseExpr(); - if (R == nullptr) - return nullptr; - return make<MemberExpr>(L, "->", R); - } - } - return nullptr; - case 'q': - if (First[1] == 'u') { - First += 2; - Node *Cond = parseExpr(); - if (Cond == nullptr) - return nullptr; - Node *LHS = parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<ConditionalExpr>(Cond, LHS, RHS); - } - return nullptr; - case 'r': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = parseType(); - if (T == nullptr) - return T; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("reinterpret_cast", T, Ex); - } - case 'm': - First += 2; - return parseBinaryExpr("%"); - case 'M': - First += 2; - return parseBinaryExpr("%="); - case 's': - First += 2; - return parseBinaryExpr(">>"); - case 'S': - First += 2; - return parseBinaryExpr(">>="); - } - return nullptr; - case 's': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = parseType(); - if (T == nullptr) - return T; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("static_cast", T, Ex); - } - case 'p': { - First += 2; - Node *Child = parseExpr(); - if (Child == nullptr) - return nullptr; - return make<ParameterPackExpansion>(Child); - } - case 'r': - return parseUnresolvedName(); - case 't': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return Ty; - return make<EnclosingExpr>("sizeof (", Ty, ")"); - } - case 'z': { - First += 2; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("sizeof (", Ex, ")"); - } - case 'Z': - First += 2; - if (look() == 'T') { - Node *R = parseTemplateParam(); - if (R == nullptr) - return nullptr; - return make<SizeofParamPackExpr>(R); - } else if (look() == 'f') { - Node *FP = parseFunctionParam(); - if (FP == nullptr) - return nullptr; - return make<EnclosingExpr>("sizeof... (", FP, ")"); - } - return nullptr; - case 'P': { - First += 2; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - return make<EnclosingExpr>( - "sizeof... (", make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)), - ")"); - } - } - return nullptr; - case 't': - switch (First[1]) { - case 'e': { - First += 2; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("typeid (", Ex, ")"); - } - case 'i': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return Ty; - return make<EnclosingExpr>("typeid (", Ty, ")"); - } - case 'l': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin)); - } - case 'r': - First += 2; - return make<NameType>("throw"); - case 'w': { - First += 2; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return nullptr; - return make<ThrowExpr>(Ex); - } - } - return nullptr; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return parseUnresolvedName(); - } - return nullptr; -} - -// <call-offset> ::= h <nv-offset> _ -// ::= v <v-offset> _ -// -// <nv-offset> ::= <offset number> -// # non-virtual base override -// -// <v-offset> ::= <offset number> _ <virtual offset number> -// # virtual base override, with vcall offset -bool Db::parseCallOffset() { - // Just scan through the call offset, we never add this information into the - // output. - if (consumeIf('h')) - return parseNumber(true).empty() || !consumeIf('_'); - if (consumeIf('v')) - return parseNumber(true).empty() || !consumeIf('_') || - parseNumber(true).empty() || !consumeIf('_'); - return true; -} - -// <special-name> ::= TV <type> # virtual table -// ::= TT <type> # VTT structure (construction vtable index) -// ::= TI <type> # typeinfo structure -// ::= TS <type> # typeinfo name (null-terminated byte string) -// ::= Tc <call-offset> <call-offset> <base encoding> -// # base is the nominal target function of thunk -// # first call-offset is 'this' adjustment -// # second call-offset is result adjustment -// ::= T <call-offset> <base encoding> -// # base is the nominal target function of thunk -// ::= GV <object name> # Guard variable for one-time initialization -// # No <type> -// ::= TW <object name> # Thread-local wrapper -// ::= TH <object name> # Thread-local initialization -// ::= GR <object name> _ # First temporary -// ::= GR <object name> <seq-id> _ # Subsequent temporaries -// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first -// extension ::= GR <object name> # reference temporary for object -Node *Db::parseSpecialName() { - switch (look()) { - case 'T': - switch (look(1)) { - // TV <type> # virtual table - case 'V': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("vtable for ", Ty); - } - // TT <type> # VTT structure (construction vtable index) - case 'T': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("VTT for ", Ty); - } - // TI <type> # typeinfo structure - case 'I': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("typeinfo for ", Ty); - } - // TS <type> # typeinfo name (null-terminated byte string) - case 'S': { - First += 2; - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("typeinfo name for ", Ty); - } - // Tc <call-offset> <call-offset> <base encoding> - case 'c': { - First += 2; - if (parseCallOffset() || parseCallOffset()) - return nullptr; - Node *Encoding = parseEncoding(); - if (Encoding == nullptr) - return nullptr; - return make<SpecialName>("covariant return thunk to ", Encoding); - } - // extension ::= TC <first type> <number> _ <second type> - // # construction vtable for second-in-first - case 'C': { - First += 2; - Node *FirstType = parseType(); - if (FirstType == nullptr) - return nullptr; - if (parseNumber(true).empty() || !consumeIf('_')) - return nullptr; - Node *SecondType = parseType(); - if (SecondType == nullptr) - return nullptr; - return make<CtorVtableSpecialName>(SecondType, FirstType); - } - // TW <object name> # Thread-local wrapper - case 'W': { - First += 2; - Node *Name = parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("thread-local wrapper routine for ", Name); - } - // TH <object name> # Thread-local initialization - case 'H': { - First += 2; - Node *Name = parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("thread-local initialization routine for ", Name); - } - // T <call-offset> <base encoding> - default: { - ++First; - bool IsVirt = look() == 'v'; - if (parseCallOffset()) - return nullptr; - Node *BaseEncoding = parseEncoding(); - if (BaseEncoding == nullptr) - return nullptr; - if (IsVirt) - return make<SpecialName>("virtual thunk to ", BaseEncoding); - else - return make<SpecialName>("non-virtual thunk to ", BaseEncoding); - } - } - case 'G': - switch (look(1)) { - // GV <object name> # Guard variable for one-time initialization - case 'V': { - First += 2; - Node *Name = parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("guard variable for ", Name); - } - // GR <object name> # reference temporary for object - // GR <object name> _ # First temporary - // GR <object name> <seq-id> _ # Subsequent temporaries - case 'R': { - First += 2; - Node *Name = parseName(); - if (Name == nullptr) - return nullptr; - size_t Count; - bool ParsedSeqId = !parseSeqId(&Count); - if (!consumeIf('_') && ParsedSeqId) - return nullptr; - return make<SpecialName>("reference temporary for ", Name); - } - } - } - return nullptr; -} - -// <encoding> ::= <function name> <bare-function-type> -// ::= <data name> -// ::= <special-name> -Node *Db::parseEncoding() { - if (look() == 'G' || look() == 'T') - return parseSpecialName(); - - auto IsEndOfEncoding = [&] { - // The set of chars that can potentially follow an <encoding> (none of which - // can start a <type>). Enumerating these allows us to avoid speculative - // parsing. - return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_'; - }; - - NameState NameInfo(this); - Node *Name = parseName(&NameInfo); - if (Name == nullptr) - return nullptr; - - if (resolveForwardTemplateRefs(NameInfo)) - return nullptr; - - if (IsEndOfEncoding()) - return Name; - - Node *Attrs = nullptr; - if (consumeIf("Ua9enable_ifI")) { - size_t BeforeArgs = Names.size(); - while (!consumeIf('E')) { - Node *Arg = parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs)); - } - - Node *ReturnType = nullptr; - if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) { - ReturnType = parseType(); - if (ReturnType == nullptr) - return nullptr; - } - - if (consumeIf('v')) - return make<FunctionEncoding>(ReturnType, Name, NodeArray(), - Attrs, NameInfo.CVQualifiers, - NameInfo.ReferenceQualifier); - - size_t ParamsBegin = Names.size(); - do { - Node *Ty = parseType(); - if (Ty == nullptr) - return nullptr; - Names.push_back(Ty); - } while (!IsEndOfEncoding()); - - return make<FunctionEncoding>(ReturnType, Name, - popTrailingNodeArray(ParamsBegin), - Attrs, NameInfo.CVQualifiers, - NameInfo.ReferenceQualifier); -} - -template <class Float> -struct FloatData; - -template <> -struct FloatData<float> -{ - static const size_t mangled_size = 8; - static const size_t max_demangled_size = 24; - static constexpr const char* spec = "%af"; -}; - -constexpr const char* FloatData<float>::spec; - -template <> -struct FloatData<double> -{ - static const size_t mangled_size = 16; - static const size_t max_demangled_size = 32; - static constexpr const char* spec = "%a"; -}; - -constexpr const char* FloatData<double>::spec; - -template <> -struct FloatData<long double> -{ -#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) - static const size_t mangled_size = 32; -#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) - static const size_t mangled_size = 16; -#else - static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms -#endif - static const size_t max_demangled_size = 40; - static constexpr const char *spec = "%LaL"; -}; - -constexpr const char *FloatData<long double>::spec; - -template <class Float> Node *Db::parseFloatingLiteral() { - const size_t N = FloatData<Float>::mangled_size; - if (numLeft() <= N) - return nullptr; - StringView Data(First, First + N); - for (char C : Data) - if (!std::isxdigit(C)) - return nullptr; - First += N; - if (!consumeIf('E')) - return nullptr; - return make<FloatExpr<Float>>(Data); -} - -// <seq-id> ::= <0-9A-Z>+ -bool Db::parseSeqId(size_t *Out) { - if (!(look() >= '0' && look() <= '9') && - !(look() >= 'A' && look() <= 'Z')) - return true; - - size_t Id = 0; - while (true) { - if (look() >= '0' && look() <= '9') { - Id *= 36; - Id += static_cast<size_t>(look() - '0'); - } else if (look() >= 'A' && look() <= 'Z') { - Id *= 36; - Id += static_cast<size_t>(look() - 'A') + 10; - } else { - *Out = Id; - return false; - } - ++First; - } -} - -// <substitution> ::= S <seq-id> _ -// ::= S_ -// <substitution> ::= Sa # ::std::allocator -// <substitution> ::= Sb # ::std::basic_string -// <substitution> ::= Ss # ::std::basic_string < char, -// ::std::char_traits<char>, -// ::std::allocator<char> > -// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > -// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > -// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > -Node *Db::parseSubstitution() { - if (!consumeIf('S')) - return nullptr; - - if (std::islower(look())) { - Node *SpecialSub; - switch (look()) { - case 'a': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator); - break; - case 'b': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string); - break; - case 's': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string); - break; - case 'i': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream); - break; - case 'o': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream); - break; - case 'd': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream); - break; - default: - return nullptr; - } - // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution> - // has ABI tags, the tags are appended to the substitution; the result is a - // substitutable component. - Node *WithTags = parseAbiTags(SpecialSub); - if (WithTags != SpecialSub) { - Subs.push_back(WithTags); - SpecialSub = WithTags; - } - return SpecialSub; - } - - // ::= S_ - if (consumeIf('_')) { - if (Subs.empty()) - return nullptr; - return Subs[0]; - } - - // ::= S <seq-id> _ - size_t Index = 0; - if (parseSeqId(&Index)) - return nullptr; - ++Index; - if (!consumeIf('_') || Index >= Subs.size()) - return nullptr; - return Subs[Index]; -} - -// <template-param> ::= T_ # first template parameter -// ::= T <parameter-2 non-negative number> _ -Node *Db::parseTemplateParam() { - if (!consumeIf('T')) - return nullptr; - - size_t Index = 0; - if (!consumeIf('_')) { - if (parsePositiveInteger(&Index)) - return nullptr; - ++Index; - if (!consumeIf('_')) - return nullptr; - } - - // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter list - // are mangled as the corresponding artificial template type parameter. - if (ParsingLambdaParams) - return make<NameType>("auto"); - - // If we're in a context where this <template-param> refers to a - // <template-arg> further ahead in the mangled name (currently just conversion - // operator types), then we should only look it up in the right context. - if (PermitForwardTemplateReferences) { - ForwardTemplateRefs.push_back(make<ForwardTemplateReference>(Index)); - return ForwardTemplateRefs.back(); - } - - if (Index >= TemplateParams.size()) - return nullptr; - return TemplateParams[Index]; -} - -// <template-arg> ::= <type> # type or template -// ::= X <expression> E # expression -// ::= <expr-primary> # simple expressions -// ::= J <template-arg>* E # argument pack -// ::= LZ <encoding> E # extension -Node *Db::parseTemplateArg() { - switch (look()) { - case 'X': { - ++First; - Node *Arg = parseExpr(); - if (Arg == nullptr || !consumeIf('E')) - return nullptr; - return Arg; - } - case 'J': { - ++First; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - NodeArray Args = popTrailingNodeArray(ArgsBegin); - return make<TemplateArgumentPack>(Args); - } - case 'L': { - // ::= LZ <encoding> E # extension - if (look(1) == 'Z') { - First += 2; - Node *Arg = parseEncoding(); - if (Arg == nullptr || !consumeIf('E')) - return nullptr; - return Arg; - } - // ::= <expr-primary> # simple expressions - return parseExprPrimary(); - } - default: - return parseType(); - } -} - -// <template-args> ::= I <template-arg>* E -// extension, the abi says <template-arg>+ -Node *Db::parseTemplateArgs(bool TagTemplates) { - if (!consumeIf('I')) - return nullptr; - - // <template-params> refer to the innermost <template-args>. Clear out any - // outer args that we may have inserted into TemplateParams. - if (TagTemplates) - TemplateParams.clear(); - - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - if (TagTemplates) { - auto OldParams = std::move(TemplateParams); - Node *Arg = parseTemplateArg(); - TemplateParams = std::move(OldParams); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - Node *TableEntry = Arg; - if (Arg->getKind() == Node::KTemplateArgumentPack) { - TableEntry = make<ParameterPack>( - static_cast<TemplateArgumentPack*>(TableEntry)->getElements()); - } - TemplateParams.push_back(TableEntry); - } else { - Node *Arg = parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - } - return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin)); -} - -// <discriminator> := _ <non-negative number> # when number < 10 -// := __ <non-negative number> _ # when number >= 10 -// extension := decimal-digit+ # at the end of string - -const char* -parse_discriminator(const char* first, const char* last) -{ - // parse but ignore discriminator - if (first != last) - { - if (*first == '_') - { - const char* t1 = first+1; - if (t1 != last) - { - if (std::isdigit(*t1)) - first = t1+1; - else if (*t1 == '_') - { - for (++t1; t1 != last && std::isdigit(*t1); ++t1) - ; - if (t1 != last && *t1 == '_') - first = t1 + 1; - } - } - } - else if (std::isdigit(*first)) - { - const char* t1 = first+1; - for (; t1 != last && std::isdigit(*t1); ++t1) - ; - if (t1 == last) - first = last; - } - } - return first; -} - -// <mangled-name> ::= _Z <encoding> -// ::= <type> -// extension ::= ___Z <encoding> _block_invoke -// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+ -// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+ -Node *Db::parse() { - if (consumeIf("_Z")) { - Node *Encoding = parseEncoding(); - if (Encoding == nullptr) - return nullptr; - if (look() == '.') { - Encoding = make<DotSuffix>(Encoding, StringView(First, Last)); - First = Last; - } - if (numLeft() != 0) - return nullptr; - return Encoding; - } - - if (consumeIf("___Z")) { - Node *Encoding = parseEncoding(); - if (Encoding == nullptr || !consumeIf("_block_invoke")) - return nullptr; - bool RequireNumber = consumeIf('_'); - if (parseNumber().empty() && RequireNumber) - return nullptr; - if (numLeft() != 0) - return nullptr; - return make<SpecialName>("invocation function for block in ", Encoding); - } - - Node *Ty = parseType(); - if (numLeft() != 0) - return nullptr; - return Ty; -} - -bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, - size_t InitSize) { - size_t BufferSize; - if (Buf == nullptr) { - Buf = static_cast<char *>(std::malloc(InitSize)); - if (Buf == nullptr) - return true; - BufferSize = InitSize; - } else - BufferSize = *N; - - S.reset(Buf, BufferSize); - return false; -} +//===----------------------------------------------------------------------===// +// Code beyond this point should not be synchronized with libc++abi. +//===----------------------------------------------------------------------===// -} // unnamed namespace +using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; char *llvm::itaniumDemangle(const char *MangledName, char *Buf, size_t *N, int *Status) { @@ -4961,14 +333,14 @@ char *llvm::itaniumDemangle(const char *MangledName, char *Buf, } int InternalStatus = demangle_success; - Db Parser(MangledName, MangledName + std::strlen(MangledName)); + Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); OutputStream S; Node *AST = Parser.parse(); if (AST == nullptr) InternalStatus = demangle_invalid_mangled_name; - else if (initializeOutputStream(Buf, N, S, 1024)) + else if (!initializeOutputStream(Buf, N, S, 1024)) InternalStatus = demangle_memory_alloc_failure; else { assert(Parser.ForwardTemplateRefs.empty()); @@ -4984,13 +356,11 @@ char *llvm::itaniumDemangle(const char *MangledName, char *Buf, return InternalStatus == demangle_success ? Buf : nullptr; } -namespace llvm { - ItaniumPartialDemangler::ItaniumPartialDemangler() - : RootNode(nullptr), Context(new Db{nullptr, nullptr}) {} + : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {} ItaniumPartialDemangler::~ItaniumPartialDemangler() { - delete static_cast<Db *>(Context); + delete static_cast<Demangler *>(Context); } ItaniumPartialDemangler::ItaniumPartialDemangler( @@ -5008,16 +378,16 @@ operator=(ItaniumPartialDemangler &&Other) { // Demangle MangledName into an AST, storing it into this->RootNode. bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { - Db *Parser = static_cast<Db *>(Context); + Demangler *Parser = static_cast<Demangler *>(Context); size_t Len = std::strlen(MangledName); Parser->reset(MangledName, MangledName + Len); RootNode = Parser->parse(); return RootNode == nullptr; } -static char *printNode(Node *RootNode, char *Buf, size_t *N) { +static char *printNode(const Node *RootNode, char *Buf, size_t *N) { OutputStream S; - if (initializeOutputStream(Buf, N, S, 128)) + if (!initializeOutputStream(Buf, N, S, 128)) return nullptr; RootNode->print(S); S += '\0'; @@ -5030,24 +400,24 @@ char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { if (!isFunction()) return nullptr; - Node *Name = static_cast<FunctionEncoding *>(RootNode)->getName(); + const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); while (true) { switch (Name->getKind()) { case Node::KAbiTagAttr: - Name = static_cast<AbiTagAttr *>(Name)->Base; + Name = static_cast<const AbiTagAttr *>(Name)->Base; continue; case Node::KStdQualifiedName: - Name = static_cast<StdQualifiedName *>(Name)->Child; + Name = static_cast<const StdQualifiedName *>(Name)->Child; continue; case Node::KNestedName: - Name = static_cast<NestedName *>(Name)->Name; + Name = static_cast<const NestedName *>(Name)->Name; continue; case Node::KLocalName: - Name = static_cast<LocalName *>(Name)->Entity; + Name = static_cast<const LocalName *>(Name)->Entity; continue; case Node::KNameWithTemplateArgs: - Name = static_cast<NameWithTemplateArgs *>(Name)->Name; + Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; continue; default: return printNode(Name, Buf, N); @@ -5059,20 +429,20 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, size_t *N) const { if (!isFunction()) return nullptr; - Node *Name = static_cast<FunctionEncoding *>(RootNode)->getName(); + const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); OutputStream S; - if (initializeOutputStream(Buf, N, S, 128)) + if (!initializeOutputStream(Buf, N, S, 128)) return nullptr; KeepGoingLocalFunction: while (true) { if (Name->getKind() == Node::KAbiTagAttr) { - Name = static_cast<AbiTagAttr *>(Name)->Base; + Name = static_cast<const AbiTagAttr *>(Name)->Base; continue; } if (Name->getKind() == Node::KNameWithTemplateArgs) { - Name = static_cast<NameWithTemplateArgs *>(Name)->Name; + Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; continue; } break; @@ -5083,10 +453,10 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, S += "std"; break; case Node::KNestedName: - static_cast<NestedName *>(Name)->Qual->print(S); + static_cast<const NestedName *>(Name)->Qual->print(S); break; case Node::KLocalName: { - auto *LN = static_cast<LocalName *>(Name); + auto *LN = static_cast<const LocalName *>(Name); LN->Encoding->print(S); S += "::"; Name = LN->Entity; @@ -5115,7 +485,7 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams(); OutputStream S; - if (initializeOutputStream(Buf, N, S, 128)) + if (!initializeOutputStream(Buf, N, S, 128)) return nullptr; S += '('; @@ -5133,10 +503,11 @@ char *ItaniumPartialDemangler::getFunctionReturnType( return nullptr; OutputStream S; - if (initializeOutputStream(Buf, N, S, 128)) + if (!initializeOutputStream(Buf, N, S, 128)) return nullptr; - if (Node *Ret = static_cast<FunctionEncoding *>(RootNode)->getReturnType()) + if (const Node *Ret = + static_cast<const FunctionEncoding *>(RootNode)->getReturnType()) Ret->print(S); S += '\0'; @@ -5154,12 +525,12 @@ bool ItaniumPartialDemangler::hasFunctionQualifiers() const { assert(RootNode != nullptr && "must call partialDemangle()"); if (!isFunction()) return false; - auto *E = static_cast<FunctionEncoding *>(RootNode); + auto *E = static_cast<const FunctionEncoding *>(RootNode); return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone; } bool ItaniumPartialDemangler::isCtorOrDtor() const { - Node *N = static_cast<Node *>(RootNode); + const Node *N = static_cast<const Node *>(RootNode); while (N) { switch (N->getKind()) { default: @@ -5168,22 +539,22 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const { return true; case Node::KAbiTagAttr: - N = static_cast<AbiTagAttr *>(N)->Base; + N = static_cast<const AbiTagAttr *>(N)->Base; break; case Node::KFunctionEncoding: - N = static_cast<FunctionEncoding *>(N)->getName(); + N = static_cast<const FunctionEncoding *>(N)->getName(); break; case Node::KLocalName: - N = static_cast<LocalName *>(N)->Entity; + N = static_cast<const LocalName *>(N)->Entity; break; case Node::KNameWithTemplateArgs: - N = static_cast<NameWithTemplateArgs *>(N)->Name; + N = static_cast<const NameWithTemplateArgs *>(N)->Name; break; case Node::KNestedName: - N = static_cast<NestedName *>(N)->Name; + N = static_cast<const NestedName *>(N)->Name; break; case Node::KStdQualifiedName: - N = static_cast<StdQualifiedName *>(N)->Child; + N = static_cast<const StdQualifiedName *>(N)->Child; break; } } @@ -5192,17 +563,16 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const { bool ItaniumPartialDemangler::isFunction() const { assert(RootNode != nullptr && "must call partialDemangle()"); - return static_cast<Node *>(RootNode)->getKind() == Node::KFunctionEncoding; + return static_cast<const Node *>(RootNode)->getKind() == + Node::KFunctionEncoding; } bool ItaniumPartialDemangler::isSpecialName() const { assert(RootNode != nullptr && "must call partialDemangle()"); - auto K = static_cast<Node *>(RootNode)->getKind(); + auto K = static_cast<const Node *>(RootNode)->getKind(); return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName; } bool ItaniumPartialDemangler::isData() const { return !isFunction() && !isSpecialName(); } - -} |