Index: libcxxabi/trunk/src/cxa_demangle.cpp =================================================================== --- libcxxabi/trunk/src/cxa_demangle.cpp +++ libcxxabi/trunk/src/cxa_demangle.cpp @@ -1522,6 +1522,7 @@ S += "new"; if (IsArray) S += "[]"; + S += ' '; if (!ExprList.empty()) { S += "("; ExprList.printWithComma(S); @@ -1879,67 +1880,839 @@ } }; -struct Db -{ - // Name stack, this is used by the parser to hold temporary names that were - // parsed. The parser colapses multiple names into new nodes to construct - // the AST. Once the parser is finished, names.size() == 1. - PODSmallVector Names; +struct Db { + const char *First; + const char *Last; - // Substitution table. Itanium supports name substitutions as a means of - // compression. The string "S42_" refers to the 44nd entry (base-36) in this - // table. - PODSmallVector Subs; + // Name stack, this is used by the parser to hold temporary names that were + // parsed. The parser colapses multiple names into new nodes to construct + // the AST. Once the parser is finished, names.size() == 1. + PODSmallVector Names; + + // Substitution table. Itanium supports name substitutions as a means of + // compression. The string "S42_" refers to the 44nd entry (base-36) in this + // table. + PODSmallVector Subs; + + // 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 TemplateParams; + + Qualifiers CV = QualNone; + FunctionRefQual RefQuals = FrefQualNone; + unsigned EncodingDepth = 0; + bool ParsedCtorDtorCV = false; + bool TagTemplates = true; + bool FixForwardReferences = false; + bool TryToParseTemplateArgs = true; + + BumpPointerAllocator ASTAllocator; + + template T *make(Args &&... args) { + return new (ASTAllocator.allocate(sizeof(T))) + T(std::forward(args)...); + } + + template NodeArray makeNodeArray(It begin, It end) { + size_t sz = static_cast(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(Last - First) <= Lookahead) + return '\0'; + return First[Lookahead]; + } + + size_t numLeft() const { return static_cast(Last - First); } + + StringView parseNumber(bool AllowNegative = false); + Qualifiers parseCVQualifiers(); + + /// Parse the production. + Node *parseExpr(); + Node *parsePrefixExpr(StringView Kind); + Node *parseBinaryExpr(StringView Kind); + Node *parseIntegerLiteral(StringView Lit); + Node *parseExprPrimary(); + template Node *parseFloatingLiteral(); + Node *parseFunctionParam(); + Node *parseNewExpr(); + Node *parseConversionExpr(); + + // FIXME: remove this when all the parse_* functions have been rewritten. + template + Node *legacyParse() { + size_t BeforeType = Names.size(); + const char *OrigFirst = First; + const char *T = parse_fn(First, Last, *this); + 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) { + db.First = first; + db.Last = last; + Node *R = db.parseExpr(); + if (R == nullptr) + return first; + db.Names.push_back(R); + return db.First; +} + +const char *parse_expr_primary(const char *first, const char *last, Db &db) { + db.First = first; + db.Last = last; + Node *R = db.parseExprPrimary(); + 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, + bool *ends_with_template_args = 0); +const char *parse_template_args(const char *first, const char *last, Db &db); +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 &); - // 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 TemplateParams; +// ::= [n] +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); +} + +Node *Db::parsePrefixExpr(StringView Kind) { + Node *E = parseExpr(); + if (E == nullptr) + return nullptr; + return make(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(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; +} - Qualifiers CV = QualNone; - FunctionRefQual RefQuals = FrefQualNone; - unsigned EncodingDepth = 0; - bool ParsedCtorDtorCV = false; - bool TagTemplates = true; - bool FixForwardReferences = false; - bool TryToParseTemplateArgs = true; +// ::= 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; +} - BumpPointerAllocator ASTAllocator; +// [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) == '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 = 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); + } else if (!consumeIf('E')) + return nullptr; + return make(ExprList, Ty, NodeArray(), Global, IsArray); +} - template T* make(Args&& ...args) - { - return new (ASTAllocator.allocate(sizeof(T))) - T(std::forward(args)...); - } +// 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 = legacyParse(); + } + + 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(Ty, Exprs); + } + + Node *E[1] = {parseExpr()}; + if (E[0] == nullptr) + return nullptr; + return make(Ty, makeNodeArray(E, E + 1)); +} - template NodeArray makeNodeArray(It begin, It end) - { - size_t sz = static_cast(end - begin); - void* mem = ASTAllocator.allocate(sizeof(Node*) * sz); - Node** data = new (mem) Node*[sz]; - std::copy(begin, end, data); - return NodeArray(data, sz); +// ::= 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 = legacyParse(); + 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; + } + } +} - NodeArray popTrailingNodeArray(size_t FromPosition) - { - assert(FromPosition <= Names.size()); - NodeArray res = makeNodeArray( - Names.begin() + (long)FromPosition, Names.end()); - Names.dropBack(FromPosition); - return 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': + 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 = legacyParse(); + if (Ty == nullptr) + return nullptr; + return make("alignof (", Ty, ")"); } -}; - -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, - bool* ends_with_template_args = 0); -const char* parse_expression(const char* first, const char* last, Db& db); -const char* parse_template_args(const char* first, const char* last, Db& 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); + 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 = 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': { + 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 = legacyParse(); + 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': + 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': + 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': + if (First[1] == 'x') { + First += 2; + Node *Base = parseExpr(); + if (Base == nullptr) + return nullptr; + Node *Index = parseExpr(); + if (Index == nullptr) + return Index; + return make(Base, Index); + } + 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(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("noexcept (", Ex, ")"); + } + return nullptr; + case 'o': + switch (First[1]) { + case 'n': + return legacyParse(); + 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(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(L, "->", R); + } + } + return nullptr; + case 'q': + if (First[1] == 'u') { + First += 2; + Node *Cond = parseExpr(); + Node *LHS = parseExpr(); + Node *RHS = parseExpr(); + if (Cond && LHS && RHS) + return make(Cond, LHS, RHS); + } + return nullptr; + case 'r': + switch (First[1]) { + case 'c': { + First += 2; + Node *T = legacyParse(); + if (T == nullptr) + return T; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("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 = legacyParse(); + if (T == nullptr) + return T; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("static_cast", T, Ex); + } + case 'p': { + First += 2; + Node *Child = parseExpr(); + if (Child == nullptr) + return nullptr; + return make(Child); + } + case 'r': + return legacyParse(); + case 't': { + First += 2; + Node *Ty = legacyParse(); + if (Ty == nullptr) + return Ty; + return make("sizeof (", Ty, ")"); + } + case 'z': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("sizeof (", Ex, ")"); + } + case 'Z': + First += 2; + if (look() == 'T') { + Node *R = legacyParse(); + if (R == nullptr) + return nullptr; + return make(R); + } else if (look() == 'f') { + Node *FP = parseFunctionParam(); + if (FP == nullptr) + return nullptr; + return make("sizeof...", FP, ")"); + } + return nullptr; + } + return nullptr; + case 't': + switch (First[1]) { + case 'e': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("typeid (", Ex, ")"); + } + case 'i': { + First += 2; + Node *Ty = legacyParse(); + if (Ty == nullptr) + return Ty; + return make("typeid (", Ty, ")"); + } + case 'r': + First += 2; + return make("throw"); + case 'w': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return nullptr; + return make(Ex); + } + } + return nullptr; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return legacyParse(); + } + return nullptr; +} // ::= [n] @@ -2003,32 +2776,23 @@ 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"; + static constexpr const char *spec = "%LaL"; }; -constexpr const char* FloatData::spec; +constexpr const char *FloatData::spec; -template -const char* -parse_floating_number(const char* first, const char* last, Db& db) -{ - const size_t N = FloatData::mangled_size; - if (static_cast(last - first) <= N) - return first; - last = first + N; - const char* t = first; - for (; t != last; ++t) - { - if (!isxdigit(*t)) - return first; - } - if (*t == 'E') - { - db.Names.push_back( - db.make>(StringView(first, t))); - first = t + 1; - } - return first; +template Node *Db::parseFloatingLiteral() { + const size_t N = FloatData::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>(Data); } // ::= [0-9]* @@ -2449,455 +3213,135 @@ return first; } -// cc # const_cast (expression) +// ::= [ ] const char* -parse_const_cast_expr(const char* first, const char* last, Db& db) +parse_simple_id(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') + if (first != last) { - const char* t = parse_type(first+2, last, db); - if (t != first+2) + const char* t = parse_source_name(first, last, db); + if (t != first) { - const char* t1 = parse_expression(t, last, db); + const char* t1 = parse_template_args(t, last, db); if (t1 != t) { if (db.Names.size() < 2) return first; - auto from_expr = db.Names.back(); + auto args = db.Names.back(); db.Names.pop_back(); - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "const_cast", db.Names.back(), from_expr); - first = t1; + db.Names.back() = + db.make(db.Names.back(), args); } + first = t1; } + else + first = t; } return first; } -// dc # dynamic_cast (expression) +// ::= +// ::= +// ::= const char* -parse_dynamic_cast_expr(const char* first, const char* last, Db& db) +parse_unresolved_type(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') + if (first != last) { - const char* t = parse_type(first+2, last, db); - if (t != first+2) + const char* t = first; + switch (*first) { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) + case 'T': + { + size_t k0 = db.Names.size(); + t = parse_template_param(first, last, db); + size_t k1 = db.Names.size(); + if (t != first && k1 == k0 + 1) { - if (db.Names.size() < 2) - return first; - auto from_expr = db.Names.back(); - db.Names.pop_back(); - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "dynamic_cast", db.Names.back(), from_expr); - first = t1; + db.Subs.push_back(db.Names.back()); + first = t; } - } - } - return first; -} - -// rc # reinterpret_cast (expression) - -const char* -parse_reinterpret_cast_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) + else + { + for (; k1 != k0; --k1) + db.Names.pop_back(); + } + break; + } + case 'D': + t = parse_decltype(first, last, db); + if (t != first) { - if (db.Names.size() < 2) - return first; - auto from_expr = db.Names.back(); - db.Names.pop_back(); if (db.Names.empty()) return first; - db.Names.back() = db.make( - "reinterpret_cast", db.Names.back(), from_expr); - first = t1; + db.Subs.push_back(db.Names.back()); + first = t; } - } - } - return first; -} - -// sc # static_cast (expression) - -const char* -parse_static_cast_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) + break; + case 'S': + t = parse_substitution(first, last, db); + if (t != first) + first = t; + else { - if (db.Names.size() < 2) - return first; - auto from_expr = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make( - "static_cast", db.Names.back(), from_expr); - first = t1; + if (last - first > 2 && first[1] == 't') + { + t = parse_unqualified_name(first+2, last, db); + if (t != first+2) + { + if (db.Names.empty()) + return first; + db.Names.back() = + db.make(db.Names.back()); + db.Subs.push_back(db.Names.back()); + first = t; + } + } } - } - } - return first; -} - -// sp # pack expansion - -const char* -parse_pack_expansion(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'p') - { - size_t before = db.Names.size(); - const char* t = parse_expression(first+2, last, db); - if (before + 1 != db.Names.size()) - return first; - if (t != first+2) - first = t; - db.Names.back() = db.make(db.Names.back()); - } - return first; -} - -// st # sizeof (a type) - -const char* -parse_sizeof_type_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 't') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "sizeof (", db.Names.back(), ")"); - first = t; - } + break; + } } return first; } -// sz # sizeof (a expression) +// ::= # e.g., ~T or ~decltype(f()) +// ::= # e.g., ~A<2*N> const char* -parse_sizeof_expr_expr(const char* first, const char* last, Db& db) +parse_destructor_name(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 's' && first[1] == 'z') + if (first != last) { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) + const char* t = parse_unresolved_type(first, last, db); + if (t == first) + t = parse_simple_id(first, last, db); + if (t != first) { if (db.Names.empty()) return first; - db.Names.back() = db.make( - "sizeof (", db.Names.back(), ")"); + db.Names.back() = db.make(db.Names.back()); first = t; } } return first; } -// sZ # size of a parameter pack +// ::= # unresolved name +// extension ::= # unresolved operator-function-id +// extension ::= # unresolved operator template-id +// ::= on # unresolved operator-function-id +// ::= on # unresolved operator template-id +// ::= dn # destructor or pseudo-destructor; +// # e.g. ~X or ~X const char* -parse_sizeof_param_pack_expr(const char* first, const char* last, Db& db) +parse_base_unresolved_name(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') + if (last - first >= 2) { - size_t k0 = db.Names.size(); - const char* t = parse_template_param(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()); - first = t; - } - } - return first; -} - -// ::= 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 - -const char* -parse_function_param(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && *first == 'f') - { - if (first[1] == 'p') - { - Qualifiers cv; - const char* t = parse_cv_qualifiers(first+2, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') - { - db.Names.push_back( - db.make(StringView(t, t1))); - first = t1+1; - } - } - else if (first[1] == 'L') - { - Qualifiers cv; - const char* t0 = parse_number(first+2, last); - if (t0 != last && *t0 == 'p') - { - ++t0; - const char* t = parse_cv_qualifiers(t0, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') - { - db.Names.push_back( - db.make(StringView(t, t1))); - first = t1+1; - } - } - } - } - return first; -} - -// sZ # size of a function parameter pack - -const char* -parse_sizeof_function_param_pack_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') - { - const char* t = parse_function_param(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "sizeof...(", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// te # typeid (expression) -// ti # typeid (type) - -const char* -parse_typeid_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) - { - const char* t; - if (first[1] == 'e') - t = parse_expression(first+2, last, db); - else - t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "typeid(", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// tw # throw expression - -const char* -parse_throw_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 't' && first[1] == 'w') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make(db.Names.back()); - first = t; - } - } - return first; -} - -// ds # expr.*expr - -const char* -parse_dot_star_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 's') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto rhs_expr = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make( - db.Names.back(), ".*", rhs_expr); - first = t1; - } - } - } - return first; -} - -// ::= [ ] - -const char* -parse_simple_id(const char* first, const char* last, Db& db) -{ - if (first != last) - { - const char* t = parse_source_name(first, last, db); - if (t != first) - { - const char* 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); - } - first = t1; - } - else - first = t; - } - return first; -} - -// ::= -// ::= -// ::= - -const char* -parse_unresolved_type(const char* first, const char* last, Db& db) -{ - if (first != last) - { - const char* t = first; - switch (*first) - { - case 'T': - { - size_t k0 = db.Names.size(); - t = parse_template_param(first, last, db); - size_t k1 = db.Names.size(); - if (t != first && k1 == k0 + 1) - { - db.Subs.push_back(db.Names.back()); - first = t; - } - else - { - for (; k1 != k0; --k1) - db.Names.pop_back(); - } - break; - } - case 'D': - t = parse_decltype(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - db.Subs.push_back(db.Names.back()); - first = t; - } - break; - case 'S': - t = parse_substitution(first, last, db); - if (t != first) - first = t; - else - { - if (last - first > 2 && first[1] == 't') - { - t = parse_unqualified_name(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make(db.Names.back()); - db.Subs.push_back(db.Names.back()); - first = t; - } - } - } - break; - } - } - return first; -} - -// ::= # e.g., ~T or ~decltype(f()) -// ::= # e.g., ~A<2*N> - -const char* -parse_destructor_name(const char* first, const char* last, Db& db) -{ - if (first != last) - { - const char* t = parse_unresolved_type(first, last, db); - if (t == first) - t = parse_simple_id(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make(db.Names.back()); - first = t; - } - } - return first; -} - -// ::= # unresolved name -// extension ::= # unresolved operator-function-id -// extension ::= # unresolved operator template-id -// ::= on # unresolved operator-function-id -// ::= on # unresolved operator template-id -// ::= dn # destructor or pseudo-destructor; -// # e.g. ~X or ~X - -const char* -parse_base_unresolved_name(const char* first, const char* last, Db& db) -{ - if (last - first >= 2) - { - if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') + if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') { if (first[0] == 'o') { @@ -3127,233 +3571,23 @@ return first; } -// dt # expr.name +// ::= R # & ref-qualifier +// ::= O # && ref-qualifier + +// ::= F [Y] [] E const char* -parse_dot_expr(const char* first, const char* last, Db& db) +parse_function_type(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 'd' && first[1] == 't') + if (first != last && *first == 'F') { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) + const char* t = first+1; + if (t != last) { - const char* t1 = parse_unresolved_name(t, last, db); - if (t1 != t) + if (*t == 'Y') { - if (db.Names.size() < 2) - return first; - auto name = db.Names.back(); - db.Names.pop_back(); - if (db.Names.empty()) - return first; - db.Names.back() = db.make(db.Names.back(), ".", name); - first = t1; - } - } - } - return first; -} - -// cl + E # call - -const char* -parse_call_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') - { - const char* t = parse_expression(first+2, last, db); - if (t == last || t == first + 2 || db.Names.empty()) - return first; - Node* callee = db.Names.back(); - db.Names.pop_back(); - size_t args_begin = db.Names.size(); - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == last || t1 == t) - return first; - t = t1; - } - if (db.Names.size() < args_begin) - return first; - ++t; - CallExpr* the_call = db.make( - callee, db.popTrailingNodeArray(args_begin)); - db.Names.push_back(the_call); - first = t; - } - return first; -} - -// [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 - -const char* -parse_new_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 4) - { - const char* t = first; - bool parsed_gs = false; - if (t[0] == 'g' && t[1] == 's') - { - t += 2; - parsed_gs = true; - } - if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a')) - { - bool is_array = t[1] == 'a'; - t += 2; - if (t == last) - return first; - size_t first_expr_in_list = db.Names.size(); - NodeArray ExprList, init_list; - while (*t != '_') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - } - if (first_expr_in_list > db.Names.size()) - return first; - ExprList = db.popTrailingNodeArray(first_expr_in_list); - ++t; - const char* t1 = parse_type(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - bool has_init = false; - if (last - t >= 3 && t[0] == 'p' && t[1] == 'i') - { - t += 2; - has_init = true; - size_t init_list_begin = db.Names.size(); - while (*t != 'E') - { - t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - } - if (init_list_begin > db.Names.size()) - return first; - init_list = db.popTrailingNodeArray(init_list_begin); - } - if (*t != 'E' || db.Names.empty()) - return first; - auto type = db.Names.back(); - db.Names.pop_back(); - db.Names.push_back( - db.make(ExprList, type, init_list, - parsed_gs, is_array)); - first = t+1; - } - } - return first; -} - -// cv # conversion with one argument -// cv _ * E # conversion with a different number of arguments - -const char* -parse_conversion_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') - { - bool TryToParseTemplateArgs = db.TryToParseTemplateArgs; - db.TryToParseTemplateArgs = false; - size_t type_index = db.Names.size(); - const char* t = parse_type(first+2, last, db); - db.TryToParseTemplateArgs = TryToParseTemplateArgs; - if (t != first+2 && t != last) - { - size_t expr_list_begin = db.Names.size(); - if (*t != '_') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t) - return first; - t = t1; - } - else - { - ++t; - if (t == last) - return first; - if (*t != 'E') - { - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - } - } - ++t; - } - if (db.Names.size() < expr_list_begin || - type_index + 1 != expr_list_begin) - return first; - NodeArray expressions = db.makeNodeArray( - db.Names.begin() + (long)expr_list_begin, db.Names.end()); - auto* conv_expr = db.make( - db.Names[type_index], expressions); - db.Names.dropBack(type_index); - db.Names.push_back(conv_expr); - first = t; - } - } - return first; -} - -// pt # expr->name - -const char* -parse_arrow_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'p' && first[1] == 't') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto tmp = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make( - db.Names.back(), "->", tmp); - 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) + /* extern "C" */ + if (++t == last) return first; } const char* t1 = parse_type(t, last, db); @@ -4317,344 +4551,137 @@ return first; } -const char* -parse_integer_literal(const char* first, const char* last, StringView lit, Db& db) +Node* maybe_change_special_sub_name(Node* inp, Db& db) { - const char* t = parse_number(first, last); - if (t != first && t != last && *t == 'E') + if (inp->K != Node::KSpecialSubstitution) + return inp; + auto Kind = static_cast(inp)->SSK; + switch (Kind) { - db.Names.push_back( - db.make(lit, StringView(first, t))); - first = t+1; + case SpecialSubKind::string: + case SpecialSubKind::istream: + case SpecialSubKind::ostream: + case SpecialSubKind::iostream: + return db.make(Kind); + default: + break; } - return first; + return inp; } -// ::= L E # integer literal -// ::= L E # floating literal -// ::= L E # string literal -// ::= L E # nullptr literal (i.e., "LDnE") -// ::= L _ E # complex floating point literal (C 2000) -// ::= L E # external 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 # ? +// extension ::= const char* -parse_expr_primary(const char* first, const char* last, Db& db) +parse_ctor_dtor_name(const char* first, const char* last, Db& db) { - if (last - first >= 4 && *first == 'L') + if (last-first >= 2 && !db.Names.empty()) { - switch (first[1]) + switch (first[0]) { - case 'w': + case 'C': + switch (first[1]) { - const char* t = parse_integer_literal(first+2, last, "wchar_t", db); - if (t != first+2) - first = t; + case '1': + case '2': + case '3': + case '5': + if (db.Names.empty()) + return first; + db.Names.back() = + maybe_change_special_sub_name(db.Names.back(), db); + db.Names.push_back( + db.make(db.Names.back(), false)); + first += 2; + first = parse_abi_tag_seq(first, last, db); + db.ParsedCtorDtorCV = true; + break; } break; - case 'b': - if (first[3] == 'E') + case 'D': + switch (first[1]) { - switch (first[2]) - { - case '0': - db.Names.push_back(db.make(0)); - first += 4; - break; - case '1': - db.Names.push_back(db.make(1)); - first += 4; - break; - } + case '0': + case '1': + case '2': + case '5': + if (db.Names.empty()) + return first; + db.Names.push_back( + db.make(db.Names.back(), true)); + first += 2; + first = parse_abi_tag_seq(first, last, db); + db.ParsedCtorDtorCV = true; + break; } break; - case 'c': + } + } + return first; +} + +// ::= Ut [] _ [] +// ::= +// +// ::= Ul E [ ] _ +// +// ::= + # Parameter types or "v" if the lambda has no parameters +const char* +parse_unnamed_type_name(const char* first, const char* last, Db& db) +{ + if (last - first > 2 && first[0] == 'U') + { + char type = first[1]; + switch (type) + { + case 't': + { + const char* t0 = first+2; + if (t0 == last) + return first; + StringView count; + if (std::isdigit(*t0)) { - const char* t = parse_integer_literal(first+2, last, "char", db); - if (t != first+2) - first = t; + const char* t1 = t0 + 1; + while (t1 != last && std::isdigit(*t1)) + ++t1; + count = StringView(t0, t1); + t0 = t1; } + if (t0 == last || *t0 != '_') + return first; + db.Names.push_back(db.make(count)); + first = t0 + 1; + first = parse_abi_tag_seq(first, last, db); + } break; - case 'a': + case 'l': + { + size_t begin_pos = db.Names.size(); + const char* t0 = first+2; + NodeArray lambda_params; + if (first[2] == 'v') { - const char* t = parse_integer_literal(first+2, last, "signed char", db); - if (t != first+2) - first = t; + ++t0; } - break; - case 'h': + else { - const char* t = parse_integer_literal(first+2, last, "unsigned char", db); - if (t != first+2) - first = t; - } - break; - case 's': - { - const char* t = parse_integer_literal(first+2, last, "short", db); - if (t != first+2) - first = t; - } - break; - case 't': - { - const char* t = parse_integer_literal(first+2, last, "unsigned short", db); - if (t != first+2) - first = t; - } - break; - case 'i': - { - const char* t = parse_integer_literal(first+2, last, "", db); - if (t != first+2) - first = t; - } - break; - case 'j': - { - const char* t = parse_integer_literal(first+2, last, "u", db); - if (t != first+2) - first = t; - } - break; - case 'l': - { - const char* t = parse_integer_literal(first+2, last, "l", db); - if (t != first+2) - first = t; - } - break; - case 'm': - { - const char* t = parse_integer_literal(first+2, last, "ul", db); - if (t != first+2) - first = t; - } - break; - case 'x': - { - const char* t = parse_integer_literal(first+2, last, "ll", db); - if (t != first+2) - first = t; - } - break; - case 'y': - { - const char* t = parse_integer_literal(first+2, last, "ull", db); - if (t != first+2) - first = t; - } - break; - case 'n': - { - const char* t = parse_integer_literal(first+2, last, "__int128", db); - if (t != first+2) - first = t; - } - break; - case 'o': - { - const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db); - if (t != first+2) - first = t; - } - break; - case 'f': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'd': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'e': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case '_': - if (first[2] == 'Z') - { - const char* t = parse_encoding(first+3, last, db); - if (t != first+3 && t != last && *t == 'E') - first = t+1; - } - break; - case 'T': - // Invalid mangled name per - // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html - break; - default: - { - // might be named type - const char* t = parse_type(first+1, last, db); - if (t != first+1 && t != last) - { - if (*t != 'E') - { - const char* n = t; - for (; n != last && isdigit(*n); ++n) - ; - if (n != t && n != last && *n == 'E') - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - db.Names.back(), StringView(t, n)); - first = n+1; - break; - } - } - else - { - first = t+1; - break; - } - } - } - } - } - return first; -} - -Node* maybe_change_special_sub_name(Node* inp, Db& db) -{ - if (inp->K != Node::KSpecialSubstitution) - return inp; - auto Kind = static_cast(inp)->SSK; - switch (Kind) - { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - return db.make(Kind); - default: - break; - } - return inp; -} - -// ::= 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 # ? -// extension ::= -const char* -parse_ctor_dtor_name(const char* first, const char* last, Db& db) -{ - if (last-first >= 2 && !db.Names.empty()) - { - switch (first[0]) - { - case 'C': - switch (first[1]) - { - case '1': - case '2': - case '3': - case '5': - if (db.Names.empty()) - return first; - db.Names.back() = - maybe_change_special_sub_name(db.Names.back(), db); - db.Names.push_back( - db.make(db.Names.back(), false)); - first += 2; - first = parse_abi_tag_seq(first, last, db); - db.ParsedCtorDtorCV = true; - break; - } - break; - case 'D': - switch (first[1]) - { - case '0': - case '1': - case '2': - case '5': - if (db.Names.empty()) - return first; - db.Names.push_back( - db.make(db.Names.back(), true)); - first += 2; - first = parse_abi_tag_seq(first, last, db); - db.ParsedCtorDtorCV = true; - break; - } - break; - } - } - return first; -} - -// ::= Ut [] _ [] -// ::= -// -// ::= Ul E [ ] _ -// -// ::= + # Parameter types or "v" if the lambda has no parameters -const char* -parse_unnamed_type_name(const char* first, const char* last, Db& db) -{ - if (last - first > 2 && first[0] == 'U') - { - char type = first[1]; - switch (type) - { - case 't': - { - const char* t0 = first+2; - if (t0 == last) - return first; - StringView count; - if (std::isdigit(*t0)) - { - const char* t1 = t0 + 1; - while (t1 != last && std::isdigit(*t1)) - ++t1; - count = StringView(t0, t1); - t0 = t1; - } - if (t0 == last || *t0 != '_') - return first; - db.Names.push_back(db.make(count)); - first = t0 + 1; - first = parse_abi_tag_seq(first, last, db); - } - break; - case 'l': - { - size_t begin_pos = db.Names.size(); - const char* t0 = first+2; - NodeArray lambda_params; - if (first[2] == 'v') - { - ++t0; - } - else - { - while (true) - { - const char* t1 = parse_type(t0, last, db); - if (t1 == t0) - break; - t0 = t1; - } - if (db.Names.size() < begin_pos) - return first; - lambda_params = db.popTrailingNodeArray(begin_pos); + while (true) + { + const char* t1 = parse_type(t0, last, db); + if (t1 == t0) + break; + t0 = t1; + } + if (db.Names.size() < begin_pos) + return first; + lambda_params = db.popTrailingNodeArray(begin_pos); } if (t0 == last || *t0 != 'E') return first; @@ -4762,631 +4789,6 @@ return first; } -// at # alignof (a type) - -const char* -parse_alignof_type(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'a' && first[1] == 't') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make("alignof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// az # alignof (a expression) - -const char* -parse_alignof_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make("alignof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -const char* -parse_noexcept_expression(const char* first, const char* last, Db& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make("noexcept (", db.Names.back(), ")"); - first = t1; - } - return first; -} - -const char* -parse_prefix_expression(const char* first, const char* last, StringView op, Db& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make(op, db.Names.back()); - first = t1; - } - return first; -} - -const char* -parse_binary_expression(const char* first, const char* last, StringView op, Db& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - if (db.Names.size() < 2) - return first; - auto op2 = db.Names.back(); - db.Names.pop_back(); - auto op1 = db.Names.back(); - db.Names.back() = db.make(op1, op, op2); - first = t2; - } - } - return first; -} - -// ::= -// ::= -// ::= -// ::= 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 -// ::= - -const char* -parse_expression(const char* first, const char* last, Db& db) -{ - if (last - first >= 2) - { - const char* t = first; - bool parsed_gs = false; - if (last - first >= 4 && t[0] == 'g' && t[1] == 's') - { - t += 2; - parsed_gs = true; - } - switch (*t) - { - case 'L': - first = parse_expr_primary(first, last, db); - break; - case 'T': - first = parse_template_param(first, last, db); - break; - case 'f': - first = parse_function_param(first, last, db); - break; - case 'a': - switch (t[1]) - { - case 'a': - t = parse_binary_expression(first+2, last, "&&", db); - if (t != first+2) - first = t; - break; - case 'd': - t = parse_prefix_expression(first+2, last, "&", db); - if (t != first+2) - first = t; - break; - case 'n': - t = parse_binary_expression(first+2, last, "&", db); - if (t != first+2) - first = t; - break; - case 'N': - t = parse_binary_expression(first+2, last, "&=", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, "=", db); - if (t != first+2) - first = t; - break; - case 't': - first = parse_alignof_type(first, last, db); - break; - case 'z': - first = parse_alignof_expr(first, last, db); - break; - } - break; - case 'c': - switch (t[1]) - { - case 'c': - first = parse_const_cast_expr(first, last, db); - break; - case 'l': - first = parse_call_expr(first, last, db); - break; - case 'm': - t = parse_binary_expression(first+2, last, ",", db); - if (t != first+2) - first = t; - break; - case 'o': - t = parse_prefix_expression(first+2, last, "~", db); - if (t != first+2) - first = t; - break; - case 'v': - first = parse_conversion_expr(first, last, db); - break; - } - break; - case 'd': - switch (t[1]) - { - case 'a': - { - const char* t1 = parse_expression(t+2, last, db); - if (t1 != t+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - db.Names.back(), parsed_gs, /*is_array=*/true); - first = t1; - } - } - break; - case 'c': - first = parse_dynamic_cast_expr(first, last, db); - break; - case 'e': - t = parse_prefix_expression(first+2, last, "*", db); - if (t != first+2) - first = t; - break; - case 'l': - { - const char* t1 = parse_expression(t+2, last, db); - if (t1 != t+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - db.Names.back(), parsed_gs, /*is_array=*/false); - first = t1; - } - } - break; - case 'n': - return parse_unresolved_name(first, last, db); - case 's': - first = parse_dot_star_expr(first, last, db); - break; - case 't': - first = parse_dot_expr(first, last, db); - break; - case 'v': - t = parse_binary_expression(first+2, last, "/", db); - if (t != first+2) - first = t; - break; - case 'V': - t = parse_binary_expression(first+2, last, "/=", db); - if (t != first+2) - first = t; - break; - } - break; - case 'e': - switch (t[1]) - { - case 'o': - t = parse_binary_expression(first+2, last, "^", db); - if (t != first+2) - first = t; - break; - case 'O': - t = parse_binary_expression(first+2, last, "^=", db); - if (t != first+2) - first = t; - break; - case 'q': - t = parse_binary_expression(first+2, last, "==", db); - if (t != first+2) - first = t; - break; - } - break; - case 'g': - switch (t[1]) - { - case 'e': - t = parse_binary_expression(first+2, last, ">=", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_binary_expression(first+2, last, ">", db); - if (t != first+2) - first = t; - break; - } - break; - case 'i': - if (t[1] == 'x') - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - if (db.Names.size() < 2) - return first; - auto op2 = db.Names.back(); - db.Names.pop_back(); - auto op1 = db.Names.back(); - db.Names.back() = - db.make(op1, op2); - first = t2; - } - else if (!db.Names.empty()) - db.Names.pop_back(); - } - } - break; - case 'l': - switch (t[1]) - { - case 'e': - t = parse_binary_expression(first+2, last, "<=", db); - if (t != first+2) - first = t; - break; - case 's': - t = parse_binary_expression(first+2, last, "<<", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, "<<=", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_binary_expression(first+2, last, "<", db); - if (t != first+2) - first = t; - break; - } - break; - case 'm': - switch (t[1]) - { - case 'i': - t = parse_binary_expression(first+2, last, "-", db); - if (t != first+2) - first = t; - break; - case 'I': - t = parse_binary_expression(first+2, last, "-=", db); - if (t != first+2) - first = t; - break; - case 'l': - t = parse_binary_expression(first+2, last, "*", db); - if (t != first+2) - first = t; - break; - case 'L': - t = parse_binary_expression(first+2, last, "*=", db); - if (t != first+2) - first = t; - break; - case 'm': - if (first+2 != last && first[2] == '_') - { - t = parse_prefix_expression(first+3, last, "--", db); - if (t != first+3) - first = t; - } - else - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make(db.Names.back(), "--"); - first = t1; - } - } - break; - } - break; - case 'n': - switch (t[1]) - { - case 'a': - case 'w': - first = parse_new_expr(first, last, db); - break; - case 'e': - t = parse_binary_expression(first+2, last, "!=", db); - if (t != first+2) - first = t; - break; - case 'g': - t = parse_prefix_expression(first+2, last, "-", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_prefix_expression(first+2, last, "!", db); - if (t != first+2) - first = t; - break; - case 'x': - t = parse_noexcept_expression(first+2, last, db); - if (t != first+2) - first = t; - break; - } - break; - case 'o': - switch (t[1]) - { - case 'n': - return parse_unresolved_name(first, last, db); - case 'o': - t = parse_binary_expression(first+2, last, "||", db); - if (t != first+2) - first = t; - break; - case 'r': - t = parse_binary_expression(first+2, last, "|", db); - if (t != first+2) - first = t; - break; - case 'R': - t = parse_binary_expression(first+2, last, "|=", db); - if (t != first+2) - first = t; - break; - } - break; - case 'p': - switch (t[1]) - { - case 'm': - t = parse_binary_expression(first+2, last, "->*", db); - if (t != first+2) - first = t; - break; - case 'l': - t = parse_binary_expression(first+2, last, "+", db); - if (t != first+2) - first = t; - break; - case 'L': - t = parse_binary_expression(first+2, last, "+=", db); - if (t != first+2) - first = t; - break; - case 'p': - if (first+2 != last && first[2] == '_') - { - t = parse_prefix_expression(first+3, last, "++", db); - if (t != first+3) - first = t; - } - else - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make(db.Names.back(), "++"); - first = t1; - } - } - break; - case 's': - t = parse_prefix_expression(first+2, last, "+", db); - if (t != first+2) - first = t; - break; - case 't': - first = parse_arrow_expr(first, last, db); - break; - } - break; - case 'q': - if (t[1] == 'u') - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - const char* t3 = parse_expression(t2, last, db); - if (t3 != t2) - { - if (db.Names.size() < 3) - return first; - auto op3 = db.Names.back(); - db.Names.pop_back(); - auto op2 = db.Names.back(); - db.Names.pop_back(); - auto op1 = db.Names.back(); - db.Names.back() = - db.make(op1, op2, op3); - first = t3; - } - else - { - if (db.Names.size() < 2) - return first; - db.Names.pop_back(); - db.Names.pop_back(); - } - } - else if (!db.Names.empty()) - db.Names.pop_back(); - } - } - break; - case 'r': - switch (t[1]) - { - case 'c': - first = parse_reinterpret_cast_expr(first, last, db); - break; - case 'm': - t = parse_binary_expression(first+2, last, "%", db); - if (t != first+2) - first = t; - break; - case 'M': - t = parse_binary_expression(first+2, last, "%=", db); - if (t != first+2) - first = t; - break; - case 's': - t = parse_binary_expression(first+2, last, ">>", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, ">>=", db); - if (t != first+2) - first = t; - break; - } - break; - case 's': - switch (t[1]) - { - case 'c': - first = parse_static_cast_expr(first, last, db); - break; - case 'p': - first = parse_pack_expansion(first, last, db); - break; - case 'r': - return parse_unresolved_name(first, last, db); - case 't': - first = parse_sizeof_type_expr(first, last, db); - break; - case 'z': - first = parse_sizeof_expr_expr(first, last, db); - break; - case 'Z': - if (last - t >= 3) - { - switch (t[2]) - { - case 'T': - first = parse_sizeof_param_pack_expr(first, last, db); - break; - case 'f': - first = parse_sizeof_function_param_pack_expr(first, last, db); - break; - } - } - break; - } - break; - case 't': - switch (t[1]) - { - case 'e': - case 'i': - first = parse_typeid_expr(first, last, db); - break; - case 'r': - db.Names.push_back(db.make("throw")); - first += 2; - break; - case 'w': - first = parse_throw_expr(first, last, db); - break; - } - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return parse_unresolved_name(first, last, db); - } - } - return first; -} - // ::= # type or template // ::= X E # expression // ::= # simple expressions Index: libcxxabi/trunk/test/test_demangle.pass.cpp =================================================================== --- libcxxabi/trunk/test/test_demangle.pass.cpp +++ libcxxabi/trunk/test/test_demangle.pass.cpp @@ -29617,6 +29617,45 @@ {"_Z1fIJicEEvDp7MuncherIAstT__S1_E", "void f(Muncher, Muncher)"}, {"_ZN1SIJifcEE1fIJdjEEEiDp4MerpIJifcT_EE", "int S::f(Merp, Merp)"}, {"_Z1pIJicEEiDp4MerpIXsZT_EJT_EE", "int p(Merp, Merp)"}, + + // Some expression symbols found in clang's test/CodeGenCXX/mangle-exprs.cpp + {"_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE", "void Casts::implicit<4u>(enable_if<(4u) <= (4), void>::type*)"}, + {"_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE", "void Casts::cstyle<4u>(enable_if<(4u) <= ((unsigned int)(4)), void>::type*)"}, + {"_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE", "void Casts::functional<4u>(enable_if<(4u) <= ((unsigned int)(4)), void>::type*)"}, + {"_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_scjLi4EEvE4typeE", "void Casts::static_<4u>(enable_if<(4u) <= (static_cast(4)), void>::type*)"}, + {"_ZN5Casts12reinterpret_ILj4EiEEvPN9enable_ifIXleT_szrcPT0_Li0EEvE4typeE", "void Casts::reinterpret_<4u, int>(enable_if<(4u) <= (sizeof (reinterpret_cast(0))), void>::type*)"}, + {"_ZN5Casts6const_IiXadL_ZNS_1iEEEEEvPN9enable_ifIXleLi0EszccPT_T0_EvE4typeE", "void Casts::const_(enable_if<(0) <= (sizeof (const_cast(&(Casts::i)))), void>::type*)"}, + {"_ZN5Casts8dynamic_INS_1SEXadL_ZNS_1sEEEEEvPN9enable_ifIXleLi0EszdcPT_T0_EvE4typeE", "void Casts::dynamic_(enable_if<(0) <= (sizeof (dynamic_cast(&(Casts::s)))), void>::type*)"}, + {"_ZN5Casts1fILi6EEENS_1TIXT_EEEv", "Casts::T<6> Casts::f<6>()"}, + {"_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE", "void Casts::auto_(decltype(new auto((int)())))"}, + {"_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE", "void Casts::scalar_(decltype(((int)()) , ((int)())))"}, + {"_ZN5test11aIsEEDTcl3foocvT__EEES1_", "decltype(foo((short)())) test1::a(short)"}, + {"_ZN5test21aIPFfvEEEvT_DTclfL0p_EE", "void test2::a(float (*)(), decltype(fp()))"}, + {"_ZN5test21bIPFfvEEEDTclfp_EET_", "decltype(fp()) test2::b(float (*)())"}, + {"_ZN5test21cIPFfvEEEvT_PFvDTclfL1p_EEE", "void test2::c(float (*)(), void (*)(decltype(fp())))"}, + {"_ZN5test21dIPFfvEEEvT_PFDTclfL0p_EEvE", "void test2::d(float (*)(), decltype(fp()) (*)())"}, + {"_ZN5test21eIPFfvEEEvPFDTclfp_EET_E", "void test2::e(decltype(fp()) (*)(float (*)()))"}, + {"_ZN5test21fIPFfvEEEvPFvT_DTclfL0p_EEE", "void test2::f(void (*)(float (*)(), decltype(fp())))"}, + {"_ZN5test21gIPFfvEEEvT_DTclfL0p_EE", "void test2::g(float (*)(), decltype(fp()))"}, + {"_ZN5test21hIPFfvEEEvT_DTcvPFDTclfL0p_EEvELi0EE", "void test2::h(float (*)(), decltype((decltype(fp()) (*)())(0)))"}, + {"_ZN5test21iIPFfvEEEvDTcvPFDTclfp_EET_ELi0EE", "void test2::i(decltype((decltype(fp()) (*)(float (*)()))(0)))"}, + {"_ZZN5test21gIPFfvEEEvT_DTclfL0p_EEE8variable", "void test2::g(float (*)(), decltype(fp()))::variable"}, + {"_ZN5test31aINS_1XEMS1_PiEEvT_T0_DTdsfL0p_fL0p0_E", "void test3::a(test3::X, int* test3::X::*, decltype(fp.*fp0))"}, + {"_ZN5test43tf1INS_1XEEEvDTnw_T_piLi1EEE", "void test4::tf1(decltype(new test4::X(1)))"}, + {"_ZN5test51aIiEEvDTnxcvT__EE", "void test5::a(decltype(noexcept ((int)())))"}, + {"_ZN5test62f1IiEEvDTcvT_dtdtL_ZNS_1zEE2ua1iE", "void test6::f1(decltype((int)(test6::z.ua.i)))"}, + {"_ZN5test62f2IiEEvDTcvT_dtdtL_ZNS_1zEE2ub1iE", "void test6::f2(decltype((int)(test6::z.ub.i)))"}, + {"_ZN5test62f3IiEEvDTcvT_dtdtL_ZNS_1zEE1s1iE", "void test6::f3(decltype((int)(test6::z.s.i)))"}, + {"_ZN5test62f4IiEEvDTcvT_dtdtL_ZNS_1zEE4uuss1iE", "void test6::f4(decltype((int)(test6::z.uuss.i)))"}, + {"_ZN5test62f5IiEEvDTcvT_dtptL_ZNS_2zpEE2ua1iE", "void test6::f5(decltype((int)(test6::zp->ua.i)))"}, + {"_ZN5test62f6IiEEvDTcvT_dtptL_ZNS_2zpEE2ub1iE", "void test6::f6(decltype((int)(test6::zp->ub.i)))"}, + {"_ZN5test62f7IiEEvDTcvT_dtptL_ZNS_2zpEE1s1iE", "void test6::f7(decltype((int)(test6::zp->s.i)))"}, + {"_ZN5test62f8IiEEvDTcvT_dtptL_ZNS_2zpEE4uuss1iE", "void test6::f8(decltype((int)(test6::zp->uuss.i)))"}, + {"_ZN5test73fD2IiEEDTcmcvNS_1DEL_ZNS_1bEEcvT__EES2_", "decltype(((test7::D)(test7::b)) , ((int)())) test7::fD2(int)"}, + {"_ZN5test73fT2IiEEDTcvT__EES1_", "decltype((int)()) test7::fT2(int)"}, + {"_ZN5test73fT4IiEEDTcvT_Li1EES1_", "decltype((int)(1)) test7::fT4(int)"}, + {"_ZN5test73fT6INS_1BEEEDTcvT__Li1ELi2EEES2_", "decltype((test7::B)(1, 2)) test7::fT6(test7::B)"}, + {"_ZNK5test81XIiE3barIiEEDTcl3fooIT_EEEv", "decltype(foo()) test8::X::bar() const"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); @@ -29749,6 +29788,36 @@ "_Z1fUa9enable_ifIXLi1EEEv", // enable_if attribute "_ZDC2a12a2E", // decomposition decl "_ZW6FooBarE2f3v", // C++ modules TS + + // FIXME: Why does clang generate the "cp" expr? + "_ZN5test11bIsEEDTcp3foocvT__EEES1_", + + // Initializer list expressions: + "_ZN5test43tf2INS_1XEEEvDTnw_T_piilLi1EEEE", + "_ZN5test43tf3INS_1XEEEvDTnw_T_ilLi1EEE", + "_ZN5test73fA1IiEEDTcmtlNS_1AELi1ELi2EEcvT__EES2_", + "_ZN5test73fA2IiEEDTcmcvNS_1AEilLi1ELi2EEcvT__EES2_", + "_ZN5test73fB1IiEEDTcmtlNS_1BELi1ELi2EEcvT__EES2_", + "_ZN5test73fB2IiEEDTcmcvNS_1BEilLi1ELi2EEcvT__EES2_", + "_ZN5test73fC1IiEEDTcmtlNS_1CEilLi1ELi2EEEcvT__EES2_", + "_ZN5test73fC2IiEEDTcmcvNS_1CEilLi1ELi2EEcvT__EES2_", + "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_", + "_ZN5test73fE1IiEEDTcmtlNS_1EELi1ELi2EEcvT__EES2_", + "_ZN5test73fE2IiEEDTcmcvNS_1EEilLi1ELi2EEcvT__EES2_", + "_ZN5test73fF1IiEEDTcmtlNS_1FEilLi1ELi2EEEcvT__EES2_", + "_ZN5test73fF2IiEEDTcmcvNS_1FEilLi1ELi2EEcvT__EES2_", + "_ZN5test73fT1IiEEDTtlT_EES1_", + "_ZN5test73fT3IiEEDTtlT_Li1EEES1_", + "_ZN5test73fT5INS_1BEEEDTtlT_Li1ELi2EEES2_", + "_ZN5test73fT7INS_1AEEEDTtlT_ilEEES2_", + "_ZN5test73fT8INS_1AEEEDTcvT_ilEES2_", + "_ZN5test73fT9INS_1AEEEDTtlT_ilLi1EEEES2_", + "_ZN5test73fTAINS_1AEEEDTcvT_ilLi1EEES2_", + "_ZN5test73fTBINS_1CEEEDTtlT_ilLi1ELi2EEEES2_", + "_ZN5test73fTCINS_1CEEEDTcvT_ilLi1ELi2EEES2_", + + // Designated init expressions + "_ZN15designated_init1fINS_1AEEEvDTtlT_di1adi1bdxLi3EdXLi1ELi4ELi9EEE", }; const size_t num_xfails = sizeof(xfail_cases) / sizeof(xfail_cases[0]);