[demangler] Rewrite parse_nested_name in the new style.

git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@325022 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index 1cadff4..f2e7d28 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -1983,12 +1983,28 @@
   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 @@
   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 @@
   }
 };
 
+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_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 @@
   return nullptr;
 }
 
+// <CV-Qualifiers> ::= [r] [V] [K]
 Qualifiers Db::parseCVQualifiers() {
   Qualifiers CVR = QualNone;
   if (consumeIf('r'))
@@ -3715,33 +3919,6 @@
     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 @@
     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 @@
 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)
@@ -4857,178 +4955,6 @@
     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
 //  extension      := decimal-digit+               # at the end of string