[libcxxabi] r324111 - [demangler] Clean up the expression parser
Erik Pilkington via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 2 10:04:32 PST 2018
Author: epilk
Date: Fri Feb 2 10:04:32 2018
New Revision: 324111
URL: http://llvm.org/viewvc/llvm-project?rev=324111&view=rev
Log:
[demangler] Clean up the expression parser
This commit cleans up the expression parser, using a new style:
- parse* functions now return Node pointers.
- The mangled name is now held in Db and accessed with look() and consume()
- LLVM coding style
This style is meant to avoid the 2 most common types of bugs in the
old demanger, namely misusing the Names stack (ie, calling back() on
empty) and going out of bounds on the mangled name. I also think it
makes the demangler a lot cleaner.
Differential revision: https://reviews.llvm.org/D41887
Modified:
libcxxabi/trunk/src/cxa_demangle.cpp
libcxxabi/trunk/test/test_demangle.pass.cpp
Modified: libcxxabi/trunk/src/cxa_demangle.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=324111&r1=324110&r2=324111&view=diff
==============================================================================
--- libcxxabi/trunk/src/cxa_demangle.cpp (original)
+++ libcxxabi/trunk/src/cxa_demangle.cpp Fri Feb 2 10:04:32 2018
@@ -1522,6 +1522,7 @@ public:
S += "new";
if (IsArray)
S += "[]";
+ S += ' ';
if (!ExprList.empty()) {
S += "(";
ExprList.printWithComma(S);
@@ -1879,67 +1880,839 @@ public:
}
};
-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<Node*, 32> Names;
+struct Db {
+ const char *First;
+ const char *Last;
+
+ // Name stack, this is used by the parser to hold temporary names that were
+ // parsed. The parser colapses multiple names into new nodes to construct
+ // the AST. Once the parser is finished, names.size() == 1.
+ PODSmallVector<Node *, 32> Names;
+
+ // Substitution table. Itanium supports name substitutions as a means of
+ // compression. The string "S42_" refers to the 44nd entry (base-36) in this
+ // table.
+ PODSmallVector<Node *, 32> Subs;
+
+ // Template parameter table. Like the above, but referenced like "T42_".
+ // This has a smaller size compared to Subs and Names because it can be
+ // stored on the stack.
+ PODSmallVector<Node *, 8> TemplateParams;
+
+ Qualifiers CV = QualNone;
+ FunctionRefQual RefQuals = FrefQualNone;
+ unsigned EncodingDepth = 0;
+ bool ParsedCtorDtorCV = false;
+ bool TagTemplates = true;
+ bool FixForwardReferences = false;
+ bool TryToParseTemplateArgs = true;
+
+ BumpPointerAllocator ASTAllocator;
+
+ template <class T, class... Args> T *make(Args &&... args) {
+ return new (ASTAllocator.allocate(sizeof(T)))
+ T(std::forward<Args>(args)...);
+ }
+
+ template <class It> NodeArray makeNodeArray(It begin, It end) {
+ size_t sz = static_cast<size_t>(end - begin);
+ void *mem = ASTAllocator.allocate(sizeof(Node *) * sz);
+ Node **data = new (mem) Node *[sz];
+ std::copy(begin, end, data);
+ return NodeArray(data, sz);
+ }
+
+ NodeArray popTrailingNodeArray(size_t FromPosition) {
+ assert(FromPosition <= Names.size());
+ NodeArray res =
+ makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
+ Names.dropBack(FromPosition);
+ return res;
+ }
+
+ bool consumeIf(StringView S) {
+ if (StringView(First, Last).startsWith(S)) {
+ First += S.size();
+ return true;
+ }
+ return false;
+ }
+
+ bool consumeIf(char C) {
+ if (First != Last && *First == C) {
+ ++First;
+ return true;
+ }
+ return false;
+ }
+
+ char consume() { return First != Last ? *First++ : '\0'; }
+
+ char look(unsigned Lookahead = 0) {
+ if (static_cast<size_t>(Last - First) <= Lookahead)
+ return '\0';
+ return First[Lookahead];
+ }
+
+ size_t numLeft() const { return static_cast<size_t>(Last - First); }
+
+ StringView parseNumber(bool AllowNegative = false);
+ Qualifiers parseCVQualifiers();
+
+ /// Parse the <expr> production.
+ Node *parseExpr();
+ Node *parsePrefixExpr(StringView Kind);
+ Node *parseBinaryExpr(StringView Kind);
+ Node *parseIntegerLiteral(StringView Lit);
+ Node *parseExprPrimary();
+ template <class Float> Node *parseFloatingLiteral();
+ Node *parseFunctionParam();
+ Node *parseNewExpr();
+ Node *parseConversionExpr();
+
+ // FIXME: remove this when all the parse_* functions have been rewritten.
+ template <const char *(*parse_fn)(const char *, const char *, Db &)>
+ 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;
+ }
+};
- // Substitution table. Itanium supports name substitutions as a means of
- // compression. The string "S42_" refers to the 44nd entry (base-36) in this
- // table.
- PODSmallVector<Node*, 32> Subs;
+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<Node *, 8> TemplateParams;
+// <number> ::= [n] <non-negative decimal integer>
+StringView Db::parseNumber(bool AllowNegative) {
+ const char *Tmp = First;
+ if (AllowNegative)
+ consumeIf('n');
+ if (numLeft() == 0 || !std::isdigit(*First))
+ return StringView();
+ while (numLeft() != 0 && std::isdigit(*First))
+ ++First;
+ return StringView(Tmp, First);
+}
+
+Node *Db::parsePrefixExpr(StringView Kind) {
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return nullptr;
+ return make<PrefixExpr>(Kind, E);
+}
+
+Node *Db::parseBinaryExpr(StringView Kind) {
+ Node *LHS = parseExpr();
+ if (LHS == nullptr)
+ return nullptr;
+ Node *RHS = parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<BinaryExpr>(LHS, Kind, RHS);
+}
+
+Node *Db::parseIntegerLiteral(StringView Lit) {
+ StringView Tmp = parseNumber(true);
+ if (!Tmp.empty() && consumeIf('E'))
+ return make<IntegerExpr>(Lit, Tmp);
+ return nullptr;
+}
+
+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;
+// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter
+// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter
+// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+Node *Db::parseFunctionParam() {
+ if (consumeIf("fp")) {
+ parseCVQualifiers();
+ StringView Num = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<FunctionParam>(Num);
+ }
+ if (consumeIf("fL")) {
+ if (parseNumber().empty())
+ return nullptr;
+ if (!consumeIf('p'))
+ return nullptr;
+ parseCVQualifiers();
+ StringView Num = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<FunctionParam>(Num);
+ }
+ return nullptr;
+}
- BumpPointerAllocator ASTAllocator;
+// [gs] nw <expression>* _ <type> E # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// <initializer> ::= pi <expression>* E # parenthesized initialization
+Node *Db::parseNewExpr() {
+ bool Global = consumeIf("gs");
+ bool IsArray = look(1) == 'a';
+ if (!consumeIf("nw") && !consumeIf("na"))
+ return nullptr;
+ size_t Exprs = Names.size();
+ while (!consumeIf('_')) {
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ Names.push_back(Ex);
+ }
+ NodeArray ExprList = popTrailingNodeArray(Exprs);
+ Node *Ty = legacyParse<parse_type>();
+ if (Ty == nullptr)
+ return Ty;
+ if (consumeIf("pi")) {
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *Init = parseExpr();
+ if (Init == nullptr)
+ return Init;
+ Names.push_back(Init);
+ }
+ NodeArray Inits = popTrailingNodeArray(InitsBegin);
+ return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
+ } else if (!consumeIf('E'))
+ return nullptr;
+ return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
+}
- template <class T, class... Args> T* make(Args&& ...args)
- {
- return new (ASTAllocator.allocate(sizeof(T)))
- T(std::forward<Args>(args)...);
- }
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+Node *Db::parseConversionExpr() {
+ if (!consumeIf("cv"))
+ return nullptr;
+ Node *Ty;
+ {
+ SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
+ Ty = legacyParse<parse_type>();
+ }
+
+ if (Ty == nullptr)
+ return nullptr;
+
+ if (consumeIf('_')) {
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ }
+ NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+ return make<ConversionExpr>(Ty, Exprs);
+ }
+
+ Node *E[1] = {parseExpr()};
+ if (E[0] == nullptr)
+ return nullptr;
+ return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
+}
- template <class It> NodeArray makeNodeArray(It begin, It end)
- {
- size_t sz = static_cast<size_t>(end - begin);
- void* mem = ASTAllocator.allocate(sizeof(Node*) * sz);
- Node** data = new (mem) Node*[sz];
- std::copy(begin, end, data);
- return NodeArray(data, sz);
- }
+// <expr-primary> ::= L <type> <value number> E # integer literal
+// ::= L <type> <value float> E # floating literal
+// ::= L <string type> E # string literal
+// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
+// FIXME: ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
+// ::= L <mangled-name> E # external name
+Node *Db::parseExprPrimary() {
+ if (!consumeIf('L'))
+ return nullptr;
+ switch (look()) {
+ case 'w':
+ ++First;
+ return parseIntegerLiteral("wchar_t");
+ case 'b':
+ if (consumeIf("b0E"))
+ return make<BoolExpr>(0);
+ if (consumeIf("b1E"))
+ return make<BoolExpr>(1);
+ return nullptr;
+ case 'c':
+ ++First;
+ return parseIntegerLiteral("char");
+ case 'a':
+ ++First;
+ return parseIntegerLiteral("signed char");
+ case 'h':
+ ++First;
+ return parseIntegerLiteral("unsigned char");
+ case 's':
+ ++First;
+ return parseIntegerLiteral("short");
+ case 't':
+ ++First;
+ return parseIntegerLiteral("unsigned short");
+ case 'i':
+ ++First;
+ return parseIntegerLiteral("");
+ case 'j':
+ ++First;
+ return parseIntegerLiteral("u");
+ case 'l':
+ ++First;
+ return parseIntegerLiteral("l");
+ case 'm':
+ ++First;
+ return parseIntegerLiteral("ul");
+ case 'x':
+ ++First;
+ return parseIntegerLiteral("ll");
+ case 'y':
+ ++First;
+ return parseIntegerLiteral("ull");
+ case 'n':
+ ++First;
+ return parseIntegerLiteral("__int128");
+ case 'o':
+ ++First;
+ return parseIntegerLiteral("unsigned __int128");
+ case 'f':
+ ++First;
+ return parseFloatingLiteral<float>();
+ case 'd':
+ ++First;
+ return parseFloatingLiteral<double>();
+ case 'e':
+ ++First;
+ return parseFloatingLiteral<long double>();
+ case '_':
+ if (consumeIf("_Z")) {
+ Node *R = legacyParse<parse_encoding>();
+ 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<parse_type>();
+ if (T == nullptr)
+ return nullptr;
+ StringView N = parseNumber();
+ if (!N.empty()) {
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<IntegerCastExpr>(T, N);
+ }
+ if (consumeIf('E'))
+ return T;
+ return nullptr;
+ }
+ }
+}
- NodeArray popTrailingNodeArray(size_t FromPosition)
- {
- assert(FromPosition <= Names.size());
- NodeArray res = makeNodeArray(
- Names.begin() + (long)FromPosition, Names.end());
- Names.dropBack(FromPosition);
- return res;
+// <expression> ::= <unary operator-name> <expression>
+// ::= <binary operator-name> <expression> <expression>
+// ::= <ternary operator-name> <expression> <expression> <expression>
+// ::= cl <expression>+ E # call
+// ::= cv <type> <expression> # conversion with one argument
+// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
+// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// ::= [gs] dl <expression> # delete expression
+// ::= [gs] da <expression> # delete[] expression
+// ::= pp_ <expression> # prefix ++
+// ::= mm_ <expression> # prefix --
+// ::= ti <type> # typeid (type)
+// ::= te <expression> # typeid (expression)
+// ::= dc <type> <expression> # dynamic_cast<type> (expression)
+// ::= sc <type> <expression> # static_cast<type> (expression)
+// ::= cc <type> <expression> # const_cast<type> (expression)
+// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
+// ::= st <type> # sizeof (a type)
+// ::= sz <expression> # sizeof (an expression)
+// ::= at <type> # alignof (a type)
+// ::= az <expression> # alignof (an expression)
+// ::= nx <expression> # noexcept (expression)
+// ::= <template-param>
+// ::= <function-param>
+// ::= dt <expression> <unresolved-name> # expr.name
+// ::= pt <expression> <unresolved-name> # expr->name
+// ::= ds <expression> <expression> # expr.*expr
+// ::= sZ <template-param> # size of a parameter pack
+// ::= sZ <function-param> # size of a function parameter pack
+// ::= sp <expression> # pack expansion
+// ::= tw <expression> # throw expression
+// ::= tr # throw with no operand (rethrow)
+// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
+// # freestanding dependent name (e.g., T::x),
+// # objectless nonstatic member reference
+// ::= fL <binary-operator-name> <expression> <expression>
+// ::= fR <binary-operator-name> <expression> <expression>
+// ::= fl <binary-operator-name> <expression>
+// ::= fr <binary-operator-name> <expression>
+// ::= <expr-primary>
+Node *Db::parseExpr() {
+ bool Global = consumeIf("gs");
+ if (numLeft() < 2)
+ return nullptr;
+
+ switch (*First) {
+ case 'L':
+ return parseExprPrimary();
+ case 'T':
+ return legacyParse<parse_template_param>();
+ 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<parse_type>();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("alignof (", Ty, ")");
+ }
+ case 'z': {
+ First += 2;
+ Node *Ty = parseExpr();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("alignof (", Ty, ")");
+ }
+ }
+ return nullptr;
+ case 'c':
+ switch (First[1]) {
+ // cc <type> <expression> # const_cast<type>(expression)
+ case 'c': {
+ First += 2;
+ Node *Ty = legacyParse<parse_type>();
+ if (Ty == nullptr)
+ return Ty;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("const_cast", Ty, Ex);
+ }
+ // cl <expression>+ E # call
+ case 'l': {
+ First += 2;
+ Node *Callee = parseExpr();
+ if (Callee == nullptr)
+ return Callee;
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ }
+ return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
}
-};
-
-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 'm':
+ First += 2;
+ return parseBinaryExpr(",");
+ case 'o':
+ First += 2;
+ return parsePrefixExpr("~");
+ case 'v':
+ return parseConversionExpr();
+ }
+ return nullptr;
+ case 'd':
+ switch (First[1]) {
+ case 'a': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
+ }
+ case 'c': {
+ First += 2;
+ Node *T = legacyParse<parse_type>();
+ if (T == nullptr)
+ return T;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("dynamic_cast", T, Ex);
+ }
+ case 'e':
+ First += 2;
+ return parsePrefixExpr("*");
+ case 'l': {
+ First += 2;
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ return make<DeleteExpr>(E, Global, /*is_array=*/false);
+ }
+ case 'n':
+ return legacyParse<parse_unresolved_name>();
+ case 's': {
+ First += 2;
+ Node *LHS = parseExpr();
+ if (LHS == nullptr)
+ return nullptr;
+ Node *RHS = parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<MemberExpr>(LHS, ".*", RHS);
+ }
+ case 't': {
+ First += 2;
+ Node *LHS = parseExpr();
+ if (LHS == nullptr)
+ return LHS;
+ Node *RHS = parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<MemberExpr>(LHS, ".", RHS);
+ }
+ case 'v':
+ First += 2;
+ return parseBinaryExpr("/");
+ case 'V':
+ First += 2;
+ return parseBinaryExpr("/=");
+ }
+ return nullptr;
+ case 'e':
+ switch (First[1]) {
+ case 'o':
+ First += 2;
+ return parseBinaryExpr("^");
+ case 'O':
+ First += 2;
+ return parseBinaryExpr("^=");
+ case 'q':
+ First += 2;
+ return parseBinaryExpr("==");
+ }
+ return nullptr;
+ case 'g':
+ switch (First[1]) {
+ case 'e':
+ First += 2;
+ return parseBinaryExpr(">=");
+ case 't':
+ First += 2;
+ return parseBinaryExpr(">");
+ }
+ return nullptr;
+ case 'i':
+ if (First[1] == 'x') {
+ First += 2;
+ Node *Base = parseExpr();
+ if (Base == nullptr)
+ return nullptr;
+ Node *Index = parseExpr();
+ if (Index == nullptr)
+ return Index;
+ return make<ArraySubscriptExpr>(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<PostfixExpr>(Ex, "--");
+ }
+ return nullptr;
+ case 'n':
+ switch (First[1]) {
+ case 'a':
+ case 'w':
+ return parseNewExpr();
+ case 'e':
+ First += 2;
+ return parseBinaryExpr("!=");
+ case 'g':
+ First += 2;
+ return parsePrefixExpr("-");
+ case 't':
+ First += 2;
+ return parsePrefixExpr("!");
+ case 'x':
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("noexcept (", Ex, ")");
+ }
+ return nullptr;
+ case 'o':
+ switch (First[1]) {
+ case 'n':
+ return legacyParse<parse_unresolved_name>();
+ case 'o':
+ First += 2;
+ return parseBinaryExpr("||");
+ case 'r':
+ First += 2;
+ return parseBinaryExpr("|");
+ case 'R':
+ First += 2;
+ return parseBinaryExpr("|=");
+ }
+ return nullptr;
+ case 'p':
+ switch (First[1]) {
+ case 'm':
+ First += 2;
+ return parseBinaryExpr("->*");
+ case 'l':
+ First += 2;
+ return parseBinaryExpr("+");
+ case 'L':
+ First += 2;
+ return parseBinaryExpr("+=");
+ case 'p': {
+ First += 2;
+ if (consumeIf('_'))
+ return parsePrefixExpr("++");
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<PostfixExpr>(Ex, "++");
+ }
+ case 's':
+ First += 2;
+ return parsePrefixExpr("+");
+ case 't': {
+ First += 2;
+ Node *L = parseExpr();
+ if (L == nullptr)
+ return nullptr;
+ Node *R = parseExpr();
+ if (R == nullptr)
+ return nullptr;
+ return make<MemberExpr>(L, "->", R);
+ }
+ }
+ return nullptr;
+ case 'q':
+ if (First[1] == 'u') {
+ First += 2;
+ Node *Cond = parseExpr();
+ Node *LHS = parseExpr();
+ Node *RHS = parseExpr();
+ if (Cond && LHS && RHS)
+ return make<ConditionalExpr>(Cond, LHS, RHS);
+ }
+ return nullptr;
+ case 'r':
+ switch (First[1]) {
+ case 'c': {
+ First += 2;
+ Node *T = legacyParse<parse_type>();
+ if (T == nullptr)
+ return T;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("reinterpret_cast", T, Ex);
+ }
+ case 'm':
+ First += 2;
+ return parseBinaryExpr("%");
+ case 'M':
+ First += 2;
+ return parseBinaryExpr("%=");
+ case 's':
+ First += 2;
+ return parseBinaryExpr(">>");
+ case 'S':
+ First += 2;
+ return parseBinaryExpr(">>=");
+ }
+ return nullptr;
+ case 's':
+ switch (First[1]) {
+ case 'c': {
+ First += 2;
+ Node *T = legacyParse<parse_type>();
+ if (T == nullptr)
+ return T;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("static_cast", T, Ex);
+ }
+ case 'p': {
+ First += 2;
+ Node *Child = parseExpr();
+ if (Child == nullptr)
+ return nullptr;
+ return make<ParameterPackExpansion>(Child);
+ }
+ case 'r':
+ return legacyParse<parse_unresolved_name>();
+ case 't': {
+ First += 2;
+ Node *Ty = legacyParse<parse_type>();
+ if (Ty == nullptr)
+ return Ty;
+ return make<EnclosingExpr>("sizeof (", Ty, ")");
+ }
+ case 'z': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("sizeof (", Ex, ")");
+ }
+ case 'Z':
+ First += 2;
+ if (look() == 'T') {
+ Node *R = legacyParse<parse_template_param>();
+ if (R == nullptr)
+ return nullptr;
+ return make<SizeofParamPackExpr>(R);
+ } else if (look() == 'f') {
+ Node *FP = parseFunctionParam();
+ if (FP == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("sizeof...", FP, ")");
+ }
+ return nullptr;
+ }
+ return nullptr;
+ case 't':
+ switch (First[1]) {
+ case 'e': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("typeid (", Ex, ")");
+ }
+ case 'i': {
+ First += 2;
+ Node *Ty = legacyParse<parse_type>();
+ if (Ty == nullptr)
+ return Ty;
+ return make<EnclosingExpr>("typeid (", Ty, ")");
+ }
+ case 'r':
+ First += 2;
+ return make<NameType>("throw");
+ case 'w': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<ThrowExpr>(Ex);
+ }
+ }
+ return nullptr;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return legacyParse<parse_unresolved_name>();
+ }
+ return nullptr;
+}
// <number> ::= [n] <non-negative decimal integer>
@@ -2003,32 +2776,23 @@ struct FloatData<long double>
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<long double>::spec;
+constexpr const char *FloatData<long double>::spec;
-template <class Float>
-const char*
-parse_floating_number(const char* first, const char* last, Db& db)
-{
- const size_t N = FloatData<Float>::mangled_size;
- if (static_cast<std::size_t>(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<FloatExpr<Float>>(StringView(first, t)));
- first = t + 1;
- }
- return first;
+template <class Float> Node *Db::parseFloatingLiteral() {
+ const size_t N = FloatData<Float>::mangled_size;
+ if (numLeft() <= N)
+ return nullptr;
+ StringView Data(First, First + N);
+ for (char C : Data)
+ if (!std::isxdigit(C))
+ return nullptr;
+ First += N;
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<FloatExpr<Float>>(Data);
}
// <positive length number> ::= [0-9]*
@@ -2449,2928 +3213,1524 @@ parse_template_param(const char* first,
return first;
}
-// cc <type> <expression> # const_cast<type> (expression)
+// <simple-id> ::= <source-name> [ <template-args> ]
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<CastExpr>(
- "const_cast", db.Names.back(), from_expr);
- first = t1;
+ db.Names.back() =
+ db.make<NameWithTemplateArgs>(db.Names.back(), args);
}
+ first = t1;
}
+ else
+ first = t;
}
return first;
}
-// dc <type> <expression> # dynamic_cast<type> (expression)
+// <unresolved-type> ::= <template-param>
+// ::= <decltype>
+// ::= <substitution>
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)
+ {
+ 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.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<CastExpr>(
- "dynamic_cast", db.Names.back(), from_expr);
- first = t1;
+ 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<StdQualifiedName>(db.Names.back());
+ db.Subs.push_back(db.Names.back());
+ first = t;
+ }
+ }
+ }
+ break;
+ }
}
return first;
}
-// rc <type> <expression> # reinterpret_cast<type> (expression)
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
const char*
-parse_reinterpret_cast_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] == 'r' && first[1] == 'c')
+ if (first != last)
{
- const char* t = parse_type(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)
{
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- 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<CastExpr>(
- "reinterpret_cast", db.Names.back(), from_expr);
- first = t1;
- }
+ if (db.Names.empty())
+ return first;
+ db.Names.back() = db.make<DtorName>(db.Names.back());
+ first = t;
}
}
return first;
}
-// sc <type> <expression> # static_cast<type> (expression)
+// <base-unresolved-name> ::= <simple-id> # unresolved name
+// extension ::= <operator-name> # unresolved operator-function-id
+// extension ::= <operator-name> <template-args> # unresolved operator template-id
+// ::= on <operator-name> # unresolved operator-function-id
+// ::= on <operator-name> <template-args> # unresolved operator template-id
+// ::= dn <destructor-name> # destructor or pseudo-destructor;
+// # e.g. ~X or ~X<N-1>
const char*
-parse_static_cast_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] == 'c')
+ if (last - first >= 2)
{
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
+ if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
{
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
+ if (first[0] == 'o')
{
- if (db.Names.size() < 2)
- return first;
- auto from_expr = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<CastExpr>(
- "static_cast", db.Names.back(), from_expr);
- first = t1;
+ const char* t = parse_operator_name(first+2, last, db);
+ if (t != first+2)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.Names.size() < 2)
+ return first;
+ auto args = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() =
+ db.make<NameWithTemplateArgs>(
+ db.Names.back(), args);
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_destructor_name(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ }
+ else
+ {
+ const char* t = parse_simple_id(first, last, db);
+ if (t == first)
+ {
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.Names.size() < 2)
+ return first;
+ auto args = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() =
+ db.make<NameWithTemplateArgs>(
+ db.Names.back(), args);
+ }
+ }
}
+ else
+ first = t;
}
}
return first;
}
-// sp <expression> # pack expansion
+// <unresolved-qualifier-level> ::= <simple-id>
const char*
-parse_pack_expansion(const char* first, const char* last, Db& db)
+parse_unresolved_qualifier_level(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<ParameterPackExpansion>(db.Names.back());
- }
- return first;
+ return parse_simple_id(first, last, db);
}
-// st <type> # 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<EnclosingExpr>(
- "sizeof (", db.Names.back(), ")");
- first = t;
- }
- }
- return first;
-}
-
-// sz <expr> # sizeof (a expression)
+// <unresolved-name>
+// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
+// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+// # A::x, N::y, A<T>::z; "gs" means leading "::"
+// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+// # T::N::x /decltype(p)::N::x
+// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
const char*
-parse_sizeof_expr_expr(const char* first, const char* last, Db& db)
+parse_unresolved_name(const char* first, const char* last, Db& db)
{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
+ if (last - first > 2)
{
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
+ const char* t = first;
+ bool global = false;
+ if (t[0] == 'g' && t[1] == 's')
{
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<EnclosingExpr>(
- "sizeof (", db.Names.back(), ")");
- first = t;
+ global = true;
+ t += 2;
}
- }
- return first;
-}
-
-// sZ <template-param> # size of a parameter pack
-
-const char*
-parse_sizeof_param_pack_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
- {
- 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)
+ const char* t2 = parse_base_unresolved_name(t, last, db);
+ if (t2 != t)
{
- db.Names.back() = db.make<SizeofParamPackExpr>(db.Names.back());
- first = t;
+ if (global)
+ {
+ if (db.Names.empty())
+ return first;
+ db.Names.back() =
+ db.make<GlobalQualifiedName>(db.Names.back());
+ }
+ first = t2;
+ }
+ else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+ {
+ if (t[2] == 'N')
+ {
+ t += 3;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.Names.size() < 2)
+ return first;
+ auto args = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() = db.make<NameWithTemplateArgs>(
+ db.Names.back(), args);
+ t = t1;
+ if (t == last)
+ {
+ db.Names.pop_back();
+ return first;
+ }
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.Names.size() < 2)
+ return first;
+ auto s = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() =
+ db.make<QualifiedName>(db.Names.back(), s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.Names.empty())
+ db.Names.pop_back();
+ return first;
+ }
+ if (db.Names.size() < 2)
+ return first;
+ auto s = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() =
+ db.make<QualifiedName>(db.Names.back(), s);
+ first = t1;
+ }
+ else
+ {
+ t += 2;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.Names.size() < 2)
+ return first;
+ auto args = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() =
+ db.make<NameWithTemplateArgs>(
+ db.Names.back(), args);
+ t = t1;
+ }
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.Names.empty())
+ db.Names.pop_back();
+ return first;
+ }
+ if (db.Names.size() < 2)
+ return first;
+ auto s = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() =
+ db.make<QualifiedName>(db.Names.back(), s);
+ first = t1;
+ }
+ else
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ if (global)
+ {
+ if (db.Names.empty())
+ return first;
+ db.Names.back() =
+ db.make<GlobalQualifiedName>(
+ db.Names.back());
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.Names.size() < 2)
+ return first;
+ auto s = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() = db.make<QualifiedName>(
+ db.Names.back(), s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.Names.empty())
+ db.Names.pop_back();
+ return first;
+ }
+ if (db.Names.size() < 2)
+ return first;
+ auto s = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() =
+ db.make<QualifiedName>(db.Names.back(), s);
+ first = t1;
+ }
+ }
}
}
return first;
}
-// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter
-// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
-// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter
-// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+// <ref-qualifier> ::= R # & ref-qualifier
+// <ref-qualifier> ::= O # && ref-qualifier
+
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
const char*
-parse_function_param(const char* first, const char* last, Db& db)
+parse_function_type(const char* first, const char* last, Db& db)
{
- if (last - first >= 3 && *first == 'f')
+ if (first != last && *first == 'F')
{
- if (first[1] == 'p')
+ const char* t = first+1;
+ if (t != last)
{
- Qualifiers cv;
- const char* t = parse_cv_qualifiers(first+2, last, cv);
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
+ if (*t == 'Y')
{
- db.Names.push_back(
- db.make<FunctionParam>(StringView(t, t1)));
- first = t1+1;
+ /* extern "C" */
+ if (++t == last)
+ return first;
}
- }
- else if (first[1] == 'L')
- {
- Qualifiers cv;
- const char* t0 = parse_number(first+2, last);
- if (t0 != last && *t0 == 'p')
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t && !db.Names.empty())
{
- ++t0;
- const char* t = parse_cv_qualifiers(t0, last, cv);
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
+ Node* ret_type = db.Names.back();
+ db.Names.pop_back();
+ size_t params_begin = db.Names.size();
+ t = t1;
+ FunctionRefQual RefQuals = FrefQualNone;
+ while (true)
{
- db.Names.push_back(
- db.make<FunctionParam>(StringView(t, t1)));
- first = t1+1;
+ 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<FunctionType>(
+ ret_type, db.popTrailingNodeArray(params_begin));
+ if (RefQuals)
+ fty = db.make<FunctionRefQualType>(fty, RefQuals);
+ db.Names.push_back(fty);
+ first = t;
}
}
}
return first;
}
-// sZ <function-param> # size of a function parameter pack
+// <pointer-to-member-type> ::= M <class type> <member type>
const char*
-parse_sizeof_function_param_pack_expr(const char* first, const char* last, Db& db)
+parse_pointer_to_member_type(const char* first, const char* last, Db& db)
{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
+ if (first != last && *first == 'M')
{
- const char* t = parse_function_param(first+2, last, db);
- if (t != first+2)
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1)
{
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<EnclosingExpr>(
- "sizeof...(", db.Names.back(), ")");
- first = t;
- }
- }
- return first;
-}
-
-// te <expression> # typeid (expression)
-// ti <type> # 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<EnclosingExpr>(
- "typeid(", db.Names.back(), ")");
- first = t;
- }
- }
- return first;
-}
-
-// tw <expression> # 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<ThrowExpr>(db.Names.back());
- first = t;
- }
- }
- return first;
-}
-
-// ds <expression> <expression> # 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)
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
{
if (db.Names.size() < 2)
return first;
- auto rhs_expr = db.Names.back();
+ auto func = std::move(db.Names.back());
db.Names.pop_back();
- db.Names.back() = db.make<MemberExpr>(
- db.Names.back(), ".*", rhs_expr);
- first = t1;
+ auto ClassType = std::move(db.Names.back());
+ db.Names.back() =
+ db.make<PointerToMemberType>(ClassType, func);
+ first = t2;
}
}
}
return first;
}
-// <simple-id> ::= <source-name> [ <template-args> ]
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
const char*
-parse_simple_id(const char* first, const char* last, Db& db)
+parse_array_type(const char* first, const char* last, Db& db)
{
- if (first != last)
+ if (first != last && *first == 'A' && first+1 != last)
{
- const char* t = parse_source_name(first, last, db);
- if (t != first)
+ if (first[1] == '_')
{
- const char* t1 = parse_template_args(t, last, db);
- if (t1 != t)
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
{
- if (db.Names.size() < 2)
+ if (db.Names.empty())
return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<NameWithTemplateArgs>(db.Names.back(), args);
+ db.Names.back() = db.make<ArrayType>(db.Names.back());
+ first = t;
}
- first = t1;
}
- else
- first = t;
- }
- return first;
-}
-
-// <unresolved-type> ::= <template-param>
-// ::= <decltype>
-// ::= <substitution>
-
-const char*
-parse_unresolved_type(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t = first;
- switch (*first)
+ else if ('1' <= first[1] && first[1] <= '9')
{
- 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)
+ const char* t = parse_number(first+1, last);
+ if (t != last && *t == '_')
{
- if (db.Names.empty())
- return first;
- db.Subs.push_back(db.Names.back());
- first = 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<ArrayType>(db.Names.back(),
+ StringView(first + 1, t));
+ first = t2;
+ }
}
- break;
- case 'S':
- t = parse_substitution(first, last, db);
- if (t != first)
- first = t;
- else
+ }
+ else
+ {
+ const char* t = parse_expression(first+1, last, db);
+ if (t != first+1 && t != last && *t == '_')
{
- if (last - first > 2 && first[1] == 't')
+ const char* t2 = parse_type(++t, last, db);
+ if (t2 != t)
{
- t = parse_unqualified_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<StdQualifiedName>(db.Names.back());
- db.Subs.push_back(db.Names.back());
- first = 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<ArrayType>(base_type, dimension_expr);
+ first = t2;
}
}
- break;
- }
+ }
}
return first;
}
-// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
-// ::= <simple-id> # e.g., ~A<2*N>
+// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
+// ::= DT <expression> E # decltype of an expression (C++0x)
const char*
-parse_destructor_name(const char* first, const char* last, Db& db)
+parse_decltype(const char* first, const char* last, Db& db)
{
- if (first != last)
+ if (last - first >= 4 && first[0] == 'D')
{
- const char* t = parse_unresolved_type(first, last, db);
- if (t == first)
- t = parse_simple_id(first, last, db);
- if (t != first)
+ switch (first[1])
{
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<DtorName>(db.Names.back());
- first = t;
+ 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<EnclosingExpr>(
+ "decltype(", db.Names.back(), ")");
+ first = t+1;
+ }
+ }
+ break;
}
}
return first;
}
-// <base-unresolved-name> ::= <simple-id> # unresolved name
-// extension ::= <operator-name> # unresolved operator-function-id
-// extension ::= <operator-name> <template-args> # unresolved operator template-id
-// ::= on <operator-name> # unresolved operator-function-id
-// ::= on <operator-name> <template-args> # unresolved operator template-id
-// ::= dn <destructor-name> # destructor or pseudo-destructor;
-// # e.g. ~X or ~X<N-1>
+// extension:
+// <vector-type> ::= Dv <positive dimension number> _
+// <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
const char*
-parse_base_unresolved_name(const char* first, const char* last, Db& db)
+parse_vector_type(const char* first, const char* last, Db& db)
{
- if (last - first >= 2)
+ if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
{
- if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
+ if ('1' <= first[2] && first[2] <= '9')
{
- if (first[0] == 'o')
+ const char* t = parse_number(first+2, last);
+ if (t == last || *t != '_')
+ return first;
+ const char* num = first + 2;
+ size_t sz = static_cast<size_t>(t - num);
+ if (++t != last)
{
- const char* t = parse_operator_name(first+2, last, db);
- if (t != first+2)
+ if (*t != 'p')
{
- first = parse_template_args(t, last, db);
- if (first != t)
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
{
- if (db.Names.size() < 2)
+ if (db.Names.empty())
return first;
- auto args = db.Names.back();
- db.Names.pop_back();
db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), args);
+ db.make<VectorType>(db.Names.back(),
+ StringView(num, num + sz));
+ first = t1;
}
}
- }
- else
- {
- const char* t = parse_destructor_name(first+2, last, db);
- if (t != first+2)
+ else
+ {
+ ++t;
+ db.Names.push_back(
+ db.make<VectorType>(StringView(num, num + sz)));
first = t;
+ }
}
}
else
{
- const char* t = parse_simple_id(first, last, db);
- if (t == first)
+ Node* num = nullptr;
+ const char* t1 = first+2;
+ if (*t1 != '_')
{
- t = parse_operator_name(first, last, db);
- if (t != first)
+ const char* t = parse_expression(t1, last, db);
+ if (t != t1)
{
- first = parse_template_args(t, last, db);
- if (first != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), args);
- }
+ if (db.Names.empty())
+ return first;
+ num = db.Names.back();
+ db.Names.pop_back();
+ t1 = t;
}
}
- else
- first = 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<VectorType>(db.Names.back(), num);
+ else
+ db.Names.back() =
+ db.make<VectorType>(db.Names.back(), StringView());
+ first = t;
+ } else if (num)
+ db.Names.push_back(num);
+ }
}
}
return first;
}
-// <unresolved-qualifier-level> ::= <simple-id>
-
-const char*
-parse_unresolved_qualifier_level(const char* first, const char* last, Db& db)
-{
- return parse_simple_id(first, last, db);
-}
+// <type> ::= <builtin-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-param>
+// ::= <template-template-param> <template-args>
+// ::= <decltype>
+// ::= <substitution>
+// ::= <CV-Qualifiers> <type>
+// ::= P <type> # pointer-to
+// ::= R <type> # reference-to
+// ::= O <type> # rvalue reference-to (C++0x)
+// ::= C <type> # complex pair (C 2000)
+// ::= G <type> # imaginary (C 2000)
+// ::= Dp <type> # pack expansion (C++0x)
+// ::= U <source-name> <type> # vendor extended type qualifier
+// extension := U <objc-name> <objc-type> # objc-type<identifier>
+// extension := <vector-type> # <vector-type> starts with Dv
-// <unresolved-name>
-// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
-// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
-// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
-// # A::x, N::y, A<T>::z; "gs" means leading "::"
-// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
-// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
-// # T::N::x /decltype(p)::N::x
-// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
const char*
-parse_unresolved_name(const char* first, const char* last, Db& db)
+parse_type(const char* first, const char* last, Db& db)
{
- if (last - first > 2)
+ if (first != last)
{
- const char* t = first;
- bool global = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- global = true;
- t += 2;
- }
- const char* t2 = parse_base_unresolved_name(t, last, db);
- if (t2 != t)
- {
- if (global)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<GlobalQualifiedName>(db.Names.back());
- }
- first = t2;
- }
- else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+ switch (*first)
{
- if (t[2] == 'N')
- {
- t += 3;
- const char* t1 = parse_unresolved_type(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- t1 = parse_template_args(t, last, db);
- if (t1 != t)
+ case 'r':
+ case 'V':
+ case 'K':
+ {
+ Qualifiers cv = QualNone;
+ const char* t = parse_cv_qualifiers(first, last, cv);
+ if (t != first)
{
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<NameWithTemplateArgs>(
- db.Names.back(), args);
- t = t1;
- if (t == last)
+ bool is_function = *t == 'F';
+ size_t k0 = db.Names.size();
+ const char* t1 = parse_type(t, last, db);
+ size_t k1 = db.Names.size();
+ if (t1 != t && k0 + 1 == k1)
{
- db.Names.pop_back();
- return first;
+ if (is_function)
+ db.Subs.pop_back();
+ if (cv)
+ {
+ if (is_function)
+ db.Names.back() = db.make<FunctionQualType>(
+ db.Names.back(), cv);
+ else
+ db.Names.back() =
+ db.make<QualType>(db.Names.back(), cv);
+ }
+ db.Subs.push_back(db.Names.back());
+ first = t1;
}
}
- while (*t != 'E')
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last || db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), s);
- t = t1;
- }
- ++t;
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.Names.empty())
- db.Names.pop_back();
- return first;
- }
- if (db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), s);
- first = t1;
- }
- else
- {
- t += 2;
- const char* t1 = parse_unresolved_type(t, last, db);
- if (t1 != t)
+ }
+ break;
+ default:
+ {
+ const char* t = parse_builtin_type(first, last, db);
+ if (t != first)
{
- t = t1;
- t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), args);
- t = t1;
- }
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.Names.empty())
- db.Names.pop_back();
- return first;
- }
- if (db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), s);
- first = t1;
+ first = t;
}
else
{
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- if (global)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<GlobalQualifiedName>(
- db.Names.back());
- }
- while (*t != 'E')
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last || db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<QualifiedName>(
- db.Names.back(), s);
- t = t1;
- }
- ++t;
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
+ switch (*first)
{
- if (!db.Names.empty())
- db.Names.pop_back();
- return first;
- }
- if (db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), s);
- first = t1;
- }
- }
- }
- }
- return first;
-}
-
-// dt <expression> <unresolved-name> # expr.name
-
-const char*
-parse_dot_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_unresolved_name(t, last, db);
- if (t1 != t)
- {
- 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<MemberExpr>(db.Names.back(), ".", name);
- first = t1;
- }
- }
- }
- return first;
-}
-
-// cl <expression>+ 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<CallExpr>(
- callee, db.popTrailingNodeArray(args_begin));
- db.Names.push_back(the_call);
- first = t;
- }
- return first;
-}
-
-// [gs] nw <expression>* _ <type> E # new (expr-list) type
-// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// <initializer> ::= pi <expression>* E # parenthesized initialization
-
-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<NewExpr>(ExprList, type, init_list,
- parsed_gs, is_array));
- first = t+1;
- }
- }
- return first;
-}
-
-// cv <type> <expression> # conversion with one argument
-// cv <type> _ <expression>* 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<ConversionExpr>(
- db.Names[type_index], expressions);
- db.Names.dropBack(type_index);
- db.Names.push_back(conv_expr);
- first = t;
- }
- }
- return first;
-}
-
-// pt <expression> <expression> # 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<MemberExpr>(
- db.Names.back(), "->", tmp);
- first = t1;
- }
- }
- }
- return first;
-}
-
-// <ref-qualifier> ::= R # & ref-qualifier
-// <ref-qualifier> ::= O # && ref-qualifier
-
-// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] 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<FunctionType>(
- ret_type, db.popTrailingNodeArray(params_begin));
- if (RefQuals)
- fty = db.make<FunctionRefQualType>(fty, RefQuals);
- db.Names.push_back(fty);
- first = t;
- }
- }
- }
- return first;
-}
-
-// <pointer-to-member-type> ::= M <class type> <member type>
-
-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<PointerToMemberType>(ClassType, func);
- first = t2;
- }
- }
- }
- return first;
-}
-
-// <array-type> ::= A <positive dimension number> _ <element type>
-// ::= A [<dimension expression>] _ <element type>
-
-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<ArrayType>(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<ArrayType>(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<ArrayType>(base_type, dimension_expr);
- first = t2;
- }
- }
- }
- }
- return first;
-}
-
-// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
-// ::= DT <expression> 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<EnclosingExpr>(
- "decltype(", db.Names.back(), ")");
- first = t+1;
- }
- }
- break;
- }
- }
- return first;
-}
-
-// extension:
-// <vector-type> ::= Dv <positive dimension number> _
-// <extended element type>
-// ::= Dv [<dimension expression>] _ <element type>
-// <extended element type> ::= <element type>
-// ::= 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<size_t>(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<VectorType>(db.Names.back(),
- StringView(num, num + sz));
- first = t1;
- }
- }
- else
- {
- ++t;
- db.Names.push_back(
- db.make<VectorType>(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<VectorType>(db.Names.back(), num);
- else
- db.Names.back() =
- db.make<VectorType>(db.Names.back(), StringView());
- first = t;
- } else if (num)
- db.Names.push_back(num);
- }
- }
- }
- return first;
-}
-
-// <type> ::= <builtin-type>
-// ::= <function-type>
-// ::= <class-enum-type>
-// ::= <array-type>
-// ::= <pointer-to-member-type>
-// ::= <template-param>
-// ::= <template-template-param> <template-args>
-// ::= <decltype>
-// ::= <substitution>
-// ::= <CV-Qualifiers> <type>
-// ::= P <type> # pointer-to
-// ::= R <type> # reference-to
-// ::= O <type> # rvalue reference-to (C++0x)
-// ::= C <type> # complex pair (C 2000)
-// ::= G <type> # imaginary (C 2000)
-// ::= Dp <type> # pack expansion (C++0x)
-// ::= U <source-name> <type> # vendor extended type qualifier
-// extension := U <objc-name> <objc-type> # objc-type<identifier>
-// extension := <vector-type> # <vector-type> starts with Dv
-
-// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
-// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
-
-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<FunctionQualType>(
- db.Names.back(), cv);
- else
- db.Names.back() =
- db.make<QualType>(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<PostfixQualifiedType>(
- 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<PostfixQualifiedType>(
- 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<RValueReferenceType>(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<PointerType>(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<LValueReferenceType>(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<NameType*>(db.Names.back())->getName().startsWith("objcproto"))
- {
- db.Names.back() = db.make<VendorExtQualType>(type, db.Names.back());
- }
- else
- {
- auto* proto = static_cast<NameType*>(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<ObjCProtoName>(type, db.Names.back());
- }
- else
- {
- db.Names.push_back(db.make<VendorExtQualType>(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
- // <template-param> it might be followed by <template-args>.
- 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 <template-template-param> <template-args>
- 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<ParameterPackExpansion>(
- 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;
-}
-
-// <operator-name>
-// ::= aa # &&
-// ::= ad # & (unary)
-// ::= an # &
-// ::= aN # &=
-// ::= aS # =
-// ::= cl # ()
-// ::= cm # ,
-// ::= co # ~
-// ::= cv <type> # (cast)
-// ::= da # delete[]
-// ::= de # * (unary)
-// ::= dl # delete
-// ::= dv # /
-// ::= dV # /=
-// ::= eo # ^
-// ::= eO # ^=
-// ::= eq # ==
-// ::= ge # >=
-// ::= gt # >
-// ::= ix # []
-// ::= le # <=
-// ::= li <source-name> # operator ""
-// ::= ls # <<
-// ::= lS # <<=
-// ::= lt # <
-// ::= mi # -
-// ::= mI # -=
-// ::= ml # *
-// ::= mL # *=
-// ::= mm # -- (postfix in <expression> context)
-// ::= na # new[]
-// ::= ne # !=
-// ::= ng # - (unary)
-// ::= nt # !
-// ::= nw # new
-// ::= oo # ||
-// ::= or # |
-// ::= oR # |=
-// ::= pm # ->*
-// ::= pl # +
-// ::= pL # +=
-// ::= pp # ++ (postfix in <expression> context)
-// ::= ps # + (unary)
-// ::= pt # ->
-// ::= qu # ?
-// ::= rm # %
-// ::= rM # %=
-// ::= rs # >>
-// ::= rS # >>=
-// ::= v <digit> <source-name> # vendor extended operator
-// extension ::= <operator-name> <abi-tag-seq>
-const char*
-parse_operator_name(const char* first, const char* last, Db& db)
-{
- const char* original_first = first;
- if (last - first >= 2)
- {
- switch (first[0])
- {
- case 'a':
- switch (first[1])
- {
- case 'a':
- db.Names.push_back(db.make<NameType>("operator&&"));
- first += 2;
- break;
- case 'd':
- case 'n':
- db.Names.push_back(db.make<NameType>("operator&"));
- first += 2;
- break;
- case 'N':
- db.Names.push_back(db.make<NameType>("operator&="));
- first += 2;
- break;
- case 'S':
- db.Names.push_back(db.make<NameType>("operator="));
- first += 2;
- break;
- }
- break;
- case 'c':
- switch (first[1])
- {
- case 'l':
- db.Names.push_back(db.make<NameType>("operator()"));
- first += 2;
- break;
- case 'm':
- db.Names.push_back(db.make<NameType>("operator,"));
- first += 2;
- break;
- case 'o':
- db.Names.push_back(db.make<NameType>("operator~"));
- first += 2;
- break;
- case 'v':
- {
- bool TryToParseTemplateArgs = db.TryToParseTemplateArgs;
- db.TryToParseTemplateArgs = false;
- const char* t = parse_type(first+2, last, db);
- db.TryToParseTemplateArgs = TryToParseTemplateArgs;
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<ConversionOperatorType>(db.Names.back());
- db.ParsedCtorDtorCV = true;
- first = t;
- }
- }
- break;
- }
- break;
- case 'd':
- switch (first[1])
- {
- case 'a':
- db.Names.push_back(db.make<NameType>("operator delete[]"));
- first += 2;
- break;
- case 'e':
- db.Names.push_back(db.make<NameType>("operator*"));
- first += 2;
- break;
- case 'l':
- db.Names.push_back(db.make<NameType>("operator delete"));
- first += 2;
- break;
- case 'v':
- db.Names.push_back(db.make<NameType>("operator/"));
- first += 2;
- break;
- case 'V':
- db.Names.push_back(db.make<NameType>("operator/="));
- first += 2;
- break;
- }
- break;
- case 'e':
- switch (first[1])
- {
- case 'o':
- db.Names.push_back(db.make<NameType>("operator^"));
- first += 2;
- break;
- case 'O':
- db.Names.push_back(db.make<NameType>("operator^="));
- first += 2;
- break;
- case 'q':
- db.Names.push_back(db.make<NameType>("operator=="));
- first += 2;
- break;
- }
- break;
- case 'g':
- switch (first[1])
- {
- case 'e':
- db.Names.push_back(db.make<NameType>("operator>="));
- first += 2;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("operator>"));
- first += 2;
- break;
- }
- break;
- case 'i':
- if (first[1] == 'x')
- {
- db.Names.push_back(db.make<NameType>("operator[]"));
- first += 2;
- }
- break;
- case 'l':
- switch (first[1])
- {
- case 'e':
- db.Names.push_back(db.make<NameType>("operator<="));
- first += 2;
- break;
- case 'i':
- {
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<LiteralOperator>(db.Names.back());
- first = t;
- }
- }
- break;
- case 's':
- db.Names.push_back(db.make<NameType>("operator<<"));
- first += 2;
- break;
- case 'S':
- db.Names.push_back(db.make<NameType>("operator<<="));
- first += 2;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("operator<"));
- first += 2;
- break;
- }
- break;
- case 'm':
- switch (first[1])
- {
- case 'i':
- db.Names.push_back(db.make<NameType>("operator-"));
- first += 2;
- break;
- case 'I':
- db.Names.push_back(db.make<NameType>("operator-="));
- first += 2;
- break;
- case 'l':
- db.Names.push_back(db.make<NameType>("operator*"));
- first += 2;
- break;
- case 'L':
- db.Names.push_back(db.make<NameType>("operator*="));
- first += 2;
- break;
- case 'm':
- db.Names.push_back(db.make<NameType>("operator--"));
- first += 2;
- break;
- }
- break;
- case 'n':
- switch (first[1])
- {
- case 'a':
- db.Names.push_back(db.make<NameType>("operator new[]"));
- first += 2;
- break;
- case 'e':
- db.Names.push_back(db.make<NameType>("operator!="));
- first += 2;
- break;
- case 'g':
- db.Names.push_back(db.make<NameType>("operator-"));
- first += 2;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("operator!"));
- first += 2;
- break;
- case 'w':
- db.Names.push_back(db.make<NameType>("operator new"));
- first += 2;
- break;
- }
- break;
- case 'o':
- switch (first[1])
- {
- case 'o':
- db.Names.push_back(db.make<NameType>("operator||"));
- first += 2;
- break;
- case 'r':
- db.Names.push_back(db.make<NameType>("operator|"));
- first += 2;
- break;
- case 'R':
- db.Names.push_back(db.make<NameType>("operator|="));
- first += 2;
- break;
- }
- break;
- case 'p':
- switch (first[1])
- {
- case 'm':
- db.Names.push_back(db.make<NameType>("operator->*"));
- first += 2;
- break;
- case 'l':
- db.Names.push_back(db.make<NameType>("operator+"));
- first += 2;
- break;
- case 'L':
- db.Names.push_back(db.make<NameType>("operator+="));
- first += 2;
- break;
- case 'p':
- db.Names.push_back(db.make<NameType>("operator++"));
- first += 2;
- break;
- case 's':
- db.Names.push_back(db.make<NameType>("operator+"));
- first += 2;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("operator->"));
- first += 2;
- break;
- }
- break;
- case 'q':
- if (first[1] == 'u')
- {
- db.Names.push_back(db.make<NameType>("operator?"));
- first += 2;
- }
- break;
- case 'r':
- switch (first[1])
- {
- case 'm':
- db.Names.push_back(db.make<NameType>("operator%"));
- first += 2;
- break;
- case 'M':
- db.Names.push_back(db.make<NameType>("operator%="));
- first += 2;
- break;
- case 's':
- db.Names.push_back(db.make<NameType>("operator>>"));
- first += 2;
- break;
- case 'S':
- db.Names.push_back(db.make<NameType>("operator>>="));
- first += 2;
- break;
- }
- break;
- case 'v':
- if (std::isdigit(first[1]))
- {
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<ConversionOperatorType>(db.Names.back());
- first = t;
- }
- }
- break;
- }
- }
-
- if (original_first != first)
- first = parse_abi_tag_seq(first, last, db);
-
- return first;
-}
-
-const char*
-parse_integer_literal(const char* first, const char* last, StringView lit, Db& db)
-{
- const char* t = parse_number(first, last);
- if (t != first && t != last && *t == 'E')
- {
- db.Names.push_back(
- db.make<IntegerExpr>(lit, StringView(first, t)));
- first = t+1;
- }
- return first;
-}
-
-// <expr-primary> ::= L <type> <value number> E # integer literal
-// ::= L <type> <value float> E # floating literal
-// ::= L <string type> E # string literal
-// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
-// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
-// ::= L <mangled-name> E # external name
-
-const char*
-parse_expr_primary(const char* first, const char* last, Db& db)
-{
- if (last - first >= 4 && *first == 'L')
- {
- switch (first[1])
- {
- case 'w':
- {
- const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'b':
- if (first[3] == 'E')
- {
- switch (first[2])
- {
- case '0':
- db.Names.push_back(db.make<BoolExpr>(0));
- first += 4;
- break;
- case '1':
- db.Names.push_back(db.make<BoolExpr>(1));
- first += 4;
- break;
- }
- }
- break;
- case 'c':
- {
- const char* t = parse_integer_literal(first+2, last, "char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'a':
- {
- const char* t = parse_integer_literal(first+2, last, "signed char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'h':
- {
- 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<float>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'd':
- {
- const char* t = parse_floating_number<double>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'e':
- {
- const char* t = parse_floating_number<long double>(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')
+ case 'A':
+ t = parse_array_type(first, last, db);
+ if (t != first)
{
if (db.Names.empty())
return first;
- db.Names.back() = db.make<IntegerCastExpr>(
- db.Names.back(), StringView(t, n));
- first = n+1;
- break;
+ first = t;
+ db.Subs.push_back(db.Names.back());
}
- }
- 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<SpecialSubstitution*>(inp)->SSK;
- switch (Kind)
- {
- case SpecialSubKind::string:
- case SpecialSubKind::istream:
- case SpecialSubKind::ostream:
- case SpecialSubKind::iostream:
- return db.make<ExpandedSpecialSubstitution>(Kind);
- default:
- break;
- }
- return inp;
-}
-
-// <ctor-dtor-name> ::= C1 # complete object constructor
-// ::= C2 # base object constructor
-// ::= C3 # complete object allocating constructor
-// extension ::= C5 # ?
-// ::= D0 # deleting destructor
-// ::= D1 # complete object destructor
-// ::= D2 # base object destructor
-// extension ::= D5 # ?
-// extension ::= <ctor-dtor-name> <abi-tag-seq>
-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<CtorDtorName>(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<CtorDtorName>(db.Names.back(), true));
- first += 2;
- first = parse_abi_tag_seq(first, last, db);
- db.ParsedCtorDtorCV = true;
- break;
- }
- break;
- }
- }
- return first;
-}
-
-// <unnamed-type-name> ::= Ut [<nonnegative number>] _ [<abi-tag-seq>]
-// ::= <closure-type-name>
-//
-// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
-//
-// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
-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<UnnamedTypeName>(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)
+ case 'C':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.Names.empty())
+ return first;
+ db.Names.back() = db.make<PostfixQualifiedType>(
+ 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<PostfixQualifiedType>(
+ 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<RValueReferenceType>(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<PointerType>(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<LValueReferenceType>(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;
- t0 = t1;
- }
- if (db.Names.size() < begin_pos)
- return first;
- lambda_params = db.popTrailingNodeArray(begin_pos);
- }
- if (t0 == last || *t0 != 'E')
- return first;
- ++t0;
- 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<LambdaTypeName>(lambda_params, count));
- first = t0 + 1;
- }
- break;
- }
- }
- return first;
-}
-
-// <unqualified-name> ::= <operator-name>
-// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <unnamed-type-name>
-
-const char*
-parse_unqualified_name(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t;
- switch (*first)
- {
- case 'C':
- case 'D':
- t = parse_ctor_dtor_name(first, last, db);
- if (t != first)
- first = t;
- break;
- case 'U':
- t = parse_unnamed_type_name(first, last, db);
- if (t != first)
- first = t;
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- t = parse_source_name(first, last, db);
- if (t != first)
- first = t;
- break;
- default:
- t = parse_operator_name(first, last, db);
- if (t != first)
- first = t;
- break;
- };
- }
- return first;
-}
-
-// <unscoped-name> ::= <unqualified-name>
-// ::= St <unqualified-name> # ::std::
-// extension ::= StL<unqualified-name>
-
-const char*
-parse_unscoped_name(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- const char* t0 = first;
- bool St = false;
- if (first[0] == 'S' && first[1] == 't')
- {
- t0 += 2;
- St = true;
- if (t0 != last && *t0 == 'L')
- ++t0;
- }
- const char* t1 = parse_unqualified_name(t0, last, db);
- if (t1 != t0)
- {
- if (St)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<StdQualifiedName>(db.Names.back());
+ }
+ 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<NameType*>(db.Names.back())->getName().startsWith("objcproto"))
+ {
+ db.Names.back() = db.make<VendorExtQualType>(type, db.Names.back());
+ }
+ else
+ {
+ auto* proto = static_cast<NameType*>(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<ObjCProtoName>(type, db.Names.back());
+ }
+ else
+ {
+ db.Names.push_back(db.make<VendorExtQualType>(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
+ // <template-param> it might be followed by <template-args>.
+ 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 <template-template-param> <template-args>
+ 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<ParameterPackExpansion>(
+ 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;
}
- first = t1;
- }
- }
- return first;
-}
-
-// at <type> # 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<EnclosingExpr>("alignof (", db.Names.back(), ")");
- first = t;
- }
- }
- return first;
-}
-
-// az <expression> # 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<EnclosingExpr>("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<EnclosingExpr>("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<PrefixExpr>(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<BinaryExpr>(op1, op, op2);
- first = t2;
}
}
return first;
}
-// <expression> ::= <unary operator-name> <expression>
-// ::= <binary operator-name> <expression> <expression>
-// ::= <ternary operator-name> <expression> <expression> <expression>
-// ::= cl <expression>+ E # call
-// ::= cv <type> <expression> # conversion with one argument
-// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
-// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
-// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// ::= [gs] dl <expression> # delete expression
-// ::= [gs] da <expression> # delete[] expression
-// ::= pp_ <expression> # prefix ++
-// ::= mm_ <expression> # prefix --
-// ::= ti <type> # typeid (type)
-// ::= te <expression> # typeid (expression)
-// ::= dc <type> <expression> # dynamic_cast<type> (expression)
-// ::= sc <type> <expression> # static_cast<type> (expression)
-// ::= cc <type> <expression> # const_cast<type> (expression)
-// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
-// ::= st <type> # sizeof (a type)
-// ::= sz <expression> # sizeof (an expression)
-// ::= at <type> # alignof (a type)
-// ::= az <expression> # alignof (an expression)
-// ::= nx <expression> # noexcept (expression)
-// ::= <template-param>
-// ::= <function-param>
-// ::= dt <expression> <unresolved-name> # expr.name
-// ::= pt <expression> <unresolved-name> # expr->name
-// ::= ds <expression> <expression> # expr.*expr
-// ::= sZ <template-param> # size of a parameter pack
-// ::= sZ <function-param> # size of a function parameter pack
-// ::= sp <expression> # pack expansion
-// ::= tw <expression> # throw expression
-// ::= tr # throw with no operand (rethrow)
-// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
-// # freestanding dependent name (e.g., T::x),
-// # objectless nonstatic member reference
-// ::= <expr-primary>
-
+// <operator-name>
+// ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= li <source-name> # operator ""
+// ::= ls # <<
+// ::= lS # <<=
+// ::= lt # <
+// ::= mi # -
+// ::= mI # -=
+// ::= ml # *
+// ::= mL # *=
+// ::= mm # -- (postfix in <expression> context)
+// ::= na # new[]
+// ::= ne # !=
+// ::= ng # - (unary)
+// ::= nt # !
+// ::= nw # new
+// ::= oo # ||
+// ::= or # |
+// ::= oR # |=
+// ::= pm # ->*
+// ::= pl # +
+// ::= pL # +=
+// ::= pp # ++ (postfix in <expression> context)
+// ::= ps # + (unary)
+// ::= pt # ->
+// ::= qu # ?
+// ::= rm # %
+// ::= rM # %=
+// ::= rs # >>
+// ::= rS # >>=
+// ::= v <digit> <source-name> # vendor extended operator
+// extension ::= <operator-name> <abi-tag-seq>
const char*
-parse_expression(const char* first, const char* last, Db& db)
+parse_operator_name(const char* first, const char* last, Db& db)
{
+ const char* original_first = first;
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)
+ switch (first[0])
{
- 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])
+ switch (first[1])
{
case 'a':
- t = parse_binary_expression(first+2, last, "&&", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator&&"));
+ first += 2;
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;
+ db.Names.push_back(db.make<NameType>("operator&"));
+ first += 2;
break;
case 'N':
- t = parse_binary_expression(first+2, last, "&=", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator&="));
+ first += 2;
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);
+ db.Names.push_back(db.make<NameType>("operator="));
+ first += 2;
break;
}
break;
case 'c':
- switch (t[1])
+ switch (first[1])
{
- case 'c':
- first = parse_const_cast_expr(first, last, db);
- break;
case 'l':
- first = parse_call_expr(first, last, db);
+ db.Names.push_back(db.make<NameType>("operator()"));
+ first += 2;
break;
case 'm':
- t = parse_binary_expression(first+2, last, ",", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator,"));
+ first += 2;
break;
case 'o':
- t = parse_prefix_expression(first+2, last, "~", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator~"));
+ first += 2;
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)
+ bool TryToParseTemplateArgs = db.TryToParseTemplateArgs;
+ db.TryToParseTemplateArgs = false;
+ const char* t = parse_type(first+2, last, db);
+ db.TryToParseTemplateArgs = TryToParseTemplateArgs;
+ if (t != first+2)
{
if (db.Names.empty())
return first;
- db.Names.back() = db.make<DeleteExpr>(
- db.Names.back(), parsed_gs, /*is_array=*/true);
- first = t1;
+ db.Names.back() =
+ db.make<ConversionOperatorType>(db.Names.back());
+ db.ParsedCtorDtorCV = true;
+ first = t;
}
}
break;
- case 'c':
- first = parse_dynamic_cast_expr(first, last, db);
+ }
+ break;
+ case 'd':
+ switch (first[1])
+ {
+ case 'a':
+ db.Names.push_back(db.make<NameType>("operator delete[]"));
+ first += 2;
break;
case 'e':
- t = parse_prefix_expression(first+2, last, "*", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator*"));
+ first += 2;
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<DeleteExpr>(
- 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);
+ db.Names.push_back(db.make<NameType>("operator delete"));
+ first += 2;
break;
case 'v':
- t = parse_binary_expression(first+2, last, "/", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator/"));
+ first += 2;
break;
case 'V':
- t = parse_binary_expression(first+2, last, "/=", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator/="));
+ first += 2;
break;
}
break;
case 'e':
- switch (t[1])
+ switch (first[1])
{
case 'o':
- t = parse_binary_expression(first+2, last, "^", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator^"));
+ first += 2;
break;
case 'O':
- t = parse_binary_expression(first+2, last, "^=", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator^="));
+ first += 2;
break;
case 'q':
- t = parse_binary_expression(first+2, last, "==", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator=="));
+ first += 2;
break;
}
break;
case 'g':
- switch (t[1])
+ switch (first[1])
{
case 'e':
- t = parse_binary_expression(first+2, last, ">=", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator>="));
+ first += 2;
break;
case 't':
- t = parse_binary_expression(first+2, last, ">", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator>"));
+ first += 2;
break;
}
break;
case 'i':
- if (t[1] == 'x')
+ if (first[1] == 'x')
+ {
+ db.Names.push_back(db.make<NameType>("operator[]"));
+ first += 2;
+ }
+ break;
+ case 'l':
+ switch (first[1])
{
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
+ case 'e':
+ db.Names.push_back(db.make<NameType>("operator<="));
+ first += 2;
+ break;
+ case 'i':
{
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
{
- if (db.Names.size() < 2)
+ if (db.Names.empty())
return first;
- auto op2 = db.Names.back();
- db.Names.pop_back();
- auto op1 = db.Names.back();
db.Names.back() =
- db.make<ArraySubscriptExpr>(op1, op2);
- first = t2;
+ db.make<LiteralOperator>(db.Names.back());
+ first = t;
}
- 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;
+ db.Names.push_back(db.make<NameType>("operator<<"));
+ first += 2;
break;
case 'S':
- t = parse_binary_expression(first+2, last, "<<=", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator<<="));
+ first += 2;
break;
case 't':
- t = parse_binary_expression(first+2, last, "<", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator<"));
+ first += 2;
break;
}
break;
case 'm':
- switch (t[1])
+ switch (first[1])
{
case 'i':
- t = parse_binary_expression(first+2, last, "-", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator-"));
+ first += 2;
break;
case 'I':
- t = parse_binary_expression(first+2, last, "-=", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator-="));
+ first += 2;
break;
case 'l':
- t = parse_binary_expression(first+2, last, "*", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator*"));
+ first += 2;
break;
case 'L':
- t = parse_binary_expression(first+2, last, "*=", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator*="));
+ first += 2;
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<PostfixExpr>(db.Names.back(), "--");
- first = t1;
- }
- }
+ db.Names.push_back(db.make<NameType>("operator--"));
+ first += 2;
break;
}
break;
case 'n':
- switch (t[1])
+ switch (first[1])
{
case 'a':
- case 'w':
- first = parse_new_expr(first, last, db);
+ db.Names.push_back(db.make<NameType>("operator new[]"));
+ first += 2;
break;
case 'e':
- t = parse_binary_expression(first+2, last, "!=", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator!="));
+ first += 2;
break;
case 'g':
- t = parse_prefix_expression(first+2, last, "-", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator-"));
+ first += 2;
break;
case 't':
- t = parse_prefix_expression(first+2, last, "!", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator!"));
+ first += 2;
break;
- case 'x':
- t = parse_noexcept_expression(first+2, last, db);
- if (t != first+2)
- first = t;
+ case 'w':
+ db.Names.push_back(db.make<NameType>("operator new"));
+ first += 2;
break;
}
break;
case 'o':
- switch (t[1])
+ switch (first[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;
+ db.Names.push_back(db.make<NameType>("operator||"));
+ first += 2;
break;
case 'r':
- t = parse_binary_expression(first+2, last, "|", db);
- if (t != first+2)
- first = t;
+ db.Names.push_back(db.make<NameType>("operator|"));
+ first += 2;
break;
case 'R':
- t = parse_binary_expression(first+2, last, "|=", db);
+ db.Names.push_back(db.make<NameType>("operator|="));
+ first += 2;
+ break;
+ }
+ break;
+ case 'p':
+ switch (first[1])
+ {
+ case 'm':
+ db.Names.push_back(db.make<NameType>("operator->*"));
+ first += 2;
+ break;
+ case 'l':
+ db.Names.push_back(db.make<NameType>("operator+"));
+ first += 2;
+ break;
+ case 'L':
+ db.Names.push_back(db.make<NameType>("operator+="));
+ first += 2;
+ break;
+ case 'p':
+ db.Names.push_back(db.make<NameType>("operator++"));
+ first += 2;
+ break;
+ case 's':
+ db.Names.push_back(db.make<NameType>("operator+"));
+ first += 2;
+ break;
+ case 't':
+ db.Names.push_back(db.make<NameType>("operator->"));
+ first += 2;
+ break;
+ }
+ break;
+ case 'q':
+ if (first[1] == 'u')
+ {
+ db.Names.push_back(db.make<NameType>("operator?"));
+ first += 2;
+ }
+ break;
+ case 'r':
+ switch (first[1])
+ {
+ case 'm':
+ db.Names.push_back(db.make<NameType>("operator%"));
+ first += 2;
+ break;
+ case 'M':
+ db.Names.push_back(db.make<NameType>("operator%="));
+ first += 2;
+ break;
+ case 's':
+ db.Names.push_back(db.make<NameType>("operator>>"));
+ first += 2;
+ break;
+ case 'S':
+ db.Names.push_back(db.make<NameType>("operator>>="));
+ first += 2;
+ break;
+ }
+ break;
+ case 'v':
+ if (std::isdigit(first[1]))
+ {
+ const char* t = parse_source_name(first+2, last, db);
if (t != first+2)
+ {
+ if (db.Names.empty())
+ return first;
+ db.Names.back() =
+ db.make<ConversionOperatorType>(db.Names.back());
first = t;
+ }
+ }
+ break;
+ }
+ }
+
+ if (original_first != first)
+ first = parse_abi_tag_seq(first, last, db);
+
+ return first;
+}
+
+Node* maybe_change_special_sub_name(Node* inp, Db& db)
+{
+ if (inp->K != Node::KSpecialSubstitution)
+ return inp;
+ auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK;
+ switch (Kind)
+ {
+ case SpecialSubKind::string:
+ case SpecialSubKind::istream:
+ case SpecialSubKind::ostream:
+ case SpecialSubKind::iostream:
+ return db.make<ExpandedSpecialSubstitution>(Kind);
+ default:
+ break;
+ }
+ return inp;
+}
+
+// <ctor-dtor-name> ::= C1 # complete object constructor
+// ::= C2 # base object constructor
+// ::= C3 # complete object allocating constructor
+// extension ::= C5 # ?
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+// extension ::= D5 # ?
+// extension ::= <ctor-dtor-name> <abi-tag-seq>
+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<CtorDtorName>(db.Names.back(), false));
+ first += 2;
+ first = parse_abi_tag_seq(first, last, db);
+ db.ParsedCtorDtorCV = true;
break;
}
break;
- case 'p':
- switch (t[1])
+ case 'D':
+ switch (first[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<PostfixExpr>(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);
+ case '0':
+ case '1':
+ case '2':
+ case '5':
+ if (db.Names.empty())
+ return first;
+ db.Names.push_back(
+ db.make<CtorDtorName>(db.Names.back(), true));
+ first += 2;
+ first = parse_abi_tag_seq(first, last, db);
+ db.ParsedCtorDtorCV = true;
break;
}
break;
- case 'q':
- if (t[1] == 'u')
+ }
+ }
+ return first;
+}
+
+// <unnamed-type-name> ::= Ut [<nonnegative number>] _ [<abi-tag-seq>]
+// ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+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 = 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<ConditionalExpr>(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();
- }
+ 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<UnnamedTypeName>(count));
+ first = t0 + 1;
+ first = parse_abi_tag_seq(first, last, db);
+ }
break;
- case 'r':
- switch (t[1])
+ case 'l':
+ {
+ size_t begin_pos = db.Names.size();
+ const char* t0 = first+2;
+ NodeArray lambda_params;
+ if (first[2] == 'v')
{
- 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;
+ ++t0;
}
- break;
- case 's':
- switch (t[1])
+ else
{
- 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)
+ while (true)
{
- 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);
+ const char* t1 = parse_type(t0, last, db);
+ if (t1 == t0)
break;
- }
+ t0 = t1;
}
- break;
+ if (db.Names.size() < begin_pos)
+ return first;
+ lambda_params = db.popTrailingNodeArray(begin_pos);
}
- break;
- case 't':
- switch (t[1])
+ if (t0 == last || *t0 != 'E')
+ return first;
+ ++t0;
+ if (t0 == last)
+ return first;
+ StringView count;
+ if (std::isdigit(*t0))
{
- case 'e':
- case 'i':
- first = parse_typeid_expr(first, last, db);
- break;
- case 'r':
- db.Names.push_back(db.make<NameType>("throw"));
- first += 2;
- break;
- case 'w':
- first = parse_throw_expr(first, last, db);
- break;
+ 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<LambdaTypeName>(lambda_params, count));
+ first = t0 + 1;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+
+const char*
+parse_unqualified_name(const char* first, const char* last, Db& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'C':
+ case 'D':
+ t = parse_ctor_dtor_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case 'U':
+ t = parse_unnamed_type_name(first, last, db);
+ if (t != first)
+ first = t;
break;
case '1':
case '2':
@@ -5381,7 +4741,49 @@ parse_expression(const char* first, cons
case '7':
case '8':
case '9':
- return parse_unresolved_name(first, last, db);
+ t = parse_source_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ default:
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ };
+ }
+ return first;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+
+const char*
+parse_unscoped_name(const char* first, const char* last, Db& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ bool St = false;
+ if (first[0] == 'S' && first[1] == 't')
+ {
+ t0 += 2;
+ St = true;
+ if (t0 != last && *t0 == 'L')
+ ++t0;
+ }
+ const char* t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (St)
+ {
+ if (db.Names.empty())
+ return first;
+ db.Names.back() =
+ db.make<StdQualifiedName>(db.Names.back());
+ }
+ first = t1;
}
}
return first;
Modified: libcxxabi/trunk/test/test_demangle.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=324111&r1=324110&r2=324111&view=diff
==============================================================================
--- libcxxabi/trunk/test/test_demangle.pass.cpp (original)
+++ libcxxabi/trunk/test/test_demangle.pass.cpp Fri Feb 2 10:04:32 2018
@@ -29617,6 +29617,45 @@ const char* cases[][2] =
{"_Z1fIJicEEvDp7MuncherIAstT__S1_E", "void f<int, char>(Muncher<int [sizeof (int)]>, Muncher<char [sizeof (char)]>)"},
{"_ZN1SIJifcEE1fIJdjEEEiDp4MerpIJifcT_EE", "int S<int, float, char>::f<double, unsigned int>(Merp<int, float, char, double>, Merp<int, float, char, unsigned int>)"},
{"_Z1pIJicEEiDp4MerpIXsZT_EJT_EE", "int p<int, char>(Merp<sizeof...(int, char), int>, Merp<sizeof...(int, char), char>)"},
+
+ // 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<unsigned int>(4)), void>::type*)"},
+ {"_ZN5Casts12reinterpret_ILj4EiEEvPN9enable_ifIXleT_szrcPT0_Li0EEvE4typeE", "void Casts::reinterpret_<4u, int>(enable_if<(4u) <= (sizeof (reinterpret_cast<int*>(0))), void>::type*)"},
+ {"_ZN5Casts6const_IiXadL_ZNS_1iEEEEEvPN9enable_ifIXleLi0EszccPT_T0_EvE4typeE", "void Casts::const_<int, &(Casts::i)>(enable_if<(0) <= (sizeof (const_cast<int*>(&(Casts::i)))), void>::type*)"},
+ {"_ZN5Casts8dynamic_INS_1SEXadL_ZNS_1sEEEEEvPN9enable_ifIXleLi0EszdcPT_T0_EvE4typeE", "void Casts::dynamic_<Casts::S, &(Casts::s)>(enable_if<(0) <= (sizeof (dynamic_cast<Casts::S*>(&(Casts::s)))), void>::type*)"},
+ {"_ZN5Casts1fILi6EEENS_1TIXT_EEEv", "Casts::T<6> Casts::f<6>()"},
+ {"_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE", "void Casts::auto_<int>(decltype(new auto((int)())))"},
+ {"_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE", "void Casts::scalar_<int>(decltype(((int)()) , ((int)())))"},
+ {"_ZN5test11aIsEEDTcl3foocvT__EEES1_", "decltype(foo((short)())) test1::a<short>(short)"},
+ {"_ZN5test21aIPFfvEEEvT_DTclfL0p_EE", "void test2::a<float (*)()>(float (*)(), decltype(fp()))"},
+ {"_ZN5test21bIPFfvEEEDTclfp_EET_", "decltype(fp()) test2::b<float (*)()>(float (*)())"},
+ {"_ZN5test21cIPFfvEEEvT_PFvDTclfL1p_EEE", "void test2::c<float (*)()>(float (*)(), void (*)(decltype(fp())))"},
+ {"_ZN5test21dIPFfvEEEvT_PFDTclfL0p_EEvE", "void test2::d<float (*)()>(float (*)(), decltype(fp()) (*)())"},
+ {"_ZN5test21eIPFfvEEEvPFDTclfp_EET_E", "void test2::e<float (*)()>(decltype(fp()) (*)(float (*)()))"},
+ {"_ZN5test21fIPFfvEEEvPFvT_DTclfL0p_EEE", "void test2::f<float (*)()>(void (*)(float (*)(), decltype(fp())))"},
+ {"_ZN5test21gIPFfvEEEvT_DTclfL0p_EE", "void test2::g<float (*)()>(float (*)(), decltype(fp()))"},
+ {"_ZN5test21hIPFfvEEEvT_DTcvPFDTclfL0p_EEvELi0EE", "void test2::h<float (*)()>(float (*)(), decltype((decltype(fp()) (*)())(0)))"},
+ {"_ZN5test21iIPFfvEEEvDTcvPFDTclfp_EET_ELi0EE", "void test2::i<float (*)()>(decltype((decltype(fp()) (*)(float (*)()))(0)))"},
+ {"_ZZN5test21gIPFfvEEEvT_DTclfL0p_EEE8variable", "void test2::g<float (*)()>(float (*)(), decltype(fp()))::variable"},
+ {"_ZN5test31aINS_1XEMS1_PiEEvT_T0_DTdsfL0p_fL0p0_E", "void test3::a<test3::X, int* test3::X::*>(test3::X, int* test3::X::*, decltype(fp.*fp0))"},
+ {"_ZN5test43tf1INS_1XEEEvDTnw_T_piLi1EEE", "void test4::tf1<test4::X>(decltype(new test4::X(1)))"},
+ {"_ZN5test51aIiEEvDTnxcvT__EE", "void test5::a<int>(decltype(noexcept ((int)())))"},
+ {"_ZN5test62f1IiEEvDTcvT_dtdtL_ZNS_1zEE2ua1iE", "void test6::f1<int>(decltype((int)(test6::z.ua.i)))"},
+ {"_ZN5test62f2IiEEvDTcvT_dtdtL_ZNS_1zEE2ub1iE", "void test6::f2<int>(decltype((int)(test6::z.ub.i)))"},
+ {"_ZN5test62f3IiEEvDTcvT_dtdtL_ZNS_1zEE1s1iE", "void test6::f3<int>(decltype((int)(test6::z.s.i)))"},
+ {"_ZN5test62f4IiEEvDTcvT_dtdtL_ZNS_1zEE4uuss1iE", "void test6::f4<int>(decltype((int)(test6::z.uuss.i)))"},
+ {"_ZN5test62f5IiEEvDTcvT_dtptL_ZNS_2zpEE2ua1iE", "void test6::f5<int>(decltype((int)(test6::zp->ua.i)))"},
+ {"_ZN5test62f6IiEEvDTcvT_dtptL_ZNS_2zpEE2ub1iE", "void test6::f6<int>(decltype((int)(test6::zp->ub.i)))"},
+ {"_ZN5test62f7IiEEvDTcvT_dtptL_ZNS_2zpEE1s1iE", "void test6::f7<int>(decltype((int)(test6::zp->s.i)))"},
+ {"_ZN5test62f8IiEEvDTcvT_dtptL_ZNS_2zpEE4uuss1iE", "void test6::f8<int>(decltype((int)(test6::zp->uuss.i)))"},
+ {"_ZN5test73fD2IiEEDTcmcvNS_1DEL_ZNS_1bEEcvT__EES2_", "decltype(((test7::D)(test7::b)) , ((int)())) test7::fD2<int>(int)"},
+ {"_ZN5test73fT2IiEEDTcvT__EES1_", "decltype((int)()) test7::fT2<int>(int)"},
+ {"_ZN5test73fT4IiEEDTcvT_Li1EES1_", "decltype((int)(1)) test7::fT4<int>(int)"},
+ {"_ZN5test73fT6INS_1BEEEDTcvT__Li1ELi2EEES2_", "decltype((test7::B)(1, 2)) test7::fT6<test7::B>(test7::B)"},
+ {"_ZNK5test81XIiE3barIiEEDTcl3fooIT_EEEv", "decltype(foo<int>()) test8::X<int>::bar<int>() const"},
};
const unsigned N = sizeof(cases) / sizeof(cases[0]);
@@ -29749,6 +29788,36 @@ const char *xfail_cases[] = {
"_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]);
More information about the cfe-commits
mailing list