Index: src/cxa_demangle.cpp =================================================================== --- src/cxa_demangle.cpp +++ src/cxa_demangle.cpp @@ -323,6 +323,23 @@ } }; +class NameType final : public Node { + const StringView Name; + +public: + NameType(StringView Name_) : Node(KNameType), Name(Name_) { + setCachedRHSComponent(false); + setCachedArray(false); + setCachedFunction(false); + ParameterPackSize = NoParameterPack; + } + + StringView getName() const { return Name; } + StringView getBaseName() const override { return Name; } + + void printLeft(OutputStream &s) const override { s += Name; } +}; + class VendorExtQualType final : public Node { const Node *Ty; const Node *Ext; @@ -339,11 +356,18 @@ setCachedFunction(Ty->CachedFunction); } + bool isObjCObject() const { + return Ext->getKind() == KObjCProtoName && + Ty->getKind() == KNameType && + static_cast(Ty)->getName() == "objc_object"; + } + const Node* getQual() const { return Ext; } void printLeft(OutputStream &S) const override { Ty->print(S); - S += " "; + if (Ext->getKind() != KObjCProtoName) + S += " "; Ext->printLeft(S); } }; @@ -442,23 +466,6 @@ void printRight(OutputStream &S) const override { Ty->printRight(S); } }; -class NameType final : public Node { - const StringView Name; - -public: - NameType(StringView Name_) : Node(KNameType), Name(Name_) { - setCachedRHSComponent(false); - setCachedArray(false); - setCachedFunction(false); - ParameterPackSize = NoParameterPack; - } - - StringView getName() const { return Name; } - StringView getBaseName() const override { return Name; } - - void printLeft(OutputStream &s) const override { s += Name; } -}; - class AbiTagAttr final : public Node { const Node* Base; StringView Tag; @@ -482,29 +489,22 @@ }; class ObjCProtoName : public Node { - Node *Ty; - Node *Protocol; + StringView Protocol; friend class PointerType; public: - ObjCProtoName(Node *Ty_, Node *Protocol_) - : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) { + ObjCProtoName(StringView Protocol_) + : Node(KObjCProtoName), Protocol(Protocol_) { setCachedRHSComponent(false); setCachedArray(false); setCachedFunction(false); ParameterPackSize = NoParameterPack; } - bool isObjCObject() const { - return Ty->getKind() == KNameType && - static_cast(Ty)->getName() == "objc_object"; - } - void printLeft(OutputStream &S) const override { - Ty->print(S); S += "<"; - Protocol->print(S); + S += Protocol; S += ">"; } }; @@ -525,30 +525,29 @@ return Pointee->hasRHSComponent(S); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputStream &S) const override { // We rewrite objc_object* into id. - if (Pointee->getKind() != KObjCProtoName || - !static_cast(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; + if (Pointee->getKind() == KVendorExtQualType && + static_cast(Pointee)->isObjCObject()) { + const auto *ExtQual = static_cast(Pointee); + S += "id"; + ExtQual->getQual()->print(S); } else { - const auto *objcProto = static_cast(Pointee); - s += "id<"; - objcProto->Protocol->print(s); - s += ">"; + Pointee->printLeft(S); + if (Pointee->hasArray(S)) + S += " "; + if (Pointee->hasArray(S) || Pointee->hasFunction(S)) + S += "("; + S += "*"; } } - void printRight(OutputStream &s) const override { - if (Pointee->getKind() != KObjCProtoName || - !static_cast(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); + void printRight(OutputStream &S) const override { + if (Pointee->getKind() != KVendorExtQualType || + !static_cast(Pointee)->isObjCObject()) { + if (Pointee->hasArray(S) || Pointee->hasFunction(S)) + S += ")"; + Pointee->printRight(S); } } }; @@ -2142,6 +2141,8 @@ StringView parseNumber(bool AllowNegative = false); Qualifiers parseCVQualifiers(); + bool parsePositiveInteger(size_t *Out); + StringView parseBareSourceName(); /// Parse the production. Node *parseExpr(); @@ -2155,6 +2156,16 @@ Node *parseNewExpr(); Node *parseConversionExpr(); + /// Parse the production. + Node *parseType(); + Node *parseFunctionType(); + Node *parseVectorType(); + Node *parseDecltype(); + Node *parseArrayType(); + Node *parsePointerToMemberType(); + Node *parseQualifiedType(bool &AppliesToFunction); + Node *parseClassEnumType(); + // FIXME: remove this when all the parse_* functions have been rewritten. template Node *legacyParse() { @@ -2168,6 +2179,18 @@ Names.pop_back(); return R; } + template + Node *legacyParse() { + size_t BeforeType = Names.size(); + const char *OrigFirst = First; + const char *T = parse_fn(First, Last, *this, nullptr); + if (T == OrigFirst || BeforeType + 1 != Names.size()) + return nullptr; + First = T; + Node *R = Names.back(); + Names.pop_back(); + return R; + } }; const char* @@ -2194,7 +2217,30 @@ return db.First; } -const char* parse_type(const char* first, const char* last, Db& db); +const char* +parse_type(const char* first, const char* last, Db& db) +{ + db.First = first; + db.Last = last; + Node *R = db.parseType(); + if (R == nullptr) + return first; + db.Names.push_back(R); + return db.First; +} + +const char* +parse_decltype(const char* first, const char* last, Db& db) +{ + db.First = first; + db.Last = last; + Node *R = db.parseDecltype(); + if (R == nullptr) + return first; + db.Names.push_back(R); + return db.First; +} + const char* parse_encoding(const char* first, const char* last, Db& db); const char* parse_name(const char* first, const char* last, Db& db, bool* ends_with_template_args = 0); @@ -2202,8 +2248,8 @@ const char* parse_template_param(const char*, const char*, Db&); const char* parse_operator_name(const char* first, const char* last, Db& db); const char* parse_unqualified_name(const char* first, const char* last, Db& db); -const char* parse_decltype(const char* first, const char* last, Db& db); const char* parse_unresolved_name(const char*, const char*, Db&); +const char* parse_substitution(const char*, const char*, Db&); // ::= [n] StringView Db::parseNumber(bool AllowNegative) { @@ -2217,408 +2263,960 @@ return StringView(Tmp, First); } -Node *Db::parsePrefixExpr(StringView Kind) { - Node *E = parseExpr(); - if (E == nullptr) - return nullptr; - return make(Kind, E); - // FIXME inline this +// ::= [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(consume() - '0'); + } + return false; } -Node *Db::parseBinaryExpr(StringView Kind) { - Node *LHS = parseExpr(); - if (LHS == nullptr) +StringView Db::parseBareSourceName() { + size_t Int = 0; + if (parsePositiveInteger(&Int) || numLeft() < Int) + return StringView(); + StringView R(First, First + Int); + First += Int; + return R; +} + +// ::= R # & ref-qualifier +// ::= O # && ref-qualifier +// +// ::= F [Y] [] E +Node *Db::parseFunctionType() { + if (!consumeIf('F')) return nullptr; - Node *RHS = parseExpr(); - if (RHS == nullptr) + consumeIf('Y'); // extern "C" + Node *ReturnType = parseType(); + if (ReturnType == nullptr) return nullptr; - return make(LHS, Kind, RHS); -} -Node *Db::parseIntegerLiteral(StringView Lit) { - StringView Tmp = parseNumber(true); - if (!Tmp.empty() && consumeIf('E')) - return make(Lit, Tmp); - 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); + } -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; + NodeArray Params = popTrailingNodeArray(ParamsBegin); + Node *Fn = make(ReturnType, Params); + if (ReferenceQualifier) + Fn = make(Fn, ReferenceQualifier); + return Fn; } -// ::= fp _ # L == 0, first parameter -// ::= fp _ # L == 0, second and later parameters -// ::= fL p _ # L > 0, first parameter -// ::= fL p _ # L > 0, second and later parameters -Node *Db::parseFunctionParam() { - if (consumeIf("fp")) { - parseCVQualifiers(); - StringView Num = parseNumber(); +// extension: +// ::= Dv _ +// +// ::= Dv [] _ +// ::= +// ::= p # AltiVec vector pixel +Node *Db::parseVectorType() { + if (!consumeIf("Dv")) + return nullptr; + if (*First >= '1' && *First <= '9') { + StringView DimensionNumber = parseNumber(); if (!consumeIf('_')) return nullptr; - return make(Num); - } - if (consumeIf("fL")) { - if (parseNumber().empty()) + if (consumeIf('p')) + return make(DimensionNumber); + Node *ElemType = parseType(); + if (ElemType == nullptr) return nullptr; - if (!consumeIf('p')) + return make(ElemType, DimensionNumber); + } + + if (!consumeIf('_')) { + Node *DimExpr = parseExpr(); + if (!DimExpr) return nullptr; - parseCVQualifiers(); - StringView Num = parseNumber(); if (!consumeIf('_')) return nullptr; - return make(Num); + Node *ElemType = parseType(); + if (!ElemType) + return nullptr; + return make(ElemType, DimExpr); } + return nullptr; } -// [gs] nw * _ E # new (expr-list) type -// [gs] nw * _ # new (expr-list) type (init) -// [gs] na * _ E # new[] (expr-list) type -// [gs] na * _ # new[] (expr-list) type (init) -// ::= pi * E # parenthesized initialization -Node *Db::parseNewExpr() { - bool Global = consumeIf("gs"); - bool IsArray = look(1) == 'w'; - if (!consumeIf("nw") && !consumeIf("na")) +// ::= Dt E # decltype of an id-expression or class member access (C++0x) +// ::= DT E # decltype of an expression (C++0x) +Node *Db::parseDecltype() { + if (!consumeIf('D')) 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 = legacyParse(); - 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(ExprList, Ty, Inits, Global, IsArray); - } - return make(ExprList, Ty, NodeArray(), Global, IsArray); + if (!consumeIf('t') && !consumeIf('T')) + return nullptr; + Node *E = parseExpr(); + if (E == nullptr) + return nullptr; + if (!consumeIf('E')) + return nullptr; + return make("decltype(", E, ")"); } -// cv # conversion with one argument -// cv _ * E # conversion with a different number of arguments -Node *Db::parseConversionExpr() { - if (!consumeIf("cv")) +// ::= A _ +// ::= A [] _ +Node *Db::parseArrayType() { + if (!consumeIf('A')) return nullptr; - Node *Ty; - { - SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); - Ty = legacyParse(); + + if (std::isdigit(*First)) { + StringView Dimension = parseNumber(); + if (!consumeIf('_')) + return nullptr; + Node *Ty = parseType(); + if (Ty == nullptr) + return nullptr; + return make(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(ElementType, DimExpr); } + Node *Ty = parseType(); if (Ty == nullptr) return nullptr; + return make(Ty); +} - if (consumeIf('_')) { - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = legacyParse(); - if (E == nullptr) - return E; - Names.push_back(E); +// ::= M +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(ClassType, MemberType); +} + +// ::= +// +// ::= * +// +// ::= U [] # vendor extended type qualifier +// +// ::= [r] [V] [K] # restrict (C99), volatile, const +Node *Db::parseQualifiedType(bool &AppliesToFunction) { + // First, parse the * + PODSmallVector ExtendedQualifiers; + while (consumeIf('U')) { + StringView Result = parseBareSourceName(); + if (Result.empty()) + return nullptr; + + if (Result.startsWith("objcproto")) { + StringView ProtoName = Result.dropFront(std::strlen("objcproto")); + StringView BareProto; + { + SwapAndRestore SaveFirst(First, ProtoName.begin()), + SaveLast(Last, ProtoName.end()); + StringView SN = parseBareSourceName(); + if (SN.empty()) + return nullptr; + ExtendedQualifiers.push_back(make(SN)); + continue; + } } - NodeArray Exprs = popTrailingNodeArray(ExprsBegin); - return make(Ty, Exprs); + + // FIXME: parse the optional here. + + ExtendedQualifiers.push_back(make(Result)); } - Node *E = parseExpr(); - if (E == nullptr) + // Next, parse any cvr qualifiers. + Qualifiers CVR = parseCVQualifiers(); + + if (CVR == QualNone && ExtendedQualifiers.empty()) return nullptr; - return make(Ty, makeNodeArray(&E, &E + 1)); -} -// ::= L E # integer literal -// ::= L E # floating literal -// ::= L E # string literal -// ::= L E # nullptr literal (i.e., "LDnE") -// FIXME: ::= L _ E # complex floating point literal (C 2000) -// ::= L E # external name -Node *Db::parseExprPrimary() { - if (!consumeIf('L')) + Node *Ty = parseType(); + if (!Ty) return nullptr; - switch (look()) { - case 'w': - ++First; - return parseIntegerLiteral("wchar_t"); - case 'b': - if (consumeIf("b0E")) - return make(0); - if (consumeIf("b1E")) - return make(1); + AppliesToFunction = Ty->getKind() == Node::KFunctionType || + Ty->getKind() == Node::KFunctionRefQualType; + // Apply the qualifiers to Ty. + if (CVR != QualNone) { + if (AppliesToFunction) + Ty = make(Ty, CVR); + else + Ty = make(Ty, CVR); + } + for (auto* ExtQ : ExtendedQualifiers) + Ty = make(Ty, ExtQ); + return Ty; +} + +// ::= # non-dependent type name, dependent type name, or dependent typename-specifier +// ::= Ts # dependent elaborated type specifier using 'struct' or 'class' +// ::= Tu # dependent elaborated type specifier using 'union' +// ::= Te # dependent elaborated type specifier using 'enum' +Node *Db::parseClassEnumType() { + // FIXME: try to parse the elaborated type specifiers here! + return legacyParse(); +} + +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= P # pointer +// ::= R # l-value reference +// ::= O # r-value reference (C++11) +// ::= C # complex pair (C99) +// ::= G # imaginary (C99) +// ::= # See Compression below +// extension ::= U # objc-type +// extension ::= # starts with Dv +// +// ::= objcproto # k0 = 9 + + k1 +// ::= # PU<11+>objcproto 11objc_object 11objc_object -> id +Node *Db::parseType() { + if (numLeft() == 0) return nullptr; + + Node *Result = nullptr; + + switch (*First) { + // ::= + case 'U': + case 'r': + case 'V': + case 'K': { + bool AppliesToFunction = false; + Result = parseQualifiedType(AppliesToFunction); + // Functions have the rule that both them and their qualifiers form just one + // entry in the substitution table. Bail out before the (now) qualified + // function gets inserted into the substitution table. + if (AppliesToFunction) + return Result; + break; + } + // ::= v # void + case 'v': + ++First; + return make("void"); + // ::= w # wchar_t + case 'w': + ++First; + return make("wchar_t"); + // ::= b # bool + case 'b': + ++First; + return make("bool"); + // ::= c # char case 'c': ++First; - return parseIntegerLiteral("char"); + return make("char"); + // ::= a # signed char case 'a': ++First; - return parseIntegerLiteral("signed char"); + return make("signed char"); + // ::= h # unsigned char case 'h': ++First; - return parseIntegerLiteral("unsigned char"); + return make("unsigned char"); + // ::= s # short case 's': ++First; - return parseIntegerLiteral("short"); + return make("short"); + // ::= t # unsigned short case 't': ++First; - return parseIntegerLiteral("unsigned short"); + return make("unsigned short"); + // ::= i # int case 'i': ++First; - return parseIntegerLiteral(""); + return make("int"); + // ::= j # unsigned int case 'j': ++First; - return parseIntegerLiteral("u"); + return make("unsigned int"); + // ::= l # long case 'l': ++First; - return parseIntegerLiteral("l"); + return make("long"); + // ::= m # unsigned long case 'm': ++First; - return parseIntegerLiteral("ul"); + return make("unsigned long"); + // ::= x # long long, __int64 case 'x': ++First; - return parseIntegerLiteral("ll"); + return make("long long"); + // ::= y # unsigned long long, __int64 case 'y': ++First; - return parseIntegerLiteral("ull"); + return make("unsigned long long"); + // ::= n # __int128 case 'n': ++First; - return parseIntegerLiteral("__int128"); + return make("__int128"); + // ::= o # unsigned __int128 case 'o': ++First; - return parseIntegerLiteral("unsigned __int128"); + return make("unsigned __int128"); + // ::= f # float case 'f': ++First; - return parseFloatingLiteral(); + return make("float"); + // ::= d # double case 'd': ++First; - return parseFloatingLiteral(); + return make("double"); + // ::= e # long double, __float80 case 'e': ++First; - return parseFloatingLiteral(); - case '_': - if (consumeIf("_Z")) { - Node *R = legacyParse(); - 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 = legacyParse(); - if (T == nullptr) + return make("long double"); + // ::= g # __float128 + case 'g': + ++First; + return make("__float128"); + // ::= z # ellipsis + case 'z': + ++First; + return make("..."); + + // ::= u # vendor extended type + case 'u': { + ++First; + StringView Res = parseBareSourceName(); + if (Res.empty()) return nullptr; - StringView N = parseNumber(); - if (!N.empty()) { - if (!consumeIf('E')) - return nullptr; - return make(T, N); - } - if (consumeIf('E')) - return T; - return nullptr; - } + return make(Res); } -} - -// ::= -// ::= -// ::= -// ::= cl + E # call -// ::= cv # conversion with one argument -// ::= cv _ * E # conversion with a different number of arguments -// ::= [gs] nw * _ E # new (expr-list) type -// ::= [gs] nw * _ # new (expr-list) type (init) -// ::= [gs] na * _ E # new[] (expr-list) type -// ::= [gs] na * _ # new[] (expr-list) type (init) -// ::= [gs] dl # delete expression -// ::= [gs] da # delete[] expression -// ::= pp_ # prefix ++ -// ::= mm_ # prefix -- -// ::= ti # typeid (type) -// ::= te # typeid (expression) -// ::= dc # dynamic_cast (expression) -// ::= sc # static_cast (expression) -// ::= cc # const_cast (expression) -// ::= rc # reinterpret_cast (expression) -// ::= st # sizeof (a type) -// ::= sz # sizeof (an expression) -// ::= at # alignof (a type) -// ::= az # alignof (an expression) -// ::= nx # noexcept (expression) -// ::= -// ::= -// ::= dt # expr.name -// ::= pt # expr->name -// ::= ds # expr.*expr -// ::= sZ # size of a parameter pack -// ::= sZ # size of a function parameter pack -// ::= sp # pack expansion -// ::= tw # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= fL -// ::= fR -// ::= fl -// ::= fr -// ::= -Node *Db::parseExpr() { - bool Global = consumeIf("gs"); - if (numLeft() < 2) - return nullptr; - - switch (*First) { - case 'L': return parseExprPrimary(); - case 'T': return legacyParse(); - case 'f': return parseFunctionParam(); - case 'a': + case 'D': + if (numLeft() < 2) + return nullptr; switch (First[1]) { - case 'a': - First += 2; - return parseBinaryExpr("&&"); + // ::= Dd # IEEE 754r decimal floating point (64 bits) case 'd': First += 2; - return parsePrefixExpr("&"); - case 'n': - First += 2; - return parseBinaryExpr("&"); - case 'N': - First += 2; - return parseBinaryExpr("&="); - case 'S': + return make("decimal64"); + // ::= De # IEEE 754r decimal floating point (128 bits) + case 'e': First += 2; - return parseBinaryExpr("="); - case 't': { + return make("decimal128"); + // ::= Df # IEEE 754r decimal floating point (32 bits) + case 'f': First += 2; - Node *Ty = legacyParse(); - if (Ty == nullptr) - return nullptr; - return make("alignof (", Ty, ")"); - } - case 'z': { + return make("decimal32"); + // ::= Dh # IEEE 754r half-precision floating point (16 bits) + case 'h': First += 2; - Node *Ty = parseExpr(); - if (Ty == nullptr) - return nullptr; - return make("alignof (", Ty, ")"); - } - } - return nullptr; - case 'c': - switch (First[1]) { - // cc # const_cast (expression) - case 'c': { + return make("decimal16"); + // ::= Di # char32_t + case 'i': First += 2; - Node *Ty = legacyParse(); - if (Ty == nullptr) - return Ty; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make("const_cast", Ty, Ex); - } - // cl + E # call - case 'l': { + return make("char32_t"); + // ::= Ds # char16_t + case 's': 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(Callee, popTrailingNodeArray(ExprsBegin)); - } - case 'm': + return make("char16_t"); + // ::= Da # auto (in dependent new-expressions) + case 'a': First += 2; - return parseBinaryExpr(","); - case 'o': + return make("auto"); + // ::= Dc # decltype(auto) + case 'c': First += 2; - return parsePrefixExpr("~"); - case 'v': - return parseConversionExpr(); - } - return nullptr; - case 'd': - switch (First[1]) { - case 'a': { + return make("decltype(auto)"); + // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) + case 'n': First += 2; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make(Ex, Global, /*is_array=*/true); + return make("std::nullptr_t"); + + // ::= + case 't': + case 'T': { + Result = parseDecltype(); + break; } - case 'c': { - First += 2; - Node *T = legacyParse(); - if (T == nullptr) - return T; - Node *Ex = parseExpr(); - if (Ex == nullptr) - return Ex; - return make("dynamic_cast", T, Ex); + // extension ::= # starts with Dv + case 'v': { + Result = parseVectorType(); + break; } - case 'e': - First += 2; - return parsePrefixExpr("*"); - case 'l': { + // ::= Dp # pack expansion (C++0x) + case 'p': { First += 2; - Node *E = parseExpr(); - if (E == nullptr) - return E; - return make(E, Global, /*is_array=*/false); + Node *Child = parseType(); + if (!Child) + return nullptr; + Result = make(Child); + break; } - case 'n': { - First++; - return legacyParse(); } - case 's': { - First += 2; - Node *LHS = parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = parseExpr(); - if (RHS == nullptr) + break; + // ::= + case 'F': { + Result = parseFunctionType(); + break; + } + // ::= + case 'A': { + Result = parseArrayType(); + break; + } + // ::= + case 'M': { + Result = parsePointerToMemberType(); + break; + } + // ::= + case 'T': { + Result = legacyParse(); + if (Result == nullptr) + return nullptr; + + // Result could be either of: + // ::= + // ::= + // + // ::= + // ::= + // + // If this is followed by some , and we're permitted to + // parse them, take the second production. + + if (TryToParseTemplateArgs && numLeft() != 0 && *First == 'I') { + Node *TA = legacyParse(); + if (TA == nullptr) return nullptr; - return make(LHS, ".*", RHS); + Result = make(Result, TA); } - case 't': { - First += 2; - Node *LHS = parseExpr(); - if (LHS == nullptr) - return LHS; - Node *RHS = parseExpr(); - if (RHS == nullptr) + break; + } + // ::= P # pointer + case 'P': { + ++First; + Node *Ptr = parseType(); + if (Ptr == nullptr) + return nullptr; + Result = make(Ptr); + break; + } + // ::= R # l-value reference + case 'R': { + ++First; + Node *Ref = parseType(); + if (Ref == nullptr) + return nullptr; + Result = make(Ref); + break; + } + // ::= O # r-value reference (C++11) + case 'O': { + ++First; + Node *Ref = parseType(); + if (Ref == nullptr) + return nullptr; + Result = make(Ref); + break; + } + // ::= C # complex pair (C99) + case 'C': { + ++First; + Node *P = parseType(); + if (P == nullptr) + return nullptr; + Result = make(P, " complex"); + break; + } + // ::= G # imaginary (C99) + case 'G': { + ++First; + Node *P = parseType(); + if (P == nullptr) + return P; + Result = make(P, " imaginary"); + break; + } + // ::= # See Compression below + case 'S': { + if (numLeft() < 2 || First[1] != 't') { + Node *Sub = legacyParse(); + if (Sub == nullptr) return nullptr; - return make(LHS, ".", RHS); + + // Sub could be either of: + // ::= + // ::= + // + // ::= + // ::= + // + // If this is followed by some , and we're permitted to + // parse them, take the second production. + + if (TryToParseTemplateArgs && numLeft() != 0 && *First == 'I') { + Node *TA = legacyParse(); + if (TA == nullptr) + return nullptr; + Result = make(Sub, TA); + break; + } + + // If all we parsed was a substitution, don't re-insert into the + // substitution table. + return Sub; } - case 'v': + _LIBCPP_FALLTHROUGH(); + } + // ::= + default: { + Result = parseClassEnumType(); + break; + } + } + + // If we parsed a type, insert it into the substitution table. Note that all + // s and 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(Kind, E); + // FIXME inline this +} + +Node *Db::parseBinaryExpr(StringView Kind) { + Node *LHS = parseExpr(); + if (LHS == nullptr) + return nullptr; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make(LHS, Kind, RHS); +} + +Node *Db::parseIntegerLiteral(StringView Lit) { + StringView Tmp = parseNumber(true); + if (!Tmp.empty() && consumeIf('E')) + return make(Lit, Tmp); + return nullptr; +} + +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; +} + +// ::= fp _ # L == 0, first parameter +// ::= fp _ # L == 0, second and later parameters +// ::= fL p _ # L > 0, first parameter +// ::= fL p _ # L > 0, second and later parameters +Node *Db::parseFunctionParam() { + if (consumeIf("fp")) { + parseCVQualifiers(); + StringView Num = parseNumber(); + if (!consumeIf('_')) + return nullptr; + return make(Num); + } + if (consumeIf("fL")) { + if (parseNumber().empty()) + return nullptr; + if (!consumeIf('p')) + return nullptr; + parseCVQualifiers(); + StringView Num = parseNumber(); + if (!consumeIf('_')) + return nullptr; + return make(Num); + } + return nullptr; +} + +// [gs] nw * _ E # new (expr-list) type +// [gs] nw * _ # new (expr-list) type (init) +// [gs] na * _ E # new[] (expr-list) type +// [gs] na * _ # new[] (expr-list) type (init) +// ::= pi * E # parenthesized initialization +Node *Db::parseNewExpr() { + bool Global = consumeIf("gs"); + bool IsArray = look(1) == 'w'; + 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(ExprList, Ty, Inits, Global, IsArray); + } + return make(ExprList, Ty, NodeArray(), Global, IsArray); +} + +// cv # conversion with one argument +// cv _ * E # conversion with a different number of arguments +Node *Db::parseConversionExpr() { + if (!consumeIf("cv")) + return nullptr; + Node *Ty; + { + SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); + Ty = parseType(); + } + + if (Ty == nullptr) + return nullptr; + + if (consumeIf('_')) { + size_t ExprsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = parseType(); + if (E == nullptr) + return E; + Names.push_back(E); + } + NodeArray Exprs = popTrailingNodeArray(ExprsBegin); + return make(Ty, Exprs); + } + + Node *E = parseExpr(); + if (E == nullptr) + return nullptr; + return make(Ty, makeNodeArray(&E, &E + 1)); +} + +// ::= L E # integer literal +// ::= L E # floating literal +// ::= L E # string literal +// ::= L E # nullptr literal (i.e., "LDnE") +// FIXME: ::= L _ E # complex floating point literal (C 2000) +// ::= L 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(0); + if (consumeIf("b1E")) + return make(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(); + case 'd': + ++First; + return parseFloatingLiteral(); + case 'e': + ++First; + return parseFloatingLiteral(); + case '_': + if (consumeIf("_Z")) { + Node *R = legacyParse(); + 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(T, N); + } + if (consumeIf('E')) + return T; + return nullptr; + } + } +} + +// ::= +// ::= +// ::= +// ::= cl + E # call +// ::= cv # conversion with one argument +// ::= cv _ * E # conversion with a different number of arguments +// ::= [gs] nw * _ E # new (expr-list) type +// ::= [gs] nw * _ # new (expr-list) type (init) +// ::= [gs] na * _ E # new[] (expr-list) type +// ::= [gs] na * _ # new[] (expr-list) type (init) +// ::= [gs] dl # delete expression +// ::= [gs] da # delete[] expression +// ::= pp_ # prefix ++ +// ::= mm_ # prefix -- +// ::= ti # typeid (type) +// ::= te # typeid (expression) +// ::= dc # dynamic_cast (expression) +// ::= sc # static_cast (expression) +// ::= cc # const_cast (expression) +// ::= rc # reinterpret_cast (expression) +// ::= st # sizeof (a type) +// ::= sz # sizeof (an expression) +// ::= at # alignof (a type) +// ::= az # alignof (an expression) +// ::= nx # noexcept (expression) +// ::= +// ::= +// ::= dt # expr.name +// ::= pt # expr->name +// ::= ds # expr.*expr +// ::= sZ # size of a parameter pack +// ::= sZ # size of a function parameter pack +// ::= sp # pack expansion +// ::= tw # throw expression +// ::= tr # throw with no operand (rethrow) +// ::= # f(p), N::f(p), ::f(p), +// # freestanding dependent name (e.g., T::x), +// # objectless nonstatic member reference +// ::= fL +// ::= fR +// ::= fl +// ::= fr +// ::= +Node *Db::parseExpr() { + bool Global = consumeIf("gs"); + if (numLeft() < 2) + return nullptr; + + switch (*First) { + case 'L': return parseExprPrimary(); + case 'T': return legacyParse(); + case 'f': return parseFunctionParam(); + 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("alignof (", Ty, ")"); + } + case 'z': { + First += 2; + Node *Ty = parseExpr(); + if (Ty == nullptr) + return nullptr; + return make("alignof (", Ty, ")"); + } + } + return nullptr; + case 'c': + switch (First[1]) { + // cc # const_cast (expression) + case 'c': { + First += 2; + Node *Ty = parseType(); + if (Ty == nullptr) + return Ty; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("const_cast", Ty, Ex); + } + // cl + 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(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(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("dynamic_cast", T, Ex); + } + case 'e': + First += 2; + return parsePrefixExpr("*"); + case 'l': { + First += 2; + Node *E = parseExpr(); + if (E == nullptr) + return E; + return make(E, Global, /*is_array=*/false); + } + case 'n': { + First++; + return legacyParse(); + } + case 's': { + First += 2; + Node *LHS = parseExpr(); + if (LHS == nullptr) + return nullptr; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make(LHS, ".*", RHS); + } + case 't': { + First += 2; + Node *LHS = parseExpr(); + if (LHS == nullptr) + return LHS; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make(LHS, ".", RHS); + } + case 'v': First += 2; return parseBinaryExpr("/"); case 'V': @@ -2790,7 +3388,7 @@ switch (First[1]) { case 'c': { First += 2; - Node *T = legacyParse(); + Node *T = parseType(); if (T == nullptr) return T; Node *Ex = parseExpr(); @@ -2816,7 +3414,7 @@ switch (First[1]) { case 'c': { First += 2; - Node *T = legacyParse(); + Node *T = parseType(); if (T == nullptr) return T; Node *Ex = parseExpr(); @@ -2836,7 +3434,7 @@ } case 't': { First += 2; - Node *Ty = legacyParse(); + Node *Ty = parseType(); if (Ty == nullptr) return Ty; return make("sizeof (", Ty, ")"); @@ -2875,7 +3473,7 @@ } case 'i': { First += 2; - Node *Ty = legacyParse(); + Node *Ty = parseType(); if (Ty == nullptr) return Ty; return make("typeid(", Ty, ")"); @@ -3103,224 +3701,45 @@ db.Names.push_back(db.make(SpecialSubKind::ostream)); first += 2; break; - case 'd': - db.Names.push_back(db.make(SpecialSubKind::iostream)); - first += 2; - break; - case '_': - if (!db.Subs.empty()) - { - db.Names.push_back(db.Subs[0]); - first += 2; - } - break; - default: - if (std::isdigit(first[1]) || std::isupper(first[1])) - { - size_t sub = 0; - const char* t = first+1; - if (std::isdigit(*t)) - sub = static_cast(*t - '0'); - else - sub = static_cast(*t - 'A') + 10; - for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) - { - sub *= 36; - if (std::isdigit(*t)) - sub += static_cast(*t - '0'); - else - sub += static_cast(*t - 'A') + 10; - } - if (t == last || *t != '_') - return first; - ++sub; - if (sub < db.Subs.size()) - { - db.Names.push_back(db.Subs[sub]); - first = t+1; - } - } - break; - } - } - } - return first; -} - -// ::= v # void -// ::= w # wchar_t -// ::= b # bool -// ::= c # char -// ::= a # signed char -// ::= h # unsigned char -// ::= s # short -// ::= t # unsigned short -// ::= i # int -// ::= j # unsigned int -// ::= l # long -// ::= m # unsigned long -// ::= x # long long, __int64 -// ::= y # unsigned long long, __int64 -// ::= n # __int128 -// ::= o # unsigned __int128 -// ::= f # float -// ::= d # double -// ::= e # long double, __float80 -// ::= g # __float128 -// ::= z # ellipsis -// ::= Dd # IEEE 754r decimal floating point (64 bits) -// ::= De # IEEE 754r decimal floating point (128 bits) -// ::= Df # IEEE 754r decimal floating point (32 bits) -// ::= Dh # IEEE 754r half-precision floating point (16 bits) -// ::= Di # char32_t -// ::= Ds # char16_t -// ::= Da # auto (in dependent new-expressions) -// ::= Dc # decltype(auto) -// ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) -// ::= u # vendor extended type - -const char* -parse_builtin_type(const char* first, const char* last, Db& db) -{ - if (first != last) - { - switch (*first) - { - case 'v': - db.Names.push_back(db.make("void")); - ++first; - break; - case 'w': - db.Names.push_back(db.make("wchar_t")); - ++first; - break; - case 'b': - db.Names.push_back(db.make("bool")); - ++first; - break; - case 'c': - db.Names.push_back(db.make("char")); - ++first; - break; - case 'a': - db.Names.push_back(db.make("signed char")); - ++first; - break; - case 'h': - db.Names.push_back(db.make("unsigned char")); - ++first; - break; - case 's': - db.Names.push_back(db.make("short")); - ++first; - break; - case 't': - db.Names.push_back(db.make("unsigned short")); - ++first; - break; - case 'i': - db.Names.push_back(db.make("int")); - ++first; - break; - case 'j': - db.Names.push_back(db.make("unsigned int")); - ++first; - break; - case 'l': - db.Names.push_back(db.make("long")); - ++first; - break; - case 'm': - db.Names.push_back(db.make("unsigned long")); - ++first; - break; - case 'x': - db.Names.push_back(db.make("long long")); - ++first; - break; - case 'y': - db.Names.push_back(db.make("unsigned long long")); - ++first; - break; - case 'n': - db.Names.push_back(db.make("__int128")); - ++first; - break; - case 'o': - db.Names.push_back(db.make("unsigned __int128")); - ++first; - break; - case 'f': - db.Names.push_back(db.make("float")); - ++first; - break; - case 'd': - db.Names.push_back(db.make("double")); - ++first; - break; - case 'e': - db.Names.push_back(db.make("long double")); - ++first; - break; - case 'g': - db.Names.push_back(db.make("__float128")); - ++first; - break; - case 'z': - db.Names.push_back(db.make("...")); - ++first; - break; - case 'u': - { - const char*t = parse_source_name(first+1, last, db); - if (t != first+1) - first = t; - } - break; - case 'D': - if (first+1 != last) - { - switch (first[1]) + case 'd': + db.Names.push_back(db.make(SpecialSubKind::iostream)); + first += 2; + break; + case '_': + if (!db.Subs.empty()) { - case 'd': - db.Names.push_back(db.make("decimal64")); - first += 2; - break; - case 'e': - db.Names.push_back(db.make("decimal128")); - first += 2; - break; - case 'f': - db.Names.push_back(db.make("decimal32")); - first += 2; - break; - case 'h': - db.Names.push_back(db.make("decimal16")); - first += 2; - break; - case 'i': - db.Names.push_back(db.make("char32_t")); - first += 2; - break; - case 's': - db.Names.push_back(db.make("char16_t")); - first += 2; - break; - case 'a': - db.Names.push_back(db.make("auto")); - first += 2; - break; - case 'c': - db.Names.push_back(db.make("decltype(auto)")); - first += 2; - break; - case 'n': - db.Names.push_back(db.make("std::nullptr_t")); + db.Names.push_back(db.Subs[0]); first += 2; - break; } + break; + default: + if (std::isdigit(first[1]) || std::isupper(first[1])) + { + size_t sub = 0; + const char* t = first+1; + if (std::isdigit(*t)) + sub = static_cast(*t - '0'); + else + sub = static_cast(*t - 'A') + 10; + for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) + { + sub *= 36; + if (std::isdigit(*t)) + sub += static_cast(*t - '0'); + else + sub += static_cast(*t - 'A') + 10; + } + if (t == last || *t != '_') + return first; + ++sub; + if (sub < db.Subs.size()) + { + db.Names.push_back(db.Subs[sub]); + first = t+1; + } + } + break; } - break; } } return first; @@ -3644,742 +4063,121 @@ t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.Names.size() < 2) - return first; - auto args = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make( - db.Names.back(), args); - t = t1; - if (t == last) - { - db.Names.pop_back(); - return first; - } - } - while (*t != 'E') - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.Names.size() < 2) - return first; - auto s = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make(db.Names.back(), s); - t = t1; - } - ++t; - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.Names.empty()) - db.Names.pop_back(); - return first; - } - if (db.Names.size() < 2) - return first; - auto s = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make(db.Names.back(), s); - first = t1; - } - else - { - t += 2; - const char* t1 = parse_unresolved_type(t, last, db); - if (t1 != t) - { - t = t1; - t1 = parse_template_args(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto args = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make( - db.Names.back(), args); - t = t1; - } - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.Names.empty()) - db.Names.pop_back(); - return first; - } - if (db.Names.size() < 2) - return first; - auto s = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make(db.Names.back(), s); - first = t1; - } - else - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - if (global) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make( - db.Names.back()); - } - while (*t != 'E') - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.Names.size() < 2) - return first; - auto s = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make( - db.Names.back(), s); - t = t1; - } - ++t; - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.Names.empty()) - db.Names.pop_back(); - return first; - } - if (db.Names.size() < 2) - return first; - auto s = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make(db.Names.back(), s); - first = t1; - } - } - } - } - return first; -} - -// ::= R # & ref-qualifier -// ::= O # && ref-qualifier - -// ::= F [Y] [] E - -const char* -parse_function_type(const char* first, const char* last, Db& db) -{ - if (first != last && *first == 'F') - { - const char* t = first+1; - if (t != last) - { - if (*t == 'Y') - { - /* extern "C" */ - if (++t == last) - return first; - } - const char* t1 = parse_type(t, last, db); - if (t1 != t && !db.Names.empty()) - { - Node* ret_type = db.Names.back(); - db.Names.pop_back(); - size_t params_begin = db.Names.size(); - t = t1; - FunctionRefQual RefQuals = FrefQualNone; - while (true) - { - if (t == last) - { - if (!db.Names.empty()) - db.Names.pop_back(); - return first; - } - if (*t == 'E') - { - ++t; - break; - } - if (*t == 'v') - { - ++t; - continue; - } - if (*t == 'R' && t+1 != last && t[1] == 'E') - { - RefQuals = FrefQualLValue; - ++t; - continue; - } - if (*t == 'O' && t+1 != last && t[1] == 'E') - { - RefQuals = FrefQualRValue; - ++t; - continue; - } - size_t k0 = db.Names.size(); - t1 = parse_type(t, last, db); - size_t k1 = db.Names.size(); - if (t1 == t || t1 == last || k1 < k0) - return first; - t = t1; - } - if (db.Names.empty() || params_begin > db.Names.size()) - return first; - Node* fty = db.make( - ret_type, db.popTrailingNodeArray(params_begin)); - if (RefQuals) - fty = db.make(fty, RefQuals); - db.Names.push_back(fty); - first = t; - } - } - } - return first; -} - -// ::= M - -const char* -parse_pointer_to_member_type(const char* first, const char* last, Db& db) -{ - if (first != last && *first == 'M') - { - const char* t = parse_type(first+1, last, db); - if (t != first+1) - { - const char* t2 = parse_type(t, last, db); - if (t2 != t) - { - if (db.Names.size() < 2) - return first; - auto func = std::move(db.Names.back()); - db.Names.pop_back(); - auto ClassType = std::move(db.Names.back()); - db.Names.back() = - db.make(ClassType, func); - first = t2; - } - } - } - return first; -} - -// ::= A _ -// ::= A [] _ - -const char* -parse_array_type(const char* first, const char* last, Db& db) -{ - if (first != last && *first == 'A' && first+1 != last) - { - if (first[1] == '_') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make(db.Names.back()); - first = t; - } - } - else if ('1' <= first[1] && first[1] <= '9') - { - const char* t = parse_number(first+1, last); - if (t != last && *t == '_') - { - const char* t2 = parse_type(t+1, last, db); - if (t2 != t+1) - { - if (db.Names.empty()) + if (db.Names.size() < 2) return first; - db.Names.back() = - db.make(db.Names.back(), - StringView(first + 1, t)); - first = t2; + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make( + db.Names.back(), args); + t = t1; + if (t == last) + { + db.Names.pop_back(); + return first; + } } - } - } - else - { - const char* t = parse_expression(first+1, last, db); - if (t != first+1 && t != last && *t == '_') - { - const char* t2 = parse_type(++t, last, db); - if (t2 != t) + while (*t != 'E') { - if (db.Names.size() < 2) + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last || db.Names.size() < 2) return first; - auto base_type = std::move(db.Names.back()); + auto s = db.Names.back(); db.Names.pop_back(); - auto dimension_expr = std::move(db.Names.back()); db.Names.back() = - db.make(base_type, dimension_expr); - first = t2; + db.make(db.Names.back(), s); + t = t1; } - } - } - } - return first; -} - -// ::= Dt E # decltype of an id-expression or class member access (C++0x) -// ::= DT E # decltype of an expression (C++0x) - -const char* -parse_decltype(const char* first, const char* last, Db& db) -{ - if (last - first >= 4 && first[0] == 'D') - { - switch (first[1]) - { - case 't': - case 'T': - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2 && t != last && *t == 'E') + ++t; + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "decltype(", db.Names.back(), ")"); - first = t+1; + if (!db.Names.empty()) + db.Names.pop_back(); + return first; } + if (db.Names.size() < 2) + return first; + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make(db.Names.back(), s); + first = t1; } - break; - } - } - return first; -} - -// extension: -// ::= Dv _ -// -// ::= Dv [] _ -// ::= -// ::= p # AltiVec vector pixel - -const char* -parse_vector_type(const char* first, const char* last, Db& db) -{ - if (last - first > 3 && first[0] == 'D' && first[1] == 'v') - { - if ('1' <= first[2] && first[2] <= '9') - { - const char* t = parse_number(first+2, last); - if (t == last || *t != '_') - return first; - const char* num = first + 2; - size_t sz = static_cast(t - num); - if (++t != last) + else { - if (*t != 'p') + t += 2; + const char* t1 = parse_unresolved_type(t, last, db); + if (t1 != t) { - const char* t1 = parse_type(t, last, db); + t = t1; + t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.Names.empty()) + if (db.Names.size() < 2) return first; + auto args = db.Names.back(); + db.Names.pop_back(); db.Names.back() = - db.make(db.Names.back(), - StringView(num, num + sz)); - first = t1; + db.make( + db.Names.back(), args); + t = t1; } - } - else - { - ++t; - db.Names.push_back( - db.make(StringView(num, num + sz))); - first = t; - } - } - } - else - { - Node* num = nullptr; - const char* t1 = first+2; - if (*t1 != '_') - { - const char* t = parse_expression(t1, last, db); - if (t != t1) - { - if (db.Names.empty()) + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) + { + if (!db.Names.empty()) + db.Names.pop_back(); + return first; + } + if (db.Names.size() < 2) return first; - num = db.Names.back(); + auto s = db.Names.back(); db.Names.pop_back(); - t1 = t; + db.Names.back() = + db.make(db.Names.back(), s); + first = t1; } - } - if (t1 != last && *t1 == '_' && ++t1 != last) - { - const char* t = parse_type(t1, last, db); - if (t != t1) + else { - if (db.Names.empty()) + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last) return first; - if (num) - db.Names.back() = - db.make(db.Names.back(), num); - else + t = t1; + if (global) + { + if (db.Names.empty()) + return first; db.Names.back() = - db.make(db.Names.back(), StringView()); - first = t; - } else if (num) - db.Names.push_back(num); - } - } - } - return first; -} - -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= P # pointer-to -// ::= R # reference-to -// ::= O # rvalue reference-to (C++0x) -// ::= C # complex pair (C 2000) -// ::= G # imaginary (C 2000) -// ::= Dp # pack expansion (C++0x) -// ::= U # vendor extended type qualifier -// extension := U # objc-type -// extension := # starts with Dv - -// ::= objcproto # k0 = 9 + + k1 -// := # PU<11+>objcproto 11objc_object 11objc_object -> id - -const char* -parse_type(const char* first, const char* last, Db& db) -{ - if (first != last) - { - switch (*first) - { - case 'r': - case 'V': - case 'K': - { - Qualifiers cv = QualNone; - const char* t = parse_cv_qualifiers(first, last, cv); - if (t != first) - { - bool is_function = *t == 'F'; - size_t k0 = db.Names.size(); - const char* t1 = parse_type(t, last, db); - size_t k1 = db.Names.size(); - if (t1 != t && k0 + 1 == k1) + db.make( + db.Names.back()); + } + while (*t != 'E') { - if (is_function) - db.Subs.pop_back(); - if (cv) - { - if (is_function) - db.Names.back() = db.make( - db.Names.back(), cv); - else - db.Names.back() = - db.make(db.Names.back(), cv); - } - db.Subs.push_back(db.Names.back()); - first = t1; + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last || db.Names.size() < 2) + return first; + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make( + db.Names.back(), s); + t = t1; } - } - } - break; - default: - { - const char* t = parse_builtin_type(first, last, db); - if (t != first) - { - first = t; - } - else - { - switch (*first) + ++t; + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) { - case 'A': - t = parse_array_type(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - first = t; - db.Subs.push_back(db.Names.back()); - } - break; - case 'C': - t = parse_type(first+1, last, db); - if (t != first+1) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - db.Names.back(), " complex"); - first = t; - db.Subs.push_back(db.Names.back()); - } - break; - case 'F': - t = parse_function_type(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - first = t; - db.Subs.push_back(db.Names.back()); - } - break; - case 'G': - t = parse_type(first+1, last, db); - if (t != first+1) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - db.Names.back(), " imaginary"); - first = t; - db.Subs.push_back(db.Names.back()); - } - break; - case 'M': - t = parse_pointer_to_member_type(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - first = t; - db.Subs.push_back(db.Names.back()); - } - break; - case 'O': - { - size_t k0 = db.Names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.Names.size(); - if (t != first+1 || k0 + 1 == k1) - { - db.Names.back() = - db.make(db.Names.back()); - db.Subs.push_back(db.Names.back()); - first = t; - } - break; - } - case 'P': - { - size_t k0 = db.Names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.Names.size(); - if (t != first+1 && k0 + 1 == k1) - { - db.Names.back() = db.make(db.Names.back()); - db.Subs.push_back(db.Names.back()); - first = t; - } - break; - } - case 'R': - { - size_t k0 = db.Names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.Names.size(); - if (t != first+1 && k0 + 1 == k1) - { - db.Names.back() = - db.make(db.Names.back()); - db.Subs.push_back(db.Names.back()); - first = t; - } - break; - } - case 'T': - { - size_t k0 = db.Names.size(); - t = parse_template_param(first, last, db); - size_t k1 = db.Names.size(); - if (t != first && k0 + 1 == k1) - { - db.Subs.push_back(db.Names.back()); - if (db.TryToParseTemplateArgs && k1 == k0+1) - { - const char* t1 = parse_template_args(t, last, db); - if (t1 != t) - { - auto args = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make< - NameWithTemplateArgs>( - db.Names.back(), args); - db.Subs.push_back(db.Names.back()); - t = t1; - } - } - first = t; - } - break; - } - case 'U': - if (first+1 != last) - { - t = parse_source_name(first+1, last, db); - if (t != first+1) - { - const char* t2 = parse_type(t, last, db); - if (t2 != t) - { - if (db.Names.size() < 2) - return first; - auto type = db.Names.back(); - db.Names.pop_back(); - if (db.Names.back()->K != Node::KNameType || - !static_cast(db.Names.back())->getName().startsWith("objcproto")) - { - db.Names.back() = db.make(type, db.Names.back()); - } - else - { - auto* proto = static_cast(db.Names.back()); - db.Names.pop_back(); - t = parse_source_name(proto->getName().begin() + 9, proto->getName().end(), db); - if (t != proto->getName().begin() + 9) - { - db.Names.back() = db.make(type, db.Names.back()); - } - else - { - db.Names.push_back(db.make(type, proto)); - } - } - db.Subs.push_back(db.Names.back()); - first = t2; - } - } - } - break; - case 'S': - if (first+1 != last && first[1] == 't') - { - t = parse_name(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - db.Subs.push_back(db.Names.back()); - first = t; - } - } - else - { - t = parse_substitution(first, last, db); - if (t != first) - { - first = t; - // Parsed a substitution. If the substitution is a - // it might be followed by . - if (db.TryToParseTemplateArgs) - { - t = parse_template_args(first, last, db); - if (t != first) - { - if (db.Names.size() < 2) - return first; - auto template_args = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make< - NameWithTemplateArgs>( - db.Names.back(), template_args); - // Need to create substitution for - db.Subs.push_back(db.Names.back()); - first = t; - } - } - } - } - break; - case 'D': - if (first+1 != last) - { - switch (first[1]) - { - case 'p': - { - size_t k0 = db.Names.size(); - t = parse_type(first+2, last, db); - size_t k1 = db.Names.size(); - if (t != first+2 && k0 + 1 == k1) - { - db.Names.back() = - db.make( - db.Names.back()); - db.Subs.push_back(db.Names.back()); - first = t; - return first; - } - break; - } - case 't': - case 'T': - t = parse_decltype(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - db.Subs.push_back(db.Names.back()); - first = t; - return first; - } - break; - case 'v': - t = parse_vector_type(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - db.Subs.push_back(db.Names.back()); - first = t; - return first; - } - break; - } - } - _LIBCPP_FALLTHROUGH(); - default: - // must check for builtin-types before class-enum-types to avoid - // ambiguities with operator-names - t = parse_builtin_type(first, last, db); - if (t != first) - { - first = t; - } - else - { - t = parse_name(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - db.Subs.push_back(db.Names.back()); - first = t; - } - } - break; + if (!db.Names.empty()) + db.Names.pop_back(); + return first; } - } - break; + if (db.Names.size() < 2) + return first; + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make(db.Names.back(), s); + first = t1; + } } } } Index: test/test_demangle.pass.cpp =================================================================== --- test/test_demangle.pass.cpp +++ test/test_demangle.pass.cpp @@ -29617,6 +29617,9 @@ {"_Z1fIJicEEvDp7MuncherIAstT__S1_E", "void f(Muncher, Muncher)"}, {"_ZN1SIJifcEE1fIJdjEEEiDp4MerpIJifcT_EE", "int S::f(Merp, Merp)"}, {"_Z1pIJicEEiDp4MerpIXsZT_EJT_EE", "int p(Merp, Merp)"}, + + // Multiple qualifiers on the same type should all get the same entry in the substitution table. + {"_Z1fPU3AS1KiS0_", "f(int const AS1*, int const AS1*)"} }; const unsigned N = sizeof(cases) / sizeof(cases[0]);