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;
|
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
|
||||||
|
|
Loading…
Reference in New Issue