KCtorDtorName,
KDtorName,
KUnnamedTypeName,
- KLambdaTypeName,
+ KClosureTypeName,
KExpr,
KBracedExpr,
KBracedRangeExpr,
}
};
-class LambdaTypeName : public Node {
+class ClosureTypeName : public Node {
NodeArray Params;
StringView Count;
public:
- LambdaTypeName(NodeArray Params_, StringView Count_)
- : Node(KLambdaTypeName), Params(Params_), Count(Count_) {
+ ClosureTypeName(NodeArray Params_, StringView Count_)
+ : Node(KClosureTypeName), Params(Params_), Count(Count_) {
for (Node *P : Params)
ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
}
// stored on the stack.
PODSmallVector<Node *, 8> TemplateParams;
- Qualifiers CV = QualNone;
- FunctionRefQual RefQuals = FrefQualNone;
unsigned EncodingDepth = 0;
- bool ParsedCtorDtorCV = false;
- bool EndsWithTemplateArgs = false;
bool TagTemplates = true;
bool FixForwardReferences = false;
bool TryToParseTemplateArgs = true;
BumpPointerAllocator ASTAllocator;
- // A couple of members of Db are local to a specific name. When recursively
- // parsing names we need to swap and restore them all.
- struct SwapAndRestoreNameState {
- SwapAndRestore<Qualifiers> SaveQualifiers;
- SwapAndRestore<FunctionRefQual> SaveRefQualifiers;
- SwapAndRestore<bool> SaveEndsWithTemplateArgs;
- SwapAndRestore<bool> SaveParsedCtorDtorCV;
-
- SwapAndRestoreNameState(Db &Parser)
- : SaveQualifiers(Parser.CV, QualNone),
- SaveRefQualifiers(Parser.RefQuals, FrefQualNone),
- SaveEndsWithTemplateArgs(Parser.EndsWithTemplateArgs, false),
- SaveParsedCtorDtorCV(Parser.ParsedCtorDtorCV, false) {}
- };
-
template <class T, class... Args> T *make(Args &&... args) {
return new (ASTAllocator.allocate(sizeof(T)))
T(std::forward<Args>(args)...);
Node *parseClassEnumType();
Node *parseQualifiedType();
- Node *parseNestedName();
- Node *parseCtorDtorName(Node *&SoFar);
+ Node *parseEncoding();
+ bool parseCallOffset();
+ Node *parseSpecialName();
+
+ /// Holds some extra information about a <name> that is being parsed. This
+ /// information is only pertinent if the <name> refers to an <encoding>.
+ struct NameState {
+ bool CtorDtorConversion = false;
+ bool EndsWithTemplateArgs = false;
+ Qualifiers CVQualifiers = QualNone;
+ FunctionRefQual ReferenceQualifier = FrefQualNone;
+ };
+
+ /// Parse the <name> production>
+ Node *parseName(NameState *State = nullptr);
+ Node *parseLocalName(NameState *State);
+ Node *parseOperatorName(NameState *State);
+ Node *parseUnqualifiedName(NameState *State);
+ Node *parseUnnamedTypeName(NameState *State);
+ Node *parseSourceName(NameState *State);
+ Node *parseUnscopedName(NameState *State);
+ Node *parseNestedName(NameState *State);
+ Node *parseCtorDtorName(Node *&SoFar, NameState *State);
+
Node *parseAbiTags(Node *N);
// FIXME: remove this when all the parse_* functions have been rewritten.
Names.pop_back();
return R;
}
- template <const char *(*parse_fn)(const char *, const char *, Db &, bool *)>
- Node *legacyParse() {
- size_t BeforeType = Names.size();
- const char *OrigFirst = First;
- const char *T = parse_fn(First, Last, *this, nullptr);
- if (T == OrigFirst || BeforeType + 1 != Names.size())
- return nullptr;
- First = T;
- Node *R = Names.back();
- Names.pop_back();
- return R;
- }
};
-const char *parse_nested_name(const char *first, const char *last, Db &db,
- bool *endsWithTemplateArgs) {
- db.First = first;
- db.Last = last;
- Node *R = db.parseNestedName();
- if (endsWithTemplateArgs)
- *endsWithTemplateArgs = db.EndsWithTemplateArgs;
- if (R == nullptr)
- return first;
- db.Names.push_back(R);
- return db.First;
-}
-
const char *parse_expression(const char *first, const char *last, Db &db) {
db.First = first;
db.Last = last;
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_source_name(const char *first, const char *last, Db &db) {
+ db.First = first;
+ db.Last = last;
+ Node *R = db.parseSourceName(/*NameState=*/nullptr);
+ if (R == nullptr)
+ return first;
+ db.Names.push_back(R);
+ return db.First;
+}
+
+const char *parse_operator_name(const char *first, const char *last, Db &db) {
+ db.First = first;
+ db.Last = last;
+ Node *R = db.parseOperatorName(/*NameState=*/nullptr);
+ if (R == nullptr)
+ return first;
+ db.Names.push_back(R);
+ return db.First;
+}
+
+const char *parse_unqualified_name(const char *first, const char *last, Db &db) {
+ db.First = first;
+ db.Last = last;
+ Node *R = db.parseUnqualifiedName(/*NameState=*/nullptr);
+ if (R == nullptr)
+ return first;
+ db.Names.push_back(R);
+ return db.First;
+}
+
+const char *parse_encoding(const char *first, const char *last, Db &db) {
+ db.First = first;
+ db.Last = last;
+ Node *R = db.parseEncoding();
+ if (R == nullptr)
+ return first;
+ db.Names.push_back(R);
+ return db.First;
+}
+
+const char* parse_discriminator(const char* first, const char* last);
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_source_name(const char *, const char *, Db &);
-const char *parse_unqualified_name(const char *first, const char *last, Db &db);
-const char *parse_decltype(const char *first, const char *last, Db &db);
const char *parse_unresolved_name(const char *, const char *, Db &);
const char *parse_substitution(const char *, const char *, Db &);
-// <ctor-dtor-name> ::= C1 # complete object constructor
-// ::= C2 # base object constructor
-// ::= C3 # complete object allocating constructor
-// extension ::= C5 # ?
-// ::= D0 # deleting destructor
-// ::= D1 # complete object destructor
-// ::= D2 # base object destructor
-// extension ::= D5 # ?
-Node *Db::parseCtorDtorName(Node *&SoFar) {
- if (SoFar->K == Node::KSpecialSubstitution) {
- auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;
- switch (SSK) {
- case SpecialSubKind::string:
- case SpecialSubKind::istream:
- case SpecialSubKind::ostream:
- case SpecialSubKind::iostream:
- SoFar = make<ExpandedSpecialSubstitution>(SSK);
- default:
- break;
- }
- }
-
- if (consumeIf('C')) {
- bool IsInherited = consumeIf('I');
- if (look() != '1' && look() != '2' && look() != '3' && look() != '5')
+// <name> ::= <nested-name> // N
+// ::= <local-name> # See Scope Encoding below // Z
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+//
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+Node *Db::parseName(NameState *State) {
+ consumeIf('L'); // extension
+
+ if (look() == 'N')
+ return parseNestedName(State);
+ if (look() == 'Z')
+ return parseLocalName(State);
+
+ // ::= <unscoped-template-name> <template-args>
+ if (look() == 'S' && look(1) != 't') {
+ Node *S = legacyParse<parse_substitution>();
+ if (look() != 'I')
return nullptr;
- ++First;
- ParsedCtorDtorCV = true;
- if (IsInherited) {
- if (legacyParse<parse_name>() == nullptr)
- return nullptr;
- }
- return make<CtorDtorName>(SoFar, false);
+ Node *TA = legacyParse<parse_template_args>();
+ if (TA == nullptr)
+ return nullptr;
+ if (State) State->EndsWithTemplateArgs = true;
+ return make<NameWithTemplateArgs>(S, TA);
}
- if (look() == 'D' &&
- (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) {
- First += 2;
- ParsedCtorDtorCV = true;
- return make<CtorDtorName>(SoFar, true);
+ Node *N = parseUnscopedName(State);
+ if (N == nullptr)
+ return nullptr;
+ // ::= <unscoped-template-name> <template-args>
+ if (look() == 'I') {
+ Subs.push_back(N);
+ Node *TA = legacyParse<parse_template_args>();
+ if (TA == nullptr)
+ return nullptr;
+ if (State) State->EndsWithTemplateArgs = true;
+ return make<NameWithTemplateArgs>(N, TA);
}
-
- return nullptr;
+ // ::= <unscoped-name>
+ return N;
}
-// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
-// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
-//
-// <prefix> ::= <prefix> <unqualified-name>
-// ::= <template-prefix> <template-args>
-// ::= <template-param>
-// ::= <decltype>
-// ::= # empty
-// ::= <substitution>
-// ::= <prefix> <data-member-prefix>
-// extension ::= L
-//
-// <template-prefix> ::= <prefix> <template unqualified-name>
-// ::= <template-param>
-// ::= <substitution>
-Node *Db::parseNestedName() {
- if (!consumeIf('N'))
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+// := Z <function encoding> E s [<discriminator>]
+// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+Node *Db::parseLocalName(NameState *State) {
+ if (!consumeIf('Z'))
+ return nullptr;
+ Node *Encoding = parseEncoding();
+ if (Encoding == nullptr || !consumeIf('E'))
return nullptr;
- CV = parseCVQualifiers();
- if (consumeIf('O')) RefQuals = FrefQualRValue;
- else if (consumeIf('R')) RefQuals = FrefQualLValue;
- else RefQuals = FrefQualNone;
-
- Node *SoFar = nullptr;
- auto PushComponent = [&](Node *Comp) {
- if (SoFar) SoFar = make<QualifiedName>(SoFar, Comp);
- else SoFar = Comp;
- EndsWithTemplateArgs = false;
- };
-
- if (consumeIf("St"))
- SoFar = make<NameType>("std");
-
- while (!consumeIf('E')) {
- consumeIf('L'); // extension
-
- // ::= <template-param>
- if (look() == 'T') {
- Node *TP = legacyParse<parse_template_param>();
- if (TP == nullptr)
- return nullptr;
- PushComponent(TP);
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <template-prefix> <template-args>
- if (look() == 'I') {
- Node *TA;
- {
- SwapAndRestoreNameState SaveState(*this);
- TA = legacyParse<parse_template_args>();
- }
- if (TA == nullptr || SoFar == nullptr)
- return nullptr;
- SoFar = make<NameWithTemplateArgs>(SoFar, TA);
- EndsWithTemplateArgs = true;
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <decltype>
- if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
- Node *DT;
- {
- SwapAndRestoreNameState SaveState(*this);
- DT = parseDecltype();
- }
- if (DT == nullptr)
- return nullptr;
- PushComponent(DT);
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <substitution>
- if (look() == 'S' && look(1) != 't') {
- Node *S = legacyParse<parse_substitution>();
- if (S == nullptr)
- return nullptr;
- PushComponent(S);
- if (SoFar != S)
- Subs.push_back(S);
- continue;
- }
-
- // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.
- if (look() == 'C' || look() == 'D') {
- if (SoFar == nullptr)
- return nullptr;
- Node *CtorDtor = parseCtorDtorName(SoFar);
- if (CtorDtor == nullptr)
- return nullptr;
- PushComponent(CtorDtor);
- SoFar = parseAbiTags(SoFar);
- if (SoFar == nullptr)
- return nullptr;
- Subs.push_back(SoFar);
- continue;
- }
+ if (consumeIf('s')) {
+ First = parse_discriminator(First, Last);
+ return make<QualifiedName>(Encoding, make<NameType>("string literal"));
+ }
- // ::= <prefix> <unqualified-name>
- Node *N = legacyParse<parse_unqualified_name>();
+ if (consumeIf('d')) {
+ parseNumber(true);
+ if (!consumeIf('_'))
+ return nullptr;
+ Node *N = parseName(State);
if (N == nullptr)
return nullptr;
- PushComponent(N);
- Subs.push_back(SoFar);
+ return make<QualifiedName>(Encoding, N);
}
- if (SoFar == nullptr || Subs.empty())
+ Node *Entity = parseName(State);
+ if (Entity == nullptr)
return nullptr;
-
- Subs.pop_back();
- return SoFar;
+ First = parse_discriminator(First, Last);
+ return make<QualifiedName>(Encoding, Entity);
}
-// <abi-tags> ::= <abi-tag> [<abi-tags>]
-// <abi-tag> ::= B <source-name>
-Node *Db::parseAbiTags(Node *N) {
- while (consumeIf('B')) {
- StringView SN = parseBareSourceName();
- if (SN.empty())
- return nullptr;
- N = make<AbiTagAttr>(N, SN);
- }
- return N;
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+Node *Db::parseUnscopedName(NameState *State) {
+ if (consumeIf("StL") || consumeIf("St")) {
+ Node *R = parseUnqualifiedName(State);
+ if (R == nullptr)
+ return nullptr;
+ return make<StdQualifiedName>(R);
+ }
+ return parseUnqualifiedName(State);
}
-// <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);
+// <unqualified-name> ::= <operator-name> [abi-tags]
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+// FIXME: ::= DC <source-name>+ E # structured binding declaration
+Node *Db::parseUnqualifiedName(NameState *State) {
+ // <ctor-dtor-name>s are special-cased in parseNestedName().
+ Node *Result;
+ if (look() == 'U')
+ Result = parseUnnamedTypeName(State);
+ else if (look() >= '1' && look() <= '9')
+ Result = parseSourceName(State);
+ else
+ Result = parseOperatorName(State);
+ if (Result != nullptr)
+ Result = parseAbiTags(Result);
+ return Result;
}
-// <positive length number> ::= [0-9]*
-bool Db::parsePositiveInteger(size_t *Out) {
- *Out = 0;
- if (look() < '0' || look() > '9')
- return true;
- while (look() >= '0' && look() <= '9') {
- *Out *= 10;
- *Out += static_cast<size_t>(consume() - '0');
+// <unnamed-type-name> ::= Ut [<nonnegative number>] _
+// ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+Node *Db::parseUnnamedTypeName(NameState *) {
+ if (consumeIf("Ut")) {
+ StringView Count = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<UnnamedTypeName>(Count);
+ }
+ if (consumeIf("Ul")) {
+ NodeArray Params;
+ if (!consumeIf("vE")) {
+ size_t ParamsBegin = Names.size();
+ do {
+ Node *P = parseType();
+ if (P == nullptr)
+ return nullptr;
+ Names.push_back(P);
+ } while (!consumeIf('E'));
+ Params = popTrailingNodeArray(ParamsBegin);
+ }
+ StringView Count = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<ClosureTypeName>(Params, Count);
}
- return false;
+ return nullptr;
}
-StringView Db::parseBareSourceName() {
- size_t Int = 0;
- if (parsePositiveInteger(&Int) || numLeft() < Int)
- return StringView();
- StringView R(First, First + Int);
- First += Int;
- return R;
+// <source-name> ::= <positive length number> <identifier>
+Node *Db::parseSourceName(NameState *) {
+ size_t Length = 0;
+ if (parsePositiveInteger(&Length))
+ return nullptr;
+ if (numLeft() < Length || Length == 0)
+ return nullptr;
+ StringView Name(First, First + Length);
+ First += Length;
+ if (Name.startsWith("_GLOBAL__N"))
+ return make<NameType>("(anonymous namespace)");
+ return make<NameType>(Name);
}
-// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
-//
-// <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw())
-// ::= DO <expression> E # computed (instantiation-dependent) noexcept
-// ::= Dw <type>+ E # dynamic exception specification with instantiation-dependent types
-//
-// <ref-qualifier> ::= R # & ref-qualifier
-// <ref-qualifier> ::= O # && ref-qualifier
-Node *Db::parseFunctionType() {
- Qualifiers CVQuals = parseCVQualifiers();
-
- Node *ExceptionSpec = nullptr;
- if (consumeIf("Do")) {
- ExceptionSpec = make<NameType>("noexcept");
- } else if (consumeIf("DO")) {
- Node *E = parseExpr();
- if (E == nullptr || !consumeIf('E'))
- return nullptr;
- ExceptionSpec = make<NoexceptSpec>(E);
- } else if (consumeIf("Dw")) {
- size_t SpecsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *T = parseType();
- if (T == nullptr)
- return nullptr;
- Names.push_back(T);
+// <operator-name> ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= li <source-name> # operator ""
+// ::= ls # <<
+// ::= lS # <<=
+// ::= lt # <
+// ::= mi # -
+// ::= mI # -=
+// ::= ml # *
+// ::= mL # *=
+// ::= mm # -- (postfix in <expression> context)
+// ::= na # new[]
+// ::= ne # !=
+// ::= ng # - (unary)
+// ::= nt # !
+// ::= nw # new
+// ::= oo # ||
+// ::= or # |
+// ::= oR # |=
+// ::= pm # ->*
+// ::= pl # +
+// ::= pL # +=
+// ::= pp # ++ (postfix in <expression> context)
+// ::= ps # + (unary)
+// ::= pt # ->
+// ::= qu # ?
+// ::= rm # %
+// ::= rM # %=
+// ::= rs # >>
+// ::= rS # >>=
+// ::= ss # <=> C++2a
+// ::= v <digit> <source-name> # vendor extended operator
+Node *Db::parseOperatorName(NameState *State) {
+ switch (look()) {
+ case 'a':
+ switch (look(1)) {
+ case 'a':
+ First += 2;
+ return make<NameType>("operator&&");
+ case 'd':
+ case 'n':
+ First += 2;
+ return make<NameType>("operator&");
+ case 'N':
+ First += 2;
+ return make<NameType>("operator&=");
+ case 'S':
+ First += 2;
+ return make<NameType>("operator=");
}
- ExceptionSpec =
- make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));
- }
-
- consumeIf("Dx"); // transaction safe
-
- if (!consumeIf('F'))
return nullptr;
- consumeIf('Y'); // extern "C"
- Node *ReturnType = parseType();
- if (ReturnType == nullptr)
- return nullptr;
-
- FunctionRefQual ReferenceQualifier = FrefQualNone;
- size_t ParamsBegin = Names.size();
- while (true) {
- if (consumeIf('E'))
- break;
- if (consumeIf('v'))
- continue;
- if (consumeIf("RE")) {
- ReferenceQualifier = FrefQualLValue;
- break;
+ case 'c':
+ switch (look(1)) {
+ case 'l':
+ First += 2;
+ return make<NameType>("operator()");
+ case 'm':
+ First += 2;
+ return make<NameType>("operator,");
+ case 'o':
+ First += 2;
+ return make<NameType>("operator~");
+ // ::= cv <type> # (cast)
+ case 'v': {
+ SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ if (State) State->CtorDtorConversion = true;
+ return make<ConversionOperatorType>(Ty);
}
- if (consumeIf("OE")) {
- ReferenceQualifier = FrefQualRValue;
- break;
}
- Node *T = parseType();
- if (T == nullptr)
- return nullptr;
- Names.push_back(T);
- }
-
- NodeArray Params = popTrailingNodeArray(ParamsBegin);
- return make<FunctionType>(ReturnType, Params, CVQuals,
- ReferenceQualifier, ExceptionSpec);
-}
-
-// extension:
-// <vector-type> ::= Dv <positive dimension number> _ <extended element type>
-// ::= Dv [<dimension expression>] _ <element type>
-// <extended element type> ::= <element type>
-// ::= p # AltiVec vector pixel
-Node *Db::parseVectorType() {
- if (!consumeIf("Dv"))
- return nullptr;
- if (look() >= '1' && look() <= '9') {
- StringView DimensionNumber = parseNumber();
- if (!consumeIf('_'))
- return nullptr;
- if (consumeIf('p'))
- return make<VectorType>(DimensionNumber);
- Node *ElemType = parseType();
- if (ElemType == nullptr)
- return nullptr;
- return make<VectorType>(ElemType, DimensionNumber);
- }
-
- if (!consumeIf('_')) {
- Node *DimExpr = parseExpr();
- if (!DimExpr)
- return nullptr;
- if (!consumeIf('_'))
- return nullptr;
- Node *ElemType = parseType();
- if (!ElemType)
- return nullptr;
- return make<VectorType>(ElemType, DimExpr);
- }
- Node *ElemType = parseType();
- if (!ElemType)
return nullptr;
- return make<VectorType>(ElemType, StringView());
-}
-
-// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
-// ::= DT <expression> E # decltype of an expression (C++0x)
-Node *Db::parseDecltype() {
- if (!consumeIf('D'))
+ case 'd':
+ switch (look(1)) {
+ case 'a':
+ First += 2;
+ return make<NameType>("operator delete[]");
+ case 'e':
+ First += 2;
+ return make<NameType>("operator*");
+ case 'l':
+ First += 2;
+ return make<NameType>("operator delete");
+ case 'v':
+ First += 2;
+ return make<NameType>("operator/");
+ case 'V':
+ First += 2;
+ return make<NameType>("operator/=");
+ }
return nullptr;
- if (!consumeIf('t') && !consumeIf('T'))
+ case 'e':
+ switch (look(1)) {
+ case 'o':
+ First += 2;
+ return make<NameType>("operator^");
+ case 'O':
+ First += 2;
+ return make<NameType>("operator^=");
+ case 'q':
+ First += 2;
+ return make<NameType>("operator==");
+ }
return nullptr;
- Node *E = parseExpr();
- if (E == nullptr)
+ case 'g':
+ switch (look(1)) {
+ case 'e':
+ First += 2;
+ return make<NameType>("operator>=");
+ case 't':
+ First += 2;
+ return make<NameType>("operator>");
+ }
return nullptr;
- if (!consumeIf('E'))
+ case 'i':
+ if (look(1) == 'x') {
+ First += 2;
+ return make<NameType>("operator[]");
+ }
return nullptr;
- return make<EnclosingExpr>("decltype(", E, ")");
-}
-
-// <array-type> ::= A <positive dimension number> _ <element type>
-// ::= A [<dimension expression>] _ <element type>
-Node *Db::parseArrayType() {
- if (!consumeIf('A'))
+ case 'l':
+ switch (look(1)) {
+ case 'e':
+ First += 2;
+ return make<NameType>("operator<=");
+ // ::= li <source-name> # operator ""
+ case 'i': {
+ First += 2;
+ Node *SN = parseSourceName(State);
+ if (SN == nullptr)
+ return nullptr;
+ return make<LiteralOperator>(SN);
+ }
+ case 's':
+ First += 2;
+ return make<NameType>("operator<<");
+ case 'S':
+ First += 2;
+ return make<NameType>("operator<<=");
+ case 't':
+ First += 2;
+ return make<NameType>("operator<");
+ }
return nullptr;
-
- if (std::isdigit(look())) {
- StringView Dimension = parseNumber();
- if (!consumeIf('_'))
- return nullptr;
- Node *Ty = parseType();
- if (Ty == nullptr)
- return nullptr;
- return make<ArrayType>(Ty, Dimension);
- }
-
- if (!consumeIf('_')) {
- Node *DimExpr = parseExpr();
- if (DimExpr == nullptr)
- return nullptr;
- if (!consumeIf('_'))
- return nullptr;
- Node *ElementType = parseType();
- if (ElementType == nullptr)
- return nullptr;
- return make<ArrayType>(ElementType, DimExpr);
- }
-
- Node *Ty = parseType();
- if (Ty == nullptr)
+ case 'm':
+ switch (look(1)) {
+ case 'i':
+ First += 2;
+ return make<NameType>("operator-");
+ case 'I':
+ First += 2;
+ return make<NameType>("operator-=");
+ case 'l':
+ First += 2;
+ return make<NameType>("operator*");
+ case 'L':
+ First += 2;
+ return make<NameType>("operator*=");
+ case 'm':
+ First += 2;
+ return make<NameType>("operator--");
+ }
return nullptr;
- return make<ArrayType>(Ty);
-}
-
-// <pointer-to-member-type> ::= M <class type> <member type>
-Node *Db::parsePointerToMemberType() {
- if (!consumeIf('M'))
+ case 'n':
+ switch (look(1)) {
+ case 'a':
+ First += 2;
+ return make<NameType>("operator new[]");
+ case 'e':
+ First += 2;
+ return make<NameType>("operator!=");
+ case 'g':
+ First += 2;
+ return make<NameType>("operator-");
+ case 't':
+ First += 2;
+ return make<NameType>("operator!");
+ case 'w':
+ First += 2;
+ return make<NameType>("operator new");
+ }
return nullptr;
- Node *ClassType = parseType();
- if (ClassType == nullptr)
+ case 'o':
+ switch (look(1)) {
+ case 'o':
+ First += 2;
+ return make<NameType>("operator||");
+ case 'r':
+ First += 2;
+ return make<NameType>("operator|");
+ case 'R':
+ First += 2;
+ return make<NameType>("operator|=");
+ }
return nullptr;
- Node *MemberType = parseType();
- if (MemberType == nullptr)
+ case 'p':
+ switch (look(1)) {
+ case 'm':
+ First += 2;
+ return make<NameType>("operator->*");
+ case 'l':
+ First += 2;
+ return make<NameType>("operator+");
+ case 'L':
+ First += 2;
+ return make<NameType>("operator+=");
+ case 'p':
+ First += 2;
+ return make<NameType>("operator++");
+ case 's':
+ First += 2;
+ return make<NameType>("operator+");
+ case 't':
+ First += 2;
+ return make<NameType>("operator->");
+ }
return nullptr;
- return make<PointerToMemberType>(ClassType, MemberType);
+ case 'q':
+ if (look(1) == 'u') {
+ First += 2;
+ return make<NameType>("operator?");
+ }
+ return nullptr;
+ case 'r':
+ switch (look(1)) {
+ case 'm':
+ First += 2;
+ return make<NameType>("operator%");
+ case 'M':
+ First += 2;
+ return make<NameType>("operator%=");
+ case 's':
+ First += 2;
+ return make<NameType>("operator>>");
+ case 'S':
+ First += 2;
+ return make<NameType>("operator>>=");
+ }
+ return nullptr;
+ case 's':
+ if (look(1) == 's') {
+ First += 2;
+ return make<NameType>("operator<=>");
+ }
+ return nullptr;
+ // ::= v <digit> <source-name> # vendor extended operator
+ case 'v':
+ if (std::isdigit(look(1))) {
+ First += 2;
+ Node *SN = parseSourceName(State);
+ if (SN == nullptr)
+ return nullptr;
+ return make<ConversionOperatorType>(SN);
+ }
+ return nullptr;
+ }
+ return nullptr;
}
-// <class-enum-type> ::= <name> # non-dependent type name, dependent type name, or dependent typename-specifier
-// ::= Ts <name> # dependent elaborated type specifier using 'struct' or 'class'
-// ::= Tu <name> # dependent elaborated type specifier using 'union'
-// ::= Te <name> # dependent elaborated type specifier using 'enum'
-Node *Db::parseClassEnumType() {
- StringView ElabSpef;
- if (consumeIf("Ts"))
- ElabSpef = "struct";
- else if (consumeIf("Tu"))
- ElabSpef = "union";
- else if (consumeIf("Te"))
- ElabSpef = "enum";
+// <ctor-dtor-name> ::= C1 # complete object constructor
+// ::= C2 # base object constructor
+// ::= C3 # complete object allocating constructor
+// extension ::= C5 # ?
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+// extension ::= D5 # ?
+Node *Db::parseCtorDtorName(Node *&SoFar, NameState *State) {
+ if (SoFar->K == Node::KSpecialSubstitution) {
+ auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;
+ switch (SSK) {
+ case SpecialSubKind::string:
+ case SpecialSubKind::istream:
+ case SpecialSubKind::ostream:
+ case SpecialSubKind::iostream:
+ SoFar = make<ExpandedSpecialSubstitution>(SSK);
+ default:
+ break;
+ }
+ }
- Node *Name = legacyParse<parse_name>();
- if (Name == nullptr)
- return nullptr;
+ if (consumeIf('C')) {
+ bool IsInherited = consumeIf('I');
+ if (look() != '1' && look() != '2' && look() != '3' && look() != '5')
+ return nullptr;
+ ++First;
+ if (State) State->CtorDtorConversion = true;
+ if (IsInherited) {
+ if (parseName() == nullptr)
+ return nullptr;
+ }
+ return make<CtorDtorName>(SoFar, false);
+ }
- if (!ElabSpef.empty())
- return make<ElaboratedTypeSpefType>(ElabSpef, Name);
+ if (look() == 'D' &&
+ (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) {
+ First += 2;
+ if (State) State->CtorDtorConversion = true;
+ return make<CtorDtorName>(SoFar, true);
+ }
- return Name;
+ return nullptr;
}
-// <qualified-type> ::= <qualifiers> <type>
-// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers>
-// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier
-Node *Db::parseQualifiedType() {
- if (consumeIf('U')) {
- StringView Qual = parseBareSourceName();
- if (Qual.empty())
- return nullptr;
+// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+//
+// <prefix> ::= <prefix> <unqualified-name>
+// ::= <template-prefix> <template-args>
+// ::= <template-param>
+// ::= <decltype>
+// ::= # empty
+// ::= <substitution>
+// ::= <prefix> <data-member-prefix>
+// extension ::= L
+//
+// <template-prefix> ::= <prefix> <template unqualified-name>
+// ::= <template-param>
+// ::= <substitution>
+Node *Db::parseNestedName(NameState *State) {
+ if (!consumeIf('N'))
+ return nullptr;
- // FIXME parse the optional <template-args> here!
+ Qualifiers CVTmp = parseCVQualifiers();
+ if (State) State->CVQualifiers = CVTmp;
- // extension ::= U <objc-name> <objc-type> # objc-type<identifier>
- if (Qual.startsWith("objcproto")) {
- StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
- StringView Proto;
- {
- SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()),
- SaveLast(Last, ProtoSourceName.end());
- Proto = parseBareSourceName();
- }
- if (Proto.empty())
+ if (consumeIf('O')) {
+ if (State) State->ReferenceQualifier = FrefQualRValue;
+ } else if (consumeIf('R')) {
+ if (State) State->ReferenceQualifier = FrefQualLValue;
+ } else
+ if (State) State->ReferenceQualifier = FrefQualNone;
+
+ Node *SoFar = nullptr;
+ auto PushComponent = [&](Node *Comp) {
+ if (SoFar) SoFar = make<QualifiedName>(SoFar, Comp);
+ else SoFar = Comp;
+ if (State) State->EndsWithTemplateArgs = false;
+ };
+
+ if (consumeIf("St"))
+ SoFar = make<NameType>("std");
+
+ while (!consumeIf('E')) {
+ consumeIf('L'); // extension
+
+ // ::= <template-param>
+ if (look() == 'T') {
+ Node *TP = legacyParse<parse_template_param>();
+ if (TP == nullptr)
return nullptr;
- Node *Child = parseQualifiedType();
- if (Child == nullptr)
+ PushComponent(TP);
+ Subs.push_back(SoFar);
+ continue;
+ }
+
+ // ::= <template-prefix> <template-args>
+ if (look() == 'I') {
+ Node *TA = legacyParse<parse_template_args>();
+ if (TA == nullptr || SoFar == nullptr)
return nullptr;
- return make<ObjCProtoName>(Child, Proto);
+ SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+ if (State) State->EndsWithTemplateArgs = true;
+ Subs.push_back(SoFar);
+ continue;
}
- Node *Child = parseQualifiedType();
- if (Child == nullptr)
+ // ::= <decltype>
+ if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
+ Node *DT = parseDecltype();
+ if (DT == nullptr)
+ return nullptr;
+ PushComponent(DT);
+ Subs.push_back(SoFar);
+ continue;
+ }
+
+ // ::= <substitution>
+ if (look() == 'S' && look(1) != 't') {
+ Node *S = legacyParse<parse_substitution>();
+ if (S == nullptr)
+ return nullptr;
+ PushComponent(S);
+ if (SoFar != S)
+ Subs.push_back(S);
+ continue;
+ }
+
+ // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.
+ if (look() == 'C' || look() == 'D') {
+ if (SoFar == nullptr)
+ return nullptr;
+ Node *CtorDtor = parseCtorDtorName(SoFar, State);
+ if (CtorDtor == nullptr)
+ return nullptr;
+ PushComponent(CtorDtor);
+ SoFar = parseAbiTags(SoFar);
+ if (SoFar == nullptr)
+ return nullptr;
+ Subs.push_back(SoFar);
+ continue;
+ }
+
+ // ::= <prefix> <unqualified-name>
+ Node *N = parseUnqualifiedName(State);
+ if (N == nullptr)
return nullptr;
- return make<VendorExtQualType>(Child, Qual);
+ PushComponent(N);
+ Subs.push_back(SoFar);
}
- Qualifiers Quals = parseCVQualifiers();
- Node *Ty = parseType();
- if (Ty == nullptr)
+ if (SoFar == nullptr || Subs.empty())
return nullptr;
- if (Quals != QualNone)
- Ty = make<QualType>(Ty, Quals);
- return Ty;
+
+ Subs.pop_back();
+ return SoFar;
}
-// <type> ::= <builtin-type>
-// ::= <qualified-type>
-// ::= <function-type>
-// ::= <class-enum-type>
-// ::= <array-type>
-// ::= <pointer-to-member-type>
-// ::= <template-param>
-// ::= <template-template-param> <template-args>
-// ::= <decltype>
-// ::= P <type> # pointer
-// ::= R <type> # l-value reference
-// ::= O <type> # r-value reference (C++11)
-// ::= C <type> # complex pair (C99)
-// ::= G <type> # imaginary (C99)
-// ::= <substitution> # See Compression below
-// extension ::= U <objc-name> <objc-type> # objc-type<identifier>
-// extension ::= <vector-type> # <vector-type> starts with Dv
-//
-// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
-// <objc-type> ::= <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
-Node *Db::parseType() {
- Node *Result = nullptr;
+// <abi-tags> ::= <abi-tag> [<abi-tags>]
+// <abi-tag> ::= B <source-name>
+Node *Db::parseAbiTags(Node *N) {
+ while (consumeIf('B')) {
+ StringView SN = parseBareSourceName();
+ if (SN.empty())
+ return nullptr;
+ N = make<AbiTagAttr>(N, SN);
+ }
+ return N;
+}
- switch (look()) {
- // ::= <qualified-type>
- case 'r':
- case 'V':
- case 'K': {
- unsigned AfterQuals = 0;
- if (look(AfterQuals) == 'r') ++AfterQuals;
- if (look(AfterQuals) == 'V') ++AfterQuals;
- if (look(AfterQuals) == 'K') ++AfterQuals;
+// <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);
+}
- if (look(AfterQuals) == 'F' ||
- (look(AfterQuals) == 'D' &&
- (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' ||
- look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) {
- Result = parseFunctionType();
- break;
- }
- _LIBCPP_FALLTHROUGH();
- }
- case 'U': {
- Result = parseQualifiedType();
- break;
+// <positive length number> ::= [0-9]*
+bool Db::parsePositiveInteger(size_t *Out) {
+ *Out = 0;
+ if (look() < '0' || look() > '9')
+ return true;
+ while (look() >= '0' && look() <= '9') {
+ *Out *= 10;
+ *Out += static_cast<size_t>(consume() - '0');
}
- // <builtin-type> ::= v # void
- case 'v':
- ++First;
- return make<NameType>("void");
- // ::= w # wchar_t
- case 'w':
- ++First;
- return make<NameType>("wchar_t");
- // ::= b # bool
- case 'b':
- ++First;
- return make<NameType>("bool");
- // ::= c # char
- case 'c':
- ++First;
- return make<NameType>("char");
- // ::= a # signed char
- case 'a':
- ++First;
- return make<NameType>("signed char");
- // ::= h # unsigned char
- case 'h':
- ++First;
- return make<NameType>("unsigned char");
- // ::= s # short
- case 's':
- ++First;
- return make<NameType>("short");
- // ::= t # unsigned short
- case 't':
- ++First;
- return make<NameType>("unsigned short");
- // ::= i # int
- case 'i':
- ++First;
- return make<NameType>("int");
- // ::= j # unsigned int
- case 'j':
- ++First;
- return make<NameType>("unsigned int");
- // ::= l # long
- case 'l':
- ++First;
- return make<NameType>("long");
- // ::= m # unsigned long
- case 'm':
- ++First;
- return make<NameType>("unsigned long");
- // ::= x # long long, __int64
- case 'x':
- ++First;
- return make<NameType>("long long");
- // ::= y # unsigned long long, __int64
- case 'y':
- ++First;
- return make<NameType>("unsigned long long");
- // ::= n # __int128
- case 'n':
- ++First;
- return make<NameType>("__int128");
- // ::= o # unsigned __int128
- case 'o':
- ++First;
- return make<NameType>("unsigned __int128");
- // ::= f # float
- case 'f':
- ++First;
- return make<NameType>("float");
- // ::= d # double
- case 'd':
- ++First;
- return make<NameType>("double");
- // ::= e # long double, __float80
- case 'e':
- ++First;
- return make<NameType>("long double");
- // ::= g # __float128
- case 'g':
- ++First;
- return make<NameType>("__float128");
- // ::= z # ellipsis
- case 'z':
- ++First;
- return make<NameType>("...");
+ return false;
+}
- // <builtin-type> ::= u <source-name> # vendor extended type
- case 'u': {
- ++First;
- StringView Res = parseBareSourceName();
- if (Res.empty())
+StringView Db::parseBareSourceName() {
+ size_t Int = 0;
+ if (parsePositiveInteger(&Int) || numLeft() < Int)
+ return StringView();
+ StringView R(First, First + Int);
+ First += Int;
+ return R;
+}
+
+// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
+//
+// <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw())
+// ::= DO <expression> E # computed (instantiation-dependent) noexcept
+// ::= Dw <type>+ E # dynamic exception specification with instantiation-dependent types
+//
+// <ref-qualifier> ::= R # & ref-qualifier
+// <ref-qualifier> ::= O # && ref-qualifier
+Node *Db::parseFunctionType() {
+ Qualifiers CVQuals = parseCVQualifiers();
+
+ Node *ExceptionSpec = nullptr;
+ if (consumeIf("Do")) {
+ ExceptionSpec = make<NameType>("noexcept");
+ } else if (consumeIf("DO")) {
+ Node *E = parseExpr();
+ if (E == nullptr || !consumeIf('E'))
return nullptr;
- return make<NameType>(Res);
+ ExceptionSpec = make<NoexceptSpec>(E);
+ } else if (consumeIf("Dw")) {
+ size_t SpecsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *T = parseType();
+ if (T == nullptr)
+ return nullptr;
+ Names.push_back(T);
+ }
+ ExceptionSpec =
+ make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));
}
- case 'D':
- switch (look(1)) {
- // ::= Dd # IEEE 754r decimal floating point (64 bits)
- case 'd':
- First += 2;
- return make<NameType>("decimal64");
- // ::= De # IEEE 754r decimal floating point (128 bits)
- case 'e':
- First += 2;
- return make<NameType>("decimal128");
- // ::= Df # IEEE 754r decimal floating point (32 bits)
- case 'f':
- First += 2;
- return make<NameType>("decimal32");
- // ::= Dh # IEEE 754r half-precision floating point (16 bits)
- case 'h':
- First += 2;
- return make<NameType>("decimal16");
- // ::= Di # char32_t
- case 'i':
- First += 2;
- return make<NameType>("char32_t");
- // ::= Ds # char16_t
- case 's':
- First += 2;
- return make<NameType>("char16_t");
- // ::= Da # auto (in dependent new-expressions)
- case 'a':
- First += 2;
- return make<NameType>("auto");
- // ::= Dc # decltype(auto)
- case 'c':
- First += 2;
- return make<NameType>("decltype(auto)");
- // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
- case 'n':
- First += 2;
- return make<NameType>("std::nullptr_t");
- // ::= <decltype>
- case 't':
- case 'T': {
- Result = parseDecltype();
- break;
- }
- // extension ::= <vector-type> # <vector-type> starts with Dv
- case 'v': {
- Result = parseVectorType();
+ consumeIf("Dx"); // transaction safe
+
+ if (!consumeIf('F'))
+ return nullptr;
+ consumeIf('Y'); // extern "C"
+ Node *ReturnType = parseType();
+ if (ReturnType == nullptr)
+ return nullptr;
+
+ FunctionRefQual ReferenceQualifier = FrefQualNone;
+ size_t ParamsBegin = Names.size();
+ while (true) {
+ if (consumeIf('E'))
break;
- }
- // ::= Dp <type> # pack expansion (C++0x)
- case 'p': {
- First += 2;
- Node *Child = parseType();
- if (!Child)
- return nullptr;
- Result = make<ParameterPackExpansion>(Child);
+ if (consumeIf('v'))
+ continue;
+ if (consumeIf("RE")) {
+ ReferenceQualifier = FrefQualLValue;
break;
}
- // Exception specifier on a function type.
- case 'o':
- case 'O':
- case 'w':
- // Transaction safe function type.
- case 'x':
- Result = parseFunctionType();
+ if (consumeIf("OE")) {
+ ReferenceQualifier = FrefQualRValue;
break;
}
- break;
- // ::= <function-type>
- case 'F': {
- Result = parseFunctionType();
- break;
+ Node *T = parseType();
+ if (T == nullptr)
+ return nullptr;
+ Names.push_back(T);
}
- // ::= <array-type>
- case 'A': {
- Result = parseArrayType();
- break;
- }
- // ::= <pointer-to-member-type>
- case 'M': {
- Result = parsePointerToMemberType();
- break;
- }
- // ::= <template-param>
- case 'T': {
- // This could be an elaborate type specifier on a <class-enum-type>.
- if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') {
- Result = parseClassEnumType();
- break;
- }
-
- Result = legacyParse<parse_template_param>();
- if (Result == nullptr)
- return nullptr;
- // Result could be either of:
- // <type> ::= <template-param>
- // <type> ::= <template-template-param> <template-args>
- //
- // <template-template-param> ::= <template-param>
- // ::= <substitution>
- //
- // If this is followed by some <template-args>, and we're permitted to
- // parse them, take the second production.
+ NodeArray Params = popTrailingNodeArray(ParamsBegin);
+ return make<FunctionType>(ReturnType, Params, CVQuals,
+ ReferenceQualifier, ExceptionSpec);
+}
- if (TryToParseTemplateArgs && look() == 'I') {
- Node *TA = legacyParse<parse_template_args>();
- if (TA == nullptr)
- return nullptr;
- Result = make<NameWithTemplateArgs>(Result, TA);
- }
- break;
- }
- // ::= P <type> # pointer
- case 'P': {
- ++First;
- Node *Ptr = parseType();
- if (Ptr == nullptr)
+// extension:
+// <vector-type> ::= Dv <positive dimension number> _ <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
+Node *Db::parseVectorType() {
+ if (!consumeIf("Dv"))
+ return nullptr;
+ if (look() >= '1' && look() <= '9') {
+ StringView DimensionNumber = parseNumber();
+ if (!consumeIf('_'))
return nullptr;
- Result = make<PointerType>(Ptr);
- break;
- }
- // ::= R <type> # l-value reference
- case 'R': {
- ++First;
- Node *Ref = parseType();
- if (Ref == nullptr)
+ if (consumeIf('p'))
+ return make<VectorType>(DimensionNumber);
+ Node *ElemType = parseType();
+ if (ElemType == nullptr)
return nullptr;
- Result = make<LValueReferenceType>(Ref);
- break;
+ return make<VectorType>(ElemType, DimensionNumber);
}
- // ::= O <type> # r-value reference (C++11)
- case 'O': {
- ++First;
- Node *Ref = parseType();
- if (Ref == nullptr)
+
+ if (!consumeIf('_')) {
+ Node *DimExpr = parseExpr();
+ if (!DimExpr)
return nullptr;
- Result = make<RValueReferenceType>(Ref);
- break;
- }
- // ::= C <type> # complex pair (C99)
- case 'C': {
- ++First;
- Node *P = parseType();
- if (P == nullptr)
+ if (!consumeIf('_'))
return nullptr;
- Result = make<PostfixQualifiedType>(P, " complex");
- break;
- }
- // ::= G <type> # imaginary (C99)
- case 'G': {
- ++First;
- Node *P = parseType();
- if (P == nullptr)
- return P;
- Result = make<PostfixQualifiedType>(P, " imaginary");
- break;
- }
- // ::= <substitution> # See Compression below
- case 'S': {
- if (look(1) && look(1) != 't') {
- Node *Sub = legacyParse<parse_substitution>();
- if (Sub == nullptr)
- return nullptr;
-
- // Sub could be either of:
- // <type> ::= <substitution>
- // <type> ::= <template-template-param> <template-args>
- //
- // <template-template-param> ::= <template-param>
- // ::= <substitution>
- //
- // If this is followed by some <template-args>, and we're permitted to
- // parse them, take the second production.
-
- if (TryToParseTemplateArgs && look() == 'I') {
- Node *TA = legacyParse<parse_template_args>();
- if (TA == nullptr)
- return nullptr;
- Result = make<NameWithTemplateArgs>(Sub, TA);
- break;
- }
-
- // If all we parsed was a substitution, don't re-insert into the
- // substitution table.
- return Sub;
- }
- _LIBCPP_FALLTHROUGH();
- }
- // ::= <class-enum-type>
- default: {
- Result = parseClassEnumType();
- break;
- }
+ Node *ElemType = parseType();
+ if (!ElemType)
+ return nullptr;
+ return make<VectorType>(ElemType, DimExpr);
}
-
- // If we parsed a type, insert it into the substitution table. Note that all
- // <builtin-type>s and <substitution>s have already bailed out, because they
- // don't get substitutions.
- if (Result != nullptr)
- Subs.push_back(Result);
- return Result;
+ Node *ElemType = parseType();
+ if (!ElemType)
+ return nullptr;
+ return make<VectorType>(ElemType, StringView());
}
-Node *Db::parsePrefixExpr(StringView Kind) {
+// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
+// ::= DT <expression> E # decltype of an expression (C++0x)
+Node *Db::parseDecltype() {
+ if (!consumeIf('D'))
+ return nullptr;
+ if (!consumeIf('t') && !consumeIf('T'))
+ return nullptr;
Node *E = parseExpr();
if (E == nullptr)
return nullptr;
- return make<PrefixExpr>(Kind, E);
-}
-
-Node *Db::parseBinaryExpr(StringView Kind) {
- Node *LHS = parseExpr();
- if (LHS == nullptr)
- return nullptr;
- Node *RHS = parseExpr();
- if (RHS == nullptr)
+ if (!consumeIf('E'))
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;
+ return make<EnclosingExpr>("decltype(", E, ")");
}
-// <CV-Qualifiers> ::= [r] [V] [K]
-Qualifiers Db::parseCVQualifiers() {
- Qualifiers CVR = QualNone;
- if (consumeIf('r'))
- addQualifiers(CVR, QualRestrict);
- if (consumeIf('V'))
- addQualifiers(CVR, QualVolatile);
- if (consumeIf('K'))
- addQualifiers(CVR, QualConst);
- return CVR;
-}
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+Node *Db::parseArrayType() {
+ if (!consumeIf('A'))
+ return nullptr;
-// <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 (std::isdigit(look())) {
+ StringView Dimension = parseNumber();
if (!consumeIf('_'))
return nullptr;
- return make<FunctionParam>(Num);
- }
- if (consumeIf("fL")) {
- if (parseNumber().empty())
+ Node *Ty = parseType();
+ if (Ty == nullptr)
return nullptr;
- if (!consumeIf('p'))
+ return make<ArrayType>(Ty, Dimension);
+ }
+
+ if (!consumeIf('_')) {
+ Node *DimExpr = parseExpr();
+ if (DimExpr == nullptr)
return nullptr;
- parseCVQualifiers();
- StringView Num = parseNumber();
if (!consumeIf('_'))
return nullptr;
- return make<FunctionParam>(Num);
- }
- return nullptr;
-}
-
-// [gs] nw <expression>* _ <type> E # new (expr-list) type
-// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// <initializer> ::= pi <expression>* E # parenthesized initialization
-Node *Db::parseNewExpr() {
- bool Global = consumeIf("gs");
- bool IsArray = look(1) == 'a';
- if (!consumeIf("nw") && !consumeIf("na"))
- return nullptr;
- size_t Exprs = Names.size();
- while (!consumeIf('_')) {
- Node *Ex = parseExpr();
- if (Ex == nullptr)
+ Node *ElementType = parseType();
+ if (ElementType == nullptr)
return nullptr;
- Names.push_back(Ex);
+ return make<ArrayType>(ElementType, DimExpr);
}
- NodeArray ExprList = popTrailingNodeArray(Exprs);
+
Node *Ty = parseType();
if (Ty == nullptr)
- return Ty;
- if (consumeIf("pi")) {
- size_t InitsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *Init = parseExpr();
- if (Init == nullptr)
- return Init;
- Names.push_back(Init);
- }
- NodeArray Inits = popTrailingNodeArray(InitsBegin);
- return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
- } else if (!consumeIf('E'))
return nullptr;
- return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
+ return make<ArrayType>(Ty);
}
-// cv <type> <expression> # conversion with one argument
-// cv <type> _ <expression>* E # conversion with a different number of arguments
-Node *Db::parseConversionExpr() {
- if (!consumeIf("cv"))
+// <pointer-to-member-type> ::= M <class type> <member type>
+Node *Db::parsePointerToMemberType() {
+ if (!consumeIf('M'))
return nullptr;
- Node *Ty;
- {
- SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
- Ty = parseType();
- }
+ Node *ClassType = parseType();
+ if (ClassType == nullptr)
+ return nullptr;
+ Node *MemberType = parseType();
+ if (MemberType == nullptr)
+ return nullptr;
+ return make<PointerToMemberType>(ClassType, MemberType);
+}
- if (Ty == nullptr)
+// <class-enum-type> ::= <name> # non-dependent type name, dependent type name, or dependent typename-specifier
+// ::= Ts <name> # dependent elaborated type specifier using 'struct' or 'class'
+// ::= Tu <name> # dependent elaborated type specifier using 'union'
+// ::= Te <name> # dependent elaborated type specifier using 'enum'
+Node *Db::parseClassEnumType() {
+ StringView ElabSpef;
+ if (consumeIf("Ts"))
+ ElabSpef = "struct";
+ else if (consumeIf("Tu"))
+ ElabSpef = "union";
+ else if (consumeIf("Te"))
+ ElabSpef = "enum";
+
+ Node *Name = parseName();
+ if (Name == nullptr)
return nullptr;
- if (consumeIf('_')) {
- size_t ExprsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *E = parseExpr();
- if (E == nullptr)
- return E;
- Names.push_back(E);
+ if (!ElabSpef.empty())
+ return make<ElaboratedTypeSpefType>(ElabSpef, Name);
+
+ return Name;
+}
+
+// <qualified-type> ::= <qualifiers> <type>
+// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers>
+// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier
+Node *Db::parseQualifiedType() {
+ if (consumeIf('U')) {
+ StringView Qual = parseBareSourceName();
+ if (Qual.empty())
+ return nullptr;
+
+ // FIXME parse the optional <template-args> here!
+
+ // extension ::= U <objc-name> <objc-type> # objc-type<identifier>
+ if (Qual.startsWith("objcproto")) {
+ StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
+ StringView Proto;
+ {
+ SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()),
+ SaveLast(Last, ProtoSourceName.end());
+ Proto = parseBareSourceName();
+ }
+ if (Proto.empty())
+ return nullptr;
+ Node *Child = parseQualifiedType();
+ if (Child == nullptr)
+ return nullptr;
+ return make<ObjCProtoName>(Child, Proto);
}
- NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
- return make<ConversionExpr>(Ty, Exprs);
+
+ Node *Child = parseQualifiedType();
+ if (Child == nullptr)
+ return nullptr;
+ return make<VendorExtQualType>(Child, Qual);
}
- Node *E[1] = {parseExpr()};
- if (E[0] == nullptr)
+ Qualifiers Quals = parseCVQualifiers();
+ Node *Ty = parseType();
+ if (Ty == nullptr)
return nullptr;
- return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
+ if (Quals != QualNone)
+ Ty = make<QualType>(Ty, Quals);
+ return Ty;
}
-// <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;
+// <type> ::= <builtin-type>
+// ::= <qualified-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-param>
+// ::= <template-template-param> <template-args>
+// ::= <decltype>
+// ::= P <type> # pointer
+// ::= R <type> # l-value reference
+// ::= O <type> # r-value reference (C++11)
+// ::= C <type> # complex pair (C99)
+// ::= G <type> # imaginary (C99)
+// ::= <substitution> # See Compression below
+// extension ::= U <objc-name> <objc-type> # objc-type<identifier>
+// extension ::= <vector-type> # <vector-type> starts with Dv
+//
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> ::= <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+Node *Db::parseType() {
+ Node *Result = nullptr;
+
switch (look()) {
+ // ::= <qualified-type>
+ case 'r':
+ case 'V':
+ case 'K': {
+ unsigned AfterQuals = 0;
+ if (look(AfterQuals) == 'r') ++AfterQuals;
+ if (look(AfterQuals) == 'V') ++AfterQuals;
+ if (look(AfterQuals) == 'K') ++AfterQuals;
+
+ if (look(AfterQuals) == 'F' ||
+ (look(AfterQuals) == 'D' &&
+ (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' ||
+ look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) {
+ Result = parseFunctionType();
+ break;
+ }
+ _LIBCPP_FALLTHROUGH();
+ }
+ case 'U': {
+ Result = parseQualifiedType();
+ break;
+ }
+ // <builtin-type> ::= v # void
+ case 'v':
+ ++First;
+ return make<NameType>("void");
+ // ::= w # wchar_t
case 'w':
++First;
- return parseIntegerLiteral("wchar_t");
+ return make<NameType>("wchar_t");
+ // ::= b # bool
case 'b':
- if (consumeIf("b0E"))
- return make<BoolExpr>(0);
- if (consumeIf("b1E"))
- return make<BoolExpr>(1);
- return nullptr;
+ ++First;
+ return make<NameType>("bool");
+ // ::= c # char
case 'c':
++First;
- return parseIntegerLiteral("char");
+ return make<NameType>("char");
+ // ::= a # signed char
case 'a':
++First;
- return parseIntegerLiteral("signed char");
+ return make<NameType>("signed char");
+ // ::= h # unsigned char
case 'h':
++First;
- return parseIntegerLiteral("unsigned char");
+ return make<NameType>("unsigned char");
+ // ::= s # short
case 's':
++First;
- return parseIntegerLiteral("short");
+ return make<NameType>("short");
+ // ::= t # unsigned short
case 't':
++First;
- return parseIntegerLiteral("unsigned short");
+ return make<NameType>("unsigned short");
+ // ::= i # int
case 'i':
++First;
- return parseIntegerLiteral("");
+ return make<NameType>("int");
+ // ::= j # unsigned int
case 'j':
++First;
- return parseIntegerLiteral("u");
+ return make<NameType>("unsigned int");
+ // ::= l # long
case 'l':
++First;
- return parseIntegerLiteral("l");
+ return make<NameType>("long");
+ // ::= m # unsigned long
case 'm':
++First;
- return parseIntegerLiteral("ul");
+ return make<NameType>("unsigned long");
+ // ::= x # long long, __int64
case 'x':
++First;
- return parseIntegerLiteral("ll");
+ return make<NameType>("long long");
+ // ::= y # unsigned long long, __int64
case 'y':
++First;
- return parseIntegerLiteral("ull");
+ return make<NameType>("unsigned long long");
+ // ::= n # __int128
case 'n':
++First;
- return parseIntegerLiteral("__int128");
+ return make<NameType>("__int128");
+ // ::= o # unsigned __int128
case 'o':
++First;
- return parseIntegerLiteral("unsigned __int128");
+ return make<NameType>("unsigned __int128");
+ // ::= f # float
case 'f':
++First;
- return parseFloatingLiteral<float>();
+ return make<NameType>("float");
+ // ::= d # double
case 'd':
++First;
- return parseFloatingLiteral<double>();
+ return make<NameType>("double");
+ // ::= e # long double, __float80
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 = parseType();
- if (T == nullptr)
+ return make<NameType>("long double");
+ // ::= g # __float128
+ case 'g':
+ ++First;
+ return make<NameType>("__float128");
+ // ::= z # ellipsis
+ case 'z':
+ ++First;
+ return make<NameType>("...");
+
+ // <builtin-type> ::= u <source-name> # vendor extended type
+ case 'u': {
+ ++First;
+ StringView Res = parseBareSourceName();
+ if (Res.empty())
return nullptr;
- StringView N = parseNumber();
- if (!N.empty()) {
- if (!consumeIf('E'))
- return nullptr;
- return make<IntegerCastExpr>(T, N);
- }
- if (consumeIf('E'))
- return T;
- return nullptr;
- }
+ return make<NameType>(Res);
}
-}
-
-// <braced-expression> ::= <expression>
-// ::= di <field source-name> <braced-expression> # .name = expr
-// ::= dx <index expression> <braced-expression> # [expr] = expr
-// ::= dX <range begin expression> <range end expression> <braced-expression>
-Node *Db::parseBracedExpr() {
- if (look() == 'd') {
+ case 'D':
switch (look(1)) {
- case 'i': {
- First += 2;
- Node *Field = legacyParse<parse_source_name>();
- if (Field == nullptr)
- return nullptr;
- Node *Init = parseBracedExpr();
- if (Init == nullptr)
- return nullptr;
- return make<BracedExpr>(Field, Init, /*isArray=*/false);
- }
- case 'x': {
- First += 2;
- Node *Index = parseExpr();
- if (Index == nullptr)
- return nullptr;
- Node *Init = parseBracedExpr();
- if (Init == nullptr)
- return nullptr;
- return make<BracedExpr>(Index, Init, /*isArray=*/true);
- }
- case 'X': {
- First += 2;
- Node *RangeBegin = parseExpr();
- if (RangeBegin == nullptr)
- return nullptr;
- Node *RangeEnd = parseExpr();
- if (RangeEnd == nullptr)
- return nullptr;
- Node *Init = parseBracedExpr();
- if (Init == nullptr)
- return nullptr;
- return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init);
- }
- }
- }
- return parseExpr();
-}
-
-// <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("&&");
+ // ::= Dd # IEEE 754r decimal floating point (64 bits)
case 'd':
First += 2;
- return parsePrefixExpr("&");
- case 'n':
- First += 2;
- return parseBinaryExpr("&");
- case 'N':
- First += 2;
- return parseBinaryExpr("&=");
- case 'S':
- First += 2;
- return parseBinaryExpr("=");
- case 't': {
- First += 2;
- Node *Ty = parseType();
- if (Ty == nullptr)
- return nullptr;
- return make<EnclosingExpr>("alignof (", Ty, ")");
- }
- case 'z': {
- First += 2;
- Node *Ty = parseExpr();
- if (Ty == nullptr)
- return nullptr;
- return make<EnclosingExpr>("alignof (", Ty, ")");
- }
- }
- return nullptr;
- case 'c':
- switch (First[1]) {
- // cc <type> <expression> # const_cast<type>(expression)
- case 'c': {
- First += 2;
- Node *Ty = parseType();
- if (Ty == nullptr)
- return Ty;
- Node *Ex = parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("const_cast", Ty, Ex);
- }
- // cl <expression>+ E # call
- case 'l': {
+ return make<NameType>("decimal64");
+ // ::= De # IEEE 754r decimal floating point (128 bits)
+ case 'e':
First += 2;
- Node *Callee = parseExpr();
- if (Callee == nullptr)
- return Callee;
- size_t ExprsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *E = parseExpr();
- if (E == nullptr)
- return E;
- Names.push_back(E);
- }
- return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
- }
- case 'm':
+ return make<NameType>("decimal128");
+ // ::= Df # IEEE 754r decimal floating point (32 bits)
+ case 'f':
First += 2;
- return parseBinaryExpr(",");
- case 'o':
+ return make<NameType>("decimal32");
+ // ::= Dh # IEEE 754r half-precision floating point (16 bits)
+ case 'h':
First += 2;
- return parsePrefixExpr("~");
- case 'v':
- return parseConversionExpr();
- }
- return nullptr;
- case 'd':
- switch (First[1]) {
- case 'a': {
+ return make<NameType>("decimal16");
+ // ::= Di # char32_t
+ case 'i':
First += 2;
- Node *Ex = parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
- }
- case 'c': {
+ return make<NameType>("char32_t");
+ // ::= Ds # char16_t
+ case 's':
First += 2;
- Node *T = parseType();
- if (T == nullptr)
- return T;
- Node *Ex = parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("dynamic_cast", T, Ex);
- }
- case 'e':
+ return make<NameType>("char16_t");
+ // ::= Da # auto (in dependent new-expressions)
+ case 'a':
First += 2;
- return parsePrefixExpr("*");
- case 'l': {
+ return make<NameType>("auto");
+ // ::= Dc # decltype(auto)
+ case 'c':
First += 2;
- Node *E = parseExpr();
- if (E == nullptr)
- return E;
- return make<DeleteExpr>(E, Global, /*is_array=*/false);
- }
+ return make<NameType>("decltype(auto)");
+ // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
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);
+ return make<NameType>("std::nullptr_t");
+
+ // ::= <decltype>
+ case 't':
+ case 'T': {
+ Result = parseDecltype();
+ break;
}
- 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);
+ // extension ::= <vector-type> # <vector-type> starts with Dv
+ case 'v': {
+ Result = parseVectorType();
+ break;
}
- case 'v':
- First += 2;
- return parseBinaryExpr("/");
- case 'V':
+ // ::= Dp <type> # pack expansion (C++0x)
+ case 'p': {
First += 2;
- return parseBinaryExpr("/=");
+ Node *Child = parseType();
+ if (!Child)
+ return nullptr;
+ Result = make<ParameterPackExpansion>(Child);
+ break;
}
- return nullptr;
- case 'e':
- switch (First[1]) {
+ // Exception specifier on a function type.
case 'o':
- First += 2;
- return parseBinaryExpr("^");
case 'O':
- First += 2;
- return parseBinaryExpr("^=");
- case 'q':
- First += 2;
- return parseBinaryExpr("==");
+ case 'w':
+ // Transaction safe function type.
+ case 'x':
+ Result = parseFunctionType();
+ break;
}
- return nullptr;
- case 'g':
- switch (First[1]) {
- case 'e':
- First += 2;
- return parseBinaryExpr(">=");
- case 't':
- First += 2;
- return parseBinaryExpr(">");
+ break;
+ // ::= <function-type>
+ case 'F': {
+ Result = parseFunctionType();
+ break;
+ }
+ // ::= <array-type>
+ case 'A': {
+ Result = parseArrayType();
+ break;
+ }
+ // ::= <pointer-to-member-type>
+ case 'M': {
+ Result = parsePointerToMemberType();
+ break;
+ }
+ // ::= <template-param>
+ case 'T': {
+ // This could be an elaborate type specifier on a <class-enum-type>.
+ if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') {
+ Result = parseClassEnumType();
+ break;
}
- return nullptr;
- case 'i':
- switch (First[1]) {
- case 'x': {
- First += 2;
- Node *Base = parseExpr();
- if (Base == nullptr)
+
+ Result = legacyParse<parse_template_param>();
+ if (Result == nullptr)
+ return nullptr;
+
+ // Result could be either of:
+ // <type> ::= <template-param>
+ // <type> ::= <template-template-param> <template-args>
+ //
+ // <template-template-param> ::= <template-param>
+ // ::= <substitution>
+ //
+ // If this is followed by some <template-args>, and we're permitted to
+ // parse them, take the second production.
+
+ if (TryToParseTemplateArgs && look() == 'I') {
+ Node *TA = legacyParse<parse_template_args>();
+ if (TA == nullptr)
return nullptr;
- Node *Index = parseExpr();
- if (Index == nullptr)
- return Index;
- return make<ArraySubscriptExpr>(Base, Index);
+ Result = make<NameWithTemplateArgs>(Result, TA);
}
- case 'l': {
- First += 2;
- size_t InitsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *E = parseBracedExpr();
- if (E == nullptr)
+ break;
+ }
+ // ::= P <type> # pointer
+ case 'P': {
+ ++First;
+ Node *Ptr = parseType();
+ if (Ptr == nullptr)
+ return nullptr;
+ Result = make<PointerType>(Ptr);
+ break;
+ }
+ // ::= R <type> # l-value reference
+ case 'R': {
+ ++First;
+ Node *Ref = parseType();
+ if (Ref == nullptr)
+ return nullptr;
+ Result = make<LValueReferenceType>(Ref);
+ break;
+ }
+ // ::= O <type> # r-value reference (C++11)
+ case 'O': {
+ ++First;
+ Node *Ref = parseType();
+ if (Ref == nullptr)
+ return nullptr;
+ Result = make<RValueReferenceType>(Ref);
+ break;
+ }
+ // ::= C <type> # complex pair (C99)
+ case 'C': {
+ ++First;
+ Node *P = parseType();
+ if (P == nullptr)
+ return nullptr;
+ Result = make<PostfixQualifiedType>(P, " complex");
+ break;
+ }
+ // ::= G <type> # imaginary (C99)
+ case 'G': {
+ ++First;
+ Node *P = parseType();
+ if (P == nullptr)
+ return P;
+ Result = make<PostfixQualifiedType>(P, " imaginary");
+ break;
+ }
+ // ::= <substitution> # See Compression below
+ case 'S': {
+ if (look(1) && look(1) != 't') {
+ Node *Sub = legacyParse<parse_substitution>();
+ if (Sub == nullptr)
+ return nullptr;
+
+ // Sub could be either of:
+ // <type> ::= <substitution>
+ // <type> ::= <template-template-param> <template-args>
+ //
+ // <template-template-param> ::= <template-param>
+ // ::= <substitution>
+ //
+ // If this is followed by some <template-args>, and we're permitted to
+ // parse them, take the second production.
+
+ if (TryToParseTemplateArgs && look() == 'I') {
+ Node *TA = legacyParse<parse_template_args>();
+ if (TA == nullptr)
return nullptr;
- Names.push_back(E);
+ Result = make<NameWithTemplateArgs>(Sub, TA);
+ break;
}
- return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
- }
- }
- return nullptr;
- case 'l':
- switch (First[1]) {
- case 'e':
- First += 2;
- return parseBinaryExpr("<=");
- case 's':
- First += 2;
- return parseBinaryExpr("<<");
- case 'S':
- First += 2;
- return parseBinaryExpr("<<=");
- case 't':
- First += 2;
- return parseBinaryExpr("<");
- }
- return nullptr;
- case 'm':
- switch (First[1]) {
- case 'i':
- First += 2;
- return parseBinaryExpr("-");
- case 'I':
- First += 2;
- return parseBinaryExpr("-=");
- case 'l':
- First += 2;
- return parseBinaryExpr("*");
- case 'L':
- First += 2;
- return parseBinaryExpr("*=");
- case 'm':
- First += 2;
- if (consumeIf('_'))
- return parsePrefixExpr("--");
- Node *Ex = parseExpr();
- if (Ex == nullptr)
- return nullptr;
- return make<PostfixExpr>(Ex, "--");
+
+ // If all we parsed was a substitution, don't re-insert into the
+ // substitution table.
+ return Sub;
}
+ _LIBCPP_FALLTHROUGH();
+ }
+ // ::= <class-enum-type>
+ default: {
+ Result = parseClassEnumType();
+ break;
+ }
+ }
+
+ // If we parsed a type, insert it into the substitution table. Note that all
+ // <builtin-type>s and <substitution>s have already bailed out, because they
+ // don't get substitutions.
+ if (Result != nullptr)
+ Subs.push_back(Result);
+ return Result;
+}
+
+Node *Db::parsePrefixExpr(StringView Kind) {
+ Node *E = parseExpr();
+ if (E == nullptr)
return nullptr;
- 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 make<PrefixExpr>(Kind, E);
+}
+
+Node *Db::parseBinaryExpr(StringView Kind) {
+ Node *LHS = parseExpr();
+ if (LHS == nullptr)
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("|=");
- }
+ Node *RHS = parseExpr();
+ if (RHS == nullptr)
return nullptr;
- case 'p':
- switch (First[1]) {
+ return make<BinaryExpr>(LHS, Kind, RHS);
+}
+
+Node *Db::parseIntegerLiteral(StringView Lit) {
+ StringView Tmp = parseNumber(true);
+ if (!Tmp.empty() && consumeIf('E'))
+ return make<IntegerExpr>(Lit, Tmp);
+ return nullptr;
+}
+
+// <CV-Qualifiers> ::= [r] [V] [K]
+Qualifiers Db::parseCVQualifiers() {
+ Qualifiers CVR = QualNone;
+ if (consumeIf('r'))
+ addQualifiers(CVR, QualRestrict);
+ if (consumeIf('V'))
+ addQualifiers(CVR, QualVolatile);
+ if (consumeIf('K'))
+ addQualifiers(CVR, QualConst);
+ return CVR;
+}
+
+// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter
+// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter
+// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+Node *Db::parseFunctionParam() {
+ if (consumeIf("fp")) {
+ parseCVQualifiers();
+ StringView Num = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<FunctionParam>(Num);
+ }
+ if (consumeIf("fL")) {
+ if (parseNumber().empty())
+ return nullptr;
+ if (!consumeIf('p'))
+ return nullptr;
+ parseCVQualifiers();
+ StringView Num = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<FunctionParam>(Num);
+ }
+ return nullptr;
+}
+
+// [gs] nw <expression>* _ <type> E # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// <initializer> ::= pi <expression>* E # parenthesized initialization
+Node *Db::parseNewExpr() {
+ bool Global = consumeIf("gs");
+ bool IsArray = look(1) == 'a';
+ if (!consumeIf("nw") && !consumeIf("na"))
+ return nullptr;
+ size_t Exprs = Names.size();
+ while (!consumeIf('_')) {
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ Names.push_back(Ex);
+ }
+ NodeArray ExprList = popTrailingNodeArray(Exprs);
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return Ty;
+ if (consumeIf("pi")) {
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *Init = parseExpr();
+ if (Init == nullptr)
+ return Init;
+ Names.push_back(Init);
+ }
+ NodeArray Inits = popTrailingNodeArray(InitsBegin);
+ return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
+ } else if (!consumeIf('E'))
+ return nullptr;
+ return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
+}
+
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+Node *Db::parseConversionExpr() {
+ if (!consumeIf("cv"))
+ return nullptr;
+ Node *Ty;
+ {
+ SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
+ Ty = parseType();
+ }
+
+ if (Ty == nullptr)
+ return nullptr;
+
+ if (consumeIf('_')) {
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ }
+ NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+ return make<ConversionExpr>(Ty, Exprs);
+ }
+
+ Node *E[1] = {parseExpr()};
+ if (E[0] == nullptr)
+ return nullptr;
+ return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
+}
+
+// <expr-primary> ::= L <type> <value number> E # integer literal
+// ::= L <type> <value float> E # floating literal
+// ::= L <string type> E # string literal
+// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
+// FIXME: ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
+// ::= L <mangled-name> E # external name
+Node *Db::parseExprPrimary() {
+ if (!consumeIf('L'))
+ return nullptr;
+ switch (look()) {
+ case 'w':
+ ++First;
+ return parseIntegerLiteral("wchar_t");
+ case 'b':
+ if (consumeIf("b0E"))
+ return make<BoolExpr>(0);
+ if (consumeIf("b1E"))
+ return make<BoolExpr>(1);
+ return nullptr;
+ case 'c':
+ ++First;
+ return parseIntegerLiteral("char");
+ case 'a':
+ ++First;
+ return parseIntegerLiteral("signed char");
+ case 'h':
+ ++First;
+ return parseIntegerLiteral("unsigned char");
+ case 's':
+ ++First;
+ return parseIntegerLiteral("short");
+ case 't':
+ ++First;
+ return parseIntegerLiteral("unsigned short");
+ case 'i':
+ ++First;
+ return parseIntegerLiteral("");
+ case 'j':
+ ++First;
+ return parseIntegerLiteral("u");
+ case 'l':
+ ++First;
+ return parseIntegerLiteral("l");
+ case 'm':
+ ++First;
+ return parseIntegerLiteral("ul");
+ case 'x':
+ ++First;
+ return parseIntegerLiteral("ll");
+ case 'y':
+ ++First;
+ return parseIntegerLiteral("ull");
+ case 'n':
+ ++First;
+ return parseIntegerLiteral("__int128");
+ case 'o':
+ ++First;
+ return parseIntegerLiteral("unsigned __int128");
+ case 'f':
+ ++First;
+ return parseFloatingLiteral<float>();
+ case 'd':
+ ++First;
+ return parseFloatingLiteral<double>();
+ case 'e':
+ ++First;
+ return parseFloatingLiteral<long double>();
+ case '_':
+ if (consumeIf("_Z")) {
+ Node *R = parseEncoding();
+ if (R != nullptr && consumeIf('E'))
+ return R;
+ }
+ return nullptr;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ return nullptr;
+ default: {
+ // might be named type
+ Node *T = parseType();
+ if (T == nullptr)
+ return nullptr;
+ StringView N = parseNumber();
+ if (!N.empty()) {
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<IntegerCastExpr>(T, N);
+ }
+ if (consumeIf('E'))
+ return T;
+ return nullptr;
+ }
+ }
+}
+
+// <braced-expression> ::= <expression>
+// ::= di <field source-name> <braced-expression> # .name = expr
+// ::= dx <index expression> <braced-expression> # [expr] = expr
+// ::= dX <range begin expression> <range end expression> <braced-expression>
+Node *Db::parseBracedExpr() {
+ if (look() == 'd') {
+ switch (look(1)) {
+ case 'i': {
+ First += 2;
+ Node *Field = parseSourceName(/*NameState=*/nullptr);
+ if (Field == nullptr)
+ return nullptr;
+ Node *Init = parseBracedExpr();
+ if (Init == nullptr)
+ return nullptr;
+ return make<BracedExpr>(Field, Init, /*isArray=*/false);
+ }
+ case 'x': {
+ First += 2;
+ Node *Index = parseExpr();
+ if (Index == nullptr)
+ return nullptr;
+ Node *Init = parseBracedExpr();
+ if (Init == nullptr)
+ return nullptr;
+ return make<BracedExpr>(Index, Init, /*isArray=*/true);
+ }
+ case 'X': {
+ First += 2;
+ Node *RangeBegin = parseExpr();
+ if (RangeBegin == nullptr)
+ return nullptr;
+ Node *RangeEnd = parseExpr();
+ if (RangeEnd == nullptr)
+ return nullptr;
+ Node *Init = parseBracedExpr();
+ if (Init == nullptr)
+ return nullptr;
+ return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init);
+ }
+ }
+ }
+ return parseExpr();
+}
+
+// <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 = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("alignof (", Ty, ")");
+ }
+ case 'z': {
+ First += 2;
+ Node *Ty = parseExpr();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("alignof (", Ty, ")");
+ }
+ }
+ return nullptr;
+ case 'c':
+ switch (First[1]) {
+ // cc <type> <expression> # const_cast<type>(expression)
+ case 'c': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return Ty;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("const_cast", Ty, Ex);
+ }
+ // cl <expression>+ E # call
+ case 'l': {
+ First += 2;
+ Node *Callee = parseExpr();
+ if (Callee == nullptr)
+ return Callee;
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ }
+ return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
+ }
+ case 'm':
+ First += 2;
+ return parseBinaryExpr(",");
+ case 'o':
+ First += 2;
+ return parsePrefixExpr("~");
+ case 'v':
+ return parseConversionExpr();
+ }
+ return nullptr;
+ case 'd':
+ switch (First[1]) {
+ case 'a': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
+ }
+ case 'c': {
+ First += 2;
+ Node *T = parseType();
+ if (T == nullptr)
+ return T;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("dynamic_cast", T, Ex);
+ }
+ case 'e':
+ First += 2;
+ return parsePrefixExpr("*");
+ case 'l': {
+ First += 2;
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ return make<DeleteExpr>(E, Global, /*is_array=*/false);
+ }
+ case 'n':
+ return 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':
+ switch (First[1]) {
+ case 'x': {
+ First += 2;
+ Node *Base = parseExpr();
+ if (Base == nullptr)
+ return nullptr;
+ Node *Index = parseExpr();
+ if (Index == nullptr)
+ return Index;
+ return make<ArraySubscriptExpr>(Base, Index);
+ }
+ case 'l': {
+ First += 2;
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseBracedExpr();
+ if (E == nullptr)
+ return nullptr;
+ Names.push_back(E);
+ }
+ return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
+ }
+ }
+ return nullptr;
+ case 'l':
+ switch (First[1]) {
+ case 'e':
+ First += 2;
+ return parseBinaryExpr("<=");
+ case 's':
+ First += 2;
+ return parseBinaryExpr("<<");
+ case 'S':
+ First += 2;
+ return parseBinaryExpr("<<=");
+ case 't':
+ First += 2;
+ return parseBinaryExpr("<");
+ }
+ return nullptr;
+ case 'm':
+ switch (First[1]) {
+ case 'i':
+ First += 2;
+ return parseBinaryExpr("-");
+ case 'I':
+ First += 2;
+ return parseBinaryExpr("-=");
+ case 'l':
+ First += 2;
+ return parseBinaryExpr("*");
+ case 'L':
+ First += 2;
+ return parseBinaryExpr("*=");
+ case 'm':
+ First += 2;
+ if (consumeIf('_'))
+ return parsePrefixExpr("--");
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<PostfixExpr>(Ex, "--");
+ }
+ return nullptr;
+ case 'n':
+ switch (First[1]) {
+ case 'a':
+ case 'w':
+ return parseNewExpr();
+ case 'e':
+ First += 2;
+ return parseBinaryExpr("!=");
+ case 'g':
+ First += 2;
+ return parsePrefixExpr("-");
+ case 't':
+ First += 2;
+ return parsePrefixExpr("!");
+ case 'x':
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("noexcept (", Ex, ")");
+ }
+ return nullptr;
+ case 'o':
+ switch (First[1]) {
+ case 'n':
+ return 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("->*");
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>
-
-const char*
-parse_number(const char* first, const char* last)
-{
- if (first != last)
- {
- const char* t = first;
- if (*t == 'n')
- ++t;
- if (t != last)
- {
- if (*t == '0')
- {
- first = t+1;
- }
- else if ('1' <= *t && *t <= '9')
- {
- first = t+1;
- while (first != last && std::isdigit(*first))
- ++first;
- }
- }
- }
- return first;
-}
-
-template <class Float>
-struct FloatData;
-
-template <>
-struct FloatData<float>
-{
- static const size_t mangled_size = 8;
- static const size_t max_demangled_size = 24;
- static constexpr const char* spec = "%af";
-};
-
-constexpr const char* FloatData<float>::spec;
-
-template <>
-struct FloatData<double>
-{
- static const size_t mangled_size = 16;
- static const size_t max_demangled_size = 32;
- static constexpr const char* spec = "%a";
-};
-
-constexpr const char* FloatData<double>::spec;
-
-template <>
-struct FloatData<long double>
-{
-#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
- defined(__wasm__)
- static const size_t mangled_size = 32;
-#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
- static const size_t mangled_size = 16;
-#else
- static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
-#endif
- static const size_t max_demangled_size = 40;
- static constexpr const char *spec = "%LaL";
-};
-
-constexpr const char *FloatData<long double>::spec;
-
-template <class Float> Node *Db::parseFloatingLiteral() {
- const size_t N = FloatData<Float>::mangled_size;
- if (numLeft() <= N)
- return nullptr;
- StringView Data(First, First + N);
- for (char C : Data)
- if (!std::isxdigit(C))
- return nullptr;
- First += N;
- if (!consumeIf('E'))
- return nullptr;
- return make<FloatExpr<Float>>(Data);
-}
-
-// <positive length number> ::= [0-9]*
-const char*
-parse_positive_integer(const char* first, const char* last, size_t* out)
-{
- if (first != last)
- {
- char c = *first;
- if (isdigit(c) && first+1 != last)
- {
- const char* t = first+1;
- size_t n = static_cast<size_t>(c - '0');
- for (c = *t; isdigit(c); c = *t)
- {
- n = n * 10 + static_cast<size_t>(c - '0');
- if (++t == last)
- return first;
- }
- *out = n;
- first = t;
- }
- }
- return first;
-}
-
-// extension
-// <abi-tag-seq> ::= <abi-tag>*
-// <abi-tag> ::= B <positive length number> <identifier>
-const char*
-parse_abi_tag_seq(const char* first, const char* last, Db& db)
-{
- while (first != last && *first == 'B' && first+1 != last)
- {
- size_t length;
- const char* t = parse_positive_integer(first+1, last, &length);
- if (t == first+1)
- return first;
- if (static_cast<size_t>(last - t) < length || db.Names.empty())
- return first;
- db.Names.back() = db.make<AbiTagAttr>(
- db.Names.back(), StringView(t, t + length));
- first = t + length;
- }
- return first;
-}
-
-// <source-name> ::= <positive length number> <identifier> [<abi-tag-seq>]
-const char*
-parse_source_name(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- size_t length;
- const char* t = parse_positive_integer(first, last, &length);
- if (t == first)
- return first;
- if (static_cast<size_t>(last - t) >= length)
- {
- StringView r(t, t + length);
- if (r.substr(0, 10) == "_GLOBAL__N")
- db.Names.push_back(db.make<NameType>("(anonymous namespace)"));
- else
- db.Names.push_back(db.make<NameType>(r));
- first = t + length;
- first = parse_abi_tag_seq(first, last, db);
- }
- }
- return first;
-}
-
-// <substitution> ::= S <seq-id> _
-// ::= S_
-// <substitution> ::= Sa # ::std::allocator
-// <substitution> ::= Sb # ::std::basic_string
-// <substitution> ::= Ss # ::std::basic_string < char,
-// ::std::char_traits<char>,
-// ::std::allocator<char> >
-// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
-// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
-// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
-
-const char*
-parse_substitution(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- if (*first == 'S')
- {
- switch (first[1])
- {
- case 'a':
- db.Names.push_back(
- db.make<SpecialSubstitution>(
- SpecialSubKind::allocator));
- first += 2;
- break;
- case 'b':
- db.Names.push_back(
- db.make<SpecialSubstitution>(SpecialSubKind::basic_string));
- first += 2;
- break;
- case 's':
- db.Names.push_back(
- db.make<SpecialSubstitution>(
- SpecialSubKind::string));
- first += 2;
- break;
- case 'i':
- db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::istream));
- first += 2;
- break;
- case 'o':
- db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::ostream));
- first += 2;
- break;
- case 'd':
- db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::iostream));
- first += 2;
- break;
- case '_':
- if (!db.Subs.empty())
- {
- db.Names.push_back(db.Subs[0]);
- first += 2;
- }
- break;
- default:
- if (std::isdigit(first[1]) || std::isupper(first[1]))
- {
- size_t sub = 0;
- const char* t = first+1;
- if (std::isdigit(*t))
- sub = static_cast<size_t>(*t - '0');
- else
- sub = static_cast<size_t>(*t - 'A') + 10;
- for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
- {
- sub *= 36;
- if (std::isdigit(*t))
- sub += static_cast<size_t>(*t - '0');
- else
- sub += static_cast<size_t>(*t - 'A') + 10;
- }
- if (t == last || *t != '_')
- return first;
- ++sub;
- if (sub < db.Subs.size())
- {
- db.Names.push_back(db.Subs[sub]);
- first = t+1;
- }
- }
- break;
- }
- }
- }
- return first;
+ 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;
}
-// <template-param> ::= T_ # first template parameter
-// ::= T <parameter-2 non-negative number> _
-
-const char*
-parse_template_param(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- if (*first == 'T')
- {
- if (first[1] == '_')
- {
- if (!db.TemplateParams.empty())
- {
- db.Names.push_back(db.TemplateParams[0]);
- first += 2;
- }
- else
- {
- db.Names.push_back(db.make<NameType>("T_"));
- first += 2;
- db.FixForwardReferences = true;
- }
- }
- else if (isdigit(first[1]))
- {
- const char* t = first+1;
- size_t sub = static_cast<size_t>(*t - '0');
- for (++t; t != last && isdigit(*t); ++t)
- {
- sub *= 10;
- sub += static_cast<size_t>(*t - '0');
- }
- if (t == last || *t != '_')
- return first;
- ++sub;
- if (sub < db.TemplateParams.size())
- {
- db.Names.push_back(db.TemplateParams[sub]);
- first = t+1;
- }
- else
- {
- db.Names.push_back(
- db.make<NameType>(StringView(first, t + 1)));
- first = t+1;
- db.FixForwardReferences = true;
- }
- }
- }
- }
- return first;
+// <call-offset> ::= h <nv-offset> _
+// ::= v <v-offset> _
+//
+// <nv-offset> ::= <offset number>
+// # non-virtual base override
+//
+// <v-offset> ::= <offset number> _ <virtual offset number>
+// # virtual base override, with vcall offset
+bool Db::parseCallOffset() {
+ // Just scan through the call offset, we never add this information into the
+ // output.
+ if (consumeIf('h'))
+ return parseNumber(true).empty() || !consumeIf('_');
+ if (consumeIf('v'))
+ return parseNumber(true).empty() || !consumeIf('_') ||
+ parseNumber(true).empty() || !consumeIf('_');
+ return true;
}
-// <simple-id> ::= <source-name> [ <template-args> ]
-
-const char*
-parse_simple_id(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t = parse_source_name(first, last, db);
- if (t != first)
- {
- const char* t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<NameWithTemplateArgs>(db.Names.back(), args);
- }
- first = t1;
- }
- else
- first = t;
+// <special-name> ::= TV <type> # virtual table
+// ::= TT <type> # VTT structure (construction vtable index)
+// ::= TI <type> # typeinfo structure
+// ::= TS <type> # typeinfo name (null-terminated byte string)
+// ::= Tc <call-offset> <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// # first call-offset is 'this' adjustment
+// # second call-offset is result adjustment
+// ::= T <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// ::= GV <object name> # Guard variable for one-time initialization
+// # No <type>
+// ::= TW <object name> # Thread-local wrapper
+// ::= TH <object name> # Thread-local initialization
+// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// extension ::= GR <object name> # reference temporary for object
+Node *Db::parseSpecialName() {
+ switch (look()) {
+ case 'T':
+ switch (look(1)) {
+ // TV <type> # virtual table
+ case 'V': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<SpecialName>("vtable for ", Ty);
}
- 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)
- {
- case 'T':
- {
- size_t k0 = db.Names.size();
- t = parse_template_param(first, last, db);
- size_t k1 = db.Names.size();
- if (t != first && k1 == k0 + 1)
- {
- db.Subs.push_back(db.Names.back());
- first = t;
- }
- else
- {
- for (; k1 != k0; --k1)
- db.Names.pop_back();
- }
- break;
- }
- case 'D':
- t = parse_decltype(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- db.Subs.push_back(db.Names.back());
- first = t;
- }
- break;
- case 'S':
- t = parse_substitution(first, last, db);
- if (t != first)
- first = t;
- else
- {
- if (last - first > 2 && first[1] == 't')
- {
- t = parse_unqualified_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<StdQualifiedName>(db.Names.back());
- db.Subs.push_back(db.Names.back());
- first = t;
- }
- }
- }
- break;
- }
+ // TT <type> # VTT structure (construction vtable index)
+ case 'T': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<SpecialName>("VTT for ", Ty);
}
- return first;
-}
-
-// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
-// ::= <simple-id> # e.g., ~A<2*N>
-
-const char*
-parse_destructor_name(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t = parse_unresolved_type(first, last, db);
- if (t == first)
- t = parse_simple_id(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<DtorName>(db.Names.back());
- first = t;
- }
+ // TI <type> # typeinfo structure
+ case 'I': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<SpecialName>("typeinfo for ", Ty);
}
- return first;
+ // TS <type> # typeinfo name (null-terminated byte string)
+ case 'S': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<SpecialName>("typeinfo name for ", Ty);
+ }
+ // Tc <call-offset> <call-offset> <base encoding>
+ case 'c': {
+ First += 2;
+ if (parseCallOffset() || parseCallOffset())
+ return nullptr;
+ Node *Encoding = parseEncoding();
+ if (Encoding == nullptr)
+ return nullptr;
+ return make<SpecialName>("covariant return thunk to ", Encoding);
+ }
+ // extension ::= TC <first type> <number> _ <second type>
+ // # construction vtable for second-in-first
+ case 'C': {
+ First += 2;
+ Node *FirstType = parseType();
+ if (FirstType == nullptr)
+ return nullptr;
+ if (parseNumber(true).empty() || !consumeIf('_'))
+ return nullptr;
+ Node *SecondType = parseType();
+ if (SecondType == nullptr)
+ return nullptr;
+ return make<CtorVtableSpecialName>(SecondType, FirstType);
+ }
+ // TW <object name> # Thread-local wrapper
+ case 'W': {
+ First += 2;
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+ return make<SpecialName>("thread-local wrapper routine for ", Name);
+ }
+ // TH <object name> # Thread-local initialization
+ case 'H': {
+ First += 2;
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+ return make<SpecialName>("thread-local initialization routine for ", Name);
+ }
+ // T <call-offset> <base encoding>
+ default: {
+ ++First;
+ bool IsVirt = look() == 'v';
+ if (parseCallOffset())
+ return nullptr;
+ Node *BaseEncoding = parseEncoding();
+ if (BaseEncoding == nullptr)
+ return nullptr;
+ if (IsVirt)
+ return make<SpecialName>("virtual thunk to ", BaseEncoding);
+ else
+ return make<SpecialName>("non-virtual thunk to ", BaseEncoding);
+ }
+ }
+ case 'G':
+ switch (look(1)) {
+ // GV <object name> # Guard variable for one-time initialization
+ case 'V': {
+ First += 2;
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+ return make<SpecialName>("guard variable for ", Name);
+ }
+ // GR <object name> # reference temporary for object
+ case 'R': {
+ First += 2;
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+ return make<SpecialName>("reference temporary for ", Name);
+ }
+ }
+ }
+ return nullptr;
}
-// <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>
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+Node *Db::parseEncoding() {
+ // Always "tag" templates (insert them into Db::TemplateParams) unless we're
+ // doing a second parse to resolve a forward template reference, in which case
+ // we only tag templates if EncodingDepth > 1.
+ // FIXME: This is kinda broken; it would be better to make a forward reference
+ // and patch it all in one pass.
+ SwapAndRestore<bool> SaveTagTemplates(TagTemplates,
+ TagTemplates || EncodingDepth);
+ SwapAndRestore<unsigned> SaveEncodingDepth(EncodingDepth, EncodingDepth + 1);
+
+ if (look() == 'G' || look() == 'T')
+ return parseSpecialName();
+
+ auto IsEndOfEncoding = [&] {
+ // The set of chars that can potentially follow an <encoding> (none of which
+ // can start a <type>). Enumerating these allows us to avoid speculative
+ // parsing.
+ return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_';
+ };
+
+ NameState NameInfo;
+ Node *Name = parseName(&NameInfo);
+ if (Name == nullptr || IsEndOfEncoding())
+ return Name;
-const char*
-parse_base_unresolved_name(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
- {
- if (first[0] == 'o')
- {
- 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;
+ TagTemplates = false;
+
+ Node *ReturnType = nullptr;
+ if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) {
+ ReturnType = parseType();
+ if (ReturnType == nullptr)
+ return nullptr;
+ }
+
+ if (consumeIf('v'))
+ return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
+ NameInfo.CVQualifiers,
+ NameInfo.ReferenceQualifier);
+
+ size_t ParamsBegin = Names.size();
+ do {
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ Names.push_back(Ty);
+ } while (!IsEndOfEncoding());
+
+ return make<FunctionEncoding>(ReturnType, Name,
+ popTrailingNodeArray(ParamsBegin),
+ NameInfo.CVQualifiers,
+ NameInfo.ReferenceQualifier);
}
-// <unresolved-qualifier-level> ::= <simple-id>
+template <class Float>
+struct FloatData;
-const char*
-parse_unresolved_qualifier_level(const char* first, const char* last, Db& db)
+template <>
+struct FloatData<float>
{
- return parse_simple_id(first, last, db);
-}
+ static const size_t mangled_size = 8;
+ static const size_t max_demangled_size = 24;
+ static constexpr const char* spec = "%af";
+};
-// <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>
+constexpr const char* FloatData<float>::spec;
-const char*
-parse_unresolved_name(const char* first, const char* last, Db& db)
+template <>
+struct FloatData<double>
{
- if (last - first > 2)
- {
- 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')
- {
- 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;
+ static const size_t mangled_size = 16;
+ static const size_t max_demangled_size = 32;
+ static constexpr const char* spec = "%a";
+};
+
+constexpr const char* FloatData<double>::spec;
+
+template <>
+struct FloatData<long double>
+{
+#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
+ defined(__wasm__)
+ static const size_t mangled_size = 32;
+#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
+ static const size_t mangled_size = 16;
+#else
+ static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
+#endif
+ static const size_t max_demangled_size = 40;
+ static constexpr const char *spec = "%LaL";
+};
+
+constexpr const char *FloatData<long double>::spec;
+
+template <class Float> Node *Db::parseFloatingLiteral() {
+ const size_t N = FloatData<Float>::mangled_size;
+ if (numLeft() <= N)
+ return nullptr;
+ StringView Data(First, First + N);
+ for (char C : Data)
+ if (!std::isxdigit(C))
+ return nullptr;
+ First += N;
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<FloatExpr<Float>>(Data);
}
-// <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>
+// <substitution> ::= S <seq-id> _
+// ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+// ::std::char_traits<char>,
+// ::std::allocator<char> >
+// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
+// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
+// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+
const char*
-parse_operator_name(const char* first, const char* last, Db& db)
+parse_substitution(const char* first, const char* last, Db& db)
{
- const char* original_first = first;
if (last - first >= 2)
{
- switch (first[0])
+ if (*first == 'S')
{
- 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&"));
+ db.Names.push_back(
+ db.make<SpecialSubstitution>(
+ SpecialSubKind::allocator));
first += 2;
break;
- case 'N':
- db.Names.push_back(db.make<NameType>("operator&="));
+ case 'b':
+ db.Names.push_back(
+ db.make<SpecialSubstitution>(SpecialSubKind::basic_string));
first += 2;
break;
- case 'S':
- db.Names.push_back(db.make<NameType>("operator="));
+ case 's':
+ db.Names.push_back(
+ db.make<SpecialSubstitution>(
+ SpecialSubKind::string));
first += 2;
break;
- }
- break;
- case 'c':
- switch (first[1])
- {
- case 'l':
- db.Names.push_back(db.make<NameType>("operator()"));
+ case 'i':
+ db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::istream));
first += 2;
break;
- case 'm':
- db.Names.push_back(db.make<NameType>("operator,"));
+ case 'o':
+ db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::ostream));
first += 2;
break;
- case 'o':
- db.Names.push_back(db.make<NameType>("operator~"));
+ case 'd':
+ db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::iostream));
first += 2;
break;
- case 'v':
+ case '_':
+ if (!db.Subs.empty())
{
- 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;
- }
+ db.Names.push_back(db.Subs[0]);
+ first += 2;
}
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':
+ default:
+ if (std::isdigit(first[1]) || std::isupper(first[1]))
{
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
+ size_t sub = 0;
+ const char* t = first+1;
+ if (std::isdigit(*t))
+ sub = static_cast<size_t>(*t - '0');
+ else
+ sub = static_cast<size_t>(*t - 'A') + 10;
+ for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
{
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<LiteralOperator>(db.Names.back());
- first = t;
+ sub *= 36;
+ if (std::isdigit(*t))
+ sub += static_cast<size_t>(*t - '0');
+ else
+ sub += static_cast<size_t>(*t - 'A') + 10;
}
- }
- 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())
+ if (t == last || *t != '_')
return first;
- db.Names.back() =
- db.make<ConversionOperatorType>(db.Names.back());
- first = t;
+ ++sub;
+ if (sub < db.Subs.size())
+ {
+ db.Names.push_back(db.Subs[sub]);
+ first = t+1;
+ }
}
+ break;
}
- break;
}
}
-
- if (original_first != first)
- first = parse_abi_tag_seq(first, last, db);
-
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
+// <template-param> ::= T_ # first template parameter
+// ::= T <parameter-2 non-negative number> _
+
const char*
-parse_unnamed_type_name(const char* first, const char* last, Db& db)
+parse_template_param(const char* first, const char* last, Db& db)
{
- if (last - first > 2 && first[0] == 'U')
+ if (last - first >= 2)
{
- char type = first[1];
- switch (type)
+ if (*first == 'T')
{
- 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')
+ if (first[1] == '_')
{
- ++t0;
+ if (!db.TemplateParams.empty())
+ {
+ db.Names.push_back(db.TemplateParams[0]);
+ first += 2;
+ }
+ else
+ {
+ db.Names.push_back(db.make<NameType>("T_"));
+ first += 2;
+ db.FixForwardReferences = true;
+ }
}
- else
+ else if (isdigit(first[1]))
{
- while (true)
+ const char* t = first+1;
+ size_t sub = static_cast<size_t>(*t - '0');
+ for (++t; t != last && isdigit(*t); ++t)
{
- const char* t1 = parse_type(t0, last, db);
- if (t1 == t0)
- break;
- t0 = t1;
+ sub *= 10;
+ sub += static_cast<size_t>(*t - '0');
}
- if (db.Names.size() < begin_pos)
+ if (t == last || *t != '_')
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;
+ ++sub;
+ if (sub < db.TemplateParams.size())
+ {
+ db.Names.push_back(db.TemplateParams[sub]);
+ first = t+1;
+ }
+ else
+ {
+ db.Names.push_back(
+ db.make<NameType>(StringView(first, t + 1)));
+ first = t+1;
+ db.FixForwardReferences = true;
+ }
}
- 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>
+// <simple-id> ::= <source-name> [ <template-args> ]
const char*
-parse_unqualified_name(const char* first, const char* last, Db& db)
+parse_simple_id(const char* first, const char* last, Db& db)
{
- // <ctor-dtor-name>s are special-cased in parseNestedName().
-
if (first != last)
{
- const char* t;
- switch (*first)
- {
- 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)
+ const char* t = parse_source_name(first, last, db);
+ if (t != first)
{
- if (St)
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
{
- if (db.Names.empty())
+ if (db.Names.size() < 2)
return first;
+ auto args = db.Names.back();
+ db.Names.pop_back();
db.Names.back() =
- db.make<StdQualifiedName>(db.Names.back());
+ db.make<NameWithTemplateArgs>(db.Names.back(), args);
}
first = t1;
}
+ else
+ first = t;
}
return first;
}
-// <template-arg> ::= <type> # type or template
-// ::= X <expression> E # expression
-// ::= <expr-primary> # simple expressions
-// ::= J <template-arg>* E # argument pack
-// ::= LZ <encoding> E # extension
+// <unresolved-type> ::= <template-param>
+// ::= <decltype>
+// ::= <substitution>
+
const char*
-parse_template_arg(const char* first, const char* last, Db& db)
+parse_unresolved_type(const char* first, const char* last, Db& db)
{
if (first != last)
{
- const char* t;
+ const char* t = first;
switch (*first)
{
- case 'X':
- t = parse_expression(first+1, last, db);
- if (t != first+1)
+ case 'T':
+ {
+ size_t k0 = db.Names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.Names.size();
+ if (t != first && k1 == k0 + 1)
{
- if (t != last && *t == 'E')
- first = t+1;
+ db.Subs.push_back(db.Names.back());
+ first = t;
}
- break;
- case 'J': {
- t = first+1;
- if (t == last)
- return first;
- size_t ArgsBegin = db.Names.size();
- while (*t != 'E')
+ else
{
- const char* t1 = parse_template_arg(t, last, db);
- if (t1 == t)
- return first;
- t = t1;
+ for (; k1 != k0; --k1)
+ db.Names.pop_back();
}
- NodeArray Args = db.popTrailingNodeArray(ArgsBegin);
- db.Names.push_back(db.make<TemplateArgumentPack>(Args));
- first = t+1;
break;
- }
- case 'L':
- // <expr-primary> or LZ <encoding> E
- if (first+1 != last && first[1] == 'Z')
+ }
+ case 'D':
+ t = parse_decltype(first, last, db);
+ if (t != first)
{
- t = parse_encoding(first+2, last, db);
- if (t != first+2 && t != last && *t == 'E')
- first = t+1;
+ if (db.Names.empty())
+ return first;
+ db.Subs.push_back(db.Names.back());
+ first = t;
}
- else
- first = parse_expr_primary(first, last, db);
- break;
- default:
- // <type>
- first = parse_type(first, last, db);
break;
- }
- }
- return first;
-}
-
-// <template-args> ::= I <template-arg>* E
-// extension, the abi says <template-arg>+
-const char*
-parse_template_args(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2 && *first == 'I')
- {
- if (db.TagTemplates)
- db.TemplateParams.clear();
- const char* t = first+1;
- size_t begin_idx = db.Names.size();
- while (*t != 'E')
- {
- if (db.TagTemplates)
+ case 'S':
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ first = t;
+ else
{
- auto TmpParams = std::move(db.TemplateParams);
- size_t k0 = db.Names.size();
- const char* t1 = parse_template_arg(t, last, db);
- size_t k1 = db.Names.size();
- db.TemplateParams = std::move(TmpParams);
- if (t1 == t || t1 == last || k0 + 1 != k1)
- return first;
- Node *TableEntry = db.Names.back();
- if (TableEntry->getKind() == Node::KTemplateArgumentPack)
- TableEntry = db.make<ParameterPack>(
- static_cast<TemplateArgumentPack*>(TableEntry)
- ->getElements());
- db.TemplateParams.push_back(TableEntry);
- t = t1;
- continue;
+ 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;
+ }
+ }
}
- size_t k0 = db.Names.size();
- const char* t1 = parse_template_arg(t, last, db);
- size_t k1 = db.Names.size();
- if (t1 == t || t1 == last || k0 > k1)
- return first;
- t = t1;
- }
- if (begin_idx > db.Names.size())
- return first;
- first = t + 1;
- auto *tp = db.make<TemplateArgs>(
- db.popTrailingNodeArray(begin_idx));
- db.Names.push_back(tp);
+ break;
+ }
}
return first;
}
-// <discriminator> := _ <non-negative number> # when number < 10
-// := __ <non-negative number> _ # when number >= 10
-// extension := decimal-digit+ # at the end of string
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
const char*
-parse_discriminator(const char* first, const char* last)
-{
- // parse but ignore discriminator
- if (first != last)
- {
- if (*first == '_')
- {
- const char* t1 = first+1;
- if (t1 != last)
- {
- if (std::isdigit(*t1))
- first = t1+1;
- else if (*t1 == '_')
- {
- for (++t1; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 != last && *t1 == '_')
- first = t1 + 1;
- }
- }
- }
- else if (std::isdigit(*first))
+parse_destructor_name(const char* first, const char* last, Db& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_unresolved_type(first, last, db);
+ if (t == first)
+ t = parse_simple_id(first, last, db);
+ if (t != first)
{
- const char* t1 = first+1;
- for (; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 == last)
- first = last;
+ if (db.Names.empty())
+ return first;
+ db.Names.back() = db.make<DtorName>(db.Names.back());
+ first = t;
}
}
return first;
}
-// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
-// := Z <function encoding> E s [<discriminator>]
-// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+// <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_local_name(const char* first, const char* last, Db& db,
- bool* ends_with_template_args)
+parse_base_unresolved_name(const char* first, const char* last, Db& db)
{
- if (first != last && *first == 'Z')
+ if (last - first >= 2)
{
- const char* t = parse_encoding(first+1, last, db);
- if (t != first+1 && t != last && *t == 'E' && ++t != last)
+ if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
{
- switch (*t)
+ if (first[0] == 'o')
{
- case 's':
- first = parse_discriminator(t+1, last);
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<QualifiedName>(
- db.Names.back(), db.make<NameType>("string literal"));
- break;
- case 'd':
- if (++t != last)
+ const char* t = parse_operator_name(first+2, last, db);
+ if (t != first+2)
{
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
+ first = parse_template_args(t, last, db);
+ if (first != t)
{
- t = t1 + 1;
- t1 = parse_name(t, last, db,
- ends_with_template_args);
- 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<QualifiedName>(db.Names.back(), name);
- first = t1;
- }
- else if (!db.Names.empty())
- db.Names.pop_back();
+ 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);
}
}
- break;
- default:
+ }
+ 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)
{
- const char* t1 = parse_name(t, last, db,
- ends_with_template_args);
- if (t1 != t)
+ first = parse_template_args(t, last, db);
+ if (first != t)
{
- // parse but ignore discriminator
- first = parse_discriminator(t1, last);
if (db.Names.size() < 2)
return first;
- auto name = db.Names.back();
+ auto args = db.Names.back();
db.Names.pop_back();
- if (db.Names.empty())
- return first;
db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
+ db.make<NameWithTemplateArgs>(
+ db.Names.back(), args);
}
- else if (!db.Names.empty())
- db.Names.pop_back();
}
- break;
}
+ else
+ first = t;
}
}
return first;
}
-// <name> ::= <nested-name> // N
-// ::= <local-name> # See Scope Encoding below // Z
-// ::= <unscoped-template-name> <template-args>
-// ::= <unscoped-name>
+// <unresolved-qualifier-level> ::= <simple-id>
-// <unscoped-template-name> ::= <unscoped-name>
-// ::= <substitution>
+const char*
+parse_unresolved_qualifier_level(const char* first, const char* last, Db& db)
+{
+ return parse_simple_id(first, last, db);
+}
+
+// <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_name(const char* first, const char* last, Db& db,
- bool* ends_with_template_args)
+parse_unresolved_name(const char* first, const char* last, Db& db)
{
- if (last - first >= 2)
+ if (last - first > 2)
{
- const char* t0 = first;
- // extension: ignore L here
- if (*t0 == 'L')
- ++t0;
- switch (*t0)
+ const char* t = first;
+ bool global = false;
+ if (t[0] == 'g' && t[1] == 's')
{
- case 'N':
- {
- const char* t1 = parse_nested_name(t0, last, db,
- ends_with_template_args);
- if (t1 != t0)
- first = t1;
- break;
- }
- case 'Z':
- {
- const char* t1 = parse_local_name(t0, last, db,
- ends_with_template_args);
- if (t1 != t0)
- first = t1;
- break;
- }
- default:
- {
- const char* t1 = parse_unscoped_name(t0, last, db);
- if (t1 != t0)
+ 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')
+ {
+ if (t[2] == 'N')
{
- if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
+ 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.empty())
+ if (db.Names.size() < 2)
return first;
- db.Subs.push_back(db.Names.back());
- t0 = t1;
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0)
+ auto args = db.Names.back();
+ db.Names.pop_back();
+ db.Names.back() = db.make<NameWithTemplateArgs>(
+ db.Names.back(), args);
+ t = t1;
+ if (t == last)
{
- if (db.Names.size() < 2)
- return first;
- auto tmp = db.Names.back();
db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), tmp);
- first = t1;
- if (ends_with_template_args)
- *ends_with_template_args = true;
+ return first;
}
}
- else // <unscoped-name>
- 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
- { // try <substitution> <template-args>
- t1 = parse_substitution(t0, last, db);
- if (t1 != t0 && t1 != last && *t1 == 'I')
+ {
+ t += 2;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 != t)
{
- t0 = t1;
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0)
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
{
if (db.Names.size() < 2)
return first;
- auto tmp = db.Names.back();
+ 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<NameWithTemplateArgs>(
- db.Names.back(), tmp);
- first = t1;
- if (ends_with_template_args)
- *ends_with_template_args = true;
+ 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;
}
}
- break;
- }
}
}
return first;
}
-// <call-offset> ::= h <nv-offset> _
-// ::= v <v-offset> _
-//
-// <nv-offset> ::= <offset number>
-// # non-virtual base override
-//
-// <v-offset> ::= <offset number> _ <virtual offset number>
-// # virtual base override, with vcall offset
-
+// <template-arg> ::= <type> # type or template
+// ::= X <expression> E # expression
+// ::= <expr-primary> # simple expressions
+// ::= J <template-arg>* E # argument pack
+// ::= LZ <encoding> E # extension
const char*
-parse_call_offset(const char* first, const char* last)
+parse_template_arg(const char* first, const char* last, Db& db)
{
if (first != last)
{
+ const char* t;
switch (*first)
{
- case 'h':
+ case 'X':
+ t = parse_expression(first+1, last, db);
+ if (t != first+1)
{
- const char* t = parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
- first = t + 1;
+ if (t != last && *t == 'E')
+ first = t+1;
}
break;
- case 'v':
- {
- const char* t = parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
+ case 'J': {
+ t = first+1;
+ if (t == last)
+ return first;
+ size_t ArgsBegin = db.Names.size();
+ while (*t != 'E')
{
- const char* t2 = parse_number(++t, last);
- if (t2 != t && t2 != last && *t2 == '_')
- first = t2 + 1;
+ const char* t1 = parse_template_arg(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
}
+ NodeArray Args = db.popTrailingNodeArray(ArgsBegin);
+ db.Names.push_back(db.make<TemplateArgumentPack>(Args));
+ first = t+1;
+ break;
+ }
+ case 'L':
+ // <expr-primary> or LZ <encoding> E
+ if (first+1 != last && first[1] == 'Z')
+ {
+ t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ first = t+1;
}
+ else
+ first = parse_expr_primary(first, last, db);
+ break;
+ default:
+ // <type>
+ first = parse_type(first, last, db);
break;
}
}
return first;
}
-// <special-name> ::= TV <type> # virtual table
-// ::= TT <type> # VTT structure (construction vtable index)
-// ::= TI <type> # typeinfo structure
-// ::= TS <type> # typeinfo name (null-terminated byte string)
-// ::= Tc <call-offset> <call-offset> <base encoding>
-// # base is the nominal target function of thunk
-// # first call-offset is 'this' adjustment
-// # second call-offset is result adjustment
-// ::= T <call-offset> <base encoding>
-// # base is the nominal target function of thunk
-// ::= GV <object name> # Guard variable for one-time initialization
-// # No <type>
-// ::= TW <object name> # Thread-local wrapper
-// ::= TH <object name> # Thread-local initialization
-// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
-// extension ::= GR <object name> # reference temporary for object
-
+// <template-args> ::= I <template-arg>* E
+// extension, the abi says <template-arg>+
const char*
-parse_special_name(const char* first, const char* last, Db& db)
+parse_template_args(const char* first, const char* last, Db& db)
{
- if (last - first > 2)
+ if (last - first >= 2 && *first == 'I')
{
- const char* t;
- switch (*first)
+ if (db.TagTemplates)
+ db.TemplateParams.clear();
+ const char* t = first+1;
+ size_t begin_idx = db.Names.size();
+ while (*t != 'E')
{
- case 'T':
- switch (first[1])
- {
- case 'V':
- // TV <type> # virtual table
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("vtable for ", db.Names.back());
- first = t;
- }
- break;
- case 'T':
- // TT <type> # VTT structure (construction vtable index)
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("VTT for ", db.Names.back());
- first = t;
- }
- break;
- case 'I':
- // TI <type> # typeinfo structure
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("typeinfo for ", db.Names.back());
- first = t;
- }
- break;
- case 'S':
- // TS <type> # typeinfo name (null-terminated byte string)
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("typeinfo name for ", db.Names.back());
- first = t;
- }
- break;
- case 'c':
- // Tc <call-offset> <call-offset> <base encoding>
- {
- const char* t0 = parse_call_offset(first+2, last);
- if (t0 == first+2)
- break;
- const char* t1 = parse_call_offset(t0, last);
- if (t1 == t0)
- break;
- t = parse_encoding(t1, last, db);
- if (t != t1)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("covariant return thunk to ",
- db.Names.back());
- first = t;
- }
- }
- break;
- case 'C':
- // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t0 = parse_number(t, last);
- if (t0 != t && t0 != last && *t0 == '_')
- {
- const char* t1 = parse_type(++t0, last, db);
- if (t1 != t0)
- {
- if (db.Names.size() < 2)
- return first;
- auto left = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<CtorVtableSpecialName>(
- left, db.Names.back());
- first = t1;
- }
- }
- }
- break;
- case 'W':
- // TW <object name> # Thread-local wrapper
- t = parse_name(first + 2, last, db);
- if (t != first + 2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("thread-local wrapper routine for ",
- db.Names.back());
- first = t;
- }
- break;
- case 'H':
- //TH <object name> # Thread-local initialization
- t = parse_name(first + 2, last, db);
- if (t != first + 2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<SpecialName>(
- "thread-local initialization routine for ", db.Names.back());
- first = t;
- }
- break;
- default:
- // T <call-offset> <base encoding>
- {
- const char* t0 = parse_call_offset(first+1, last);
- if (t0 == first+1)
- break;
- t = parse_encoding(t0, last, db);
- if (t != t0)
- {
- if (db.Names.empty())
- return first;
- if (first[1] == 'v')
- {
- db.Names.back() =
- db.make<SpecialName>("virtual thunk to ",
- db.Names.back());
- first = t;
- }
- else
- {
- db.Names.back() =
- db.make<SpecialName>("non-virtual thunk to ",
- db.Names.back());
- first = t;
- }
- }
- }
- break;
- }
- break;
- case 'G':
- switch (first[1])
+ if (db.TagTemplates)
{
- case 'V':
- // GV <object name> # Guard variable for one-time initialization
- t = parse_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("guard variable for ", db.Names.back());
- first = t;
- }
- break;
- case 'R':
- // extension ::= GR <object name> # reference temporary for object
- t = parse_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("reference temporary for ",
- db.Names.back());
- first = t;
- }
- break;
+ auto TmpParams = std::move(db.TemplateParams);
+ size_t k0 = db.Names.size();
+ const char* t1 = parse_template_arg(t, last, db);
+ size_t k1 = db.Names.size();
+ db.TemplateParams = std::move(TmpParams);
+ if (t1 == t || t1 == last || k0 + 1 != k1)
+ return first;
+ Node *TableEntry = db.Names.back();
+ if (TableEntry->getKind() == Node::KTemplateArgumentPack)
+ TableEntry = db.make<ParameterPack>(
+ static_cast<TemplateArgumentPack*>(TableEntry)
+ ->getElements());
+ db.TemplateParams.push_back(TableEntry);
+ t = t1;
+ continue;
}
- break;
+ size_t k0 = db.Names.size();
+ const char* t1 = parse_template_arg(t, last, db);
+ size_t k1 = db.Names.size();
+ if (t1 == t || t1 == last || k0 > k1)
+ return first;
+ t = t1;
}
+ if (begin_idx > db.Names.size())
+ return first;
+ first = t + 1;
+ auto *tp = db.make<TemplateArgs>(
+ db.popTrailingNodeArray(begin_idx));
+ db.Names.push_back(tp);
}
return first;
}
-template <class T>
-class save_value
-{
- T& restore_;
- T original_value_;
-public:
- save_value(T& restore)
- : restore_(restore),
- original_value_(restore)
- {}
-
- ~save_value()
- {
- restore_ = std::move(original_value_);
- }
-
- save_value(const save_value&) = delete;
- save_value& operator=(const save_value&) = delete;
-};
-
-// <encoding> ::= <function name> <bare-function-type>
-// ::= <data name>
-// ::= <special-name>
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+ # at the end of string
const char*
-parse_encoding(const char* first, const char* last, Db& db)
+parse_discriminator(const char* first, const char* last)
{
+ // parse but ignore discriminator
if (first != last)
{
- save_value<decltype(db.EncodingDepth)> su(db.EncodingDepth);
- ++db.EncodingDepth;
- save_value<decltype(db.TagTemplates)> sb(db.TagTemplates);
- if (db.EncodingDepth > 1)
- db.TagTemplates = true;
- save_value<decltype(db.ParsedCtorDtorCV)> sp(db.ParsedCtorDtorCV);
- db.ParsedCtorDtorCV = false;
- switch (*first)
+ if (*first == '_')
{
- case 'G':
- case 'T':
- first = parse_special_name(first, last, db);
- break;
- default:
- {
- bool ends_with_template_args = false;
- const char* t = parse_name(first, last, db,
- &ends_with_template_args);
- if (db.Names.empty())
- return first;
- Qualifiers cv = db.CV;
- FunctionRefQual ref = db.RefQuals;
- if (t != first)
+ const char* t1 = first+1;
+ if (t1 != last)
{
- if (t != last && *t != 'E' && *t != '.')
+ if (std::isdigit(*t1))
+ first = t1+1;
+ else if (*t1 == '_')
{
- save_value<bool> sb2(db.TagTemplates);
- db.TagTemplates = false;
- const char* t2;
- if (db.Names.empty())
- return first;
- if (!db.Names.back())
- return first;
- Node* return_type = nullptr;
- if (!db.ParsedCtorDtorCV && ends_with_template_args)
- {
- t2 = parse_type(t, last, db);
- if (t2 == t)
- return first;
- if (db.Names.size() < 1)
- return first;
- return_type = db.Names.back();
- db.Names.pop_back();
- t = t2;
- }
-
- Node* result = nullptr;
-
- if (t != last && *t == 'v')
- {
- ++t;
- if (db.Names.empty())
- return first;
- Node* name = db.Names.back();
- db.Names.pop_back();
- result = db.make<FunctionEncoding>(
- return_type, name, NodeArray(), cv, ref);
- }
- else
- {
- size_t params_begin = db.Names.size();
- while (true)
- {
- t2 = parse_type(t, last, db);
- if (t2 == t)
- break;
- t = t2;
- }
- if (db.Names.size() < params_begin)
- return first;
- NodeArray params =
- db.popTrailingNodeArray(params_begin);
- if (db.Names.empty())
- return first;
- Node* name = db.Names.back();
- db.Names.pop_back();
- result = db.make<FunctionEncoding>(
- return_type, name, params, cv, ref);
- }
- db.Names.push_back(result);
- first = t;
+ for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 != last && *t1 == '_')
+ first = t1 + 1;
}
- else
- first = t;
}
- break;
- }
+ }
+ else if (std::isdigit(*first))
+ {
+ const char* t1 = first+1;
+ for (; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 == last)
+ first = last;
}
}
return first;