forked from OSchip/llvm-project
[demangler] Rewrite parse_nested_name in the new style.
llvm-svn: 325022
This commit is contained in:
parent
42fed626bc
commit
aec1e58c99
|
@ -1983,12 +1983,28 @@ struct Db {
|
|||
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 @@ struct Db {
|
|||
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 @@ struct Db {
|
|||
}
|
||||
};
|
||||
|
||||
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_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')) {
|
||||
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 @@ Node *Db::parseIntegerLiteral(StringView Lit) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// <CV-Qualifiers> ::= [r] [V] [K]
|
||||
Qualifiers Db::parseCVQualifiers() {
|
||||
Qualifiers CVR = QualNone;
|
||||
if (consumeIf('r'))
|
||||
|
@ -3715,33 +3919,6 @@ parse_substitution(const char* first, const char* last, Db& db)
|
|||
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 @@ parse_operator_name(const char* first, const char* last, Db& db)
|
|||
return first;
|
||||
}
|
||||
|
||||
Node* maybe_change_special_sub_name(Node* inp, Db& db)
|
||||
{
|
||||
if (inp->K != Node::KSpecialSubstitution)
|
||||
return inp;
|
||||
auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK;
|
||||
switch (Kind)
|
||||
{
|
||||
case SpecialSubKind::string:
|
||||
case SpecialSubKind::istream:
|
||||
case SpecialSubKind::ostream:
|
||||
case SpecialSubKind::iostream:
|
||||
return db.make<ExpandedSpecialSubstitution>(Kind);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return inp;
|
||||
}
|
||||
|
||||
// <ctor-dtor-name> ::= C1 # complete object constructor
|
||||
// ::= C2 # base object constructor
|
||||
// ::= C3 # complete object allocating constructor
|
||||
// extension ::= C5 # ?
|
||||
// ::= D0 # deleting destructor
|
||||
// ::= D1 # complete object destructor
|
||||
// ::= D2 # base object destructor
|
||||
// extension ::= D5 # ?
|
||||
// extension ::= <ctor-dtor-name> <abi-tag-seq>
|
||||
const char*
|
||||
parse_ctor_dtor_name(const char* first, const char* last, Db& db)
|
||||
{
|
||||
if (last-first >= 2 && !db.Names.empty())
|
||||
{
|
||||
switch (first[0])
|
||||
{
|
||||
case 'C':
|
||||
switch (first[1])
|
||||
{
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '5':
|
||||
if (db.Names.empty())
|
||||
return first;
|
||||
db.Names.back() =
|
||||
maybe_change_special_sub_name(db.Names.back(), db);
|
||||
db.Names.push_back(
|
||||
db.make<CtorDtorName>(db.Names.back(), false));
|
||||
first += 2;
|
||||
first = parse_abi_tag_seq(first, last, db);
|
||||
db.ParsedCtorDtorCV = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '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 @@ parse_unnamed_type_name(const char* first, const char* last, Db& db)
|
|||
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 @@ parse_template_args(const char* first, const char* last, Db& db)
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue