[demangler] Rewrite parse_nested_name in the new style.
git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@325022 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index 1cadff4..f2e7d28 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -1983,12 +1983,28 @@
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)...);
@@ -2063,6 +2079,10 @@
Node *parseClassEnumType();
Node *parseQualifiedType(bool &AppliesToFunction);
+ Node *parseNestedName();
+ Node *parseCtorDtorName(Node *&SoFar);
+ Node *parseAbiTags(Node *N);
+
// FIXME: remove this when all the parse_* functions have been rewritten.
template <const char *(*parse_fn)(const char *, const char *, Db &)>
Node *legacyParse() {
@@ -2090,6 +2110,19 @@
}
};
+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;
@@ -2143,6 +2176,176 @@
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')) {
+ if (look() != '1' && look() != '2' && look() != '3' && look() != '5')
+ return nullptr;
+ ++First;
+ ParsedCtorDtorCV = true;
+ return make<CtorDtorName>(SoFar, false);
+ }
+
+ if (look() == 'D' &&
+ (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) {
+ First += 2;
+ ParsedCtorDtorCV = true;
+ return make<CtorDtorName>(SoFar, true);
+ }
+
+ 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() {
+ if (!consumeIf('N'))
+ 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;
+ }
+
+ // ::= <prefix> <unqualified-name>
+ Node *N = legacyParse<parse_unqualified_name>();
+ if (N == nullptr)
+ return nullptr;
+ PushComponent(N);
+ Subs.push_back(SoFar);
+ }
+
+ if (SoFar == nullptr || Subs.empty())
+ return nullptr;
+
+ Subs.pop_back();
+ return SoFar;
+}
+
+// <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;
+}
+
// <number> ::= [n] <non-negative decimal integer>
StringView Db::parseNumber(bool AllowNegative) {
const char *Tmp = First;
@@ -2737,6 +2940,7 @@
return nullptr;
}
+// <CV-Qualifiers> ::= [r] [V] [K]
Qualifiers Db::parseCVQualifiers() {
Qualifiers CVR = QualNone;
if (consumeIf('r'))
@@ -3715,33 +3919,6 @@
return first;
}
-// <CV-Qualifiers> ::= [r] [V] [K]
-
-const char*
-parse_cv_qualifiers(const char* first, const char* last, Qualifiers& cv)
-{
- cv = QualNone;
- if (first != last)
- {
- if (*first == 'r')
- {
- addQualifiers(cv, QualRestrict);
- ++first;
- }
- if (*first == 'V')
- {
- addQualifiers(cv, QualVolatile);
- ++first;
- }
- if (*first == 'K')
- {
- addQualifiers(cv, QualConst);
- ++first;
- }
- }
- return first;
-}
-
// <template-param> ::= T_ # first template parameter
// ::= T <parameter-2 non-negative number> _
@@ -4513,81 +4690,6 @@
return first;
}
-Node* maybe_change_special_sub_name(Node* inp, Db& db)
-{
- if (inp->K != Node::KSpecialSubstitution)
- return inp;
- auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK;
- switch (Kind)
- {
- case SpecialSubKind::string:
- case SpecialSubKind::istream:
- case SpecialSubKind::ostream:
- case SpecialSubKind::iostream:
- return db.make<ExpandedSpecialSubstitution>(Kind);
- default:
- break;
- }
- return inp;
-}
-
-// <ctor-dtor-name> ::= C1 # complete object constructor
-// ::= C2 # base object constructor
-// ::= C3 # complete object allocating constructor
-// extension ::= C5 # ?
-// ::= D0 # deleting destructor
-// ::= D1 # complete object destructor
-// ::= D2 # base object destructor
-// extension ::= D5 # ?
-// extension ::= <ctor-dtor-name> <abi-tag-seq>
-const char*
-parse_ctor_dtor_name(const char* first, const char* last, Db& db)
-{
- if (last-first >= 2 && !db.Names.empty())
- {
- switch (first[0])
- {
- case 'C':
- switch (first[1])
- {
- case '1':
- case '2':
- case '3':
- case '5':
- if (db.Names.empty())
- return first;
- db.Names.back() =
- maybe_change_special_sub_name(db.Names.back(), db);
- db.Names.push_back(
- db.make<CtorDtorName>(db.Names.back(), false));
- first += 2;
- first = parse_abi_tag_seq(first, last, db);
- db.ParsedCtorDtorCV = true;
- break;
- }
- break;
- case 'D':
- switch (first[1])
- {
- case '0':
- case '1':
- case '2':
- case '5':
- if (db.Names.empty())
- return first;
- db.Names.push_back(
- db.make<CtorDtorName>(db.Names.back(), true));
- first += 2;
- first = parse_abi_tag_seq(first, last, db);
- db.ParsedCtorDtorCV = true;
- break;
- }
- break;
- }
- }
- return first;
-}
-
// <unnamed-type-name> ::= Ut [<nonnegative number>] _ [<abi-tag-seq>]
// ::= <closure-type-name>
//
@@ -4678,17 +4780,13 @@
const char*
parse_unqualified_name(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 'C':
- case 'D':
- t = parse_ctor_dtor_name(first, last, db);
- if (t != first)
- first = t;
- break;
case 'U':
t = parse_unnamed_type_name(first, last, db);
if (t != first)
@@ -4857,178 +4955,6 @@
return first;
}
-// <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>
-
-const char*
-parse_nested_name(const char* first, const char* last, Db& db,
- bool* ends_with_template_args)
-{
- if (first != last && *first == 'N')
- {
- Qualifiers cv;
- const char* t0 = parse_cv_qualifiers(first+1, last, cv);
- if (t0 == last)
- return first;
- db.RefQuals = FrefQualNone;
- if (*t0 == 'R')
- {
- db.RefQuals = FrefQualLValue;
- ++t0;
- }
- else if (*t0 == 'O')
- {
- db.RefQuals = FrefQualRValue;
- ++t0;
- }
- db.Names.push_back(db.make<EmptyName>());
- if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
- {
- t0 += 2;
- db.Names.back() = db.make<NameType>("std");
- }
- if (t0 == last)
- return first;
- bool pop_subs = false;
- bool component_ends_with_template_args = false;
- while (*t0 != 'E')
- {
- component_ends_with_template_args = false;
- const char* t1;
- switch (*t0)
- {
- case 'S':
- if (t0 + 1 != last && t0[1] == 't')
- goto do_parse_unqualified_name;
- t1 = parse_substitution(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KEmptyName)
- {
- db.Names.back() = db.make<QualifiedName>(
- db.Names.back(), name);
- db.Subs.push_back(db.Names.back());
- }
- else
- db.Names.back() = name;
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'T':
- t1 = parse_template_param(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KEmptyName)
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
- else
- db.Names.back() = name;
- db.Subs.push_back(db.Names.back());
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'D':
- if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
- goto do_parse_unqualified_name;
- t1 = parse_decltype(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KEmptyName)
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
- else
- db.Names.back() = name;
- db.Subs.push_back(db.Names.back());
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'I':
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<NameWithTemplateArgs>(
- db.Names.back(), name);
- db.Subs.push_back(db.Names.back());
- t0 = t1;
- component_ends_with_template_args = true;
- }
- else
- return first;
- break;
- case 'L':
- if (++t0 == last)
- return first;
- break;
- default:
- do_parse_unqualified_name:
- t1 = parse_unqualified_name(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KEmptyName)
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
- else
- db.Names.back() = name;
- db.Subs.push_back(db.Names.back());
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- }
- }
- first = t0 + 1;
- db.CV = cv;
- if (pop_subs && !db.Subs.empty())
- db.Subs.pop_back();
- if (ends_with_template_args)
- *ends_with_template_args = component_ends_with_template_args;
- }
- return first;
-}
-
// <discriminator> := _ <non-negative number> # when number < 10
// := __ <non-negative number> _ # when number >= 10
// extension := decimal-digit+ # at the end of string