1,150 changes: 392 additions & 758 deletions libcxxabi/src/demangle/ItaniumDemangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,62 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {

Node *parseAbiTags(Node *N);

struct OperatorInfo {
enum OIKind : unsigned char {
Prefix, // Prefix unary: @ expr
Postfix, // Postfix unary: expr @
Binary, // Binary: lhs @ rhs
Array, // Array index: lhs [ rhs ]
Member, // Member access: lhs @ rhs
New, // New
Del, // Delete
Call, // Function call: expr (expr*)
CCast, // C cast: (type)expr
Conditional, // Conditional: expr ? expr : expr
// Below do not have operator names
NamedCast, // Named cast, @<type>(expr)
OfIdOp, // alignof, sizeof, typeid

Unnameable = NamedCast,
};
char Enc[2]; // Encoding
OIKind Kind; // Kind of operator
bool Flag : 1; // Entry-specific flag
const char *Name; // Spelling

public:
constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, const char *N)
: Enc{E[0], E[1]}, Kind{K}, Flag{F}, Name{N} {}

public:
bool operator<(const OperatorInfo &Other) const {
return *this < Other.Enc;
}
bool operator<(const char *Peek) const {
return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]);
}
bool operator==(const char *Peek) const {
return Enc[0] == Peek[0] && Enc[1] == Peek[1];
}
bool operator!=(const char *Peek) const { return !this->operator==(Peek); }

public:
StringView getSymbol() const {
StringView Res = Name;
if (Kind < Unnameable) {
assert(Res.startsWith("operator") &&
"operator name does not start with 'operator'");
Res = Res.dropFront(sizeof("operator") - 1);
Res.consumeFront(' ');
}
return Res;
}
StringView getName() const { return Name; }
OIKind getKind() const { return Kind; }
bool getFlag() const { return Flag; }
};
const OperatorInfo *parseOperatorEncoding();

/// Parse the <unresolved-name> production.
Node *parseUnresolvedName(bool Global);
Node *parseSimpleId();
Expand Down Expand Up @@ -2808,92 +2864,111 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
return make<NameType>(Name);
}

// <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 # <=
// If the next 2 chars are an operator encoding, consume them and return their
// OperatorInfo. Otherwise return nullptr.
template <typename Derived, typename Alloc>
const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo *
AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
static const OperatorInfo Ops[] = {
// Keep ordered by encoding
{"aN", OperatorInfo::Binary, false, "operator&="},
{"aS", OperatorInfo::Binary, false, "operator="},
{"aa", OperatorInfo::Binary, false, "operator&&"},
{"ad", OperatorInfo::Prefix, false, "operator&"},
{"an", OperatorInfo::Binary, false, "operator&"},
{"at", OperatorInfo::OfIdOp, /*Type*/ true, "alignof ("},
{"az", OperatorInfo::OfIdOp, /*Type*/ false, "alignof ("},
{"cc", OperatorInfo::NamedCast, false, "const_cast"},
{"cl", OperatorInfo::Call, false, "operator()"},
{"cm", OperatorInfo::Binary, false, "operator,"},
{"co", OperatorInfo::Prefix, false, "operator~"},
{"cv", OperatorInfo::CCast, false, "operator"}, // C Cast
{"dV", OperatorInfo::Binary, false, "operator/="},
{"da", OperatorInfo::Del, /*Ary*/ true, "operator delete[]"},
{"dc", OperatorInfo::NamedCast, false, "dynamic_cast"},
{"de", OperatorInfo::Prefix, false, "operator*"},
{"dl", OperatorInfo::Del, /*Ary*/ false, "operator delete"},
{"ds", OperatorInfo::Member, /*Named*/ false, "operator.*"},
{"dt", OperatorInfo::Member, /*Named*/ false, "operator."},
{"dv", OperatorInfo::Binary, false, "operator/"},
{"eO", OperatorInfo::Binary, false, "operator^="},
{"eo", OperatorInfo::Binary, false, "operator^"},
{"eq", OperatorInfo::Binary, false, "operator=="},
{"ge", OperatorInfo::Binary, false, "operator>="},
{"gt", OperatorInfo::Binary, false, "operator>"},
{"ix", OperatorInfo::Array, false, "operator[]"},
{"lS", OperatorInfo::Binary, false, "operator<<="},
{"le", OperatorInfo::Binary, false, "operator<="},
{"ls", OperatorInfo::Binary, false, "operator<<"},
{"lt", OperatorInfo::Binary, false, "operator<"},
{"mI", OperatorInfo::Binary, false, "operator-="},
{"mL", OperatorInfo::Binary, false, "operator*="},
{"mi", OperatorInfo::Binary, false, "operator-"},
{"ml", OperatorInfo::Binary, false, "operator*"},
{"mm", OperatorInfo::Postfix, false, "operator--"},
{"na", OperatorInfo::New, /*Ary*/ true, "operator new[]"},
{"ne", OperatorInfo::Binary, false, "operator!="},
{"ng", OperatorInfo::Prefix, false, "operator-"},
{"nt", OperatorInfo::Prefix, false, "operator!"},
{"nw", OperatorInfo::New, /*Ary*/ false, "operator new"},
{"oR", OperatorInfo::Binary, false, "operator|="},
{"oo", OperatorInfo::Binary, false, "operator||"},
{"or", OperatorInfo::Binary, false, "operator|"},
{"pL", OperatorInfo::Binary, false, "operator+="},
{"pl", OperatorInfo::Binary, false, "operator+"},
{"pm", OperatorInfo::Member, /*Named*/ false, "operator->*"},
{"pp", OperatorInfo::Postfix, false, "operator++"},
{"ps", OperatorInfo::Prefix, false, "operator+"},
{"pt", OperatorInfo::Member, /*Named*/ true, "operator->"},
{"qu", OperatorInfo::Conditional, false, "operator?"},
{"rM", OperatorInfo::Binary, false, "operator%="},
{"rS", OperatorInfo::Binary, false, "operator>>="},
{"rc", OperatorInfo::NamedCast, false, "reinterpret_cast"},
{"rm", OperatorInfo::Binary, false, "operator%"},
{"rs", OperatorInfo::Binary, false, "operator>>"},
{"sc", OperatorInfo::NamedCast, false, "static_cast"},
{"ss", OperatorInfo::Binary, false, "operator<=>"},
{"st", OperatorInfo::OfIdOp, /*Type*/ true, "sizeof ("},
{"sz", OperatorInfo::OfIdOp, /*Type*/ false, "sizeof ("},
{"te", OperatorInfo::OfIdOp, /*Type*/ false, "typeid ("},
{"ti", OperatorInfo::OfIdOp, /*Type*/ true, "typeid ("},
};
const auto NumOps = sizeof(Ops) / sizeof(Ops[0]);

#ifndef NDEBUG
{
// Verify table order.
static bool Done;
if (!Done) {
Done = true;
for (const auto *Op = &Ops[0]; Op != &Ops[NumOps - 1]; Op++)
assert(Op[0] < Op[1] && "Operator table is not ordered");
}
}
#endif

if (numLeft() < 2)
return nullptr;

auto Op = std::lower_bound(
&Ops[0], &Ops[NumOps], First,
[](const OperatorInfo &Op_, const char *Enc_) { return Op_ < Enc_; });
if (Op == &Ops[NumOps] || *Op != First)
return nullptr;

First += 2;
return Op;
}

// <operator-name> ::= See parseOperatorEncoding()
// ::= 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
// ::= v <digit> <source-name> # vendor extended operator
template <typename Derived, typename Alloc>
Node *
AbstractManglingParser<Derived, Alloc>::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=");
}
return nullptr;
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': {
First += 2;
if (const auto *Op = parseOperatorEncoding()) {
if (Op->getKind() == OperatorInfo::CCast) {
// ::= cv <type> # (cast)
SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
// If we're parsing an encoding, State != nullptr and the conversion
// operators' <type> could have a <template-param> that refers to some
Expand All @@ -2907,192 +2982,37 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
if (State) State->CtorDtorConversion = true;
return make<ConversionOperatorType>(Ty);
}
}
return nullptr;
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;
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;
case 'g':
switch (look(1)) {
case 'e':
First += 2;
return make<NameType>("operator>=");
case 't':
First += 2;
return make<NameType>("operator>");
}
return nullptr;
case 'i':
if (look(1) == 'x') {
First += 2;
return make<NameType>("operator[]");
}
return nullptr;
case 'l':
switch (look(1)) {
case 'e':
First += 2;
return make<NameType>("operator<=");

if (Op->getKind() >= OperatorInfo::Unnameable)
/* Not a nameable operator. */
return nullptr;
if (Op->getKind() == OperatorInfo::Member && !Op->getFlag())
/* Not a nameable MemberExpr */
return nullptr;

return make<NameType>(Op->getName());
}

if (consumeIf("li")) {
// ::= li <source-name> # operator ""
case 'i': {
First += 2;
Node *SN = getDerived().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;
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;
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;
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;
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;
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 = getDerived().parseSourceName(State);
if (SN == nullptr)
return nullptr;
return make<LiteralOperator>(SN);
}

if (consumeIf('v')) {
// ::= v <digit> <source-name> # vendor extended operator
if (look() >= '0' && look() <= '9') {
First++;
Node *SN = getDerived().parseSourceName(State);
if (SN == nullptr)
return nullptr;
return make<ConversionOperatorType>(SN);
}
return nullptr;
}

return nullptr;
}

Expand Down Expand Up @@ -4374,55 +4294,34 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
if (!consumeIf('f'))
return nullptr;

char FoldKind = look();
bool IsLeftFold, HasInitializer;
HasInitializer = FoldKind == 'L' || FoldKind == 'R';
if (FoldKind == 'l' || FoldKind == 'L')
IsLeftFold = true;
else if (FoldKind == 'r' || FoldKind == 'R')
IsLeftFold = false;
else
bool IsLeftFold = false, HasInitializer = false;
switch (look()) {
default:
return nullptr;
case 'L':
IsLeftFold = true;
HasInitializer = true;
break;
case 'R':
HasInitializer = true;
break;
case 'l':
IsLeftFold = true;
break;
case 'r':
break;
}
++First;

// FIXME: This map is duplicated in parseOperatorName and parseExpr.
StringView OperatorName;
if (consumeIf("aa")) OperatorName = "&&";
else if (consumeIf("an")) OperatorName = "&";
else if (consumeIf("aN")) OperatorName = "&=";
else if (consumeIf("aS")) OperatorName = "=";
else if (consumeIf("cm")) OperatorName = ",";
else if (consumeIf("ds")) OperatorName = ".*";
else if (consumeIf("dv")) OperatorName = "/";
else if (consumeIf("dV")) OperatorName = "/=";
else if (consumeIf("eo")) OperatorName = "^";
else if (consumeIf("eO")) OperatorName = "^=";
else if (consumeIf("eq")) OperatorName = "==";
else if (consumeIf("ge")) OperatorName = ">=";
else if (consumeIf("gt")) OperatorName = ">";
else if (consumeIf("le")) OperatorName = "<=";
else if (consumeIf("ls")) OperatorName = "<<";
else if (consumeIf("lS")) OperatorName = "<<=";
else if (consumeIf("lt")) OperatorName = "<";
else if (consumeIf("mi")) OperatorName = "-";
else if (consumeIf("mI")) OperatorName = "-=";
else if (consumeIf("ml")) OperatorName = "*";
else if (consumeIf("mL")) OperatorName = "*=";
else if (consumeIf("ne")) OperatorName = "!=";
else if (consumeIf("oo")) OperatorName = "||";
else if (consumeIf("or")) OperatorName = "|";
else if (consumeIf("oR")) OperatorName = "|=";
else if (consumeIf("pl")) OperatorName = "+";
else if (consumeIf("pL")) OperatorName = "+=";
else if (consumeIf("rm")) OperatorName = "%";
else if (consumeIf("rM")) OperatorName = "%=";
else if (consumeIf("rs")) OperatorName = ">>";
else if (consumeIf("rS")) OperatorName = ">>=";
else return nullptr;

Node *Pack = getDerived().parseExpr(), *Init = nullptr;
const auto *Op = parseOperatorEncoding();
if (!Op || Op->getKind() != OperatorInfo::Binary)
return nullptr;

Node *Pack = getDerived().parseExpr();
if (Pack == nullptr)
return nullptr;

Node *Init = nullptr;
if (HasInitializer) {
Init = getDerived().parseExpr();
if (Init == nullptr)
Expand All @@ -4432,7 +4331,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
if (IsLeftFold && Init)
std::swap(Pack, Init);

return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
return make<FoldExpr>(IsLeftFold, Op->getSymbol(), Pack, Init);
}

// <expression> ::= mc <parameter type> <expr> [<offset number>] E
Expand Down Expand Up @@ -4526,350 +4425,125 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
bool Global = consumeIf("gs");
if (numLeft() < 2)
return nullptr;

switch (*First) {
case 'L':
return getDerived().parseExprPrimary();
case 'T':
return getDerived().parseTemplateParam();
case 'f': {
// Disambiguate a fold expression from a <function-param>.
if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
return getDerived().parseFunctionParam();
return getDerived().parseFoldExpr();
}
case 'a':
switch (First[1]) {
case 'a':
First += 2;
return getDerived().parseBinaryExpr("&&");
case 'd':
First += 2;
return getDerived().parsePrefixExpr("&");
case 'n':
First += 2;
return getDerived().parseBinaryExpr("&");
case 'N':
First += 2;
return getDerived().parseBinaryExpr("&=");
case 'S':
First += 2;
return getDerived().parseBinaryExpr("=");
case 't': {
First += 2;
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
const auto *Op = parseOperatorEncoding();
if (Op) {
auto Sym = Op->getSymbol();
switch (Op->getKind()) {
case OperatorInfo::Binary:
// Binary operator: lhs @ rhs
return getDerived().parseBinaryExpr(Sym);
case OperatorInfo::Prefix:
// Prefix unary operator: @ expr
return getDerived().parsePrefixExpr(Sym);
case OperatorInfo::Postfix: {
// Postfix unary operator: expr @
if (consumeIf('_'))
return getDerived().parsePrefixExpr(Sym);
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
return make<EnclosingExpr>("alignof (", Ty, ")");
return make<PostfixExpr>(Ex, Sym);
}
case 'z': {
First += 2;
Node *Ty = getDerived().parseExpr();
if (Ty == nullptr)
case OperatorInfo::Array: {
// Array Index: lhs [ rhs ]
Node *Base = getDerived().parseExpr();
if (Base == nullptr)
return nullptr;
return make<EnclosingExpr>("alignof (", Ty, ")");
}
Node *Index = getDerived().parseExpr();
if (Index == nullptr)
return nullptr;
return make<ArraySubscriptExpr>(Base, Index);
}
return nullptr;
case 'c':
switch (First[1]) {
// cc <type> <expression> # const_cast<type>(expression)
case 'c': {
First += 2;
case OperatorInfo::Member: {
// Member access lhs @ rhs
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return nullptr;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
return make<MemberExpr>(LHS, Sym, RHS);
}
case OperatorInfo::New: {
// New
// # new (expr-list) type [(init)]
// [gs] nw <expression>* _ <type> [pi <expression>*] E
// # new[] (expr-list) type [(init)]
// [gs] na <expression>* _ <type> [pi <expression>*] E
size_t Exprs = Names.size();
while (!consumeIf('_')) {
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
Names.push_back(Ex);
}
NodeArray ExprList = popTrailingNodeArray(Exprs);
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return Ty;
return nullptr;
bool HaveInits = consumeIf("pi");
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
if (!HaveInits)
return nullptr;
Node *Init = getDerived().parseExpr();
if (Init == nullptr)
return Init;
Names.push_back(Init);
}
NodeArray Inits = popTrailingNodeArray(InitsBegin);
return make<NewExpr>(ExprList, Ty, Inits, Global,
/*IsArray=*/Op->getFlag());
}
case OperatorInfo::Del: {
// Delete
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<CastExpr>("const_cast", Ty, Ex);
return nullptr;
return make<DeleteExpr>(Ex, Global, /*IsArray=*/Op->getFlag());
}
// cl <expression>+ E # call
case 'l': {
First += 2;
case OperatorInfo::Call: {
// Function Call
Node *Callee = getDerived().parseExpr();
if (Callee == nullptr)
return Callee;
return nullptr;
size_t ExprsBegin = Names.size();
while (!consumeIf('E')) {
Node *E = getDerived().parseExpr();
if (E == nullptr)
return E;
Names.push_back(E);
}
return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
}
case 'm':
First += 2;
return getDerived().parseBinaryExpr(",");
case 'o':
First += 2;
return getDerived().parsePrefixExpr("~");
case 'v':
return getDerived().parseConversionExpr();
}
return nullptr;
case 'd':
switch (First[1]) {
case 'a': {
First += 2;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
}
case 'c': {
First += 2;
Node *T = getDerived().parseType();
if (T == nullptr)
return T;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<CastExpr>("dynamic_cast", T, Ex);
}
case 'e':
First += 2;
return getDerived().parsePrefixExpr("*");
case 'l': {
First += 2;
Node *E = getDerived().parseExpr();
if (E == nullptr)
return E;
return make<DeleteExpr>(E, Global, /*is_array=*/false);
}
case 'n':
return getDerived().parseUnresolvedName(Global);
case 's': {
First += 2;
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return nullptr;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
return make<MemberExpr>(LHS, ".*", RHS);
}
case 't': {
First += 2;
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return LHS;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
return make<MemberExpr>(LHS, ".", RHS);
}
case 'v':
First += 2;
return getDerived().parseBinaryExpr("/");
case 'V':
First += 2;
return getDerived().parseBinaryExpr("/=");
}
return nullptr;
case 'e':
switch (First[1]) {
case 'o':
First += 2;
return getDerived().parseBinaryExpr("^");
case 'O':
First += 2;
return getDerived().parseBinaryExpr("^=");
case 'q':
First += 2;
return getDerived().parseBinaryExpr("==");
}
return nullptr;
case 'g':
switch (First[1]) {
case 'e':
First += 2;
return getDerived().parseBinaryExpr(">=");
case 't':
First += 2;
return getDerived().parseBinaryExpr(">");
}
return nullptr;
case 'i':
switch (First[1]) {
case 'x': {
First += 2;
Node *Base = getDerived().parseExpr();
if (Base == nullptr)
return nullptr;
Node *Index = getDerived().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 = getDerived().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 getDerived().parseBinaryExpr("<=");
case 's':
First += 2;
return getDerived().parseBinaryExpr("<<");
case 'S':
First += 2;
return getDerived().parseBinaryExpr("<<=");
case 't':
First += 2;
return getDerived().parseBinaryExpr("<");
}
return nullptr;
case 'm':
switch (First[1]) {
case 'c':
First += 2;
return parsePointerToMemberConversionExpr();
case 'i':
First += 2;
return getDerived().parseBinaryExpr("-");
case 'I':
First += 2;
return getDerived().parseBinaryExpr("-=");
case 'l':
First += 2;
return getDerived().parseBinaryExpr("*");
case 'L':
First += 2;
return getDerived().parseBinaryExpr("*=");
case 'm':
First += 2;
if (consumeIf('_'))
return getDerived().parsePrefixExpr("--");
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
return make<PostfixExpr>(Ex, "--");
return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
}
return nullptr;
case 'n':
switch (First[1]) {
case 'a':
case 'w': {
// [gs] nw <expression>* _ <type> [pi <expression>*] E # new (expr-list) type [(init)]
// [gs] na <expression>* _ <type> [pi <expression>*] E # new[] (expr-list) type [(init)]
bool IsArray = First[1] == 'a';
First += 2;
size_t Exprs = Names.size();
while (!consumeIf('_')) {
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
Names.push_back(Ex);
case OperatorInfo::CCast: {
// C Cast: (type)expr
Node *Ty;
{
SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
Ty = getDerived().parseType();
}
NodeArray ExprList = popTrailingNodeArray(Exprs);
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return nullptr;
bool HaveInits = consumeIf("pi");
size_t InitsBegin = Names.size();

size_t ExprsBegin = Names.size();
bool IsMany = consumeIf('_');
while (!consumeIf('E')) {
if (!HaveInits)
return nullptr;
Node *Init = getDerived().parseExpr();
if (Init == nullptr)
return Init;
Names.push_back(Init);
Node *E = getDerived().parseExpr();
if (E == nullptr)
return E;
Names.push_back(E);
if (!IsMany)
break;
}
NodeArray Inits = popTrailingNodeArray(InitsBegin);
return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
}
case 'e':
First += 2;
return getDerived().parseBinaryExpr("!=");
case 'g':
First += 2;
return getDerived().parsePrefixExpr("-");
case 't':
First += 2;
return getDerived().parsePrefixExpr("!");
case 'x':
First += 2;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<EnclosingExpr>("noexcept (", Ex, ")");
}
return nullptr;
case 'o':
switch (First[1]) {
case 'n':
return getDerived().parseUnresolvedName(Global);
case 'o':
First += 2;
return getDerived().parseBinaryExpr("||");
case 'r':
First += 2;
return getDerived().parseBinaryExpr("|");
case 'R':
First += 2;
return getDerived().parseBinaryExpr("|=");
}
return nullptr;
case 'p':
switch (First[1]) {
case 'm': {
First += 2;
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return LHS;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
if (!IsMany && Exprs.size() != 1)
return nullptr;
return make<MemberExpr>(LHS, "->*", RHS);
return make<ConversionExpr>(Ty, Exprs);
}
case 'l':
First += 2;
return getDerived().parseBinaryExpr("+");
case 'L':
First += 2;
return getDerived().parseBinaryExpr("+=");
case 'p': {
First += 2;
if (consumeIf('_'))
return getDerived().parsePrefixExpr("++");
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<PostfixExpr>(Ex, "++");
}
case 's':
First += 2;
return getDerived().parsePrefixExpr("+");
case 't': {
First += 2;
Node *L = getDerived().parseExpr();
if (L == nullptr)
return nullptr;
Node *R = getDerived().parseExpr();
if (R == nullptr)
return nullptr;
return make<MemberExpr>(L, "->", R);
}
}
return nullptr;
case 'q':
if (First[1] == 'u') {
First += 2;
case OperatorInfo::Conditional: {
// Conditional operator: expr ? expr : expr
Node *Cond = getDerived().parseExpr();
if (Cond == nullptr)
return nullptr;
Expand All @@ -4881,145 +4555,114 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
return nullptr;
return make<ConditionalExpr>(Cond, LHS, RHS);
}
return nullptr;
case 'r':
switch (First[1]) {
case 'c': {
First += 2;
Node *T = getDerived().parseType();
if (T == nullptr)
return T;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<CastExpr>("reinterpret_cast", T, Ex);
}
case 'm':
First += 2;
return getDerived().parseBinaryExpr("%");
case 'M':
First += 2;
return getDerived().parseBinaryExpr("%=");
case 's':
First += 2;
return getDerived().parseBinaryExpr(">>");
case 'S':
First += 2;
return getDerived().parseBinaryExpr(">>=");
}
return nullptr;
case 's':
switch (First[1]) {
case 'c': {
First += 2;
Node *T = getDerived().parseType();
if (T == nullptr)
return T;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<CastExpr>("static_cast", T, Ex);
}
case 'o':
First += 2;
return parseSubobjectExpr();
case 'p': {
First += 2;
Node *Child = getDerived().parseExpr();
if (Child == nullptr)
return nullptr;
return make<ParameterPackExpansion>(Child);
}
case 'r':
return getDerived().parseUnresolvedName(Global);
case 't': {
First += 2;
case OperatorInfo::NamedCast: {
// Named cast operation, @<type>(expr)
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return Ty;
return make<EnclosingExpr>("sizeof (", Ty, ")");
}
case 'z': {
First += 2;
return nullptr;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<EnclosingExpr>("sizeof (", Ex, ")");
return nullptr;
return make<CastExpr>(Sym, Ty, Ex);
}
case 'Z':
First += 2;
if (look() == 'T') {
Node *R = getDerived().parseTemplateParam();
if (R == nullptr)
return nullptr;
return make<SizeofParamPackExpr>(R);
} else if (look() == 'f') {
Node *FP = getDerived().parseFunctionParam();
if (FP == nullptr)
return nullptr;
return make<EnclosingExpr>("sizeof... (", FP, ")");
}
return nullptr;
case 'P': {
First += 2;
size_t ArgsBegin = Names.size();
while (!consumeIf('E')) {
Node *Arg = getDerived().parseTemplateArg();
if (Arg == nullptr)
return nullptr;
Names.push_back(Arg);
}
auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
if (!Pack)
case OperatorInfo::OfIdOp: {
// [sizeof/alignof/typeid] ( <type>|<expr> )
Node *Arg =
Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr();
if (!Arg)
return nullptr;
return make<EnclosingExpr>("sizeof... (", Pack, ")");
return make<EnclosingExpr>(Sym, Arg, ")");
}
}
DEMANGLE_UNREACHABLE;
}

if (numLeft() < 2)
return nullptr;
case 't':
switch (First[1]) {
case 'e': {
First += 2;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<EnclosingExpr>("typeid (", Ex, ")");
}
case 'i': {
First += 2;
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return Ty;
return make<EnclosingExpr>("typeid (", Ty, ")");

if (look() == 'L')
return getDerived().parseExprPrimary();
if (look() == 'T')
return getDerived().parseTemplateParam();
if (look() == 'f') {
// Disambiguate a fold expression from a <function-param>.
if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
return getDerived().parseFunctionParam();
return getDerived().parseFoldExpr();
}
if (consumeIf("il")) {
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
Node *E = getDerived().parseBracedExpr();
if (E == nullptr)
return nullptr;
Names.push_back(E);
}
case 'l': {
First += 2;
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
}
if (consumeIf("mc"))
return parsePointerToMemberConversionExpr();
if (consumeIf("nx")) {
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<EnclosingExpr>("noexcept (", Ex, ")");
}
if (consumeIf("so"))
return parseSubobjectExpr();
if (consumeIf("sp")) {
Node *Child = getDerived().parseExpr();
if (Child == nullptr)
return nullptr;
return make<ParameterPackExpansion>(Child);
}
if (consumeIf("sZ")) {
if (look() == 'T') {
Node *R = getDerived().parseTemplateParam();
if (R == nullptr)
return nullptr;
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
Node *E = getDerived().parseBracedExpr();
if (E == nullptr)
return nullptr;
Names.push_back(E);
}
return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
return make<SizeofParamPackExpr>(R);
}
case 'r':
First += 2;
return make<NameType>("throw");
case 'w': {
First += 2;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
Node *FP = getDerived().parseFunctionParam();
if (FP == nullptr)
return nullptr;
return make<EnclosingExpr>("sizeof... (", FP, ")");
}
if (consumeIf("sP")) {
size_t ArgsBegin = Names.size();
while (!consumeIf('E')) {
Node *Arg = getDerived().parseTemplateArg();
if (Arg == nullptr)
return nullptr;
return make<ThrowExpr>(Ex);
Names.push_back(Arg);
}
auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
if (!Pack)
return nullptr;
return make<EnclosingExpr>("sizeof... (", Pack, ")");
}
if (consumeIf("tl")) {
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return nullptr;
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
Node *E = getDerived().parseBracedExpr();
if (E == nullptr)
return nullptr;
Names.push_back(E);
}
return nullptr;
case 'u': {
++First;
return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
}
if (consumeIf("tr"))
return make<NameType>("throw");
if (consumeIf("tw")) {
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
return make<ThrowExpr>(Ex);
}
if (consumeIf('u')) {
Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr);
if (!Name)
return nullptr;
Expand Down Expand Up @@ -5054,18 +4697,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
}
return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin));
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return getDerived().parseUnresolvedName(Global);
}
return nullptr;

// Only unresolved names remain.
return getDerived().parseUnresolvedName(Global);
}

// <call-offset> ::= h <nv-offset> _
Expand Down
1,150 changes: 392 additions & 758 deletions llvm/include/llvm/Demangle/ItaniumDemangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,62 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {

Node *parseAbiTags(Node *N);

struct OperatorInfo {
enum OIKind : unsigned char {
Prefix, // Prefix unary: @ expr
Postfix, // Postfix unary: expr @
Binary, // Binary: lhs @ rhs
Array, // Array index: lhs [ rhs ]
Member, // Member access: lhs @ rhs
New, // New
Del, // Delete
Call, // Function call: expr (expr*)
CCast, // C cast: (type)expr
Conditional, // Conditional: expr ? expr : expr
// Below do not have operator names
NamedCast, // Named cast, @<type>(expr)
OfIdOp, // alignof, sizeof, typeid

Unnameable = NamedCast,
};
char Enc[2]; // Encoding
OIKind Kind; // Kind of operator
bool Flag : 1; // Entry-specific flag
const char *Name; // Spelling

public:
constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, const char *N)
: Enc{E[0], E[1]}, Kind{K}, Flag{F}, Name{N} {}

public:
bool operator<(const OperatorInfo &Other) const {
return *this < Other.Enc;
}
bool operator<(const char *Peek) const {
return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]);
}
bool operator==(const char *Peek) const {
return Enc[0] == Peek[0] && Enc[1] == Peek[1];
}
bool operator!=(const char *Peek) const { return !this->operator==(Peek); }

public:
StringView getSymbol() const {
StringView Res = Name;
if (Kind < Unnameable) {
assert(Res.startsWith("operator") &&
"operator name does not start with 'operator'");
Res = Res.dropFront(sizeof("operator") - 1);
Res.consumeFront(' ');
}
return Res;
}
StringView getName() const { return Name; }
OIKind getKind() const { return Kind; }
bool getFlag() const { return Flag; }
};
const OperatorInfo *parseOperatorEncoding();

/// Parse the <unresolved-name> production.
Node *parseUnresolvedName(bool Global);
Node *parseSimpleId();
Expand Down Expand Up @@ -2808,92 +2864,111 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
return make<NameType>(Name);
}

// <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 # <=
// If the next 2 chars are an operator encoding, consume them and return their
// OperatorInfo. Otherwise return nullptr.
template <typename Derived, typename Alloc>
const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo *
AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
static const OperatorInfo Ops[] = {
// Keep ordered by encoding
{"aN", OperatorInfo::Binary, false, "operator&="},
{"aS", OperatorInfo::Binary, false, "operator="},
{"aa", OperatorInfo::Binary, false, "operator&&"},
{"ad", OperatorInfo::Prefix, false, "operator&"},
{"an", OperatorInfo::Binary, false, "operator&"},
{"at", OperatorInfo::OfIdOp, /*Type*/ true, "alignof ("},
{"az", OperatorInfo::OfIdOp, /*Type*/ false, "alignof ("},
{"cc", OperatorInfo::NamedCast, false, "const_cast"},
{"cl", OperatorInfo::Call, false, "operator()"},
{"cm", OperatorInfo::Binary, false, "operator,"},
{"co", OperatorInfo::Prefix, false, "operator~"},
{"cv", OperatorInfo::CCast, false, "operator"}, // C Cast
{"dV", OperatorInfo::Binary, false, "operator/="},
{"da", OperatorInfo::Del, /*Ary*/ true, "operator delete[]"},
{"dc", OperatorInfo::NamedCast, false, "dynamic_cast"},
{"de", OperatorInfo::Prefix, false, "operator*"},
{"dl", OperatorInfo::Del, /*Ary*/ false, "operator delete"},
{"ds", OperatorInfo::Member, /*Named*/ false, "operator.*"},
{"dt", OperatorInfo::Member, /*Named*/ false, "operator."},
{"dv", OperatorInfo::Binary, false, "operator/"},
{"eO", OperatorInfo::Binary, false, "operator^="},
{"eo", OperatorInfo::Binary, false, "operator^"},
{"eq", OperatorInfo::Binary, false, "operator=="},
{"ge", OperatorInfo::Binary, false, "operator>="},
{"gt", OperatorInfo::Binary, false, "operator>"},
{"ix", OperatorInfo::Array, false, "operator[]"},
{"lS", OperatorInfo::Binary, false, "operator<<="},
{"le", OperatorInfo::Binary, false, "operator<="},
{"ls", OperatorInfo::Binary, false, "operator<<"},
{"lt", OperatorInfo::Binary, false, "operator<"},
{"mI", OperatorInfo::Binary, false, "operator-="},
{"mL", OperatorInfo::Binary, false, "operator*="},
{"mi", OperatorInfo::Binary, false, "operator-"},
{"ml", OperatorInfo::Binary, false, "operator*"},
{"mm", OperatorInfo::Postfix, false, "operator--"},
{"na", OperatorInfo::New, /*Ary*/ true, "operator new[]"},
{"ne", OperatorInfo::Binary, false, "operator!="},
{"ng", OperatorInfo::Prefix, false, "operator-"},
{"nt", OperatorInfo::Prefix, false, "operator!"},
{"nw", OperatorInfo::New, /*Ary*/ false, "operator new"},
{"oR", OperatorInfo::Binary, false, "operator|="},
{"oo", OperatorInfo::Binary, false, "operator||"},
{"or", OperatorInfo::Binary, false, "operator|"},
{"pL", OperatorInfo::Binary, false, "operator+="},
{"pl", OperatorInfo::Binary, false, "operator+"},
{"pm", OperatorInfo::Member, /*Named*/ false, "operator->*"},
{"pp", OperatorInfo::Postfix, false, "operator++"},
{"ps", OperatorInfo::Prefix, false, "operator+"},
{"pt", OperatorInfo::Member, /*Named*/ true, "operator->"},
{"qu", OperatorInfo::Conditional, false, "operator?"},
{"rM", OperatorInfo::Binary, false, "operator%="},
{"rS", OperatorInfo::Binary, false, "operator>>="},
{"rc", OperatorInfo::NamedCast, false, "reinterpret_cast"},
{"rm", OperatorInfo::Binary, false, "operator%"},
{"rs", OperatorInfo::Binary, false, "operator>>"},
{"sc", OperatorInfo::NamedCast, false, "static_cast"},
{"ss", OperatorInfo::Binary, false, "operator<=>"},
{"st", OperatorInfo::OfIdOp, /*Type*/ true, "sizeof ("},
{"sz", OperatorInfo::OfIdOp, /*Type*/ false, "sizeof ("},
{"te", OperatorInfo::OfIdOp, /*Type*/ false, "typeid ("},
{"ti", OperatorInfo::OfIdOp, /*Type*/ true, "typeid ("},
};
const auto NumOps = sizeof(Ops) / sizeof(Ops[0]);

#ifndef NDEBUG
{
// Verify table order.
static bool Done;
if (!Done) {
Done = true;
for (const auto *Op = &Ops[0]; Op != &Ops[NumOps - 1]; Op++)
assert(Op[0] < Op[1] && "Operator table is not ordered");
}
}
#endif

if (numLeft() < 2)
return nullptr;

auto Op = std::lower_bound(
&Ops[0], &Ops[NumOps], First,
[](const OperatorInfo &Op_, const char *Enc_) { return Op_ < Enc_; });
if (Op == &Ops[NumOps] || *Op != First)
return nullptr;

First += 2;
return Op;
}

// <operator-name> ::= See parseOperatorEncoding()
// ::= 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
// ::= v <digit> <source-name> # vendor extended operator
template <typename Derived, typename Alloc>
Node *
AbstractManglingParser<Derived, Alloc>::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=");
}
return nullptr;
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': {
First += 2;
if (const auto *Op = parseOperatorEncoding()) {
if (Op->getKind() == OperatorInfo::CCast) {
// ::= cv <type> # (cast)
SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
// If we're parsing an encoding, State != nullptr and the conversion
// operators' <type> could have a <template-param> that refers to some
Expand All @@ -2907,192 +2982,37 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
if (State) State->CtorDtorConversion = true;
return make<ConversionOperatorType>(Ty);
}
}
return nullptr;
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;
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;
case 'g':
switch (look(1)) {
case 'e':
First += 2;
return make<NameType>("operator>=");
case 't':
First += 2;
return make<NameType>("operator>");
}
return nullptr;
case 'i':
if (look(1) == 'x') {
First += 2;
return make<NameType>("operator[]");
}
return nullptr;
case 'l':
switch (look(1)) {
case 'e':
First += 2;
return make<NameType>("operator<=");

if (Op->getKind() >= OperatorInfo::Unnameable)
/* Not a nameable operator. */
return nullptr;
if (Op->getKind() == OperatorInfo::Member && !Op->getFlag())
/* Not a nameable MemberExpr */
return nullptr;

return make<NameType>(Op->getName());
}

if (consumeIf("li")) {
// ::= li <source-name> # operator ""
case 'i': {
First += 2;
Node *SN = getDerived().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;
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;
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;
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;
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;
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 = getDerived().parseSourceName(State);
if (SN == nullptr)
return nullptr;
return make<LiteralOperator>(SN);
}

if (consumeIf('v')) {
// ::= v <digit> <source-name> # vendor extended operator
if (look() >= '0' && look() <= '9') {
First++;
Node *SN = getDerived().parseSourceName(State);
if (SN == nullptr)
return nullptr;
return make<ConversionOperatorType>(SN);
}
return nullptr;
}

return nullptr;
}

Expand Down Expand Up @@ -4374,55 +4294,34 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
if (!consumeIf('f'))
return nullptr;

char FoldKind = look();
bool IsLeftFold, HasInitializer;
HasInitializer = FoldKind == 'L' || FoldKind == 'R';
if (FoldKind == 'l' || FoldKind == 'L')
IsLeftFold = true;
else if (FoldKind == 'r' || FoldKind == 'R')
IsLeftFold = false;
else
bool IsLeftFold = false, HasInitializer = false;
switch (look()) {
default:
return nullptr;
case 'L':
IsLeftFold = true;
HasInitializer = true;
break;
case 'R':
HasInitializer = true;
break;
case 'l':
IsLeftFold = true;
break;
case 'r':
break;
}
++First;

// FIXME: This map is duplicated in parseOperatorName and parseExpr.
StringView OperatorName;
if (consumeIf("aa")) OperatorName = "&&";
else if (consumeIf("an")) OperatorName = "&";
else if (consumeIf("aN")) OperatorName = "&=";
else if (consumeIf("aS")) OperatorName = "=";
else if (consumeIf("cm")) OperatorName = ",";
else if (consumeIf("ds")) OperatorName = ".*";
else if (consumeIf("dv")) OperatorName = "/";
else if (consumeIf("dV")) OperatorName = "/=";
else if (consumeIf("eo")) OperatorName = "^";
else if (consumeIf("eO")) OperatorName = "^=";
else if (consumeIf("eq")) OperatorName = "==";
else if (consumeIf("ge")) OperatorName = ">=";
else if (consumeIf("gt")) OperatorName = ">";
else if (consumeIf("le")) OperatorName = "<=";
else if (consumeIf("ls")) OperatorName = "<<";
else if (consumeIf("lS")) OperatorName = "<<=";
else if (consumeIf("lt")) OperatorName = "<";
else if (consumeIf("mi")) OperatorName = "-";
else if (consumeIf("mI")) OperatorName = "-=";
else if (consumeIf("ml")) OperatorName = "*";
else if (consumeIf("mL")) OperatorName = "*=";
else if (consumeIf("ne")) OperatorName = "!=";
else if (consumeIf("oo")) OperatorName = "||";
else if (consumeIf("or")) OperatorName = "|";
else if (consumeIf("oR")) OperatorName = "|=";
else if (consumeIf("pl")) OperatorName = "+";
else if (consumeIf("pL")) OperatorName = "+=";
else if (consumeIf("rm")) OperatorName = "%";
else if (consumeIf("rM")) OperatorName = "%=";
else if (consumeIf("rs")) OperatorName = ">>";
else if (consumeIf("rS")) OperatorName = ">>=";
else return nullptr;

Node *Pack = getDerived().parseExpr(), *Init = nullptr;
const auto *Op = parseOperatorEncoding();
if (!Op || Op->getKind() != OperatorInfo::Binary)
return nullptr;

Node *Pack = getDerived().parseExpr();
if (Pack == nullptr)
return nullptr;

Node *Init = nullptr;
if (HasInitializer) {
Init = getDerived().parseExpr();
if (Init == nullptr)
Expand All @@ -4432,7 +4331,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
if (IsLeftFold && Init)
std::swap(Pack, Init);

return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
return make<FoldExpr>(IsLeftFold, Op->getSymbol(), Pack, Init);
}

// <expression> ::= mc <parameter type> <expr> [<offset number>] E
Expand Down Expand Up @@ -4526,350 +4425,125 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
bool Global = consumeIf("gs");
if (numLeft() < 2)
return nullptr;

switch (*First) {
case 'L':
return getDerived().parseExprPrimary();
case 'T':
return getDerived().parseTemplateParam();
case 'f': {
// Disambiguate a fold expression from a <function-param>.
if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
return getDerived().parseFunctionParam();
return getDerived().parseFoldExpr();
}
case 'a':
switch (First[1]) {
case 'a':
First += 2;
return getDerived().parseBinaryExpr("&&");
case 'd':
First += 2;
return getDerived().parsePrefixExpr("&");
case 'n':
First += 2;
return getDerived().parseBinaryExpr("&");
case 'N':
First += 2;
return getDerived().parseBinaryExpr("&=");
case 'S':
First += 2;
return getDerived().parseBinaryExpr("=");
case 't': {
First += 2;
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
const auto *Op = parseOperatorEncoding();
if (Op) {
auto Sym = Op->getSymbol();
switch (Op->getKind()) {
case OperatorInfo::Binary:
// Binary operator: lhs @ rhs
return getDerived().parseBinaryExpr(Sym);
case OperatorInfo::Prefix:
// Prefix unary operator: @ expr
return getDerived().parsePrefixExpr(Sym);
case OperatorInfo::Postfix: {
// Postfix unary operator: expr @
if (consumeIf('_'))
return getDerived().parsePrefixExpr(Sym);
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
return make<EnclosingExpr>("alignof (", Ty, ")");
return make<PostfixExpr>(Ex, Sym);
}
case 'z': {
First += 2;
Node *Ty = getDerived().parseExpr();
if (Ty == nullptr)
case OperatorInfo::Array: {
// Array Index: lhs [ rhs ]
Node *Base = getDerived().parseExpr();
if (Base == nullptr)
return nullptr;
return make<EnclosingExpr>("alignof (", Ty, ")");
}
Node *Index = getDerived().parseExpr();
if (Index == nullptr)
return nullptr;
return make<ArraySubscriptExpr>(Base, Index);
}
return nullptr;
case 'c':
switch (First[1]) {
// cc <type> <expression> # const_cast<type>(expression)
case 'c': {
First += 2;
case OperatorInfo::Member: {
// Member access lhs @ rhs
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return nullptr;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
return make<MemberExpr>(LHS, Sym, RHS);
}
case OperatorInfo::New: {
// New
// # new (expr-list) type [(init)]
// [gs] nw <expression>* _ <type> [pi <expression>*] E
// # new[] (expr-list) type [(init)]
// [gs] na <expression>* _ <type> [pi <expression>*] E
size_t Exprs = Names.size();
while (!consumeIf('_')) {
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
Names.push_back(Ex);
}
NodeArray ExprList = popTrailingNodeArray(Exprs);
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return Ty;
return nullptr;
bool HaveInits = consumeIf("pi");
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
if (!HaveInits)
return nullptr;
Node *Init = getDerived().parseExpr();
if (Init == nullptr)
return Init;
Names.push_back(Init);
}
NodeArray Inits = popTrailingNodeArray(InitsBegin);
return make<NewExpr>(ExprList, Ty, Inits, Global,
/*IsArray=*/Op->getFlag());
}
case OperatorInfo::Del: {
// Delete
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<CastExpr>("const_cast", Ty, Ex);
return nullptr;
return make<DeleteExpr>(Ex, Global, /*IsArray=*/Op->getFlag());
}
// cl <expression>+ E # call
case 'l': {
First += 2;
case OperatorInfo::Call: {
// Function Call
Node *Callee = getDerived().parseExpr();
if (Callee == nullptr)
return Callee;
return nullptr;
size_t ExprsBegin = Names.size();
while (!consumeIf('E')) {
Node *E = getDerived().parseExpr();
if (E == nullptr)
return E;
Names.push_back(E);
}
return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
}
case 'm':
First += 2;
return getDerived().parseBinaryExpr(",");
case 'o':
First += 2;
return getDerived().parsePrefixExpr("~");
case 'v':
return getDerived().parseConversionExpr();
}
return nullptr;
case 'd':
switch (First[1]) {
case 'a': {
First += 2;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
}
case 'c': {
First += 2;
Node *T = getDerived().parseType();
if (T == nullptr)
return T;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<CastExpr>("dynamic_cast", T, Ex);
}
case 'e':
First += 2;
return getDerived().parsePrefixExpr("*");
case 'l': {
First += 2;
Node *E = getDerived().parseExpr();
if (E == nullptr)
return E;
return make<DeleteExpr>(E, Global, /*is_array=*/false);
}
case 'n':
return getDerived().parseUnresolvedName(Global);
case 's': {
First += 2;
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return nullptr;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
return make<MemberExpr>(LHS, ".*", RHS);
}
case 't': {
First += 2;
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return LHS;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
return make<MemberExpr>(LHS, ".", RHS);
}
case 'v':
First += 2;
return getDerived().parseBinaryExpr("/");
case 'V':
First += 2;
return getDerived().parseBinaryExpr("/=");
}
return nullptr;
case 'e':
switch (First[1]) {
case 'o':
First += 2;
return getDerived().parseBinaryExpr("^");
case 'O':
First += 2;
return getDerived().parseBinaryExpr("^=");
case 'q':
First += 2;
return getDerived().parseBinaryExpr("==");
}
return nullptr;
case 'g':
switch (First[1]) {
case 'e':
First += 2;
return getDerived().parseBinaryExpr(">=");
case 't':
First += 2;
return getDerived().parseBinaryExpr(">");
}
return nullptr;
case 'i':
switch (First[1]) {
case 'x': {
First += 2;
Node *Base = getDerived().parseExpr();
if (Base == nullptr)
return nullptr;
Node *Index = getDerived().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 = getDerived().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 getDerived().parseBinaryExpr("<=");
case 's':
First += 2;
return getDerived().parseBinaryExpr("<<");
case 'S':
First += 2;
return getDerived().parseBinaryExpr("<<=");
case 't':
First += 2;
return getDerived().parseBinaryExpr("<");
}
return nullptr;
case 'm':
switch (First[1]) {
case 'c':
First += 2;
return parsePointerToMemberConversionExpr();
case 'i':
First += 2;
return getDerived().parseBinaryExpr("-");
case 'I':
First += 2;
return getDerived().parseBinaryExpr("-=");
case 'l':
First += 2;
return getDerived().parseBinaryExpr("*");
case 'L':
First += 2;
return getDerived().parseBinaryExpr("*=");
case 'm':
First += 2;
if (consumeIf('_'))
return getDerived().parsePrefixExpr("--");
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
return make<PostfixExpr>(Ex, "--");
return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
}
return nullptr;
case 'n':
switch (First[1]) {
case 'a':
case 'w': {
// [gs] nw <expression>* _ <type> [pi <expression>*] E # new (expr-list) type [(init)]
// [gs] na <expression>* _ <type> [pi <expression>*] E # new[] (expr-list) type [(init)]
bool IsArray = First[1] == 'a';
First += 2;
size_t Exprs = Names.size();
while (!consumeIf('_')) {
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
Names.push_back(Ex);
case OperatorInfo::CCast: {
// C Cast: (type)expr
Node *Ty;
{
SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
Ty = getDerived().parseType();
}
NodeArray ExprList = popTrailingNodeArray(Exprs);
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return nullptr;
bool HaveInits = consumeIf("pi");
size_t InitsBegin = Names.size();

size_t ExprsBegin = Names.size();
bool IsMany = consumeIf('_');
while (!consumeIf('E')) {
if (!HaveInits)
return nullptr;
Node *Init = getDerived().parseExpr();
if (Init == nullptr)
return Init;
Names.push_back(Init);
Node *E = getDerived().parseExpr();
if (E == nullptr)
return E;
Names.push_back(E);
if (!IsMany)
break;
}
NodeArray Inits = popTrailingNodeArray(InitsBegin);
return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
}
case 'e':
First += 2;
return getDerived().parseBinaryExpr("!=");
case 'g':
First += 2;
return getDerived().parsePrefixExpr("-");
case 't':
First += 2;
return getDerived().parsePrefixExpr("!");
case 'x':
First += 2;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<EnclosingExpr>("noexcept (", Ex, ")");
}
return nullptr;
case 'o':
switch (First[1]) {
case 'n':
return getDerived().parseUnresolvedName(Global);
case 'o':
First += 2;
return getDerived().parseBinaryExpr("||");
case 'r':
First += 2;
return getDerived().parseBinaryExpr("|");
case 'R':
First += 2;
return getDerived().parseBinaryExpr("|=");
}
return nullptr;
case 'p':
switch (First[1]) {
case 'm': {
First += 2;
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return LHS;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
if (!IsMany && Exprs.size() != 1)
return nullptr;
return make<MemberExpr>(LHS, "->*", RHS);
return make<ConversionExpr>(Ty, Exprs);
}
case 'l':
First += 2;
return getDerived().parseBinaryExpr("+");
case 'L':
First += 2;
return getDerived().parseBinaryExpr("+=");
case 'p': {
First += 2;
if (consumeIf('_'))
return getDerived().parsePrefixExpr("++");
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<PostfixExpr>(Ex, "++");
}
case 's':
First += 2;
return getDerived().parsePrefixExpr("+");
case 't': {
First += 2;
Node *L = getDerived().parseExpr();
if (L == nullptr)
return nullptr;
Node *R = getDerived().parseExpr();
if (R == nullptr)
return nullptr;
return make<MemberExpr>(L, "->", R);
}
}
return nullptr;
case 'q':
if (First[1] == 'u') {
First += 2;
case OperatorInfo::Conditional: {
// Conditional operator: expr ? expr : expr
Node *Cond = getDerived().parseExpr();
if (Cond == nullptr)
return nullptr;
Expand All @@ -4881,145 +4555,114 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
return nullptr;
return make<ConditionalExpr>(Cond, LHS, RHS);
}
return nullptr;
case 'r':
switch (First[1]) {
case 'c': {
First += 2;
Node *T = getDerived().parseType();
if (T == nullptr)
return T;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<CastExpr>("reinterpret_cast", T, Ex);
}
case 'm':
First += 2;
return getDerived().parseBinaryExpr("%");
case 'M':
First += 2;
return getDerived().parseBinaryExpr("%=");
case 's':
First += 2;
return getDerived().parseBinaryExpr(">>");
case 'S':
First += 2;
return getDerived().parseBinaryExpr(">>=");
}
return nullptr;
case 's':
switch (First[1]) {
case 'c': {
First += 2;
Node *T = getDerived().parseType();
if (T == nullptr)
return T;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<CastExpr>("static_cast", T, Ex);
}
case 'o':
First += 2;
return parseSubobjectExpr();
case 'p': {
First += 2;
Node *Child = getDerived().parseExpr();
if (Child == nullptr)
return nullptr;
return make<ParameterPackExpansion>(Child);
}
case 'r':
return getDerived().parseUnresolvedName(Global);
case 't': {
First += 2;
case OperatorInfo::NamedCast: {
// Named cast operation, @<type>(expr)
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return Ty;
return make<EnclosingExpr>("sizeof (", Ty, ")");
}
case 'z': {
First += 2;
return nullptr;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<EnclosingExpr>("sizeof (", Ex, ")");
return nullptr;
return make<CastExpr>(Sym, Ty, Ex);
}
case 'Z':
First += 2;
if (look() == 'T') {
Node *R = getDerived().parseTemplateParam();
if (R == nullptr)
return nullptr;
return make<SizeofParamPackExpr>(R);
} else if (look() == 'f') {
Node *FP = getDerived().parseFunctionParam();
if (FP == nullptr)
return nullptr;
return make<EnclosingExpr>("sizeof... (", FP, ")");
}
return nullptr;
case 'P': {
First += 2;
size_t ArgsBegin = Names.size();
while (!consumeIf('E')) {
Node *Arg = getDerived().parseTemplateArg();
if (Arg == nullptr)
return nullptr;
Names.push_back(Arg);
}
auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
if (!Pack)
case OperatorInfo::OfIdOp: {
// [sizeof/alignof/typeid] ( <type>|<expr> )
Node *Arg =
Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr();
if (!Arg)
return nullptr;
return make<EnclosingExpr>("sizeof... (", Pack, ")");
return make<EnclosingExpr>(Sym, Arg, ")");
}
}
DEMANGLE_UNREACHABLE;
}

if (numLeft() < 2)
return nullptr;
case 't':
switch (First[1]) {
case 'e': {
First += 2;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<EnclosingExpr>("typeid (", Ex, ")");
}
case 'i': {
First += 2;
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return Ty;
return make<EnclosingExpr>("typeid (", Ty, ")");

if (look() == 'L')
return getDerived().parseExprPrimary();
if (look() == 'T')
return getDerived().parseTemplateParam();
if (look() == 'f') {
// Disambiguate a fold expression from a <function-param>.
if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
return getDerived().parseFunctionParam();
return getDerived().parseFoldExpr();
}
if (consumeIf("il")) {
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
Node *E = getDerived().parseBracedExpr();
if (E == nullptr)
return nullptr;
Names.push_back(E);
}
case 'l': {
First += 2;
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
}
if (consumeIf("mc"))
return parsePointerToMemberConversionExpr();
if (consumeIf("nx")) {
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return Ex;
return make<EnclosingExpr>("noexcept (", Ex, ")");
}
if (consumeIf("so"))
return parseSubobjectExpr();
if (consumeIf("sp")) {
Node *Child = getDerived().parseExpr();
if (Child == nullptr)
return nullptr;
return make<ParameterPackExpansion>(Child);
}
if (consumeIf("sZ")) {
if (look() == 'T') {
Node *R = getDerived().parseTemplateParam();
if (R == nullptr)
return nullptr;
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
Node *E = getDerived().parseBracedExpr();
if (E == nullptr)
return nullptr;
Names.push_back(E);
}
return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
return make<SizeofParamPackExpr>(R);
}
case 'r':
First += 2;
return make<NameType>("throw");
case 'w': {
First += 2;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
Node *FP = getDerived().parseFunctionParam();
if (FP == nullptr)
return nullptr;
return make<EnclosingExpr>("sizeof... (", FP, ")");
}
if (consumeIf("sP")) {
size_t ArgsBegin = Names.size();
while (!consumeIf('E')) {
Node *Arg = getDerived().parseTemplateArg();
if (Arg == nullptr)
return nullptr;
return make<ThrowExpr>(Ex);
Names.push_back(Arg);
}
auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
if (!Pack)
return nullptr;
return make<EnclosingExpr>("sizeof... (", Pack, ")");
}
if (consumeIf("tl")) {
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
return nullptr;
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
Node *E = getDerived().parseBracedExpr();
if (E == nullptr)
return nullptr;
Names.push_back(E);
}
return nullptr;
case 'u': {
++First;
return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
}
if (consumeIf("tr"))
return make<NameType>("throw");
if (consumeIf("tw")) {
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
return make<ThrowExpr>(Ex);
}
if (consumeIf('u')) {
Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr);
if (!Name)
return nullptr;
Expand Down Expand Up @@ -5054,18 +4697,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
}
return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin));
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return getDerived().parseUnresolvedName(Global);
}
return nullptr;

// Only unresolved names remain.
return getDerived().parseUnresolvedName(Global);
}

// <call-offset> ::= h <nv-offset> _
Expand Down