[llvm] r344703 - Port libcxxabi r344607 into llvm

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 17 11:50:25 PDT 2018


Author: labath
Date: Wed Oct 17 11:50:25 2018
New Revision: 344703

URL: http://llvm.org/viewvc/llvm-project?rev=344703&view=rev
Log:
Port libcxxabi r344607 into llvm

Summary:
The original commit message was:
    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.

The only difference here is the addition of a unit test which exercises
the CRTP mechanism to override a function in the parser.

Reviewers: erik.pilkington, rsmith, EricWF

Subscribers: mgorny, kristina, llvm-commits

Differential Revision: https://reviews.llvm.org/D53300

Added:
    llvm/trunk/unittests/Demangle/ItaniumDemangleTest.cpp
Modified:
    llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h
    llvm/trunk/lib/Demangle/ItaniumDemangle.cpp
    llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp
    llvm/trunk/unittests/Demangle/CMakeLists.txt

Modified: llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h?rev=344703&r1=344702&r2=344703&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h (original)
+++ llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h Wed Oct 17 11:50:25 2018
@@ -2134,8 +2134,7 @@ public:
   }
 };
 
-template <typename Alloc>
-struct Db {
+template <typename Derived, typename Alloc> struct AbstractManglingParser {
   const char *First;
   const char *Last;
 
@@ -2167,7 +2166,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<Derived &>(*this); }
 
   void reset(const char *First_, const char *Last_) {
     First = First_;
@@ -2274,7 +2276,7 @@ struct Db {
     FunctionRefQual ReferenceQualifier = FrefQualNone;
     size_t ForwardTemplateRefsBegin;
 
-    NameState(Db *Enclosing)
+    NameState(AbstractManglingParser *Enclosing)
         : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}
   };
 
@@ -2324,35 +2326,36 @@ const char* parse_discriminator(const ch
 //
 // <unscoped-template-name> ::= <unscoped-name>
 //                          ::= <substitution>
-template<typename Alloc> Node *Db<Alloc>::parseName(NameState *State) {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::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);
 
   //        ::= <unscoped-template-name> <template-args>
   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<NameWithTemplateArgs>(S, TA);
   }
 
-  Node *N = parseUnscopedName(State);
+  Node *N = getDerived().parseUnscopedName(State);
   if (N == nullptr)
     return nullptr;
   //        ::= <unscoped-template-name> <template-args>
   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;
@@ -2365,10 +2368,11 @@ template<typename Alloc> Node *Db<Alloc>
 // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
 //              := Z <function encoding> E s [<discriminator>]
 //              := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
-template<typename Alloc> Node *Db<Alloc>::parseLocalName(NameState *State) {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
   if (!consumeIf('Z'))
     return nullptr;
-  Node *Encoding = parseEncoding();
+  Node *Encoding = getDerived().parseEncoding();
   if (Encoding == nullptr || !consumeIf('E'))
     return nullptr;
 
@@ -2384,13 +2388,13 @@ template<typename Alloc> Node *Db<Alloc>
     parseNumber(true);
     if (!consumeIf('_'))
       return nullptr;
-    Node *N = parseName(State);
+    Node *N = getDerived().parseName(State);
     if (N == nullptr)
       return nullptr;
     return make<LocalName>(Encoding, N);
   }
 
-  Node *Entity = parseName(State);
+  Node *Entity = getDerived().parseName(State);
   if (Entity == nullptr)
     return nullptr;
   First = parse_discriminator(First, Last);
@@ -2400,14 +2404,16 @@ template<typename Alloc> Node *Db<Alloc>
 // <unscoped-name> ::= <unqualified-name>
 //                 ::= St <unqualified-name>   # ::std::
 // extension       ::= StL<unqualified-name>
-template<typename Alloc> Node *Db<Alloc>::parseUnscopedName(NameState *State) {
- if (consumeIf("StL") || consumeIf("St")) {
-   Node *R = parseUnqualifiedName(State);
-   if (R == nullptr)
-     return nullptr;
-   return make<StdQualifiedName>(R);
- }
- return parseUnqualifiedName(State);
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) {
+  if (consumeIf("StL") || consumeIf("St")) {
+    Node *R = getDerived().parseUnqualifiedName(State);
+    if (R == nullptr)
+      return nullptr;
+    return make<StdQualifiedName>(R);
+  }
+  return getDerived().parseUnqualifiedName(State);
 }
 
 // <unqualified-name> ::= <operator-name> [abi-tags]
@@ -2415,27 +2421,28 @@ template<typename Alloc> Node *Db<Alloc>
 //                    ::= <source-name>
 //                    ::= <unnamed-type-name>
 //                    ::= DC <source-name>+ E      # structured binding declaration
-template<typename Alloc>
-Node *Db<Alloc>::parseUnqualifiedName(NameState *State) {
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) {
   // <ctor-dtor-name>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<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));
   } else
-    Result = parseOperatorName(State);
+    Result = getDerived().parseOperatorName(State);
   if (Result != nullptr)
-    Result = parseAbiTags(Result);
+    Result = getDerived().parseAbiTags(Result);
   return Result;
 }
 
@@ -2445,7 +2452,9 @@ Node *Db<Alloc>::parseUnqualifiedName(Na
 // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
 //
 // <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters
-template<typename Alloc> Node *Db<Alloc>::parseUnnamedTypeName(NameState *) {
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *) {
   if (consumeIf("Ut")) {
     StringView Count = parseNumber();
     if (!consumeIf('_'))
@@ -2458,7 +2467,7 @@ template<typename Alloc> Node *Db<Alloc>
     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);
@@ -2474,7 +2483,8 @@ template<typename Alloc> Node *Db<Alloc>
 }
 
 // <source-name> ::= <positive length number> <identifier>
-template<typename Alloc> Node *Db<Alloc>::parseSourceName(NameState *) {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
   size_t Length = 0;
   if (parsePositiveInteger(&Length))
     return nullptr;
@@ -2538,7 +2548,9 @@ template<typename Alloc> Node *Db<Alloc>
 //                   ::= rS    # >>=
 //                   ::= ss    # <=> C++2a
 //                   ::= v <digit> <source-name>        # vendor extended operator
-template<typename Alloc> Node *Db<Alloc>::parseOperatorName(NameState *State) {
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
   switch (look()) {
   case 'a':
     switch (look(1)) {
@@ -2578,7 +2590,7 @@ template<typename Alloc> Node *Db<Alloc>
       SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences,
                                       PermitForwardTemplateReferences ||
                                           State != nullptr);
-      Node* Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return nullptr;
       if (State) State->CtorDtorConversion = true;
@@ -2642,7 +2654,7 @@ template<typename Alloc> Node *Db<Alloc>
     //                   ::= li <source-name>  # operator ""
     case 'i': {
       First += 2;
-      Node *SN = parseSourceName(State);
+      Node *SN = getDerived().parseSourceName(State);
       if (SN == nullptr)
         return nullptr;
       return make<LiteralOperator>(SN);
@@ -2763,7 +2775,7 @@ template<typename Alloc> Node *Db<Alloc>
   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<ConversionOperatorType>(SN);
@@ -2781,8 +2793,10 @@ template<typename Alloc> Node *Db<Alloc>
 //                  ::= D1  # complete object destructor
 //                  ::= D2  # base object destructor
 //   extension      ::= D5    # ?
-template<typename Alloc>
-Node *Db<Alloc>::parseCtorDtorName(Node *&SoFar, NameState *State) {
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
+                                                          NameState *State) {
   if (SoFar->getKind() == Node::KSpecialSubstitution) {
     auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;
     switch (SSK) {
@@ -2806,7 +2820,7 @@ Node *Db<Alloc>::parseCtorDtorName(Node
     ++First;
     if (State) State->CtorDtorConversion = true;
     if (IsInherited) {
-      if (parseName(State) == nullptr)
+      if (getDerived().parseName(State) == nullptr)
         return nullptr;
     }
     return make<CtorDtorName>(SoFar, false, Variant);
@@ -2840,7 +2854,9 @@ Node *Db<Alloc>::parseCtorDtorName(Node
 // <template-prefix> ::= <prefix> <template unqualified-name>
 //                   ::= <template-param>
 //                   ::= <substitution>
-template<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
   if (!consumeIf('N'))
     return nullptr;
 
@@ -2881,7 +2897,7 @@ template<typename Alloc> Node *Db<Alloc>
 
     //          ::= <template-param>
     if (look() == 'T') {
-      if (!PushComponent(parseTemplateParam()))
+      if (!PushComponent(getDerived().parseTemplateParam()))
         return nullptr;
       Subs.push_back(SoFar);
       continue;
@@ -2889,7 +2905,7 @@ template<typename Alloc> Node *Db<Alloc>
 
     //          ::= <template-prefix> <template-args>
     if (look() == 'I') {
-      Node *TA = parseTemplateArgs(State != nullptr);
+      Node *TA = getDerived().parseTemplateArgs(State != nullptr);
       if (TA == nullptr || SoFar == nullptr)
         return nullptr;
       SoFar = make<NameWithTemplateArgs>(SoFar, TA);
@@ -2902,7 +2918,7 @@ template<typename Alloc> Node *Db<Alloc>
 
     //          ::= <decltype>
     if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
-      if (!PushComponent(parseDecltype()))
+      if (!PushComponent(getDerived().parseDecltype()))
         return nullptr;
       Subs.push_back(SoFar);
       continue;
@@ -2910,7 +2926,7 @@ template<typename Alloc> Node *Db<Alloc>
 
     //          ::= <substitution>
     if (look() == 'S' && look(1) != 't') {
-      Node *S = parseSubstitution();
+      Node *S = getDerived().parseSubstitution();
       if (!PushComponent(S))
         return nullptr;
       if (SoFar != S)
@@ -2922,9 +2938,9 @@ template<typename Alloc> Node *Db<Alloc>
     if (look() == 'C' || (look() == 'D' && look(1) != 'C')) {
       if (SoFar == nullptr)
         return nullptr;
-      if (!PushComponent(parseCtorDtorName(SoFar, State)))
+      if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State)))
         return nullptr;
-      SoFar = parseAbiTags(SoFar);
+      SoFar = getDerived().parseAbiTags(SoFar);
       if (SoFar == nullptr)
         return nullptr;
       Subs.push_back(SoFar);
@@ -2932,7 +2948,7 @@ template<typename Alloc> Node *Db<Alloc>
     }
 
     //          ::= <prefix> <unqualified-name>
-    if (!PushComponent(parseUnqualifiedName(State)))
+    if (!PushComponent(getDerived().parseUnqualifiedName(State)))
       return nullptr;
     Subs.push_back(SoFar);
   }
@@ -2945,12 +2961,13 @@ template<typename Alloc> Node *Db<Alloc>
 }
 
 // <simple-id> ::= <source-name> [ <template-args> ]
-template<typename Alloc> Node *Db<Alloc>::parseSimpleId() {
-  Node *SN = parseSourceName(/*NameState=*/nullptr);
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSimpleId() {
+  Node *SN = getDerived().parseSourceName(/*NameState=*/nullptr);
   if (SN == nullptr)
     return nullptr;
   if (look() == 'I') {
-    Node *TA = parseTemplateArgs();
+    Node *TA = getDerived().parseTemplateArgs();
     if (TA == nullptr)
       return nullptr;
     return make<NameWithTemplateArgs>(SN, TA);
@@ -2960,12 +2977,13 @@ template<typename Alloc> Node *Db<Alloc>
 
 // <destructor-name> ::= <unresolved-type>  # e.g., ~T or ~decltype(f())
 //                   ::= <simple-id>        # e.g., ~A<2*N>
-template<typename Alloc> Node *Db<Alloc>::parseDestructorName() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseDestructorName() {
   Node *Result;
   if (std::isdigit(look()))
-    Result = parseSimpleId();
+    Result = getDerived().parseSimpleId();
   else
-    Result = parseUnresolvedType();
+    Result = getDerived().parseUnresolvedType();
   if (Result == nullptr)
     return nullptr;
   return make<DtorName>(Result);
@@ -2974,22 +2992,23 @@ template<typename Alloc> Node *Db<Alloc>
 // <unresolved-type> ::= <template-param>
 //                   ::= <decltype>
 //                   ::= <substitution>
-template<typename Alloc> Node *Db<Alloc>::parseUnresolvedType() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedType() {
   if (look() == 'T') {
-    Node *TP = parseTemplateParam();
+    Node *TP = getDerived().parseTemplateParam();
     if (TP == nullptr)
       return nullptr;
     Subs.push_back(TP);
     return TP;
   }
   if (look() == 'D') {
-    Node *DT = parseDecltype();
+    Node *DT = getDerived().parseDecltype();
     if (DT == nullptr)
       return nullptr;
     Subs.push_back(DT);
     return DT;
   }
-  return parseSubstitution();
+  return getDerived().parseSubstitution();
 }
 
 // <base-unresolved-name> ::= <simple-id>                                # unresolved name
@@ -2999,20 +3018,21 @@ template<typename Alloc> Node *Db<Alloc>
 //                        ::= on <operator-name> <template-args>         # unresolved operator template-id
 //                        ::= dn <destructor-name>                       # destructor or pseudo-destructor;
 //                                                                         # e.g. ~X or ~X<N-1>
-template<typename Alloc> Node *Db<Alloc>::parseBaseUnresolvedName() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() {
   if (std::isdigit(look()))
-    return parseSimpleId();
+    return getDerived().parseSimpleId();
 
   if (consumeIf("dn"))
-    return parseDestructorName();
+    return getDerived().parseDestructorName();
 
   consumeIf("on");
 
-  Node *Oper = parseOperatorName(/*NameState=*/nullptr);
+  Node *Oper = getDerived().parseOperatorName(/*NameState=*/nullptr);
   if (Oper == nullptr)
     return nullptr;
   if (look() == 'I') {
-    Node *TA = parseTemplateArgs();
+    Node *TA = getDerived().parseTemplateArgs();
     if (TA == nullptr)
       return nullptr;
     return make<NameWithTemplateArgs>(Oper, TA);
@@ -3031,18 +3051,19 @@ template<typename Alloc> Node *Db<Alloc>
 //  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name>
 //
 // <unresolved-qualifier-level> ::= <simple-id>
-template<typename Alloc> Node *Db<Alloc>::parseUnresolvedName() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() {
   Node *SoFar = nullptr;
 
   // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
   // srN <unresolved-type>                   <unresolved-qualifier-level>+ E <base-unresolved-name>
   if (consumeIf("srN")) {
-    SoFar = parseUnresolvedType();
+    SoFar = getDerived().parseUnresolvedType();
     if (SoFar == nullptr)
       return nullptr;
 
     if (look() == 'I') {
-      Node *TA = parseTemplateArgs();
+      Node *TA = getDerived().parseTemplateArgs();
       if (TA == nullptr)
         return nullptr;
       SoFar = make<NameWithTemplateArgs>(SoFar, TA);
@@ -3051,7 +3072,7 @@ template<typename Alloc> Node *Db<Alloc>
     }
 
     while (!consumeIf('E')) {
-      Node *Qual = parseSimpleId();
+      Node *Qual = getDerived().parseSimpleId();
       if (Qual == nullptr)
         return nullptr;
       SoFar = make<QualifiedName>(SoFar, Qual);
@@ -3059,7 +3080,7 @@ template<typename Alloc> Node *Db<Alloc>
         return nullptr;
     }
 
-    Node *Base = parseBaseUnresolvedName();
+    Node *Base = getDerived().parseBaseUnresolvedName();
     if (Base == nullptr)
       return nullptr;
     return make<QualifiedName>(SoFar, Base);
@@ -3069,7 +3090,7 @@ template<typename Alloc> Node *Db<Alloc>
 
   // [gs] <base-unresolved-name>                     # x or (with "gs") ::x
   if (!consumeIf("sr")) {
-    SoFar = parseBaseUnresolvedName();
+    SoFar = getDerived().parseBaseUnresolvedName();
     if (SoFar == nullptr)
       return nullptr;
     if (Global)
@@ -3080,7 +3101,7 @@ template<typename Alloc> Node *Db<Alloc>
   // [gs] sr <unresolved-qualifier-level>+ E   <base-unresolved-name>
   if (std::isdigit(look())) {
     do {
-      Node *Qual = parseSimpleId();
+      Node *Qual = getDerived().parseSimpleId();
       if (Qual == nullptr)
         return nullptr;
       if (SoFar)
@@ -3096,12 +3117,12 @@ template<typename Alloc> Node *Db<Alloc>
   //      sr <unresolved-type>                 <base-unresolved-name>
   //      sr <unresolved-type> <template-args> <base-unresolved-name>
   else {
-    SoFar = parseUnresolvedType();
+    SoFar = getDerived().parseUnresolvedType();
     if (SoFar == nullptr)
       return nullptr;
 
     if (look() == 'I') {
-      Node *TA = parseTemplateArgs();
+      Node *TA = getDerived().parseTemplateArgs();
       if (TA == nullptr)
         return nullptr;
       SoFar = make<NameWithTemplateArgs>(SoFar, TA);
@@ -3112,7 +3133,7 @@ template<typename Alloc> Node *Db<Alloc>
 
   assert(SoFar != nullptr);
 
-  Node *Base = parseBaseUnresolvedName();
+  Node *Base = getDerived().parseBaseUnresolvedName();
   if (Base == nullptr)
     return nullptr;
   return make<QualifiedName>(SoFar, Base);
@@ -3120,7 +3141,8 @@ template<typename Alloc> Node *Db<Alloc>
 
 // <abi-tags> ::= <abi-tag> [<abi-tags>]
 // <abi-tag> ::= B <source-name>
-template<typename Alloc> Node *Db<Alloc>::parseAbiTags(Node *N) {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) {
   while (consumeIf('B')) {
     StringView SN = parseBareSourceName();
     if (SN.empty())
@@ -3133,8 +3155,9 @@ template<typename Alloc> Node *Db<Alloc>
 }
 
 // <number> ::= [n] <non-negative decimal integer>
-template<typename Alloc>
-StringView Db<Alloc>::parseNumber(bool AllowNegative) {
+template <typename Alloc, typename Derived>
+StringView
+AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) {
   const char *Tmp = First;
   if (AllowNegative)
     consumeIf('n');
@@ -3146,7 +3169,8 @@ StringView Db<Alloc>::parseNumber(bool A
 }
 
 // <positive length number> ::= [0-9]*
-template<typename Alloc> bool Db<Alloc>::parsePositiveInteger(size_t *Out) {
+template <typename Alloc, typename Derived>
+bool AbstractManglingParser<Alloc, Derived>::parsePositiveInteger(size_t *Out) {
   *Out = 0;
   if (look() < '0' || look() > '9')
     return true;
@@ -3157,7 +3181,8 @@ template<typename Alloc> bool Db<Alloc>:
   return false;
 }
 
-template<typename Alloc> StringView Db<Alloc>::parseBareSourceName() {
+template <typename Alloc, typename Derived>
+StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() {
   size_t Int = 0;
   if (parsePositiveInteger(&Int) || numLeft() < Int)
     return StringView();
@@ -3174,7 +3199,8 @@ template<typename Alloc> StringView Db<A
 //
 // <ref-qualifier> ::= R                   # & ref-qualifier
 // <ref-qualifier> ::= O                   # && ref-qualifier
-template<typename Alloc> Node *Db<Alloc>::parseFunctionType() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseFunctionType() {
   Qualifiers CVQuals = parseCVQualifiers();
 
   Node *ExceptionSpec = nullptr;
@@ -3183,7 +3209,7 @@ template<typename Alloc> Node *Db<Alloc>
     if (!ExceptionSpec)
       return nullptr;
   } else if (consumeIf("DO")) {
-    Node *E = parseExpr();
+    Node *E = getDerived().parseExpr();
     if (E == nullptr || !consumeIf('E'))
       return nullptr;
     ExceptionSpec = make<NoexceptSpec>(E);
@@ -3192,7 +3218,7 @@ template<typename Alloc> Node *Db<Alloc>
   } else if (consumeIf("Dw")) {
     size_t SpecsBegin = Names.size();
     while (!consumeIf('E')) {
-      Node *T = parseType();
+      Node *T = getDerived().parseType();
       if (T == nullptr)
         return nullptr;
       Names.push_back(T);
@@ -3208,7 +3234,7 @@ template<typename Alloc> Node *Db<Alloc>
   if (!consumeIf('F'))
     return nullptr;
   consumeIf('Y'); // extern "C"
-  Node *ReturnType = parseType();
+  Node *ReturnType = getDerived().parseType();
   if (ReturnType == nullptr)
     return nullptr;
 
@@ -3227,7 +3253,7 @@ template<typename Alloc> Node *Db<Alloc>
       ReferenceQualifier = FrefQualRValue;
       break;
     }
-    Node *T = parseType();
+    Node *T = getDerived().parseType();
     if (T == nullptr)
       return nullptr;
     Names.push_back(T);
@@ -3243,7 +3269,8 @@ template<typename Alloc> Node *Db<Alloc>
 //                         ::= Dv [<dimension expression>] _ <element type>
 // <extended element type> ::= <element type>
 //                         ::= p # AltiVec vector pixel
-template<typename Alloc> Node *Db<Alloc>::parseVectorType() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() {
   if (!consumeIf("Dv"))
     return nullptr;
   if (look() >= '1' && look() <= '9') {
@@ -3252,24 +3279,24 @@ template<typename Alloc> Node *Db<Alloc>
       return nullptr;
     if (consumeIf('p'))
       return make<PixelVectorType>(DimensionNumber);
-    Node *ElemType = parseType();
+    Node *ElemType = getDerived().parseType();
     if (ElemType == nullptr)
       return nullptr;
     return make<VectorType>(ElemType, DimensionNumber);
   }
 
   if (!consumeIf('_')) {
-    Node *DimExpr = parseExpr();
+    Node *DimExpr = getDerived().parseExpr();
     if (!DimExpr)
       return nullptr;
     if (!consumeIf('_'))
       return nullptr;
-    Node *ElemType = parseType();
+    Node *ElemType = getDerived().parseType();
     if (!ElemType)
       return nullptr;
     return make<VectorType>(ElemType, DimExpr);
   }
-  Node *ElemType = parseType();
+  Node *ElemType = getDerived().parseType();
   if (!ElemType)
     return nullptr;
   return make<VectorType>(ElemType, StringView());
@@ -3277,12 +3304,13 @@ template<typename Alloc> Node *Db<Alloc>
 
 // <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x)
 //             ::= DT <expression> E  # decltype of an expression (C++0x)
-template<typename Alloc> Node *Db<Alloc>::parseDecltype() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() {
   if (!consumeIf('D'))
     return nullptr;
   if (!consumeIf('t') && !consumeIf('T'))
     return nullptr;
-  Node *E = parseExpr();
+  Node *E = getDerived().parseExpr();
   if (E == nullptr)
     return nullptr;
   if (!consumeIf('E'))
@@ -3292,7 +3320,8 @@ template<typename Alloc> Node *Db<Alloc>
 
 // <array-type> ::= A <positive dimension number> _ <element type>
 //              ::= A [<dimension expression>] _ <element type>
-template<typename Alloc> Node *Db<Alloc>::parseArrayType() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseArrayType() {
   if (!consumeIf('A'))
     return nullptr;
 
@@ -3303,7 +3332,7 @@ template<typename Alloc> Node *Db<Alloc>
     if (!consumeIf('_'))
       return nullptr;
   } else if (!consumeIf('_')) {
-    Node *DimExpr = parseExpr();
+    Node *DimExpr = getDerived().parseExpr();
     if (DimExpr == nullptr)
       return nullptr;
     if (!consumeIf('_'))
@@ -3311,20 +3340,21 @@ template<typename Alloc> Node *Db<Alloc>
     Dimension = DimExpr;
   }
 
-  Node *Ty = parseType();
+  Node *Ty = getDerived().parseType();
   if (Ty == nullptr)
     return nullptr;
   return make<ArrayType>(Ty, Dimension);
 }
 
 // <pointer-to-member-type> ::= M <class type> <member type>
-template<typename Alloc> Node *Db<Alloc>::parsePointerToMemberType() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberType() {
   if (!consumeIf('M'))
     return nullptr;
-  Node *ClassType = parseType();
+  Node *ClassType = getDerived().parseType();
   if (ClassType == nullptr)
     return nullptr;
-  Node *MemberType = parseType();
+  Node *MemberType = getDerived().parseType();
   if (MemberType == nullptr)
     return nullptr;
   return make<PointerToMemberType>(ClassType, MemberType);
@@ -3334,7 +3364,8 @@ template<typename Alloc> Node *Db<Alloc>
 //                   ::= Ts <name>  # dependent elaborated type specifier using 'struct' or 'class'
 //                   ::= Tu <name>  # dependent elaborated type specifier using 'union'
 //                   ::= Te <name>  # dependent elaborated type specifier using 'enum'
-template<typename Alloc> Node *Db<Alloc>::parseClassEnumType() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() {
   StringView ElabSpef;
   if (consumeIf("Ts"))
     ElabSpef = "struct";
@@ -3343,7 +3374,7 @@ template<typename Alloc> Node *Db<Alloc>
   else if (consumeIf("Te"))
     ElabSpef = "enum";
 
-  Node *Name = parseName();
+  Node *Name = getDerived().parseName();
   if (Name == nullptr)
     return nullptr;
 
@@ -3356,7 +3387,8 @@ template<typename Alloc> Node *Db<Alloc>
 // <qualified-type>     ::= <qualifiers> <type>
 // <qualifiers> ::= <extended-qualifier>* <CV-qualifiers>
 // <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier
-template<typename Alloc> Node *Db<Alloc>::parseQualifiedType() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() {
   if (consumeIf('U')) {
     StringView Qual = parseBareSourceName();
     if (Qual.empty())
@@ -3375,20 +3407,20 @@ template<typename Alloc> Node *Db<Alloc>
       }
       if (Proto.empty())
         return nullptr;
-      Node *Child = parseQualifiedType();
+      Node *Child = getDerived().parseQualifiedType();
       if (Child == nullptr)
         return nullptr;
       return make<ObjCProtoName>(Child, Proto);
     }
 
-    Node *Child = parseQualifiedType();
+    Node *Child = getDerived().parseQualifiedType();
     if (Child == nullptr)
       return nullptr;
     return make<VendorExtQualType>(Child, Qual);
   }
 
   Qualifiers Quals = parseCVQualifiers();
-  Node *Ty = parseType();
+  Node *Ty = getDerived().parseType();
   if (Ty == nullptr)
     return nullptr;
   if (Quals != QualNone)
@@ -3416,7 +3448,8 @@ template<typename Alloc> Node *Db<Alloc>
 //
 // <objc-name> ::= <k0 number> objcproto <k1 number> <identifier>  # k0 = 9 + <number of digits in k1> + k1
 // <objc-type> ::= <source-name>  # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
-template<typename Alloc> Node *Db<Alloc>::parseType() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseType() {
   Node *Result = nullptr;
 
   if (TypeCallback != nullptr)
@@ -3436,13 +3469,13 @@ template<typename Alloc> Node *Db<Alloc>
         (look(AfterQuals) == 'D' &&
          (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' ||
           look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) {
-      Result = parseFunctionType();
+      Result = getDerived().parseFunctionType();
       break;
     }
     LLVM_FALLTHROUGH;
   }
   case 'U': {
-    Result = parseQualifiedType();
+    Result = getDerived().parseQualifiedType();
     break;
   }
   // <builtin-type> ::= v    # void
@@ -3580,18 +3613,18 @@ template<typename Alloc> Node *Db<Alloc>
     //             ::= <decltype>
     case 't':
     case 'T': {
-      Result = parseDecltype();
+      Result = getDerived().parseDecltype();
       break;
     }
     // extension   ::= <vector-type> # <vector-type> starts with Dv
     case 'v': {
-      Result = parseVectorType();
+      Result = getDerived().parseVectorType();
       break;
     }
     //           ::= Dp <type>       # pack expansion (C++0x)
     case 'p': {
       First += 2;
-      Node *Child = parseType();
+      Node *Child = getDerived().parseType();
       if (!Child)
         return nullptr;
       Result = make<ParameterPackExpansion>(Child);
@@ -3603,34 +3636,34 @@ template<typename Alloc> Node *Db<Alloc>
     case 'w':
     // Transaction safe function type.
     case 'x':
-      Result = parseFunctionType();
+      Result = getDerived().parseFunctionType();
       break;
     }
     break;
   //             ::= <function-type>
   case 'F': {
-    Result = parseFunctionType();
+    Result = getDerived().parseFunctionType();
     break;
   }
   //             ::= <array-type>
   case 'A': {
-    Result = parseArrayType();
+    Result = getDerived().parseArrayType();
     break;
   }
   //             ::= <pointer-to-member-type>
   case 'M': {
-    Result = parsePointerToMemberType();
+    Result = getDerived().parsePointerToMemberType();
     break;
   }
   //             ::= <template-param>
   case 'T': {
     // This could be an elaborate type specifier on a <class-enum-type>.
     if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') {
-      Result = parseClassEnumType();
+      Result = getDerived().parseClassEnumType();
       break;
     }
 
-    Result = parseTemplateParam();
+    Result = getDerived().parseTemplateParam();
     if (Result == nullptr)
       return nullptr;
 
@@ -3645,7 +3678,7 @@ template<typename Alloc> Node *Db<Alloc>
     // parse them, take the second production.
 
     if (TryToParseTemplateArgs && look() == 'I') {
-      Node *TA = parseTemplateArgs();
+      Node *TA = getDerived().parseTemplateArgs();
       if (TA == nullptr)
         return nullptr;
       Result = make<NameWithTemplateArgs>(Result, TA);
@@ -3655,7 +3688,7 @@ template<typename Alloc> Node *Db<Alloc>
   //             ::= P <type>        # pointer
   case 'P': {
     ++First;
-    Node *Ptr = parseType();
+    Node *Ptr = getDerived().parseType();
     if (Ptr == nullptr)
       return nullptr;
     Result = make<PointerType>(Ptr);
@@ -3664,7 +3697,7 @@ template<typename Alloc> Node *Db<Alloc>
   //             ::= R <type>        # l-value reference
   case 'R': {
     ++First;
-    Node *Ref = parseType();
+    Node *Ref = getDerived().parseType();
     if (Ref == nullptr)
       return nullptr;
     Result = make<ReferenceType>(Ref, ReferenceKind::LValue);
@@ -3673,7 +3706,7 @@ template<typename Alloc> Node *Db<Alloc>
   //             ::= O <type>        # r-value reference (C++11)
   case 'O': {
     ++First;
-    Node *Ref = parseType();
+    Node *Ref = getDerived().parseType();
     if (Ref == nullptr)
       return nullptr;
     Result = make<ReferenceType>(Ref, ReferenceKind::RValue);
@@ -3682,7 +3715,7 @@ template<typename Alloc> Node *Db<Alloc>
   //             ::= C <type>        # complex pair (C99)
   case 'C': {
     ++First;
-    Node *P = parseType();
+    Node *P = getDerived().parseType();
     if (P == nullptr)
       return nullptr;
     Result = make<PostfixQualifiedType>(P, " complex");
@@ -3691,7 +3724,7 @@ template<typename Alloc> Node *Db<Alloc>
   //             ::= G <type>        # imaginary (C99)
   case 'G': {
     ++First;
-    Node *P = parseType();
+    Node *P = getDerived().parseType();
     if (P == nullptr)
       return P;
     Result = make<PostfixQualifiedType>(P, " imaginary");
@@ -3700,7 +3733,7 @@ template<typename Alloc> Node *Db<Alloc>
   //             ::= <substitution>  # See Compression below
   case 'S': {
     if (look(1) && look(1) != 't') {
-      Node *Sub = parseSubstitution();
+      Node *Sub = getDerived().parseSubstitution();
       if (Sub == nullptr)
         return nullptr;
 
@@ -3715,7 +3748,7 @@ template<typename Alloc> Node *Db<Alloc>
       // parse them, take the second production.
 
       if (TryToParseTemplateArgs && look() == 'I') {
-        Node *TA = parseTemplateArgs();
+        Node *TA = getDerived().parseTemplateArgs();
         if (TA == nullptr)
           return nullptr;
         Result = make<NameWithTemplateArgs>(Sub, TA);
@@ -3730,7 +3763,7 @@ template<typename Alloc> Node *Db<Alloc>
   }
   //        ::= <class-enum-type>
   default: {
-    Result = parseClassEnumType();
+    Result = getDerived().parseClassEnumType();
     break;
   }
   }
@@ -3743,24 +3776,28 @@ template<typename Alloc> Node *Db<Alloc>
   return Result;
 }
 
-template<typename Alloc> Node *Db<Alloc>::parsePrefixExpr(StringView Kind) {
-  Node *E = parseExpr();
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) {
+  Node *E = getDerived().parseExpr();
   if (E == nullptr)
     return nullptr;
   return make<PrefixExpr>(Kind, E);
 }
 
-template<typename Alloc> Node *Db<Alloc>::parseBinaryExpr(StringView Kind) {
-  Node *LHS = parseExpr();
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) {
+  Node *LHS = getDerived().parseExpr();
   if (LHS == nullptr)
     return nullptr;
-  Node *RHS = parseExpr();
+  Node *RHS = getDerived().parseExpr();
   if (RHS == nullptr)
     return nullptr;
   return make<BinaryExpr>(LHS, Kind, RHS);
 }
 
-template<typename Alloc> Node *Db<Alloc>::parseIntegerLiteral(StringView Lit) {
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) {
   StringView Tmp = parseNumber(true);
   if (!Tmp.empty() && consumeIf('E'))
     return make<IntegerLiteral>(Lit, Tmp);
@@ -3768,7 +3805,8 @@ template<typename Alloc> Node *Db<Alloc>
 }
 
 // <CV-Qualifiers> ::= [r] [V] [K]
-template<typename Alloc> Qualifiers Db<Alloc>::parseCVQualifiers() {
+template <typename Alloc, typename Derived>
+Qualifiers AbstractManglingParser<Alloc, Derived>::parseCVQualifiers() {
   Qualifiers CVR = QualNone;
   if (consumeIf('r'))
     CVR |= QualRestrict;
@@ -3783,7 +3821,8 @@ template<typename Alloc> Qualifiers Db<A
 //                  ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _   # L == 0, second and later parameters
 //                  ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _         # L > 0, first parameter
 //                  ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _   # L > 0, second and later parameters
-template<typename Alloc> Node *Db<Alloc>::parseFunctionParam() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() {
   if (consumeIf("fp")) {
     parseCVQualifiers();
     StringView Num = parseNumber();
@@ -3810,26 +3849,27 @@ template<typename Alloc> Node *Db<Alloc>
 // [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
 // [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
 // <initializer> ::= pi <expression>* E                 # parenthesized initialization
-template<typename Alloc> Node *Db<Alloc>::parseNewExpr() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseNewExpr() {
   bool Global = consumeIf("gs");
   bool IsArray = look(1) == 'a';
   if (!consumeIf("nw") && !consumeIf("na"))
     return nullptr;
   size_t Exprs = Names.size();
   while (!consumeIf('_')) {
-    Node *Ex = parseExpr();
+    Node *Ex = getDerived().parseExpr();
     if (Ex == nullptr)
       return nullptr;
     Names.push_back(Ex);
   }
   NodeArray ExprList = popTrailingNodeArray(Exprs);
-  Node *Ty = parseType();
+  Node *Ty = getDerived().parseType();
   if (Ty == nullptr)
     return Ty;
   if (consumeIf("pi")) {
     size_t InitsBegin = Names.size();
     while (!consumeIf('E')) {
-      Node *Init = parseExpr();
+      Node *Init = getDerived().parseExpr();
       if (Init == nullptr)
         return Init;
       Names.push_back(Init);
@@ -3843,13 +3883,14 @@ template<typename Alloc> Node *Db<Alloc>
 
 // cv <type> <expression>                               # conversion with one argument
 // cv <type> _ <expression>* E                          # conversion with a different number of arguments
-template<typename Alloc> Node *Db<Alloc>::parseConversionExpr() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() {
   if (!consumeIf("cv"))
     return nullptr;
   Node *Ty;
   {
     SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
-    Ty = parseType();
+    Ty = getDerived().parseType();
   }
 
   if (Ty == nullptr)
@@ -3858,7 +3899,7 @@ template<typename Alloc> Node *Db<Alloc>
   if (consumeIf('_')) {
     size_t ExprsBegin = Names.size();
     while (!consumeIf('E')) {
-      Node *E = parseExpr();
+      Node *E = getDerived().parseExpr();
       if (E == nullptr)
         return E;
       Names.push_back(E);
@@ -3867,7 +3908,7 @@ template<typename Alloc> Node *Db<Alloc>
     return make<ConversionExpr>(Ty, Exprs);
   }
 
-  Node *E[1] = {parseExpr()};
+  Node *E[1] = {getDerived().parseExpr()};
   if (E[0] == nullptr)
     return nullptr;
   return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
@@ -3879,13 +3920,14 @@ template<typename Alloc> Node *Db<Alloc>
 //                ::= L <nullptr type> E                                 # nullptr literal (i.e., "LDnE")
 // FIXME:         ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)
 //                ::= L <mangled-name> E                                 # external name
-template<typename Alloc> Node *Db<Alloc>::parseExprPrimary() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() {
   if (!consumeIf('L'))
     return nullptr;
   switch (look()) {
   case 'w':
     ++First;
-    return parseIntegerLiteral("wchar_t");
+    return getDerived().parseIntegerLiteral("wchar_t");
   case 'b':
     if (consumeIf("b0E"))
       return make<BoolExpr>(0);
@@ -3894,55 +3936,55 @@ template<typename Alloc> Node *Db<Alloc>
     return nullptr;
   case 'c':
     ++First;
-    return parseIntegerLiteral("char");
+    return getDerived().parseIntegerLiteral("char");
   case 'a':
     ++First;
-    return parseIntegerLiteral("signed char");
+    return getDerived().parseIntegerLiteral("signed char");
   case 'h':
     ++First;
-    return parseIntegerLiteral("unsigned char");
+    return getDerived().parseIntegerLiteral("unsigned char");
   case 's':
     ++First;
-    return parseIntegerLiteral("short");
+    return getDerived().parseIntegerLiteral("short");
   case 't':
     ++First;
-    return parseIntegerLiteral("unsigned short");
+    return getDerived().parseIntegerLiteral("unsigned short");
   case 'i':
     ++First;
-    return parseIntegerLiteral("");
+    return getDerived().parseIntegerLiteral("");
   case 'j':
     ++First;
-    return parseIntegerLiteral("u");
+    return getDerived().parseIntegerLiteral("u");
   case 'l':
     ++First;
-    return parseIntegerLiteral("l");
+    return getDerived().parseIntegerLiteral("l");
   case 'm':
     ++First;
-    return parseIntegerLiteral("ul");
+    return getDerived().parseIntegerLiteral("ul");
   case 'x':
     ++First;
-    return parseIntegerLiteral("ll");
+    return getDerived().parseIntegerLiteral("ll");
   case 'y':
     ++First;
-    return parseIntegerLiteral("ull");
+    return getDerived().parseIntegerLiteral("ull");
   case 'n':
     ++First;
-    return parseIntegerLiteral("__int128");
+    return getDerived().parseIntegerLiteral("__int128");
   case 'o':
     ++First;
-    return parseIntegerLiteral("unsigned __int128");
+    return getDerived().parseIntegerLiteral("unsigned __int128");
   case 'f':
     ++First;
-    return parseFloatingLiteral<float>();
+    return getDerived().template parseFloatingLiteral<float>();
   case 'd':
     ++First;
-    return parseFloatingLiteral<double>();
+    return getDerived().template parseFloatingLiteral<double>();
   case 'e':
     ++First;
-    return parseFloatingLiteral<long double>();
+    return getDerived().template parseFloatingLiteral<long double>();
   case '_':
     if (consumeIf("_Z")) {
-      Node *R = parseEncoding();
+      Node *R = getDerived().parseEncoding();
       if (R != nullptr && consumeIf('E'))
         return R;
     }
@@ -3953,7 +3995,7 @@ template<typename Alloc> Node *Db<Alloc>
     return nullptr;
   default: {
     // might be named type
-    Node *T = parseType();
+    Node *T = getDerived().parseType();
     if (T == nullptr)
       return nullptr;
     StringView N = parseNumber();
@@ -3973,45 +4015,46 @@ template<typename Alloc> Node *Db<Alloc>
 //                     ::= di <field source-name> <braced-expression>    # .name = expr
 //                     ::= dx <index expression> <braced-expression>     # [expr] = expr
 //                     ::= dX <range begin expression> <range end expression> <braced-expression>
-template<typename Alloc> Node *Db<Alloc>::parseBracedExpr() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseBracedExpr() {
   if (look() == 'd') {
     switch (look(1)) {
     case 'i': {
       First += 2;
-      Node *Field = parseSourceName(/*NameState=*/nullptr);
+      Node *Field = getDerived().parseSourceName(/*NameState=*/nullptr);
       if (Field == nullptr)
         return nullptr;
-      Node *Init = parseBracedExpr();
+      Node *Init = getDerived().parseBracedExpr();
       if (Init == nullptr)
         return nullptr;
       return make<BracedExpr>(Field, Init, /*isArray=*/false);
     }
     case 'x': {
       First += 2;
-      Node *Index = parseExpr();
+      Node *Index = getDerived().parseExpr();
       if (Index == nullptr)
         return nullptr;
-      Node *Init = parseBracedExpr();
+      Node *Init = getDerived().parseBracedExpr();
       if (Init == nullptr)
         return nullptr;
       return make<BracedExpr>(Index, Init, /*isArray=*/true);
     }
     case 'X': {
       First += 2;
-      Node *RangeBegin = parseExpr();
+      Node *RangeBegin = getDerived().parseExpr();
       if (RangeBegin == nullptr)
         return nullptr;
-      Node *RangeEnd = parseExpr();
+      Node *RangeEnd = getDerived().parseExpr();
       if (RangeEnd == nullptr)
         return nullptr;
-      Node *Init = parseBracedExpr();
+      Node *Init = getDerived().parseBracedExpr();
       if (Init == nullptr)
         return nullptr;
       return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init);
     }
     }
   }
-  return parseExpr();
+  return getDerived().parseExpr();
 }
 
 // (not yet in the spec)
@@ -4019,7 +4062,8 @@ template<typename Alloc> Node *Db<Alloc>
 //             ::= fR <binary-operator-name> <expression> <expression>
 //             ::= fl <binary-operator-name> <expression>
 //             ::= fr <binary-operator-name> <expression>
-template<typename Alloc> Node *Db<Alloc>::parseFoldExpr() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
   if (!consumeIf('f'))
     return nullptr;
 
@@ -4069,11 +4113,11 @@ template<typename Alloc> Node *Db<Alloc>
   else if (consumeIf("rS")) OperatorName = ">>=";
   else return nullptr;
 
-  Node *Pack = parseExpr(), *Init = nullptr;
+  Node *Pack = getDerived().parseExpr(), *Init = nullptr;
   if (Pack == nullptr)
     return nullptr;
   if (HasInitializer) {
-    Init = parseExpr();
+    Init = getDerived().parseExpr();
     if (Init == nullptr)
       return nullptr;
   }
@@ -4128,49 +4172,50 @@ template<typename Alloc> Node *Db<Alloc>
 //              ::= fl <binary-operator-name> <expression>
 //              ::= fr <binary-operator-name> <expression>
 //              ::= <expr-primary>
-template<typename Alloc> Node *Db<Alloc>::parseExpr() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
   bool Global = consumeIf("gs");
   if (numLeft() < 2)
     return nullptr;
 
   switch (*First) {
   case 'L':
-    return parseExprPrimary();
+    return getDerived().parseExprPrimary();
   case 'T':
-    return parseTemplateParam();
+    return getDerived().parseTemplateParam();
   case 'f': {
     // Disambiguate a fold expression from a <function-param>.
     if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
-      return parseFunctionParam();
-    return parseFoldExpr();
+      return getDerived().parseFunctionParam();
+    return getDerived().parseFoldExpr();
   }
   case 'a':
     switch (First[1]) {
     case 'a':
       First += 2;
-      return parseBinaryExpr("&&");
+      return getDerived().parseBinaryExpr("&&");
     case 'd':
       First += 2;
-      return parsePrefixExpr("&");
+      return getDerived().parsePrefixExpr("&");
     case 'n':
       First += 2;
-      return parseBinaryExpr("&");
+      return getDerived().parseBinaryExpr("&");
     case 'N':
       First += 2;
-      return parseBinaryExpr("&=");
+      return getDerived().parseBinaryExpr("&=");
     case 'S':
       First += 2;
-      return parseBinaryExpr("=");
+      return getDerived().parseBinaryExpr("=");
     case 't': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return nullptr;
       return make<EnclosingExpr>("alignof (", Ty, ")");
     }
     case 'z': {
       First += 2;
-      Node *Ty = parseExpr();
+      Node *Ty = getDerived().parseExpr();
       if (Ty == nullptr)
         return nullptr;
       return make<EnclosingExpr>("alignof (", Ty, ")");
@@ -4182,10 +4227,10 @@ template<typename Alloc> Node *Db<Alloc>
     // cc <type> <expression>                               # const_cast<type>(expression)
     case 'c': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return Ty;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<CastExpr>("const_cast", Ty, Ex);
@@ -4193,12 +4238,12 @@ template<typename Alloc> Node *Db<Alloc>
     // cl <expression>+ E                                   # call
     case 'l': {
       First += 2;
-      Node *Callee = parseExpr();
+      Node *Callee = getDerived().parseExpr();
       if (Callee == nullptr)
         return Callee;
       size_t ExprsBegin = Names.size();
       while (!consumeIf('E')) {
-        Node *E = parseExpr();
+        Node *E = getDerived().parseExpr();
         if (E == nullptr)
           return E;
         Names.push_back(E);
@@ -4207,104 +4252,104 @@ template<typename Alloc> Node *Db<Alloc>
     }
     case 'm':
       First += 2;
-      return parseBinaryExpr(",");
+      return getDerived().parseBinaryExpr(",");
     case 'o':
       First += 2;
-      return parsePrefixExpr("~");
+      return getDerived().parsePrefixExpr("~");
     case 'v':
-      return parseConversionExpr();
+      return getDerived().parseConversionExpr();
     }
     return nullptr;
   case 'd':
     switch (First[1]) {
     case 'a': {
       First += 2;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
     }
     case 'c': {
       First += 2;
-      Node *T = parseType();
+      Node *T = getDerived().parseType();
       if (T == nullptr)
         return T;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<CastExpr>("dynamic_cast", T, Ex);
     }
     case 'e':
       First += 2;
-      return parsePrefixExpr("*");
+      return getDerived().parsePrefixExpr("*");
     case 'l': {
       First += 2;
-      Node *E = parseExpr();
+      Node *E = getDerived().parseExpr();
       if (E == nullptr)
         return E;
       return make<DeleteExpr>(E, Global, /*is_array=*/false);
     }
     case 'n':
-      return parseUnresolvedName();
+      return getDerived().parseUnresolvedName();
     case 's': {
       First += 2;
-      Node *LHS = parseExpr();
+      Node *LHS = getDerived().parseExpr();
       if (LHS == nullptr)
         return nullptr;
-      Node *RHS = parseExpr();
+      Node *RHS = getDerived().parseExpr();
       if (RHS == nullptr)
         return nullptr;
       return make<MemberExpr>(LHS, ".*", RHS);
     }
     case 't': {
       First += 2;
-      Node *LHS = parseExpr();
+      Node *LHS = getDerived().parseExpr();
       if (LHS == nullptr)
         return LHS;
-      Node *RHS = parseExpr();
+      Node *RHS = getDerived().parseExpr();
       if (RHS == nullptr)
         return nullptr;
       return make<MemberExpr>(LHS, ".", RHS);
     }
     case 'v':
       First += 2;
-      return parseBinaryExpr("/");
+      return getDerived().parseBinaryExpr("/");
     case 'V':
       First += 2;
-      return parseBinaryExpr("/=");
+      return getDerived().parseBinaryExpr("/=");
     }
     return nullptr;
   case 'e':
     switch (First[1]) {
     case 'o':
       First += 2;
-      return parseBinaryExpr("^");
+      return getDerived().parseBinaryExpr("^");
     case 'O':
       First += 2;
-      return parseBinaryExpr("^=");
+      return getDerived().parseBinaryExpr("^=");
     case 'q':
       First += 2;
-      return parseBinaryExpr("==");
+      return getDerived().parseBinaryExpr("==");
     }
     return nullptr;
   case 'g':
     switch (First[1]) {
     case 'e':
       First += 2;
-      return parseBinaryExpr(">=");
+      return getDerived().parseBinaryExpr(">=");
     case 't':
       First += 2;
-      return parseBinaryExpr(">");
+      return getDerived().parseBinaryExpr(">");
     }
     return nullptr;
   case 'i':
     switch (First[1]) {
     case 'x': {
       First += 2;
-      Node *Base = parseExpr();
+      Node *Base = getDerived().parseExpr();
       if (Base == nullptr)
         return nullptr;
-      Node *Index = parseExpr();
+      Node *Index = getDerived().parseExpr();
       if (Index == nullptr)
         return Index;
       return make<ArraySubscriptExpr>(Base, Index);
@@ -4313,7 +4358,7 @@ template<typename Alloc> Node *Db<Alloc>
       First += 2;
       size_t InitsBegin = Names.size();
       while (!consumeIf('E')) {
-        Node *E = parseBracedExpr();
+        Node *E = getDerived().parseBracedExpr();
         if (E == nullptr)
           return nullptr;
         Names.push_back(E);
@@ -4326,37 +4371,37 @@ template<typename Alloc> Node *Db<Alloc>
     switch (First[1]) {
     case 'e':
       First += 2;
-      return parseBinaryExpr("<=");
+      return getDerived().parseBinaryExpr("<=");
     case 's':
       First += 2;
-      return parseBinaryExpr("<<");
+      return getDerived().parseBinaryExpr("<<");
     case 'S':
       First += 2;
-      return parseBinaryExpr("<<=");
+      return getDerived().parseBinaryExpr("<<=");
     case 't':
       First += 2;
-      return parseBinaryExpr("<");
+      return getDerived().parseBinaryExpr("<");
     }
     return nullptr;
   case 'm':
     switch (First[1]) {
     case 'i':
       First += 2;
-      return parseBinaryExpr("-");
+      return getDerived().parseBinaryExpr("-");
     case 'I':
       First += 2;
-      return parseBinaryExpr("-=");
+      return getDerived().parseBinaryExpr("-=");
     case 'l':
       First += 2;
-      return parseBinaryExpr("*");
+      return getDerived().parseBinaryExpr("*");
     case 'L':
       First += 2;
-      return parseBinaryExpr("*=");
+      return getDerived().parseBinaryExpr("*=");
     case 'm':
       First += 2;
       if (consumeIf('_'))
-        return parsePrefixExpr("--");
-      Node *Ex = parseExpr();
+        return getDerived().parsePrefixExpr("--");
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return nullptr;
       return make<PostfixExpr>(Ex, "--");
@@ -4366,19 +4411,19 @@ template<typename Alloc> Node *Db<Alloc>
     switch (First[1]) {
     case 'a':
     case 'w':
-      return parseNewExpr();
+      return getDerived().parseNewExpr();
     case 'e':
       First += 2;
-      return parseBinaryExpr("!=");
+      return getDerived().parseBinaryExpr("!=");
     case 'g':
       First += 2;
-      return parsePrefixExpr("-");
+      return getDerived().parsePrefixExpr("-");
     case 't':
       First += 2;
-      return parsePrefixExpr("!");
+      return getDerived().parsePrefixExpr("!");
     case 'x':
       First += 2;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<EnclosingExpr>("noexcept (", Ex, ")");
@@ -4387,47 +4432,47 @@ template<typename Alloc> Node *Db<Alloc>
   case 'o':
     switch (First[1]) {
     case 'n':
-      return parseUnresolvedName();
+      return getDerived().parseUnresolvedName();
     case 'o':
       First += 2;
-      return parseBinaryExpr("||");
+      return getDerived().parseBinaryExpr("||");
     case 'r':
       First += 2;
-      return parseBinaryExpr("|");
+      return getDerived().parseBinaryExpr("|");
     case 'R':
       First += 2;
-      return parseBinaryExpr("|=");
+      return getDerived().parseBinaryExpr("|=");
     }
     return nullptr;
   case 'p':
     switch (First[1]) {
     case 'm':
       First += 2;
-      return parseBinaryExpr("->*");
+      return getDerived().parseBinaryExpr("->*");
     case 'l':
       First += 2;
-      return parseBinaryExpr("+");
+      return getDerived().parseBinaryExpr("+");
     case 'L':
       First += 2;
-      return parseBinaryExpr("+=");
+      return getDerived().parseBinaryExpr("+=");
     case 'p': {
       First += 2;
       if (consumeIf('_'))
-        return parsePrefixExpr("++");
-      Node *Ex = parseExpr();
+        return getDerived().parsePrefixExpr("++");
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<PostfixExpr>(Ex, "++");
     }
     case 's':
       First += 2;
-      return parsePrefixExpr("+");
+      return getDerived().parsePrefixExpr("+");
     case 't': {
       First += 2;
-      Node *L = parseExpr();
+      Node *L = getDerived().parseExpr();
       if (L == nullptr)
         return nullptr;
-      Node *R = parseExpr();
+      Node *R = getDerived().parseExpr();
       if (R == nullptr)
         return nullptr;
       return make<MemberExpr>(L, "->", R);
@@ -4437,13 +4482,13 @@ template<typename Alloc> Node *Db<Alloc>
   case 'q':
     if (First[1] == 'u') {
       First += 2;
-      Node *Cond = parseExpr();
+      Node *Cond = getDerived().parseExpr();
       if (Cond == nullptr)
         return nullptr;
-      Node *LHS = parseExpr();
+      Node *LHS = getDerived().parseExpr();
       if (LHS == nullptr)
         return nullptr;
-      Node *RHS = parseExpr();
+      Node *RHS = getDerived().parseExpr();
       if (RHS == nullptr)
         return nullptr;
       return make<ConditionalExpr>(Cond, LHS, RHS);
@@ -4453,59 +4498,59 @@ template<typename Alloc> Node *Db<Alloc>
     switch (First[1]) {
     case 'c': {
       First += 2;
-      Node *T = parseType();
+      Node *T = getDerived().parseType();
       if (T == nullptr)
         return T;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<CastExpr>("reinterpret_cast", T, Ex);
     }
     case 'm':
       First += 2;
-      return parseBinaryExpr("%");
+      return getDerived().parseBinaryExpr("%");
     case 'M':
       First += 2;
-      return parseBinaryExpr("%=");
+      return getDerived().parseBinaryExpr("%=");
     case 's':
       First += 2;
-      return parseBinaryExpr(">>");
+      return getDerived().parseBinaryExpr(">>");
     case 'S':
       First += 2;
-      return parseBinaryExpr(">>=");
+      return getDerived().parseBinaryExpr(">>=");
     }
     return nullptr;
   case 's':
     switch (First[1]) {
     case 'c': {
       First += 2;
-      Node *T = parseType();
+      Node *T = getDerived().parseType();
       if (T == nullptr)
         return T;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<CastExpr>("static_cast", T, Ex);
     }
     case 'p': {
       First += 2;
-      Node *Child = parseExpr();
+      Node *Child = getDerived().parseExpr();
       if (Child == nullptr)
         return nullptr;
       return make<ParameterPackExpansion>(Child);
     }
     case 'r':
-      return parseUnresolvedName();
+      return getDerived().parseUnresolvedName();
     case 't': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return Ty;
       return make<EnclosingExpr>("sizeof (", Ty, ")");
     }
     case 'z': {
       First += 2;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<EnclosingExpr>("sizeof (", Ex, ")");
@@ -4513,12 +4558,12 @@ template<typename Alloc> Node *Db<Alloc>
     case 'Z':
       First += 2;
       if (look() == 'T') {
-        Node *R = parseTemplateParam();
+        Node *R = getDerived().parseTemplateParam();
         if (R == nullptr)
           return nullptr;
         return make<SizeofParamPackExpr>(R);
       } else if (look() == 'f') {
-        Node *FP = parseFunctionParam();
+        Node *FP = getDerived().parseFunctionParam();
         if (FP == nullptr)
           return nullptr;
         return make<EnclosingExpr>("sizeof... (", FP, ")");
@@ -4528,7 +4573,7 @@ template<typename Alloc> Node *Db<Alloc>
       First += 2;
       size_t ArgsBegin = Names.size();
       while (!consumeIf('E')) {
-        Node *Arg = parseTemplateArg();
+        Node *Arg = getDerived().parseTemplateArg();
         if (Arg == nullptr)
           return nullptr;
         Names.push_back(Arg);
@@ -4544,26 +4589,26 @@ template<typename Alloc> Node *Db<Alloc>
     switch (First[1]) {
     case 'e': {
       First += 2;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return Ex;
       return make<EnclosingExpr>("typeid (", Ex, ")");
     }
     case 'i': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return Ty;
       return make<EnclosingExpr>("typeid (", Ty, ")");
     }
     case 'l': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return nullptr;
       size_t InitsBegin = Names.size();
       while (!consumeIf('E')) {
-        Node *E = parseBracedExpr();
+        Node *E = getDerived().parseBracedExpr();
         if (E == nullptr)
           return nullptr;
         Names.push_back(E);
@@ -4575,7 +4620,7 @@ template<typename Alloc> Node *Db<Alloc>
       return make<NameType>("throw");
     case 'w': {
       First += 2;
-      Node *Ex = parseExpr();
+      Node *Ex = getDerived().parseExpr();
       if (Ex == nullptr)
         return nullptr;
       return make<ThrowExpr>(Ex);
@@ -4591,7 +4636,7 @@ template<typename Alloc> Node *Db<Alloc>
   case '7':
   case '8':
   case '9':
-    return parseUnresolvedName();
+    return getDerived().parseUnresolvedName();
   }
   return nullptr;
 }
@@ -4604,7 +4649,8 @@ template<typename Alloc> Node *Db<Alloc>
 //
 // <v-offset>  ::= <offset number> _ <virtual offset number>
 //               # virtual base override, with vcall offset
-template<typename Alloc> bool Db<Alloc>::parseCallOffset() {
+template <typename Alloc, typename Derived>
+bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() {
   // Just scan through the call offset, we never add this information into the
   // output.
   if (consumeIf('h'))
@@ -4633,14 +4679,15 @@ template<typename Alloc> bool Db<Alloc>:
 //                ::= GR <object name> <seq-id> _    # Subsequent temporaries
 //      extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
 //      extension ::= GR <object name> # reference temporary for object
-template<typename Alloc> Node *Db<Alloc>::parseSpecialName() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
   switch (look()) {
   case 'T':
     switch (look(1)) {
     // TV <type>    # virtual table
     case 'V': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return nullptr;
       return make<SpecialName>("vtable for ", Ty);
@@ -4648,7 +4695,7 @@ template<typename Alloc> Node *Db<Alloc>
     // TT <type>    # VTT structure (construction vtable index)
     case 'T': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return nullptr;
       return make<SpecialName>("VTT for ", Ty);
@@ -4656,7 +4703,7 @@ template<typename Alloc> Node *Db<Alloc>
     // TI <type>    # typeinfo structure
     case 'I': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return nullptr;
       return make<SpecialName>("typeinfo for ", Ty);
@@ -4664,7 +4711,7 @@ template<typename Alloc> Node *Db<Alloc>
     // TS <type>    # typeinfo name (null-terminated byte string)
     case 'S': {
       First += 2;
-      Node *Ty = parseType();
+      Node *Ty = getDerived().parseType();
       if (Ty == nullptr)
         return nullptr;
       return make<SpecialName>("typeinfo name for ", Ty);
@@ -4674,7 +4721,7 @@ template<typename Alloc> Node *Db<Alloc>
       First += 2;
       if (parseCallOffset() || parseCallOffset())
         return nullptr;
-      Node *Encoding = parseEncoding();
+      Node *Encoding = getDerived().parseEncoding();
       if (Encoding == nullptr)
         return nullptr;
       return make<SpecialName>("covariant return thunk to ", Encoding);
@@ -4683,12 +4730,12 @@ template<typename Alloc> Node *Db<Alloc>
     //               # construction vtable for second-in-first
     case 'C': {
       First += 2;
-      Node *FirstType = parseType();
+      Node *FirstType = getDerived().parseType();
       if (FirstType == nullptr)
         return nullptr;
       if (parseNumber(true).empty() || !consumeIf('_'))
         return nullptr;
-      Node *SecondType = parseType();
+      Node *SecondType = getDerived().parseType();
       if (SecondType == nullptr)
         return nullptr;
       return make<CtorVtableSpecialName>(SecondType, FirstType);
@@ -4696,7 +4743,7 @@ template<typename Alloc> Node *Db<Alloc>
     // TW <object name> # Thread-local wrapper
     case 'W': {
       First += 2;
-      Node *Name = parseName();
+      Node *Name = getDerived().parseName();
       if (Name == nullptr)
         return nullptr;
       return make<SpecialName>("thread-local wrapper routine for ", Name);
@@ -4704,7 +4751,7 @@ template<typename Alloc> Node *Db<Alloc>
     // TH <object name> # Thread-local initialization
     case 'H': {
       First += 2;
-      Node *Name = parseName();
+      Node *Name = getDerived().parseName();
       if (Name == nullptr)
         return nullptr;
       return make<SpecialName>("thread-local initialization routine for ", Name);
@@ -4715,7 +4762,7 @@ template<typename Alloc> Node *Db<Alloc>
       bool IsVirt = look() == 'v';
       if (parseCallOffset())
         return nullptr;
-      Node *BaseEncoding = parseEncoding();
+      Node *BaseEncoding = getDerived().parseEncoding();
       if (BaseEncoding == nullptr)
         return nullptr;
       if (IsVirt)
@@ -4729,7 +4776,7 @@ template<typename Alloc> Node *Db<Alloc>
     // GV <object name> # Guard variable for one-time initialization
     case 'V': {
       First += 2;
-      Node *Name = parseName();
+      Node *Name = getDerived().parseName();
       if (Name == nullptr)
         return nullptr;
       return make<SpecialName>("guard variable for ", Name);
@@ -4739,7 +4786,7 @@ template<typename Alloc> Node *Db<Alloc>
     // GR <object name> <seq-id> _    # Subsequent temporaries
     case 'R': {
       First += 2;
-      Node *Name = parseName();
+      Node *Name = getDerived().parseName();
       if (Name == nullptr)
         return nullptr;
       size_t Count;
@@ -4756,9 +4803,10 @@ template<typename Alloc> Node *Db<Alloc>
 // <encoding> ::= <function name> <bare-function-type>
 //            ::= <data name>
 //            ::= <special-name>
-template<typename Alloc> Node *Db<Alloc>::parseEncoding() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
   if (look() == 'G' || look() == 'T')
-    return parseSpecialName();
+    return getDerived().parseSpecialName();
 
   auto IsEndOfEncoding = [&] {
     // The set of chars that can potentially follow an <encoding> (none of which
@@ -4768,7 +4816,7 @@ template<typename Alloc> Node *Db<Alloc>
   };
 
   NameState NameInfo(this);
-  Node *Name = parseName(&NameInfo);
+  Node *Name = getDerived().parseName(&NameInfo);
   if (Name == nullptr)
     return nullptr;
 
@@ -4782,7 +4830,7 @@ template<typename Alloc> Node *Db<Alloc>
   if (consumeIf("Ua9enable_ifI")) {
     size_t BeforeArgs = Names.size();
     while (!consumeIf('E')) {
-      Node *Arg = parseTemplateArg();
+      Node *Arg = getDerived().parseTemplateArg();
       if (Arg == nullptr)
         return nullptr;
       Names.push_back(Arg);
@@ -4794,7 +4842,7 @@ template<typename Alloc> Node *Db<Alloc>
 
   Node *ReturnType = nullptr;
   if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) {
-    ReturnType = parseType();
+    ReturnType = getDerived().parseType();
     if (ReturnType == nullptr)
       return nullptr;
   }
@@ -4806,7 +4854,7 @@ template<typename Alloc> Node *Db<Alloc>
 
   size_t ParamsBegin = Names.size();
   do {
-    Node *Ty = parseType();
+    Node *Ty = getDerived().parseType();
     if (Ty == nullptr)
       return nullptr;
     Names.push_back(Ty);
@@ -4852,9 +4900,9 @@ struct FloatData<long double>
     static constexpr const char *spec = "%LaL";
 };
 
-template<typename Alloc>
-template<class Float>
-Node *Db<Alloc>::parseFloatingLiteral() {
+template <typename Alloc, typename Derived>
+template <class Float>
+Node *AbstractManglingParser<Alloc, Derived>::parseFloatingLiteral() {
   const size_t N = FloatData<Float>::mangled_size;
   if (numLeft() <= N)
     return nullptr;
@@ -4869,7 +4917,8 @@ Node *Db<Alloc>::parseFloatingLiteral()
 }
 
 // <seq-id> ::= <0-9A-Z>+
-template<typename Alloc> bool Db<Alloc>::parseSeqId(size_t *Out) {
+template <typename Alloc, typename Derived>
+bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) {
   if (!(look() >= '0' && look() <= '9') &&
       !(look() >= 'A' && look() <= 'Z'))
     return true;
@@ -4900,7 +4949,8 @@ template<typename Alloc> bool Db<Alloc>:
 // <substitution> ::= Si # ::std::basic_istream<char,  std::char_traits<char> >
 // <substitution> ::= So # ::std::basic_ostream<char,  std::char_traits<char> >
 // <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
-template<typename Alloc> Node *Db<Alloc>::parseSubstitution() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
   if (!consumeIf('S'))
     return nullptr;
 
@@ -4939,7 +4989,7 @@ template<typename Alloc> Node *Db<Alloc>
     // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution>
     // has ABI tags, the tags are appended to the substitution; the result is a
     // substitutable component.
-    Node *WithTags = parseAbiTags(SpecialSub);
+    Node *WithTags = getDerived().parseAbiTags(SpecialSub);
     if (WithTags != SpecialSub) {
       Subs.push_back(WithTags);
       SpecialSub = WithTags;
@@ -4966,7 +5016,8 @@ template<typename Alloc> Node *Db<Alloc>
 
 // <template-param> ::= T_    # first template parameter
 //                  ::= T <parameter-2 non-negative number> _
-template<typename Alloc> Node *Db<Alloc>::parseTemplateParam() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
   if (!consumeIf('T'))
     return nullptr;
 
@@ -5007,11 +5058,12 @@ template<typename Alloc> Node *Db<Alloc>
 //                ::= <expr-primary>            # simple expressions
 //                ::= J <template-arg>* E       # argument pack
 //                ::= LZ <encoding> E           # extension
-template<typename Alloc> Node *Db<Alloc>::parseTemplateArg() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
   switch (look()) {
   case 'X': {
     ++First;
-    Node *Arg = parseExpr();
+    Node *Arg = getDerived().parseExpr();
     if (Arg == nullptr || !consumeIf('E'))
       return nullptr;
     return Arg;
@@ -5020,7 +5072,7 @@ template<typename Alloc> Node *Db<Alloc>
     ++First;
     size_t ArgsBegin = Names.size();
     while (!consumeIf('E')) {
-      Node *Arg = parseTemplateArg();
+      Node *Arg = getDerived().parseTemplateArg();
       if (Arg == nullptr)
         return nullptr;
       Names.push_back(Arg);
@@ -5032,23 +5084,24 @@ template<typename Alloc> Node *Db<Alloc>
     //                ::= LZ <encoding> E           # extension
     if (look(1) == 'Z') {
       First += 2;
-      Node *Arg = parseEncoding();
+      Node *Arg = getDerived().parseEncoding();
       if (Arg == nullptr || !consumeIf('E'))
         return nullptr;
       return Arg;
     }
     //                ::= <expr-primary>            # simple expressions
-    return parseExprPrimary();
+    return getDerived().parseExprPrimary();
   }
   default:
-    return parseType();
+    return getDerived().parseType();
   }
 }
 
 // <template-args> ::= I <template-arg>* E
 //     extension, the abi says <template-arg>+
-template <typename Alloc>
-Node *Db<Alloc>::parseTemplateArgs(bool TagTemplates) {
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
   if (!consumeIf('I'))
     return nullptr;
 
@@ -5061,7 +5114,7 @@ Node *Db<Alloc>::parseTemplateArgs(bool
   while (!consumeIf('E')) {
     if (TagTemplates) {
       auto OldParams = std::move(TemplateParams);
-      Node *Arg = parseTemplateArg();
+      Node *Arg = getDerived().parseTemplateArg();
       TemplateParams = std::move(OldParams);
       if (Arg == nullptr)
         return nullptr;
@@ -5075,7 +5128,7 @@ Node *Db<Alloc>::parseTemplateArgs(bool
       }
       TemplateParams.push_back(TableEntry);
     } else {
-      Node *Arg = parseTemplateArg();
+      Node *Arg = getDerived().parseTemplateArg();
       if (Arg == nullptr)
         return nullptr;
       Names.push_back(Arg);
@@ -5089,9 +5142,10 @@ Node *Db<Alloc>::parseTemplateArgs(bool
 // extension      ::= ___Z <encoding> _block_invoke
 // extension      ::= ___Z <encoding> _block_invoke<decimal-digit>+
 // extension      ::= ___Z <encoding> _block_invoke_<decimal-digit>+
-template<typename Alloc> Node *Db<Alloc>::parse() {
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parse() {
   if (consumeIf("_Z")) {
-    Node *Encoding = parseEncoding();
+    Node *Encoding = getDerived().parseEncoding();
     if (Encoding == nullptr)
       return nullptr;
     if (look() == '.') {
@@ -5104,7 +5158,7 @@ template<typename Alloc> Node *Db<Alloc>
   }
 
   if (consumeIf("___Z")) {
-    Node *Encoding = parseEncoding();
+    Node *Encoding = getDerived().parseEncoding();
     if (Encoding == nullptr || !consumeIf("_block_invoke"))
       return nullptr;
     bool RequireNumber = consumeIf('_');
@@ -5117,12 +5171,18 @@ template<typename Alloc> Node *Db<Alloc>
     return make<SpecialName>("invocation function for block in ", Encoding);
   }
 
-  Node *Ty = parseType();
+  Node *Ty = getDerived().parseType();
   if (numLeft() != 0)
     return nullptr;
   return Ty;
 }
 
+template <typename Alloc>
+struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
+  using AbstractManglingParser<ManglingParser<Alloc>,
+                               Alloc>::AbstractManglingParser;
+};
+
 }  // namespace itanium_demangle
 }  // namespace llvm
 

Modified: llvm/trunk/lib/Demangle/ItaniumDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/ItaniumDemangle.cpp?rev=344703&r1=344702&r2=344703&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/ItaniumDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/ItaniumDemangle.cpp Wed Oct 17 11:50:25 2018
@@ -322,7 +322,7 @@ public:
 // Code beyond this point should not be synchronized with libc++abi.
 //===----------------------------------------------------------------------===//
 
-using Demangler = itanium_demangle::Db<DefaultAllocator>;
+using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
 
 char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
                             size_t *N, int *Status) {

Modified: llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp?rev=344703&r1=344702&r2=344703&view=diff
==============================================================================
--- llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp (original)
+++ llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp Wed Oct 17 11:50:25 2018
@@ -221,7 +221,8 @@ struct CanonicalizerAllocator::MakeNodeI
 
 // FIXME: Also expand built-in substitutions?
 
-using CanonicalizingDemangler = itanium_demangle::Db<CanonicalizerAllocator>;
+using CanonicalizingDemangler =
+    itanium_demangle::ManglingParser<CanonicalizerAllocator>;
 }
 
 struct ItaniumManglingCanonicalizer::Impl {

Modified: llvm/trunk/unittests/Demangle/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Demangle/CMakeLists.txt?rev=344703&r1=344702&r2=344703&view=diff
==============================================================================
--- llvm/trunk/unittests/Demangle/CMakeLists.txt (original)
+++ llvm/trunk/unittests/Demangle/CMakeLists.txt Wed Oct 17 11:50:25 2018
@@ -1,8 +1,10 @@
 set(LLVM_LINK_COMPONENTS
   Demangle
+  Support
 )
 
 add_llvm_unittest(DemangleTests
+  ItaniumDemangleTest.cpp
   PartialDemangleTest.cpp
   FindTypesInMangledNameTest.cpp
 )

Added: llvm/trunk/unittests/Demangle/ItaniumDemangleTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Demangle/ItaniumDemangleTest.cpp?rev=344703&view=auto
==============================================================================
--- llvm/trunk/unittests/Demangle/ItaniumDemangleTest.cpp (added)
+++ llvm/trunk/unittests/Demangle/ItaniumDemangleTest.cpp Wed Oct 17 11:50:25 2018
@@ -0,0 +1,54 @@
+//===------------------ ItaniumDemangleTest.cpp ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Demangle/ItaniumDemangle.h"
+#include "llvm/Support/Allocator.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::itanium_demangle;
+
+namespace {
+class TestAllocator {
+  BumpPtrAllocator Alloc;
+
+public:
+  void reset() { Alloc.Reset(); }
+
+  template <typename T, typename... Args> T *makeNode(Args &&... args) {
+    return new (Alloc.Allocate(sizeof(T), alignof(T)))
+        T(std::forward<Args>(args)...);
+  }
+
+  void *allocateNodeArray(size_t sz) {
+    return Alloc.Allocate(sizeof(Node *) * sz, alignof(Node *));
+  }
+};
+} // namespace
+
+TEST(ItaniumDemangle, MethodOverride) {
+  struct TestParser : AbstractManglingParser<TestParser, TestAllocator> {
+    std::vector<char> Types;
+
+    TestParser(const char *Str)
+        : AbstractManglingParser(Str, Str + strlen(Str)) {}
+
+    Node *parseType() {
+      Types.push_back(*First);
+      return AbstractManglingParser<TestParser, TestAllocator>::parseType();
+    }
+  };
+
+  TestParser Parser("_Z1fIiEjl");
+  ASSERT_NE(nullptr, Parser.parse());
+  EXPECT_THAT(Parser.Types, testing::ElementsAre('i', 'j', 'l'));
+}




More information about the llvm-commits mailing list