Author: epilk Date: Tue Feb 13 09:09:03 2018 New Revision: 325022 URL: http://llvm.org/viewvc/llvm-project?rev=325022&view=rev Log: [demangler] Rewrite parse_nested_name in the new style.
Modified: libcxxabi/trunk/src/cxa_demangle.cpp Modified: libcxxabi/trunk/src/cxa_demangle.cpp URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=325022&r1=325021&r2=325022&view=diff ============================================================================== --- libcxxabi/trunk/src/cxa_demangle.cpp (original) +++ libcxxabi/trunk/src/cxa_demangle.cpp Tue Feb 13 09:09:03 2018 @@ -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 *f 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 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, co 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, c 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* firs 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) @@ -4856,178 +4954,6 @@ parse_template_args(const char* first, c } 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits