[demangler] Rewrite parse_nested_name in the new style.

llvm-svn: 325022
This commit is contained in:
Erik Pilkington 2018-02-13 17:09:03 +00:00
parent 42fed626bc
commit aec1e58c99
1 changed files with 206 additions and 280 deletions

View File

@ -1983,12 +1983,28 @@ struct Db {
FunctionRefQual RefQuals = FrefQualNone; FunctionRefQual RefQuals = FrefQualNone;
unsigned EncodingDepth = 0; unsigned EncodingDepth = 0;
bool ParsedCtorDtorCV = false; bool ParsedCtorDtorCV = false;
bool EndsWithTemplateArgs = false;
bool TagTemplates = true; bool TagTemplates = true;
bool FixForwardReferences = false; bool FixForwardReferences = false;
bool TryToParseTemplateArgs = true; bool TryToParseTemplateArgs = true;
BumpPointerAllocator ASTAllocator; 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) { template <class T, class... Args> T *make(Args &&... args) {
return new (ASTAllocator.allocate(sizeof(T))) return new (ASTAllocator.allocate(sizeof(T)))
T(std::forward<Args>(args)...); T(std::forward<Args>(args)...);
@ -2063,6 +2079,10 @@ struct Db {
Node *parseClassEnumType(); Node *parseClassEnumType();
Node *parseQualifiedType(bool &AppliesToFunction); 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. // FIXME: remove this when all the parse_* functions have been rewritten.
template <const char *(*parse_fn)(const char *, const char *, Db &)> template <const char *(*parse_fn)(const char *, const char *, Db &)>
Node *legacyParse() { 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) { const char *parse_expression(const char *first, const char *last, Db &db) {
db.First = first; db.First = first;
db.Last = last; 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_unresolved_name(const char *, const char *, Db &);
const char *parse_substitution(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> // <number> ::= [n] <non-negative decimal integer>
StringView Db::parseNumber(bool AllowNegative) { StringView Db::parseNumber(bool AllowNegative) {
const char *Tmp = First; const char *Tmp = First;
@ -2737,6 +2940,7 @@ Node *Db::parseIntegerLiteral(StringView Lit) {
return nullptr; return nullptr;
} }
// <CV-Qualifiers> ::= [r] [V] [K]
Qualifiers Db::parseCVQualifiers() { Qualifiers Db::parseCVQualifiers() {
Qualifiers CVR = QualNone; Qualifiers CVR = QualNone;
if (consumeIf('r')) if (consumeIf('r'))
@ -3715,33 +3919,6 @@ parse_substitution(const char* first, const char* last, Db& db)
return first; 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 // <template-param> ::= T_ # first template parameter
// ::= T <parameter-2 non-negative number> _ // ::= T <parameter-2 non-negative number> _
@ -4513,81 +4690,6 @@ parse_operator_name(const char* first, const char* last, Db& db)
return first; 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>] // <unnamed-type-name> ::= Ut [<nonnegative number>] _ [<abi-tag-seq>]
// ::= <closure-type-name> // ::= <closure-type-name>
// //
@ -4678,17 +4780,13 @@ parse_unnamed_type_name(const char* first, const char* last, Db& db)
const char* const char*
parse_unqualified_name(const char* first, const char* last, Db& db) parse_unqualified_name(const char* first, const char* last, Db& db)
{ {
// <ctor-dtor-name>s are special-cased in parseNestedName().
if (first != last) if (first != last)
{ {
const char* t; const char* t;
switch (*first) switch (*first)
{ {
case 'C':
case 'D':
t = parse_ctor_dtor_name(first, last, db);
if (t != first)
first = t;
break;
case 'U': case 'U':
t = parse_unnamed_type_name(first, last, db); t = parse_unnamed_type_name(first, last, db);
if (t != first) if (t != first)
@ -4857,178 +4955,6 @@ parse_template_args(const char* first, const char* last, Db& db)
return first; 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 // <discriminator> := _ <non-negative number> # when number < 10
// := __ <non-negative number> _ # when number >= 10 // := __ <non-negative number> _ # when number >= 10
// extension := decimal-digit+ # at the end of string // extension := decimal-digit+ # at the end of string