diff options
author | Yi Kong <yikong@google.com> | 2018-10-16 01:12:49 -0700 |
---|---|---|
committer | Yi Kong <yikong@google.com> | 2018-10-16 01:12:49 -0700 |
commit | 5ba2538a6a9027e2001c2ac7f4a23a3924a62773 (patch) | |
tree | 88e9de2f27848c89f03b9233c3391fe841c77293 | |
parent | b14f5952ea4da23effbefc6bb6b7123803100bf4 (diff) | |
parent | e878418df4fc5864a9bd7ab228874716bf98c8c2 (diff) | |
download | libcxxabi-5ba2538a6a9027e2001c2ac7f4a23a3924a62773.tar.gz |
Merge e878418 for LLVM update to 344140llvm-svn.344140
Change-Id: Iad73c26d7b08137c5c5c0c07559aab6ea3fd0c82
-rw-r--r-- | src/cxa_demangle.cpp | 5014 | ||||
-rw-r--r-- | src/cxa_personality.cpp | 2 | ||||
-rw-r--r-- | src/demangle/ItaniumDemangle.h | 5134 | ||||
-rw-r--r-- | src/demangle/Utility.h | 31 | ||||
-rw-r--r-- | src/fallback_malloc.cpp | 3 | ||||
-rw-r--r-- | src/private_typeinfo.cpp | 6 | ||||
-rw-r--r-- | test/test_exception_address_alignment.pass.cpp | 3 | ||||
-rw-r--r-- | www/index.html | 7 |
8 files changed, 5352 insertions, 4848 deletions
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp index 3a7ee06..a9a7050 100644 --- a/src/cxa_demangle.cpp +++ b/src/cxa_demangle.cpp @@ -15,1768 +15,231 @@ #include "__cxxabi_config.h" -#include "demangle/Compiler.h" -#include "demangle/StringView.h" -#include "demangle/Utility.h" +#include "demangle/ItaniumDemangle.h" #include <cassert> #include <cctype> #include <cstdio> #include <cstdlib> #include <cstring> +#include <functional> #include <numeric> #include <utility> #include <vector> -namespace { -enum : int { - demangle_unknown_error = -4, - demangle_invalid_args = -3, - demangle_invalid_mangled_name = -2, - demangle_memory_alloc_failure = -1, - demangle_success = 0, -}; - -// 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; - } - - 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; - -#ifndef NDEBUG - 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_) {} +using namespace itanium_demangle; - bool empty() const { return NumElements == 0; } - size_t size() const { return NumElements; } +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; - 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; - - // 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; - } - -public: - ReferenceType(Node *Pointee_, ReferenceKind RK_) - : Node(KReferenceType, Pointee_->RHSComponentCache), - Pointee(Pointee_), RK(RK_) {} +#ifndef NDEBUG +namespace { +struct DumpVisitor { + unsigned Depth = 0; + bool PendingNewline = false; - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + 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; } - 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 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); + template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) { + for (bool B : {wantsNewline(Vs)...}) + if (B) + return true; + return false; } -}; - -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 printStr(const char *S) { fprintf(stderr, "%s", S); } + void print(StringView SV) { + fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); } - - 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 += ")"; - } -}; - -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 += " "; - } - Name->print(S); + printStr("<null>"); } - - 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); - } -}; - -class CtorVtableSpecialName final : public Node { - const Node *FirstType; - const Node *SecondType; - -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); - } -}; - -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); - } -}; - -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 += "]"; - } - } -}; - -/// 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; - } - - // 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"); - } - _LIBCPP_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(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; + } + printStr("}"); + --Depth; + } + // Overload used when T is exactly 'bool', not merely convertible to 'bool'. + template<typename T, T * = (bool*)nullptr> + void print(T B) { + printStr(B ? "true" : "false"); + } + void print(size_t N) { + fprintf(stderr, "%zu", N); + } + void print(ReferenceKind RK) { + switch (RK) { + case ReferenceKind::LValue: + return printStr("ReferenceKind::LValue"); + case ReferenceKind::RValue: + return printStr("ReferenceKind::RValue"); + } + } + 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"); + } + } + 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(" | "); + } } - _LIBCPP_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; + return printStr("SpecialSubKind::iostream"); } } -}; - -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); + void newLine() { + printStr("\n"); + for (unsigned I = 0; I != Depth; ++I) + printStr(" "); + PendingNewline = false; } -}; - -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 += "\'"; + template<typename T> void printWithPendingNewline(T V) { + print(V); + if (wantsNewline(V)) + PendingNewline = true; } -}; - -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 += ")"; - } - 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; - } -}; - -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 += ")"; - } -}; - -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; + struct CtorArgPrinter { + DumpVisitor &Visitor; - 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 += '('; - - 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; @@ -1834,3137 +297,38 @@ 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; + void reset() { Alloc.reset(); } - 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; - - 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; - } - - /// 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(); -}; - -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; - } - _LIBCPP_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; - } - _LIBCPP_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); + void *allocateNodeArray(size_t sz) { + return Alloc.allocate(sizeof(Node *) * sz); } - 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"; }; +} // unnamed namespace -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"; -}; +//===----------------------------------------------------------------------===// +// Code beyond this point should not be synchronized with LLVM. +//===----------------------------------------------------------------------===// -constexpr const char* FloatData<double>::spec; +using Demangler = itanium_demangle::Db<DefaultAllocator>; -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"; +namespace { +enum : int { + demangle_invalid_args = -3, + demangle_invalid_mangled_name = -2, + demangle_memory_alloc_failure = -1, + demangle_success = 0, }; - -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 (look() == '.') - First = Last; - 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; -} - -} // unnamed namespace - namespace __cxxabiv1 { extern "C" _LIBCXXABI_FUNC_VIS char * __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { @@ -4975,7 +339,7 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { } int InternalStatus = demangle_success; - Db Parser(MangledName, MangledName + std::strlen(MangledName)); + Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); OutputStream S; Node *AST = Parser.parse(); diff --git a/src/cxa_personality.cpp b/src/cxa_personality.cpp index 6759d8a..ec3d981 100644 --- a/src/cxa_personality.cpp +++ b/src/cxa_personality.cpp @@ -1038,7 +1038,7 @@ __gxx_personality_v0 } #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) -extern "C" EXCEPTION_DISPOSITION +extern "C" _LIBCXXABI_FUNC_VIS EXCEPTION_DISPOSITION __gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame, PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) { diff --git a/src/demangle/ItaniumDemangle.h b/src/demangle/ItaniumDemangle.h new file mode 100644 index 0000000..32da9ff --- /dev/null +++ b/src/demangle/ItaniumDemangle.h @@ -0,0 +1,5134 @@ +//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// WARNING: This file defines its contents within an anonymous namespace. It +// should not be included anywhere other than cxa_demangle.h. +// +//===----------------------------------------------------------------------===// + +#ifndef LIBCXX_DEMANGLE_ITANIUMDEMANGLE_H +#define LIBCXX_DEMANGLE_ITANIUMDEMANGLE_H + +// FIXME: (possibly) incomplete list of features that clang mangles that this +// file does not yet support: +// - C++ modules TS + +#include "Compiler.h" +#include "StringView.h" +#include "Utility.h" + +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <numeric> +#include <utility> + +#define FOR_EACH_NODE_KIND(X) \ + X(NodeArrayNode) \ + X(DotSuffix) \ + X(VendorExtQualType) \ + X(QualType) \ + X(ConversionOperatorType) \ + X(PostfixQualifiedType) \ + X(ElaboratedTypeSpefType) \ + X(NameType) \ + X(AbiTagAttr) \ + X(EnableIfAttr) \ + X(ObjCProtoName) \ + X(PointerType) \ + X(ReferenceType) \ + X(PointerToMemberType) \ + X(ArrayType) \ + X(FunctionType) \ + X(NoexceptSpec) \ + X(DynamicExceptionSpec) \ + X(FunctionEncoding) \ + X(LiteralOperator) \ + X(SpecialName) \ + X(CtorVtableSpecialName) \ + X(QualifiedName) \ + X(NestedName) \ + X(LocalName) \ + X(VectorType) \ + X(PixelVectorType) \ + X(ParameterPack) \ + X(TemplateArgumentPack) \ + X(ParameterPackExpansion) \ + X(TemplateArgs) \ + X(ForwardTemplateReference) \ + X(NameWithTemplateArgs) \ + X(GlobalQualifiedName) \ + X(StdQualifiedName) \ + X(ExpandedSpecialSubstitution) \ + X(SpecialSubstitution) \ + X(CtorDtorName) \ + X(DtorName) \ + X(UnnamedTypeName) \ + X(ClosureTypeName) \ + X(StructuredBindingName) \ + X(BinaryExpr) \ + X(ArraySubscriptExpr) \ + X(PostfixExpr) \ + X(ConditionalExpr) \ + X(MemberExpr) \ + X(EnclosingExpr) \ + X(CastExpr) \ + X(SizeofParamPackExpr) \ + X(CallExpr) \ + X(NewExpr) \ + X(DeleteExpr) \ + X(PrefixExpr) \ + X(FunctionParam) \ + X(ConversionExpr) \ + X(InitListExpr) \ + X(FoldExpr) \ + X(ThrowExpr) \ + X(BoolExpr) \ + X(IntegerCastExpr) \ + X(IntegerLiteral) \ + X(FloatLiteral) \ + X(DoubleLiteral) \ + X(LongDoubleLiteral) \ + X(BracedExpr) \ + X(BracedRangeExpr) + +namespace { +namespace itanium_demangle { +// Base class of all AST nodes. The AST is built by the parser, then is +// traversed by the printLeft/Right functions to produce a demangled string. +class Node { +public: + enum Kind : unsigned char { +#define ENUMERATOR(NodeKind) K ## NodeKind, + FOR_EACH_NODE_KIND(ENUMERATOR) +#undef ENUMERATOR + }; + + /// 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, }; + +private: + Kind K; + + // FIXME: Make these protected. +public: + /// Tracks if this node has a component on its right side, in which case we + /// need to call printRight. + Cache RHSComponentCache; + + /// 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; + +public: + Node(Kind K_, Cache RHSComponentCache_ = Cache::No, + Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) + : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), + FunctionCache(FunctionCache_) {} + + /// Visit the most-derived object corresponding to this object. + template<typename Fn> void visit(Fn F) const; + + // The following function is provided by all derived classes: + // + // Call F with arguments that, when passed to the constructor of this node, + // would construct an equivalent node. + //template<typename Fn> void match(Fn F) const; + + 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; + } + + 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; + +#ifndef NDEBUG + DUMP_METHOD void dump() const; +#endif +}; + +class NodeArray { + Node **Elements; + size_t NumElements; + +public: + NodeArray() : Elements(nullptr), NumElements(0) {} + NodeArray(Node **Elements_, size_t NumElements_) + : Elements(Elements_), NumElements(NumElements_) {} + + bool empty() const { return NumElements == 0; } + size_t size() const { return NumElements; } + + Node **begin() const { return Elements; } + Node **end() const { return Elements + NumElements; } + + Node *operator[](size_t Idx) const { return Elements[Idx]; } + + void printWithComma(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; + } + + FirstElement = false; + } + } +}; + +struct NodeArrayNode : Node { + NodeArray Array; + NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} + + template<typename Fn> void match(Fn F) const { F(Array); } + + void printLeft(OutputStream &S) const override { + Array.printWithComma(S); + } +}; + +class DotSuffix final : public Node { + const Node *Prefix; + const StringView Suffix; + +public: + DotSuffix(const Node *Prefix_, StringView Suffix_) + : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} + + template<typename Fn> void match(Fn F) const { F(Prefix, 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(const Node *Ty_, StringView Ext_) + : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + + template<typename Fn> void match(Fn F) const { F(Ty, 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, +}; + +inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) { + return Q1 = static_cast<Qualifiers>(Q1 | Q2); +} + +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(const Node *Child_, Qualifiers Quals_) + : Node(KQualType, Child_->RHSComponentCache, + Child_->ArrayCache, Child_->FunctionCache), + Quals(Quals_), Child(Child_) {} + + template<typename Fn> void match(Fn F) const { F(Child, Quals); } + + 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(const Node *Ty_) + : Node(KConversionOperatorType), Ty(Ty_) {} + + template<typename Fn> void match(Fn F) const { F(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_) {} + + template<typename Fn> void match(Fn F) const { F(Ty, 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_) {} + + template<typename Fn> void match(Fn F) const { F(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_) {} + + template<typename Fn> void match(Fn F) const { F(Kind, 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_) {} + + template<typename Fn> void match(Fn F) const { F(Base, 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_) {} + + template<typename Fn> void match(Fn F) const { F(Conditions); } + + void printLeft(OutputStream &S) const override { + S += " [enable_if:"; + Conditions.printWithComma(S); + S += ']'; + } +}; + +class ObjCProtoName : public Node { + const Node *Ty; + StringView Protocol; + + friend class PointerType; + +public: + ObjCProtoName(const Node *Ty_, StringView Protocol_) + : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} + + template<typename Fn> void match(Fn F) const { F(Ty, Protocol); } + + bool isObjCObject() const { + return Ty->getKind() == KNameType && + static_cast<const 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(const Node *Pointee_) + : Node(KPointerType, Pointee_->RHSComponentCache), + Pointee(Pointee_) {} + + template<typename Fn> void match(Fn F) const { F(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; + + // 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; + } + +public: + ReferenceType(const Node *Pointee_, ReferenceKind RK_) + : Node(KReferenceType, Pointee_->RHSComponentCache), + Pointee(Pointee_), RK(RK_) {} + + template<typename Fn> void match(Fn F) const { F(Pointee, RK); } + + bool hasRHSComponentSlow(OutputStream &S) const override { + return Pointee->hasRHSComponent(S); + } + + 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 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(const Node *ClassType_, const Node *MemberType_) + : Node(KPointerToMemberType, MemberType_->RHSComponentCache), + ClassType(ClassType_), MemberType(MemberType_) {} + + template<typename Fn> void match(Fn F) const { F(ClassType, 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 += "("; + 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 { + const Node *Base; + NodeOrString Dimension; + +public: + ArrayType(const Node *Base_, NodeOrString Dimension_) + : Node(KArrayType, + /*RHSComponentCache=*/Cache::Yes, + /*ArrayCache=*/Cache::Yes), + Base(Base_), Dimension(Dimension_) {} + + template<typename Fn> void match(Fn F) const { F(Base, Dimension); } + + 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 { + const Node *Ret; + NodeArray Params; + Qualifiers CVQuals; + FunctionRefQual RefQual; + const Node *ExceptionSpec; + +public: + FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, + FunctionRefQual RefQual_, const Node *ExceptionSpec_) + : Node(KFunctionType, + /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, + /*FunctionCache=*/Cache::Yes), + Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), + ExceptionSpec(ExceptionSpec_) {} + + template<typename Fn> void match(Fn F) const { + F(Ret, Params, CVQuals, RefQual, 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 { + const Node *E; +public: + NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {} + + template<typename Fn> void match(Fn F) const { F(E); } + + void printLeft(OutputStream &S) const override { + S += "noexcept("; + E->print(S); + S += ")"; + } +}; + +class DynamicExceptionSpec : public Node { + NodeArray Types; +public: + DynamicExceptionSpec(NodeArray Types_) + : Node(KDynamicExceptionSpec), Types(Types_) {} + + template<typename Fn> void match(Fn F) const { F(Types); } + + void printLeft(OutputStream &S) const override { + S += "throw("; + Types.printWithComma(S); + S += ')'; + } +}; + +class FunctionEncoding final : public Node { + const Node *Ret; + const Node *Name; + NodeArray Params; + const Node *Attrs; + Qualifiers CVQuals; + FunctionRefQual RefQual; + +public: + FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_, + const Node *Attrs_, Qualifiers CVQuals_, + FunctionRefQual RefQual_) + : Node(KFunctionEncoding, + /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, + /*FunctionCache=*/Cache::Yes), + Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), + CVQuals(CVQuals_), RefQual(RefQual_) {} + + template<typename Fn> void match(Fn F) const { + F(Ret, Name, Params, Attrs, CVQuals, RefQual); + } + + Qualifiers getCVQuals() const { return CVQuals; } + FunctionRefQual getRefQual() const { return RefQual; } + NodeArray getParams() const { return Params; } + const Node *getReturnType() const { return Ret; } + + bool hasRHSComponentSlow(OutputStream &) const override { return true; } + bool hasFunctionSlow(OutputStream &) const override { return true; } + + const Node *getName() const { return Name; } + + void printLeft(OutputStream &S) const override { + if (Ret) { + Ret->printLeft(S); + if (!Ret->hasRHSComponent(S)) + S += " "; + } + 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(const Node *OpName_) + : Node(KLiteralOperator), OpName(OpName_) {} + + template<typename Fn> void match(Fn F) const { F(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_, const Node *Child_) + : Node(KSpecialName), Special(Special_), Child(Child_) {} + + template<typename Fn> void match(Fn F) const { F(Special, Child); } + + void printLeft(OutputStream &S) const override { + S += Special; + Child->print(S); + } +}; + +class CtorVtableSpecialName final : public Node { + const Node *FirstType; + const Node *SecondType; + +public: + CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_) + : Node(KCtorVtableSpecialName), + FirstType(FirstType_), SecondType(SecondType_) {} + + template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); } + + void printLeft(OutputStream &S) const override { + S += "construction vtable for "; + FirstType->print(S); + S += "-in-"; + SecondType->print(S); + } +}; + +struct NestedName : Node { + Node *Qual; + Node *Name; + + NestedName(Node *Qual_, Node *Name_) + : Node(KNestedName), Qual(Qual_), Name(Name_) {} + + template<typename Fn> void match(Fn F) const { F(Qual, Name); } + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + Qual->print(S); + S += "::"; + Name->print(S); + } +}; + +struct LocalName : Node { + Node *Encoding; + Node *Entity; + + LocalName(Node *Encoding_, Node *Entity_) + : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} + + template<typename Fn> void match(Fn F) const { F(Encoding, 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(const Node *Qualifier_, const Node *Name_) + : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} + + template<typename Fn> void match(Fn F) const { F(Qualifier, 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; + +public: + VectorType(const Node *BaseType_, NodeOrString Dimension_) + : Node(KVectorType), BaseType(BaseType_), + Dimension(Dimension_) {} + + template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } + + void printLeft(OutputStream &S) const override { + BaseType->print(S); + S += " vector["; + if (Dimension.isNode()) + Dimension.asNode()->print(S); + else if (Dimension.isString()) + S += Dimension.asString(); + S += "]"; + } +}; + +class PixelVectorType final : public Node { + const NodeOrString Dimension; + +public: + PixelVectorType(NodeOrString Dimension_) + : Node(KPixelVectorType), Dimension(Dimension_) {} + + template<typename Fn> void match(Fn F) const { F(Dimension); } + + void printLeft(OutputStream &S) const override { + // FIXME: This should demangle as "vector pixel". + S += "pixel vector["; + S += Dimension.asString(); + S += "]"; + } +}; + +/// 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; + } + + template<typename Fn> void match(Fn F) const { F(Data); } + + 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_) {} + + template<typename Fn> void match(Fn F) const { F(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(const Node *Child_) + : Node(KParameterPackExpansion), Child(Child_) {} + + template<typename Fn> void match(Fn F) const { F(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; + } + + // 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_) {} + + template<typename Fn> void match(Fn F) const { F(Params); } + + NodeArray getParams() { return Params; } + + void printLeft(OutputStream &S) const override { + S += "<"; + Params.printWithComma(S); + if (S.back() == '>') + S += " "; + S += ">"; + } +}; + +/// A forward-reference to a template argument that was not known at the point +/// where the template parameter name was parsed in a mangling. +/// +/// This is created when demangling the name of a specialization of a +/// conversion function template: +/// +/// \code +/// struct A { +/// template<typename T> operator T*(); +/// }; +/// \endcode +/// +/// When demangling a specialization of the conversion function template, we +/// encounter the name of the template (including the \c T) before we reach +/// the template argument list, so we cannot substitute the parameter name +/// for the corresponding argument while parsing. Instead, we create a +/// \c ForwardTemplateReference node that is resolved after we parse the +/// template arguments. +struct ForwardTemplateReference : Node { + size_t Index; + Node *Ref = nullptr; + + // If we're currently printing this node. It is possible (though invalid) for + // a forward template reference to refer to itself via a substitution. This + // creates a cyclic AST, which will stack overflow printing. To fix this, bail + // out if more than one print* function is active. + mutable bool Printing = false; + + ForwardTemplateReference(size_t Index_) + : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, + Cache::Unknown), + Index(Index_) {} + + // We don't provide a matcher for these, because the value of the node is + // not determined by its construction parameters, and it generally needs + // special handling. + template<typename Fn> void match(Fn F) const = delete; + + 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_) {} + + template<typename Fn> void match(Fn F) const { F(Name, 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_) {} + + template<typename Fn> void match(Fn F) const { F(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_) {} + + template<typename Fn> void match(Fn F) const { F(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_) {} + + template<typename Fn> void match(Fn F) const { F(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"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::allocator"; + break; + case SpecialSubKind::basic_string: + S += "std::basic_string"; + break; + 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_) {} + + template<typename Fn> void match(Fn F) const { F(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"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::allocator"; + break; + case SpecialSubKind::basic_string: + S += "std::basic_string"; + break; + case SpecialSubKind::string: + S += "std::string"; + break; + case SpecialSubKind::istream: + S += "std::istream"; + break; + case SpecialSubKind::ostream: + S += "std::ostream"; + break; + case SpecialSubKind::iostream: + S += "std::iostream"; + break; + } + } +}; + +class CtorDtorName final : public Node { + const Node *Basename; + const bool IsDtor; + const int Variant; + +public: + CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_) + : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_), + Variant(Variant_) {} + + template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); } + + void printLeft(OutputStream &S) const override { + if (IsDtor) + S += "~"; + S += Basename->getBaseName(); + } +}; + +class DtorName : public Node { + const Node *Base; + +public: + DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {} + + template<typename Fn> void match(Fn F) const { F(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_) {} + + template<typename Fn> void match(Fn F) const { F(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_) {} + + template<typename Fn> void match(Fn F) const { F(Params, 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_) {} + + template<typename Fn> void match(Fn F) const { F(Bindings); } + + void printLeft(OutputStream &S) const override { + S += '['; + Bindings.printWithComma(S); + S += ']'; + } +}; + +// -- Expression Nodes -- + +class BinaryExpr : public Node { + const Node *LHS; + const StringView InfixOperator; + const Node *RHS; + +public: + BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) + : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { + } + + template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, 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 Node { + const Node *Op1; + const Node *Op2; + +public: + ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) + : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} + + template<typename Fn> void match(Fn F) const { F(Op1, Op2); } + + void printLeft(OutputStream &S) const override { + S += "("; + Op1->print(S); + S += ")["; + Op2->print(S); + S += "]"; + } +}; + +class PostfixExpr : public Node { + const Node *Child; + const StringView Operator; + +public: + PostfixExpr(const Node *Child_, StringView Operator_) + : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} + + template<typename Fn> void match(Fn F) const { F(Child, Operator); } + + void printLeft(OutputStream &S) const override { + S += "("; + Child->print(S); + S += ")"; + S += Operator; + } +}; + +class ConditionalExpr : public Node { + const Node *Cond; + const Node *Then; + const Node *Else; + +public: + ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) + : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} + + template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); } + + void printLeft(OutputStream &S) const override { + S += "("; + Cond->print(S); + S += ") ? ("; + Then->print(S); + S += ") : ("; + Else->print(S); + S += ")"; + } +}; + +class MemberExpr : public Node { + const Node *LHS; + const StringView Kind; + const Node *RHS; + +public: + MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) + : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + + template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); } + + void printLeft(OutputStream &S) const override { + LHS->print(S); + S += Kind; + RHS->print(S); + } +}; + +class EnclosingExpr : public Node { + const StringView Prefix; + const Node *Infix; + const StringView Postfix; + +public: + EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) + : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), + Postfix(Postfix_) {} + + template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); } + + void printLeft(OutputStream &S) const override { + S += Prefix; + Infix->print(S); + S += Postfix; + } +}; + +class CastExpr : public Node { + // cast_kind<to>(from) + const StringView CastKind; + const Node *To; + const Node *From; + +public: + CastExpr(StringView CastKind_, const Node *To_, const Node *From_) + : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {} + + template<typename Fn> void match(Fn F) const { F(CastKind, To, From); } + + void printLeft(OutputStream &S) const override { + S += CastKind; + S += "<"; + To->printLeft(S); + S += ">("; + From->printLeft(S); + S += ")"; + } +}; + +class SizeofParamPackExpr : public Node { + const Node *Pack; + +public: + SizeofParamPackExpr(const Node *Pack_) + : Node(KSizeofParamPackExpr), Pack(Pack_) {} + + template<typename Fn> void match(Fn F) const { F(Pack); } + + void printLeft(OutputStream &S) const override { + S += "sizeof...("; + ParameterPackExpansion PPE(Pack); + PPE.printLeft(S); + S += ")"; + } +}; + +class CallExpr : public Node { + const Node *Callee; + NodeArray Args; + +public: + CallExpr(const Node *Callee_, NodeArray Args_) + : Node(KCallExpr), Callee(Callee_), Args(Args_) {} + + template<typename Fn> void match(Fn F) const { F(Callee, Args); } + + void printLeft(OutputStream &S) const override { + Callee->print(S); + S += "("; + Args.printWithComma(S); + S += ")"; + } +}; + +class NewExpr : public Node { + // new (expr_list) type(init_list) + NodeArray ExprList; + Node *Type; + NodeArray InitList; + bool IsGlobal; // ::operator new ? + bool IsArray; // new[] ? +public: + NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, + bool IsArray_) + : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), + IsGlobal(IsGlobal_), IsArray(IsArray_) {} + + template<typename Fn> void match(Fn F) const { + F(ExprList, Type, InitList, IsGlobal, 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 += ")"; + } + Type->print(S); + if (!InitList.empty()) { + S += "("; + InitList.printWithComma(S); + S += ")"; + } + + } +}; + +class DeleteExpr : public Node { + Node *Op; + bool IsGlobal; + bool IsArray; + +public: + DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) + : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + + template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); } + + void printLeft(OutputStream &S) const override { + if (IsGlobal) + S += "::"; + S += "delete"; + if (IsArray) + S += "[] "; + Op->print(S); + } +}; + +class PrefixExpr : public Node { + StringView Prefix; + Node *Child; + +public: + PrefixExpr(StringView Prefix_, Node *Child_) + : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} + + template<typename Fn> void match(Fn F) const { F(Prefix, Child); } + + void printLeft(OutputStream &S) const override { + S += Prefix; + S += "("; + Child->print(S); + S += ")"; + } +}; + +class FunctionParam : public Node { + StringView Number; + +public: + FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} + + template<typename Fn> void match(Fn F) const { F(Number); } + + void printLeft(OutputStream &S) const override { + S += "fp"; + S += Number; + } +}; + +class ConversionExpr : public Node { + const Node *Type; + NodeArray Expressions; + +public: + ConversionExpr(const Node *Type_, NodeArray Expressions_) + : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} + + template<typename Fn> void match(Fn F) const { F(Type, Expressions); } + + void printLeft(OutputStream &S) const override { + S += "("; + Type->print(S); + S += ")("; + Expressions.printWithComma(S); + S += ")"; + } +}; + +class InitListExpr : public Node { + const Node *Ty; + NodeArray Inits; +public: + InitListExpr(const Node *Ty_, NodeArray Inits_) + : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {} + + template<typename Fn> void match(Fn F) const { F(Ty, Inits); } + + void printLeft(OutputStream &S) const override { + if (Ty) + Ty->print(S); + S += '{'; + Inits.printWithComma(S); + S += '}'; + } +}; + +class BracedExpr : public Node { + const Node *Elem; + const Node *Init; + bool IsArray; +public: + BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_) + : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {} + + template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); } + + void printLeft(OutputStream &S) const override { + if (IsArray) { + S += '['; + Elem->print(S); + S += ']'; + } else { + S += '.'; + Elem->print(S); + } + if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) + S += " = "; + Init->print(S); + } +}; + +class BracedRangeExpr : public Node { + const Node *First; + const Node *Last; + const Node *Init; +public: + BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_) + : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {} + + template<typename Fn> void match(Fn F) const { F(First, Last, 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); + } +}; + +class FoldExpr : public Node { + const Node *Pack, *Init; + StringView OperatorName; + bool IsLeftFold; + +public: + FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, + const Node *Init_) + : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), + IsLeftFold(IsLeftFold_) {} + + template<typename Fn> void match(Fn F) const { + F(IsLeftFold, OperatorName, Pack, Init); + } + + void printLeft(OutputStream &S) const override { + auto PrintPack = [&] { + S += '('; + ParameterPackExpansion(Pack).print(S); + S += ')'; + }; + + S += '('; + + 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); + } + } + S += ')'; + } +}; + +class ThrowExpr : public Node { + const Node *Op; + +public: + ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {} + + template<typename Fn> void match(Fn F) const { F(Op); } + + void printLeft(OutputStream &S) const override { + S += "throw "; + Op->print(S); + } +}; + +class BoolExpr : public Node { + bool Value; + +public: + BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {} + + template<typename Fn> void match(Fn F) const { F(Value); } + + void printLeft(OutputStream &S) const override { + S += Value ? StringView("true") : StringView("false"); + } +}; + +class IntegerCastExpr : public Node { + // ty(integer) + const Node *Ty; + StringView Integer; + +public: + IntegerCastExpr(const Node *Ty_, StringView Integer_) + : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {} + + template<typename Fn> void match(Fn F) const { F(Ty, Integer); } + + void printLeft(OutputStream &S) const override { + S += "("; + Ty->print(S); + S += ")"; + S += Integer; + } +}; + +class IntegerLiteral : public Node { + StringView Type; + StringView Value; + +public: + IntegerLiteral(StringView Type_, StringView Value_) + : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} + + template<typename Fn> void match(Fn F) const { F(Type, Value); } + + void printLeft(OutputStream &S) const override { + if (Type.size() > 3) { + S += "("; + S += Type; + S += ")"; + } + + if (Value[0] == 'n') { + S += "-"; + S += Value.dropFront(1); + } else + S += Value; + + if (Type.size() <= 3) + S += Type; + } +}; + +template <class Float> struct FloatData; + +namespace float_literal_impl { +constexpr Node::Kind getFloatLiteralKind(float *) { + return Node::KFloatLiteral; +} +constexpr Node::Kind getFloatLiteralKind(double *) { + return Node::KDoubleLiteral; +} +constexpr Node::Kind getFloatLiteralKind(long double *) { + return Node::KLongDoubleLiteral; +} +} + +template <class Float> class FloatLiteralImpl : public Node { + const StringView Contents; + + static constexpr Kind KindForClass = + float_literal_impl::getFloatLiteralKind((Float *)nullptr); + +public: + FloatLiteralImpl(StringView Contents_) + : Node(KindForClass), Contents(Contents_) {} + + template<typename Fn> void match(Fn F) const { F(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); +#endif + char num[FloatData<Float>::max_demangled_size] = {0}; + int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); + s += StringView(num, num + n); + } + } +}; + +using FloatLiteral = FloatLiteralImpl<float>; +using DoubleLiteral = FloatLiteralImpl<double>; +using LongDoubleLiteral = FloatLiteralImpl<long double>; + +/// Visit the node. Calls \c F(P), where \c P is the node cast to the +/// appropriate derived class. +template<typename Fn> +void Node::visit(Fn F) const { + switch (K) { +#define CASE(X) case K ## X: return F(static_cast<const X*>(this)); + FOR_EACH_NODE_KIND(CASE) +#undef CASE + } + assert(0 && "unknown mangling node kind"); +} + +/// Determine the kind of a node from its type. +template<typename NodeT> struct NodeKind; +#define SPECIALIZATION(X) \ + template<> struct NodeKind<X> { \ + static constexpr Node::Kind Kind = Node::K##X; \ + static constexpr const char *name() { return #X; } \ + }; +FOR_EACH_NODE_KIND(SPECIALIZATION) +#undef SPECIALIZATION + +#undef FOR_EACH_NODE_KIND + +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; + } + +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); + } +}; + +template <typename Alloc> +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; + + void (*TypeCallback)(void *, const char *) = nullptr; + void *TypeCallbackContext = nullptr; + + bool TryToParseTemplateArgs = true; + bool PermitForwardTemplateReferences = false; + bool ParsingLambdaParams = false; + + Alloc ASTAllocator; + + 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> Node *make(Args &&... args) { + return ASTAllocator.template makeNode<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.allocateNodeArray(sz); + Node **data = new (mem) Node *[sz]; + std::copy(begin, end, data); + return NodeArray(data, sz); + } + + NodeArray popTrailingNodeArray(size_t FromPosition) { + assert(FromPosition <= Names.size()); + NodeArray res = + makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); + Names.dropBack(FromPosition); + return res; + } + + bool consumeIf(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; + } + + /// 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(); +}; + +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> +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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); + auto *StringLitName = make<NameType>("string literal"); + if (!StringLitName) + return nullptr; + return make<LocalName>(Encoding, StringLitName); + } + + 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> +template<typename Alloc> Node *Db<Alloc>::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 +template<typename Alloc> +Node *Db<Alloc>::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 +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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 +template<typename Alloc> Node *Db<Alloc>::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 # ? +template<typename Alloc> +Node *Db<Alloc>::parseCtorDtorName(Node *&SoFar, NameState *State) { + if (SoFar->getKind() == 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); + if (!SoFar) + return nullptr; + default: + break; + } + } + + if (consumeIf('C')) { + bool IsInherited = consumeIf('I'); + if (look() != '1' && look() != '2' && look() != '3' && look() != '5') + return nullptr; + int Variant = look() - '0'; + ++First; + if (State) State->CtorDtorConversion = true; + if (IsInherited) { + if (parseName(State) == nullptr) + return nullptr; + } + return make<CtorDtorName>(SoFar, false, Variant); + } + + if (look() == 'D' && + (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) { + int Variant = look(1) - '0'; + First += 2; + if (State) State->CtorDtorConversion = true; + return make<CtorDtorName>(SoFar, true, Variant); + } + + 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> +template<typename Alloc> Node *Db<Alloc>::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 (!Comp) return false; + if (SoFar) SoFar = make<NestedName>(SoFar, Comp); + else SoFar = Comp; + if (State) State->EndsWithTemplateArgs = false; + return SoFar != nullptr; + }; + + if (consumeIf("St")) { + SoFar = make<NameType>("std"); + if (!SoFar) + return nullptr; + } + + 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') { + if (!PushComponent(parseTemplateParam())) + return nullptr; + 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 (!SoFar) + return nullptr; + if (State) State->EndsWithTemplateArgs = true; + Subs.push_back(SoFar); + continue; + } + + // ::= <decltype> + if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { + if (!PushComponent(parseDecltype())) + return nullptr; + Subs.push_back(SoFar); + continue; + } + + // ::= <substitution> + if (look() == 'S' && look(1) != 't') { + Node *S = parseSubstitution(); + if (!PushComponent(S)) + return nullptr; + 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; + if (!PushComponent(parseCtorDtorName(SoFar, State))) + return nullptr; + SoFar = parseAbiTags(SoFar); + if (SoFar == nullptr) + return nullptr; + Subs.push_back(SoFar); + continue; + } + + // ::= <prefix> <unqualified-name> + if (!PushComponent(parseUnqualifiedName(State))) + return nullptr; + Subs.push_back(SoFar); + } + + if (SoFar == nullptr || Subs.empty()) + return nullptr; + + Subs.pop_back(); + return SoFar; +} + +// <simple-id> ::= <source-name> [ <template-args> ] +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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); + if (!SoFar) + return nullptr; + } + + while (!consumeIf('E')) { + Node *Qual = parseSimpleId(); + if (Qual == nullptr) + return nullptr; + SoFar = make<QualifiedName>(SoFar, Qual); + if (!SoFar) + return nullptr; + } + + 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; + if (!SoFar) + return nullptr; + } 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); + if (!SoFar) + return nullptr; + } + } + + 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> +template<typename Alloc> Node *Db<Alloc>::parseAbiTags(Node *N) { + while (consumeIf('B')) { + StringView SN = parseBareSourceName(); + if (SN.empty()) + return nullptr; + N = make<AbiTagAttr>(N, SN); + if (!N) + return nullptr; + } + return N; +} + +// <number> ::= [n] <non-negative decimal integer> +template<typename Alloc> +StringView Db<Alloc>::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]* +template<typename Alloc> bool Db<Alloc>::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; +} + +template<typename Alloc> StringView Db<Alloc>::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 +template<typename Alloc> Node *Db<Alloc>::parseFunctionType() { + Qualifiers CVQuals = parseCVQualifiers(); + + Node *ExceptionSpec = nullptr; + if (consumeIf("Do")) { + ExceptionSpec = make<NameType>("noexcept"); + if (!ExceptionSpec) + return nullptr; + } else if (consumeIf("DO")) { + Node *E = parseExpr(); + if (E == nullptr || !consumeIf('E')) + return nullptr; + ExceptionSpec = make<NoexceptSpec>(E); + if (!ExceptionSpec) + return nullptr; + } 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)); + if (!ExceptionSpec) + return nullptr; + } + + 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 +template<typename Alloc> Node *Db<Alloc>::parseVectorType() { + if (!consumeIf("Dv")) + return nullptr; + if (look() >= '1' && look() <= '9') { + StringView DimensionNumber = parseNumber(); + if (!consumeIf('_')) + return nullptr; + if (consumeIf('p')) + return make<PixelVectorType>(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) +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::parseArrayType() { + if (!consumeIf('A')) + return nullptr; + + NodeOrString Dimension; + + if (std::isdigit(look())) { + Dimension = parseNumber(); + if (!consumeIf('_')) + return nullptr; + } else if (!consumeIf('_')) { + Node *DimExpr = parseExpr(); + if (DimExpr == nullptr) + return nullptr; + if (!consumeIf('_')) + return nullptr; + Dimension = DimExpr; + } + + Node *Ty = parseType(); + if (Ty == nullptr) + return nullptr; + return make<ArrayType>(Ty, Dimension); +} + +// <pointer-to-member-type> ::= M <class type> <member type> +template<typename Alloc> Node *Db<Alloc>::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' +template<typename Alloc> Node *Db<Alloc>::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 +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::parseType() { + Node *Result = nullptr; + + if (TypeCallback != nullptr) + TypeCallback(TypeCallbackContext, First); + + 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; + } + _LIBCPP_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; + } + _LIBCPP_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; +} + +template<typename Alloc> Node *Db<Alloc>::parsePrefixExpr(StringView Kind) { + Node *E = parseExpr(); + if (E == nullptr) + return nullptr; + return make<PrefixExpr>(Kind, E); +} + +template<typename Alloc> Node *Db<Alloc>::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); +} + +template<typename Alloc> Node *Db<Alloc>::parseIntegerLiteral(StringView Lit) { + StringView Tmp = parseNumber(true); + if (!Tmp.empty() && consumeIf('E')) + return make<IntegerLiteral>(Lit, Tmp); + return nullptr; +} + +// <CV-Qualifiers> ::= [r] [V] [K] +template<typename Alloc> Qualifiers Db<Alloc>::parseCVQualifiers() { + Qualifiers CVR = QualNone; + if (consumeIf('r')) + CVR |= QualRestrict; + if (consumeIf('V')) + CVR |= QualVolatile; + if (consumeIf('K')) + 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 +template<typename Alloc> Node *Db<Alloc>::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 +template<typename Alloc> Node *Db<Alloc>::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 +template<typename Alloc> Node *Db<Alloc>::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 +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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); + } + auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)); + if (!Pack) + return nullptr; + return make<EnclosingExpr>("sizeof... (", Pack, ")"); + } + } + 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 +template<typename Alloc> bool Db<Alloc>::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 +template<typename Alloc> Node *Db<Alloc>::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> +template<typename Alloc> Node *Db<Alloc>::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)); + if (!Attrs) + return nullptr; + } + + 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"; +}; + +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"; +}; + +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"; +}; + +template<typename Alloc> +template<class Float> +Node *Db<Alloc>::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<FloatLiteralImpl<Float>>(Data); +} + +// <seq-id> ::= <0-9A-Z>+ +template<typename Alloc> bool Db<Alloc>::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> > +template<typename Alloc> Node *Db<Alloc>::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; + } + if (!SpecialSub) + 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> _ +template<typename Alloc> Node *Db<Alloc>::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) { + Node *ForwardRef = make<ForwardTemplateReference>(Index); + if (!ForwardRef) + return nullptr; + assert(ForwardRef->getKind() == Node::KForwardTemplateReference); + ForwardTemplateRefs.push_back( + static_cast<ForwardTemplateReference *>(ForwardRef)); + return ForwardRef; + } + + 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 +template<typename Alloc> Node *Db<Alloc>::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>+ +template <typename Alloc> +Node *Db<Alloc>::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()); + if (!TableEntry) + return nullptr; + } + TemplateParams.push_back(TableEntry); + } else { + Node *Arg = parseTemplateArg(); + if (Arg == nullptr) + return nullptr; + Names.push_back(Arg); + } + } + return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin)); +} + +// <mangled-name> ::= _Z <encoding> +// ::= <type> +// extension ::= ___Z <encoding> _block_invoke +// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+ +// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+ +template<typename Alloc> Node *Db<Alloc>::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 (look() == '.') + First = Last; + if (numLeft() != 0) + return nullptr; + return make<SpecialName>("invocation function for block in ", Encoding); + } + + Node *Ty = parseType(); + if (numLeft() != 0) + return nullptr; + return Ty; +} + +} // namespace itanium_demangle +} // namespace + +#endif // LIBCXX_DEMANGLE_ITANIUMDEMANGLE_H diff --git a/src/demangle/Utility.h b/src/demangle/Utility.h index 3909243..8611376 100644 --- a/src/demangle/Utility.h +++ b/src/demangle/Utility.h @@ -71,22 +71,6 @@ public: BufferCapacity = BufferCapacity_; } - /// Create an OutputStream from a buffer and a size. If either of these are - /// null a buffer is allocated. - static OutputStream create(char *StartBuf, size_t *Size, size_t AllocSize) { - OutputStream Result; - - if (!StartBuf || !Size) { - StartBuf = static_cast<char *>(std::malloc(AllocSize)); - if (StartBuf == nullptr) - std::terminate(); - Size = &AllocSize; - } - - Result.reset(StartBuf, *Size); - return Result; - } - /// If a ParameterPackExpansion (or similar type) is encountered, the offset /// into the pack that we're currently printing. unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); @@ -186,6 +170,21 @@ public: SwapAndRestore &operator=(const SwapAndRestore &) = delete; }; +inline 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; +} + } // namespace #endif diff --git a/src/fallback_malloc.cpp b/src/fallback_malloc.cpp index 336ad31..bec9952 100644 --- a/src/fallback_malloc.cpp +++ b/src/fallback_malloc.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// Define _LIBCPP_BUILDING_LIBRARY to ensure _LIBCPP_HAS_NO_ALIGNED_ALLOCATION +// is only defined when libc aligned allocation is not available. +#define _LIBCPP_BUILDING_LIBRARY #include "fallback_malloc.h" #include <__threading_support> diff --git a/src/private_typeinfo.cpp b/src/private_typeinfo.cpp index a0326a1..30340a1 100644 --- a/src/private_typeinfo.cpp +++ b/src/private_typeinfo.cpp @@ -64,6 +64,7 @@ is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp) return x == y; return strcmp(x->name(), y->name()) == 0; #else + (void) use_strcmp; return (x == y) || (strcmp(x->name(), y->name()) == 0); #endif } @@ -650,7 +651,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, // We get here only if there is some kind of visibility problem // in client code. syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " - "should have public visibility. At least one of them is hidden. %s" + "should have public visibility. At least one of them is hidden. %s" ", %s.\n", static_type->name(), dynamic_type->name()); // Redo the search comparing type_info's using strcmp info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; @@ -673,7 +674,8 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, info.path_dynamic_ptr_to_static_ptr == unknown) { syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " - "has hidden visibility. They should all have public visibility. " + "has hidden visibility or is defined in more than one translation " + "unit. They should all have public visibility. " "%s, %s, %s.\n", static_type->name(), dynamic_type->name(), dst_type->name()); // Redo the search comparing type_info's using strcmp diff --git a/test/test_exception_address_alignment.pass.cpp b/test/test_exception_address_alignment.pass.cpp index 138fb4d..5d36659 100644 --- a/test/test_exception_address_alignment.pass.cpp +++ b/test/test_exception_address_alignment.pass.cpp @@ -20,6 +20,7 @@ #include <cstdint> #include <cassert> +#include <__cxxabi_config.h> #include <unwind.h> @@ -27,7 +28,7 @@ struct __attribute__((aligned)) AlignedType {}; // EHABI : 8-byte aligned // Itanium: Largest supported alignment for the system -#if defined(_LIBUNWIND_ARM_EHABI) +#if defined(_LIBCXXABI_ARM_EHABI) # define EXPECTED_ALIGNMENT 8 #else # define EXPECTED_ALIGNMENT alignof(AlignedType) diff --git a/www/index.html b/www/index.html index 66bbb64..e71e55c 100644 --- a/www/index.html +++ b/www/index.html @@ -22,8 +22,9 @@ <div class="submenu"> <label>Quick Links</label> - <a href="http://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a> - <a href="http://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a> + <a href="https://libcxx.llvm.org/">libc++</a> + <a href="http://lists.llvm.org/mailman/listinfo/libcxx-dev">libcxx-dev</a> + <a href="http://lists.llvm.org/mailman/listinfo/libcxx-commits">libcxx-commits</a> <a href="http://llvm.org/bugs/">Bug Reports</a> <a href="http://llvm.org/svn/llvm-project/libcxxabi/trunk/">Browse SVN</a> <a href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/">Browse ViewVC</a> @@ -119,7 +120,7 @@ a different ABI library), this may interfere with test results.</p> <p>Send discussions to the - (<a href="http://lists.llvm.org/mailman/listinfo/cfe-dev">clang mailing list</a>).</p> + (<a href="http://lists.llvm.org/mailman/listinfo/libcxx-dev">libcxx-dev mailing list</a>).</p> <!--=====================================================================--> <h2>Frequently asked questions</h2> |