From 49b29eabc662aebcaf3f24ea69e80dcb1f903010 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Tue, 16 Oct 2018 14:29:14 +0000 Subject: [PATCH] cxa_demangle: make demangler's parsing functions overridable Summary: This uses CRTP (for performance reasons) to allow a user the override demangler functions to implement custom parsing logic. The motivation for this is LLDB, which needs to occasionaly modify the mangled names. One such instance is already implemented via the TypeCallback member, but this is very specific functionality which does not help with any other use case. Currently we have a use case for modifying the constructor flavours, which would require adding another callback. This approach does not scale. With CRTP, the user (LLDB) can override any function it needs without any special support from the demangler library. After LLDB is ported to use this instead of the TypeCallback mechanism, the callback can be removed. More context can be found in D50599. Reviewers: erik.pilkington, rsmith Subscribers: christof, ldionne, llvm-commits, libcxx-commits Differential Revision: https://reviews.llvm.org/D52992 llvm-svn: 344607 --- libcxxabi/src/cxa_demangle.cpp | 2 +- libcxxabi/src/demangle/ItaniumDemangle.h | 664 ++++++++++++----------- 2 files changed, 363 insertions(+), 303 deletions(-) diff --git a/libcxxabi/src/cxa_demangle.cpp b/libcxxabi/src/cxa_demangle.cpp index 5de2dbad8a1f..69fdca4e939b 100644 --- a/libcxxabi/src/cxa_demangle.cpp +++ b/libcxxabi/src/cxa_demangle.cpp @@ -324,7 +324,7 @@ public: // Code beyond this point should not be synchronized with LLVM. //===----------------------------------------------------------------------===// -using Demangler = itanium_demangle::Db; +using Demangler = itanium_demangle::ManglingParser; namespace { enum : int { diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index 32da9ffcb147..2f4d7863245f 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -2139,8 +2139,7 @@ public: } }; -template -struct Db { +template struct AbstractManglingParser { const char *First; const char *Last; @@ -2172,7 +2171,10 @@ struct Db { Alloc ASTAllocator; - Db(const char *First_, const char *Last_) : First(First_), Last(Last_) {} + AbstractManglingParser(const char *First_, const char *Last_) + : First(First_), Last(Last_) {} + + Derived &getDerived() { return static_cast(*this); } void reset(const char *First_, const char *Last_) { First = First_; @@ -2279,7 +2281,7 @@ struct Db { FunctionRefQual ReferenceQualifier = FrefQualNone; size_t ForwardTemplateRefsBegin; - NameState(Db *Enclosing) + NameState(AbstractManglingParser *Enclosing) : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} }; @@ -2329,35 +2331,36 @@ const char* parse_discriminator(const char* first, const char* last); // // ::= // ::= -template Node *Db::parseName(NameState *State) { +template +Node *AbstractManglingParser::parseName(NameState *State) { consumeIf('L'); // extension if (look() == 'N') - return parseNestedName(State); + return getDerived().parseNestedName(State); if (look() == 'Z') - return parseLocalName(State); + return getDerived().parseLocalName(State); // ::= if (look() == 'S' && look(1) != 't') { - Node *S = parseSubstitution(); + Node *S = getDerived().parseSubstitution(); if (S == nullptr) return nullptr; if (look() != 'I') return nullptr; - Node *TA = parseTemplateArgs(State != nullptr); + Node *TA = getDerived().parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; if (State) State->EndsWithTemplateArgs = true; return make(S, TA); } - Node *N = parseUnscopedName(State); + Node *N = getDerived().parseUnscopedName(State); if (N == nullptr) return nullptr; // ::= if (look() == 'I') { Subs.push_back(N); - Node *TA = parseTemplateArgs(State != nullptr); + Node *TA = getDerived().parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; if (State) State->EndsWithTemplateArgs = true; @@ -2370,10 +2373,11 @@ template Node *Db::parseName(NameState *State) { // := Z E [] // := Z E s [] // := Z Ed [ ] _ -template Node *Db::parseLocalName(NameState *State) { +template +Node *AbstractManglingParser::parseLocalName(NameState *State) { if (!consumeIf('Z')) return nullptr; - Node *Encoding = parseEncoding(); + Node *Encoding = getDerived().parseEncoding(); if (Encoding == nullptr || !consumeIf('E')) return nullptr; @@ -2389,13 +2393,13 @@ template Node *Db::parseLocalName(NameState *State) { parseNumber(true); if (!consumeIf('_')) return nullptr; - Node *N = parseName(State); + Node *N = getDerived().parseName(State); if (N == nullptr) return nullptr; return make(Encoding, N); } - Node *Entity = parseName(State); + Node *Entity = getDerived().parseName(State); if (Entity == nullptr) return nullptr; First = parse_discriminator(First, Last); @@ -2405,14 +2409,16 @@ template Node *Db::parseLocalName(NameState *State) { // ::= // ::= St # ::std:: // extension ::= StL -template Node *Db::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = parseUnqualifiedName(State); - if (R == nullptr) - return nullptr; - return make(R); - } - return parseUnqualifiedName(State); +template +Node * +AbstractManglingParser::parseUnscopedName(NameState *State) { + if (consumeIf("StL") || consumeIf("St")) { + Node *R = getDerived().parseUnqualifiedName(State); + if (R == nullptr) + return nullptr; + return make(R); + } + return getDerived().parseUnqualifiedName(State); } // ::= [abi-tags] @@ -2420,27 +2426,28 @@ template Node *Db::parseUnscopedName(NameState *State) { // ::= // ::= // ::= DC + E # structured binding declaration -template -Node *Db::parseUnqualifiedName(NameState *State) { +template +Node * +AbstractManglingParser::parseUnqualifiedName(NameState *State) { // s are special-cased in parseNestedName(). Node *Result; if (look() == 'U') - Result = parseUnnamedTypeName(State); + Result = getDerived().parseUnnamedTypeName(State); else if (look() >= '1' && look() <= '9') - Result = parseSourceName(State); + Result = getDerived().parseSourceName(State); else if (consumeIf("DC")) { size_t BindingsBegin = Names.size(); do { - Node *Binding = parseSourceName(State); + Node *Binding = getDerived().parseSourceName(State); if (Binding == nullptr) return nullptr; Names.push_back(Binding); } while (!consumeIf('E')); Result = make(popTrailingNodeArray(BindingsBegin)); } else - Result = parseOperatorName(State); + Result = getDerived().parseOperatorName(State); if (Result != nullptr) - Result = parseAbiTags(Result); + Result = getDerived().parseAbiTags(Result); return Result; } @@ -2450,7 +2457,9 @@ Node *Db::parseUnqualifiedName(NameState *State) { // ::= Ul E [ ] _ // // ::= + # Parameter types or "v" if the lambda has no parameters -template Node *Db::parseUnnamedTypeName(NameState *) { +template +Node * +AbstractManglingParser::parseUnnamedTypeName(NameState *) { if (consumeIf("Ut")) { StringView Count = parseNumber(); if (!consumeIf('_')) @@ -2463,7 +2472,7 @@ template Node *Db::parseUnnamedTypeName(NameState *) { if (!consumeIf("vE")) { size_t ParamsBegin = Names.size(); do { - Node *P = parseType(); + Node *P = getDerived().parseType(); if (P == nullptr) return nullptr; Names.push_back(P); @@ -2479,7 +2488,8 @@ template Node *Db::parseUnnamedTypeName(NameState *) { } // ::= -template Node *Db::parseSourceName(NameState *) { +template +Node *AbstractManglingParser::parseSourceName(NameState *) { size_t Length = 0; if (parsePositiveInteger(&Length)) return nullptr; @@ -2543,7 +2553,9 @@ template Node *Db::parseSourceName(NameState *) { // ::= rS # >>= // ::= ss # <=> C++2a // ::= v # vendor extended operator -template Node *Db::parseOperatorName(NameState *State) { +template +Node * +AbstractManglingParser::parseOperatorName(NameState *State) { switch (look()) { case 'a': switch (look(1)) { @@ -2583,7 +2595,7 @@ template Node *Db::parseOperatorName(NameState *State) { SwapAndRestore SavePermit(PermitForwardTemplateReferences, PermitForwardTemplateReferences || State != nullptr); - Node* Ty = parseType(); + Node *Ty = getDerived().parseType(); if (Ty == nullptr) return nullptr; if (State) State->CtorDtorConversion = true; @@ -2647,7 +2659,7 @@ template Node *Db::parseOperatorName(NameState *State) { // ::= li # operator "" case 'i': { First += 2; - Node *SN = parseSourceName(State); + Node *SN = getDerived().parseSourceName(State); if (SN == nullptr) return nullptr; return make(SN); @@ -2768,7 +2780,7 @@ template Node *Db::parseOperatorName(NameState *State) { case 'v': if (std::isdigit(look(1))) { First += 2; - Node *SN = parseSourceName(State); + Node *SN = getDerived().parseSourceName(State); if (SN == nullptr) return nullptr; return make(SN); @@ -2786,8 +2798,10 @@ template Node *Db::parseOperatorName(NameState *State) { // ::= D1 # complete object destructor // ::= D2 # base object destructor // extension ::= D5 # ? -template -Node *Db::parseCtorDtorName(Node *&SoFar, NameState *State) { +template +Node * +AbstractManglingParser::parseCtorDtorName(Node *&SoFar, + NameState *State) { if (SoFar->getKind() == Node::KSpecialSubstitution) { auto SSK = static_cast(SoFar)->SSK; switch (SSK) { @@ -2811,7 +2825,7 @@ Node *Db::parseCtorDtorName(Node *&SoFar, NameState *State) { ++First; if (State) State->CtorDtorConversion = true; if (IsInherited) { - if (parseName(State) == nullptr) + if (getDerived().parseName(State) == nullptr) return nullptr; } return make(SoFar, false, Variant); @@ -2845,7 +2859,9 @@ Node *Db::parseCtorDtorName(Node *&SoFar, NameState *State) { // ::=