Index: src/cxa_demangle.cpp =================================================================== --- src/cxa_demangle.cpp +++ src/cxa_demangle.cpp @@ -340,20 +340,17 @@ class VendorExtQualType final : public Node { const Node *Ty; - const Node *Ext; + StringView Ext; public: - VendorExtQualType(Node *Ty_, Node *Ext_) - : Node(KVendorExtQualType, - std::min(Ty_->ParameterPackSize, Ext_->ParameterPackSize)), + VendorExtQualType(Node *Ty_, StringView Ext_) + : Node(KVendorExtQualType, Ty_->ParameterPackSize), Ty(Ty_), Ext(Ext_) {} - const Node* getQual() const { return Ext; } - void printLeft(OutputStream &S) const override { Ty->print(S); S += " "; - Ext->print(S); + S += Ext; } }; @@ -465,12 +462,12 @@ class ObjCProtoName : public Node { Node *Ty; - Node *Protocol; + StringView Protocol; friend class PointerType; public: - ObjCProtoName(Node *Ty_, Node *Protocol_) + ObjCProtoName(Node *Ty_, StringView Protocol_) : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} bool isObjCObject() const { @@ -481,7 +478,7 @@ void printLeft(OutputStream &S) const override { Ty->print(S); S += "<"; - Protocol->print(S); + S += Protocol; S += ">"; } }; @@ -512,7 +509,7 @@ } else { const auto *objcProto = static_cast(Pointee); s += "id<"; - objcProto->Protocol->print(s); + s += objcProto->Protocol; s += ">"; } } @@ -1958,6 +1955,8 @@ StringView parseNumber(bool AllowNegative = false); Qualifiers parseCVQualifiers(); + bool parsePositiveInteger(size_t *Out); + StringView parseBareSourceName(); /// Parse the production. Node *parseExpr(); @@ -1970,6 +1969,15 @@ Node *parseNewExpr(); Node *parseConversionExpr(); + /// Parse the production. + Node *parseType(); + Node *parseFunctionType(); + Node *parseVectorType(); + Node *parseDecltype(); + Node *parseArrayType(); + Node *parsePointerToMemberType(); + Node *parseClassEnumType(); + // FIXME: remove this when all the parse_* functions have been rewritten. template Node *legacyParse() { @@ -1983,6 +1991,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 *parse_expression(const char *first, const char *last, Db &db) { @@ -2005,6 +2025,26 @@ return db.First; } +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_type(const char *first, const char *last, Db &db); const char *parse_encoding(const char *first, const char *last, Db &db); const char *parse_name(const char *first, const char *last, Db &db, @@ -2015,6 +2055,7 @@ 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) { @@ -2028,6 +2069,541 @@ return StringView(Tmp, First); } +// ::= [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; +} + +StringView Db::parseBareSourceName() { + size_t Int = 0; + if (parsePositiveInteger(&Int) || numLeft() < Int) + return StringView(); + StringView R(First, First + Int); + First += Int; + return R; +} + +// ::= F [Y] [] E +// +// ::= R # & ref-qualifier +// ::= O # && ref-qualifier +Node *Db::parseFunctionType() { + 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); + Node *Fn = make(ReturnType, Params); + if (ReferenceQualifier) + Fn = make(Fn, ReferenceQualifier); + return Fn; +} + +// extension: +// ::= Dv _ +// +// ::= Dv [] _ +// ::= +// ::= 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(DimensionNumber); + Node *ElemType = parseType(); + if (ElemType == nullptr) + return nullptr; + return make(ElemType, DimensionNumber); + } + + if (!consumeIf('_')) { + Node *DimExpr = parseExpr(); + if (!DimExpr) + return nullptr; + if (!consumeIf('_')) + return nullptr; + Node *ElemType = parseType(); + if (!ElemType) + return nullptr; + return make(ElemType, DimExpr); + } + + return nullptr; +} + +// ::= 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; + if (!consumeIf('t') && !consumeIf('T')) + return nullptr; + Node *E = parseExpr(); + if (E == nullptr) + return nullptr; + if (!consumeIf('E')) + return nullptr; + return make("decltype(", E, ")"); +} + +// ::= A _ +// ::= A [] _ +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(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); +} + +// ::= 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); +} + +// ::= # 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 (look()) { + // ::= + case 'r': + case 'V': + case 'K': { + Qualifiers Q = parseCVQualifiers(); + bool AppliesToFunction = look() == 'F'; + + Node *Child = parseType(); + if (Child == nullptr) + return nullptr; + + if (AppliesToFunction) + Result = make(Child, Q); + else + Result = make(Child, Q); + + // Itanium C++ ABI 5.1.5.3: + // For the purposes of substitution, the CV-qualifiers and ref-qualifier + // of a function type are an indivisible part of the type. + if (AppliesToFunction) + return Result; + break; + } + // ::= U [] # vendor extended type qualifier + case 'U': { + // FIXME: We should fold this into the cvr qualifier parsing above. This + // currently adds too many entries into the substitution table if multiple + // qualifiers are present on the same type, as all the qualifiers on a type + // should just get one entry in the substitution table. + ++First; + StringView Qual = parseBareSourceName(); + if (Qual.empty()) + return nullptr; + + // FIXME parse the optional here! + + Result = parseType(); + if (Result == nullptr) + return nullptr; + + // extension ::= U # objc-type + if (Qual.startsWith("objcproto")) { + StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); + StringView Proto; + { + SwapAndRestore SaveFirst(First, ProtoSourceName.begin()), + SaveLast(Last, ProtoSourceName.end()); + Proto = parseBareSourceName(); + } + if (Proto.empty()) + return nullptr; + Result = make(Result, Proto); + } else + Result = make(Result, Qual); + 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 make("char"); + // ::= a # signed char + case 'a': + ++First; + return make("signed char"); + // ::= h # unsigned char + case 'h': + ++First; + return make("unsigned char"); + // ::= s # short + case 's': + ++First; + return make("short"); + // ::= t # unsigned short + case 't': + ++First; + return make("unsigned short"); + // ::= i # int + case 'i': + ++First; + return make("int"); + // ::= j # unsigned int + case 'j': + ++First; + return make("unsigned int"); + // ::= l # long + case 'l': + ++First; + return make("long"); + // ::= m # unsigned long + case 'm': + ++First; + return make("unsigned long"); + // ::= x # long long, __int64 + case 'x': + ++First; + return make("long long"); + // ::= y # unsigned long long, __int64 + case 'y': + ++First; + return make("unsigned long long"); + // ::= n # __int128 + case 'n': + ++First; + return make("__int128"); + // ::= o # unsigned __int128 + case 'o': + ++First; + return make("unsigned __int128"); + // ::= f # float + case 'f': + ++First; + return make("float"); + // ::= d # double + case 'd': + ++First; + return make("double"); + // ::= e # long double, __float80 + case 'e': + ++First; + 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; + return make(Res); + } + case 'D': + switch (look(1)) { + // ::= Dd # IEEE 754r decimal floating point (64 bits) + case 'd': + First += 2; + return make("decimal64"); + // ::= De # IEEE 754r decimal floating point (128 bits) + case 'e': + First += 2; + return make("decimal128"); + // ::= Df # IEEE 754r decimal floating point (32 bits) + case 'f': + First += 2; + return make("decimal32"); + // ::= Dh # IEEE 754r half-precision floating point (16 bits) + case 'h': + First += 2; + return make("decimal16"); + // ::= Di # char32_t + case 'i': + First += 2; + return make("char32_t"); + // ::= Ds # char16_t + case 's': + First += 2; + return make("char16_t"); + // ::= Da # auto (in dependent new-expressions) + case 'a': + First += 2; + return make("auto"); + // ::= Dc # decltype(auto) + case 'c': + First += 2; + return make("decltype(auto)"); + // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) + case 'n': + First += 2; + return make("std::nullptr_t"); + + // ::= + case 't': + case 'T': { + Result = parseDecltype(); + break; + } + // extension ::= # starts with Dv + case 'v': { + Result = parseVectorType(); + break; + } + // ::= Dp # pack expansion (C++0x) + case 'p': { + First += 2; + Node *Child = parseType(); + if (!Child) + return nullptr; + Result = make(Child); + break; + } + } + 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 && look() == 'I') { + Node *TA = legacyParse(); + if (TA == nullptr) + return nullptr; + Result = make(Result, TA); + } + 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 (look(1) && look(1) != 't') { + Node *Sub = legacyParse(); + if (Sub == nullptr) + return nullptr; + + // Sub could be either of: + // ::= + // ::= + // + // ::= + // ::= + // + // If this is followed by some , and we're permitted to + // parse them, take the second production. + + if (TryToParseTemplateArgs && look() == '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; + } + _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) @@ -2107,7 +2683,7 @@ Names.push_back(Ex); } NodeArray ExprList = popTrailingNodeArray(Exprs); - Node *Ty = legacyParse(); + Node *Ty = parseType(); if (Ty == nullptr) return Ty; if (consumeIf("pi")) { @@ -2133,7 +2709,7 @@ Node *Ty; { SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); - Ty = legacyParse(); + Ty = parseType(); } if (Ty == nullptr) @@ -2237,7 +2813,7 @@ return nullptr; default: { // might be named type - Node *T = legacyParse(); + Node *T = parseType(); if (T == nullptr) return nullptr; StringView N = parseNumber(); @@ -2327,7 +2903,7 @@ return parseBinaryExpr("="); case 't': { First += 2; - Node *Ty = legacyParse(); + Node *Ty = parseType(); if (Ty == nullptr) return nullptr; return make("alignof (", Ty, ")"); @@ -2346,7 +2922,7 @@ // cc # const_cast(expression) case 'c': { First += 2; - Node *Ty = legacyParse(); + Node *Ty = parseType(); if (Ty == nullptr) return Ty; Node *Ex = parseExpr(); @@ -2390,7 +2966,7 @@ } case 'c': { First += 2; - Node *T = legacyParse(); + Node *T = parseType(); if (T == nullptr) return T; Node *Ex = parseExpr(); @@ -2599,7 +3175,7 @@ switch (First[1]) { case 'c': { First += 2; - Node *T = legacyParse(); + Node *T = parseType(); if (T == nullptr) return T; Node *Ex = parseExpr(); @@ -2625,7 +3201,7 @@ switch (First[1]) { case 'c': { First += 2; - Node *T = legacyParse(); + Node *T = parseType(); if (T == nullptr) return T; Node *Ex = parseExpr(); @@ -2644,7 +3220,7 @@ return legacyParse(); case 't': { First += 2; - Node *Ty = legacyParse(); + Node *Ty = parseType(); if (Ty == nullptr) return Ty; return make("sizeof (", Ty, ")"); @@ -2683,7 +3259,7 @@ } case 'i': { First += 2; - Node *Ty = legacyParse(); + Node *Ty = parseType(); if (Ty == nullptr) return Ty; return make("typeid (", Ty, ")"); @@ -2953,185 +3529,6 @@ 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("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")); - first += 2; - break; - } - } - break; - } - } - return first; -} - // ::= [r] [V] [K] const char* @@ -3571,627 +3968,6 @@ 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()) - return first; - db.Names.back() = - db.make(db.Names.back(), - StringView(first + 1, t)); - first = t2; - } - } - } - 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) - { - if (db.Names.size() < 2) - return first; - auto base_type = std::move(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; - } - } - } - } - 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') - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "decltype(", db.Names.back(), ")"); - first = t+1; - } - } - 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) - { - if (*t != 'p') - { - const char* t1 = parse_type(t, last, db); - if (t1 != t) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make(db.Names.back(), - StringView(num, num + sz)); - first = 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()) - return first; - num = db.Names.back(); - db.Names.pop_back(); - t1 = t; - } - } - if (t1 != last && *t1 == '_' && ++t1 != last) - { - const char* t = parse_type(t1, last, db); - if (t != t1) - { - if (db.Names.empty()) - return first; - if (num) - db.Names.back() = - db.make(db.Names.back(), num); - else - 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) - { - 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; - } - } - } - break; - default: - { - const char* t = parse_builtin_type(first, last, db); - if (t != first) - { - first = t; - } - else - { - switch (*first) - { - 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; - } - } - break; - } - } - } - return first; -} - // // ::= aa # && // ::= ad # & (unary)