[llvm] r327859 - [demangler] Recopy the demangler from libcxxabi.

Erik Pilkington via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 19 08:18:23 PDT 2018


Author: epilk
Date: Mon Mar 19 08:18:23 2018
New Revision: 327859

URL: http://llvm.org/viewvc/llvm-project?rev=327859&view=rev
Log:
[demangler] Recopy the demangler from libcxxabi.

Some significant work has gone into libcxxabi's copy of this file:
  - Uses an AST to represent mangled names.
  - Support/bugfixes for many C++ features.
  - Uses LLVM coding style.

Modified:
    llvm/trunk/lib/Demangle/ItaniumDemangle.cpp

Modified: llvm/trunk/lib/Demangle/ItaniumDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/ItaniumDemangle.cpp?rev=327859&r1=327858&r2=327859&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/ItaniumDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/ItaniumDemangle.cpp Mon Mar 19 08:18:23 2018
@@ -1,4 +1,4 @@
-//===- ItaniumDemangle.cpp ------------------------------------------------===//
+//===------------------------- ItaniumDemangle.cpp ------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,20 +7,22 @@
 //
 //===----------------------------------------------------------------------===//
 
+// FIXME: (possibly) incomplete list of features that clang mangles that this
+// file does not yet support:
+//   - enable_if attribute
+//   - C++ modules TS
+//   - All C++14 and C++17 features
+
 #include "llvm/Demangle/Demangle.h"
 #include "llvm/Support/Compiler.h"
-
-// This file exports a single function: llvm::itanium_demangle.
-// It also has no dependencies on the rest of llvm. It is implemented this way
-// so that it can be easily reused in libcxxabi.
-
+#include <vector>
 #include <algorithm>
-#include <cctype>
+#include <numeric>
+#include <cassert>
+#include <cstdio>
 #include <cstdlib>
 #include <cstring>
-#include <numeric>
-#include <string>
-#include <vector>
+#include <cctype>
 
 #ifdef _MSC_VER
 // snprintf is implemented in VS 2015
@@ -29,3778 +31,4256 @@
 #endif
 #endif
 
-enum {
-  unknown_error = -4,
-  invalid_args = -3,
-  invalid_mangled_name,
-  memory_alloc_failure,
-  success
-};
+namespace {
 
-enum {
-  CV_const = (1 << 0),
-  CV_volatile = (1 << 1),
-  CV_restrict = (1 << 2),
-};
-
-template <class C>
-static const char *parse_type(const char *first, const char *last, C &db);
-template <class C>
-static const char *parse_encoding(const char *first, const char *last, C &db);
-template <class C>
-static const char *parse_name(const char *first, const char *last, C &db,
-                              bool *ends_with_template_args = 0);
-template <class C>
-static const char *parse_expression(const char *first, const char *last, C &db);
-template <class C>
-static const char *parse_template_args(const char *first, const char *last,
-                                       C &db);
-template <class C>
-static const char *parse_operator_name(const char *first, const char *last,
-                                       C &db);
-template <class C>
-static const char *parse_unqualified_name(const char *first, const char *last,
-                                          C &db);
-template <class C>
-static const char *parse_decltype(const char *first, const char *last, C &db);
+class StringView {
+  const char *First;
+  const char *Last;
 
-// <number> ::= [n] <non-negative decimal integer>
+public:
+  template <size_t N>
+  StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
+  StringView(const char *First_, const char *Last_) : First(First_), Last(Last_) {}
+  StringView() : First(nullptr), Last(nullptr) {}
 
-static const char *parse_number(const char *first, const char *last) {
-  if (first != last) {
-    const char *t = first;
-    if (*t == 'n')
-      ++t;
-    if (t != last) {
-      if (*t == '0') {
-        first = t + 1;
-      } else if ('1' <= *t && *t <= '9') {
-        first = t + 1;
-        while (first != last && std::isdigit(*first))
-          ++first;
-      }
-    }
+  StringView substr(size_t From, size_t To) {
+    if (To >= size())
+      To = size() - 1;
+    if (From >= size())
+      From = size() - 1;
+    return StringView(First + From, First + To);
   }
-  return first;
-}
 
-namespace {
-template <class Float> struct float_data;
+  StringView dropFront(size_t N) const {
+    if (N >= size())
+      N = size() - 1;
+    return StringView(First + N, Last);
+  }
 
-template <> struct float_data<float> {
-  static const size_t mangled_size = 8;
-  static const size_t max_demangled_size = 24;
-  static const char *spec;
-};
-const char *float_data<float>::spec = "%af";
+  bool startsWith(StringView Str) const {
+    if (Str.size() > size())
+      return false;
+    return std::equal(Str.begin(), Str.end(), begin());
+  }
 
-template <> struct float_data<double> {
-  static const size_t mangled_size = 16;
-  static const size_t max_demangled_size = 32;
-  static const char *spec;
+  const char &operator[](size_t Idx) const { return *(begin() + Idx); }
+
+  const char *begin() const { return First; }
+  const char *end() const { return Last; }
+  size_t size() const { return static_cast<size_t>(Last - First); }
+  bool empty() const { return First == Last; }
 };
 
-const char *float_data<double>::spec = "%a";
+bool operator==(const StringView &LHS, const StringView &RHS) {
+  return LHS.size() == RHS.size() &&
+         std::equal(LHS.begin(), LHS.end(), RHS.begin());
+}
+
+// Stream that AST nodes write their string representation into after the AST
+// has been parsed.
+class OutputStream {
+  char *Buffer;
+  size_t CurrentPosition;
+  size_t BufferCapacity;
+
+  // Ensure there is at least n more positions in buffer.
+  void grow(size_t N) {
+    if (N + CurrentPosition >= BufferCapacity) {
+      BufferCapacity *= 2;
+      if (BufferCapacity < N + CurrentPosition)
+        BufferCapacity = N + CurrentPosition;
+      Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
+    }
+  }
 
-template <> struct float_data<long double> {
-#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) ||        \
-    defined(__wasm__)
-  static const size_t mangled_size = 32;
-#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
-  static const size_t mangled_size = 16;
-#else
-  static const size_t mangled_size =
-      20; // May need to be adjusted to 16 or 24 on other platforms
-#endif
-  static const size_t max_demangled_size = 40;
-  static const char *spec;
-};
+public:
+  OutputStream(char *StartBuf, size_t Size)
+      : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
 
-const char *float_data<long double>::spec = "%LaL";
-}
+  /// If a ParameterPackExpansion (or similar type) is encountered, the offset
+  /// into the pack that we're currently printing.
+  unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
 
-template <class Float, class C>
-static const char *parse_floating_number(const char *first, const char *last,
-                                         C &db) {
-  const size_t N = float_data<Float>::mangled_size;
-  if (static_cast<std::size_t>(last - first) > N) {
-    last = first + N;
-    union {
-      Float value;
-      char buf[sizeof(Float)];
-    };
-    const char *t = first;
-    char *e = buf;
-    for (; t != last; ++t, ++e) {
-      if (!isxdigit(*t))
-        return first;
-      unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
-                                : static_cast<unsigned>(*t - 'a' + 10);
-      ++t;
-      unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
-                                : static_cast<unsigned>(*t - 'a' + 10);
-      *e = static_cast<char>((d1 << 4) + d0);
-    }
-    if (*t == 'E') {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-      std::reverse(buf, e);
-#endif
-      char num[float_data<Float>::max_demangled_size] = {0};
-      int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
-      if (static_cast<std::size_t>(n) >= sizeof(num))
-        return first;
-      db.names.push_back(std::string(num, static_cast<std::size_t>(n)));
-      first = t + 1;
-    }
+  OutputStream &operator+=(StringView R) {
+    size_t Size = R.size();
+    if (Size == 0)
+      return *this;
+    grow(Size);
+    memmove(Buffer + CurrentPosition, R.begin(), Size);
+    CurrentPosition += Size;
+    return *this;
   }
-  return first;
-}
 
-// <source-name> ::= <positive length number> <identifier>
+  OutputStream &operator+=(char C) {
+    grow(1);
+    Buffer[CurrentPosition++] = C;
+    return *this;
+  }
 
-template <class C>
-static const char *parse_source_name(const char *first, const char *last,
-                                     C &db) {
-  if (first != last) {
-    char c = *first;
-    if (isdigit(c) && first + 1 != last) {
-      const char *t = first + 1;
-      size_t n = static_cast<size_t>(c - '0');
-      for (c = *t; isdigit(c); c = *t) {
-        n = n * 10 + static_cast<size_t>(c - '0');
-        if (++t == last)
-          return first;
-      }
-      if (static_cast<size_t>(last - t) >= n) {
-        std::string r(t, n);
-        if (r.substr(0, 10) == "_GLOBAL__N")
-          db.names.push_back("(anonymous namespace)");
-        else
-          db.names.push_back(std::move(r));
-        first = t + n;
-      }
-    }
+  size_t getCurrentPosition() const { return CurrentPosition; };
+
+  char back() const {
+    return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
   }
-  return first;
-}
 
-// <substitution> ::= S <seq-id> _
-//                ::= S_
-// <substitution> ::= Sa # ::std::allocator
-// <substitution> ::= Sb # ::std::basic_string
-// <substitution> ::= Ss # ::std::basic_string < char,
-//                                               ::std::char_traits<char>,
-//                                               ::std::allocator<char> >
-// <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> >
+  bool empty() const { return CurrentPosition == 0; }
 
-template <class C>
-static const char *parse_substitution(const char *first, const char *last,
-                                      C &db) {
-  if (last - first >= 2) {
-    if (*first == 'S') {
-      switch (first[1]) {
-      case 'a':
-        db.names.push_back("std::allocator");
-        first += 2;
-        break;
-      case 'b':
-        db.names.push_back("std::basic_string");
-        first += 2;
-        break;
-      case 's':
-        db.names.push_back("std::string");
-        first += 2;
-        break;
-      case 'i':
-        db.names.push_back("std::istream");
-        first += 2;
-        break;
-      case 'o':
-        db.names.push_back("std::ostream");
-        first += 2;
-        break;
-      case 'd':
-        db.names.push_back("std::iostream");
-        first += 2;
-        break;
-      case '_':
-        if (!db.subs.empty()) {
-          for (const auto &n : db.subs.front())
-            db.names.push_back(n);
-          first += 2;
-        }
-        break;
-      default:
-        if (std::isdigit(first[1]) || std::isupper(first[1])) {
-          size_t sub = 0;
-          const char *t = first + 1;
-          if (std::isdigit(*t))
-            sub = static_cast<size_t>(*t - '0');
-          else
-            sub = static_cast<size_t>(*t - 'A') + 10;
-          for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) {
-            sub *= 36;
-            if (std::isdigit(*t))
-              sub += static_cast<size_t>(*t - '0');
-            else
-              sub += static_cast<size_t>(*t - 'A') + 10;
-          }
-          if (t == last || *t != '_')
-            return first;
-          ++sub;
-          if (sub < db.subs.size()) {
-            for (const auto &n : db.subs[sub])
-              db.names.push_back(n);
-            first = t + 1;
-          }
-        }
-        break;
-      }
-    }
+  char *getBuffer() { return Buffer; }
+  char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
+  size_t getBufferCapacity() { return BufferCapacity; }
+};
+
+template <class T>
+class SwapAndRestore {
+  T &Restore;
+  T OriginalValue;
+public:
+  SwapAndRestore(T& Restore_, T NewVal)
+      : Restore(Restore_), OriginalValue(Restore) {
+    Restore = std::move(NewVal);
   }
-  return first;
-}
+  ~SwapAndRestore() { Restore = std::move(OriginalValue); }
 
-// <builtin-type> ::= v    # void
-//                ::= w    # wchar_t
-//                ::= b    # bool
-//                ::= c    # char
-//                ::= a    # signed char
-//                ::= h    # unsigned char
-//                ::= s    # short
-//                ::= t    # unsigned short
-//                ::= i    # int
-//                ::= j    # unsigned int
-//                ::= l    # long
-//                ::= m    # unsigned long
-//                ::= x    # long long, __int64
-//                ::= y    # unsigned long long, __int64
-//                ::= n    # __int128
-//                ::= o    # unsigned __int128
-//                ::= f    # float
-//                ::= d    # double
-//                ::= e    # long double, __float80
-//                ::= g    # __float128
-//                ::= z    # ellipsis
-//                ::= Dd   # IEEE 754r decimal floating point (64 bits)
-//                ::= De   # IEEE 754r decimal floating point (128 bits)
-//                ::= Df   # IEEE 754r decimal floating point (32 bits)
-//                ::= Dh   # IEEE 754r half-precision floating point (16 bits)
-//                ::= Di   # char32_t
-//                ::= Ds   # char16_t
-//                ::= Da   # auto (in dependent new-expressions)
-//                ::= Dc   # decltype(auto)
-//                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr))
-//                ::= u <source-name>    # vendor extended type
-
-template <class C>
-static const char *parse_builtin_type(const char *first, const char *last,
-                                      C &db) {
-  if (first != last) {
-    switch (*first) {
-    case 'v':
-      db.names.push_back("void");
-      ++first;
-      break;
-    case 'w':
-      db.names.push_back("wchar_t");
-      ++first;
-      break;
-    case 'b':
-      db.names.push_back("bool");
-      ++first;
-      break;
-    case 'c':
-      db.names.push_back("char");
-      ++first;
-      break;
-    case 'a':
-      db.names.push_back("signed char");
-      ++first;
-      break;
-    case 'h':
-      db.names.push_back("unsigned char");
-      ++first;
-      break;
-    case 's':
-      db.names.push_back("short");
-      ++first;
-      break;
-    case 't':
-      db.names.push_back("unsigned short");
-      ++first;
-      break;
-    case 'i':
-      db.names.push_back("int");
-      ++first;
-      break;
-    case 'j':
-      db.names.push_back("unsigned int");
-      ++first;
-      break;
-    case 'l':
-      db.names.push_back("long");
-      ++first;
-      break;
-    case 'm':
-      db.names.push_back("unsigned long");
-      ++first;
-      break;
-    case 'x':
-      db.names.push_back("long long");
-      ++first;
-      break;
-    case 'y':
-      db.names.push_back("unsigned long long");
-      ++first;
-      break;
-    case 'n':
-      db.names.push_back("__int128");
-      ++first;
-      break;
-    case 'o':
-      db.names.push_back("unsigned __int128");
-      ++first;
-      break;
-    case 'f':
-      db.names.push_back("float");
-      ++first;
-      break;
-    case 'd':
-      db.names.push_back("double");
-      ++first;
-      break;
-    case 'e':
-      db.names.push_back("long double");
-      ++first;
-      break;
-    case 'g':
-      db.names.push_back("__float128");
-      ++first;
-      break;
-    case 'z':
-      db.names.push_back("...");
-      ++first;
-      break;
-    case 'u': {
-      const char *t = parse_source_name(first + 1, last, db);
-      if (t != first + 1)
-        first = t;
-    } break;
-    case 'D':
-      if (first + 1 != last) {
-        switch (first[1]) {
-        case 'd':
-          db.names.push_back("decimal64");
-          first += 2;
-          break;
-        case 'e':
-          db.names.push_back("decimal128");
-          first += 2;
-          break;
-        case 'f':
-          db.names.push_back("decimal32");
-          first += 2;
-          break;
-        case 'h':
-          db.names.push_back("decimal16");
-          first += 2;
-          break;
-        case 'i':
-          db.names.push_back("char32_t");
-          first += 2;
-          break;
-        case 's':
-          db.names.push_back("char16_t");
-          first += 2;
-          break;
-        case 'a':
-          db.names.push_back("auto");
-          first += 2;
-          break;
-        case 'c':
-          db.names.push_back("decltype(auto)");
-          first += 2;
-          break;
-        case 'n':
-          db.names.push_back("std::nullptr_t");
-          first += 2;
-          break;
-        }
-      }
-      break;
-    }
+  SwapAndRestore(const SwapAndRestore &) = delete;
+  SwapAndRestore &operator=(const SwapAndRestore &) = delete;
+};
+
+// Base class of all AST nodes. The AST is built by the parser, then is
+// traversed by the printLeft/Right functions to produce a demangled string.
+class Node {
+public:
+  enum Kind : unsigned char {
+    KDotSuffix,
+    KVendorExtQualType,
+    KQualType,
+    KConversionOperatorType,
+    KPostfixQualifiedType,
+    KElaboratedTypeSpefType,
+    KNameType,
+    KAbiTagAttr,
+    KObjCProtoName,
+    KPointerType,
+    KLValueReferenceType,
+    KRValueReferenceType,
+    KPointerToMemberType,
+    KArrayType,
+    KFunctionType,
+    KNoexceptSpec,
+    KDynamicExceptionSpec,
+    KFunctionEncoding,
+    KLiteralOperator,
+    KSpecialName,
+    KCtorVtableSpecialName,
+    KQualifiedName,
+    KEmptyName,
+    KVectorType,
+    KParameterPack,
+    KTemplateArgumentPack,
+    KParameterPackExpansion,
+    KTemplateArgs,
+    KNameWithTemplateArgs,
+    KGlobalQualifiedName,
+    KStdQualifiedName,
+    KExpandedSpecialSubstitution,
+    KSpecialSubstitution,
+    KCtorDtorName,
+    KDtorName,
+    KUnnamedTypeName,
+    KClosureTypeName,
+    KStructuredBindingName,
+    KExpr,
+    KBracedExpr,
+    KBracedRangeExpr,
+  };
+
+  static constexpr unsigned NoParameterPack =
+    std::numeric_limits<unsigned>::max();
+  unsigned ParameterPackSize = NoParameterPack;
+
+  Kind K;
+
+  /// Three-way bool to track a cached value. Unknown is possible if this node
+  /// has an unexpanded parameter pack below it that may affect this cache.
+  enum class Cache : unsigned char { Yes, No, Unknown, };
+
+  /// Tracks if this node has a component on its right side, in which case we
+  /// need to call printRight.
+  Cache RHSComponentCache;
+
+  /// Track if this node is a (possibly qualified) array type. This can affect
+  /// how we format the output string.
+  Cache ArrayCache;
+
+  /// Track if this node is a (possibly qualified) function type. This can
+  /// affect how we format the output string.
+  Cache FunctionCache;
+
+  Node(Kind K_, unsigned ParameterPackSize_ = NoParameterPack,
+       Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No,
+       Cache FunctionCache_ = Cache::No)
+      : ParameterPackSize(ParameterPackSize_), K(K_),
+        RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_),
+        FunctionCache(FunctionCache_) {}
+
+  bool containsUnexpandedParameterPack() const {
+    return ParameterPackSize != NoParameterPack;
+  }
+
+  bool hasRHSComponent(OutputStream &S) const {
+    if (RHSComponentCache != Cache::Unknown)
+      return RHSComponentCache == Cache::Yes;
+    return hasRHSComponentSlow(S);
+  }
+
+  bool hasArray(OutputStream &S) const {
+    if (ArrayCache != Cache::Unknown)
+      return ArrayCache == Cache::Yes;
+    return hasArraySlow(S);
+  }
+
+  bool hasFunction(OutputStream &S) const {
+    if (FunctionCache != Cache::Unknown)
+      return FunctionCache == Cache::Yes;
+    return hasFunctionSlow(S);
+  }
+
+  Kind getKind() const { return K; }
+
+  virtual bool hasRHSComponentSlow(OutputStream &) const { return false; }
+  virtual bool hasArraySlow(OutputStream &) const { return false; }
+  virtual bool hasFunctionSlow(OutputStream &) const { return false; }
+
+  /// If this node is a pack expansion that expands to 0 elements. This can have
+  /// an effect on how we should format the output.
+  bool isEmptyPackExpansion() const;
+
+  void print(OutputStream &S) const {
+    printLeft(S);
+    if (RHSComponentCache != Cache::No)
+      printRight(S);
+  }
+
+  // Print the "left" side of this Node into OutputStream.
+  virtual void printLeft(OutputStream &) const = 0;
+
+  // Print the "right". This distinction is necessary to represent C++ types
+  // that appear on the RHS of their subtype, such as arrays or functions.
+  // Since most types don't have such a component, provide a default
+  // implemenation.
+  virtual void printRight(OutputStream &) const {}
+
+  virtual StringView getBaseName() const { return StringView(); }
+
+  // Silence compiler warnings, this dtor will never be called.
+  virtual ~Node() = default;
+
+#ifndef NDEBUG
+  LLVM_DUMP_METHOD void dump() const {
+    char *Buffer = static_cast<char*>(std::malloc(1024));
+    OutputStream S(Buffer, 1024);
+    print(S);
+    S += '\0';
+    printf("Symbol dump for %p: %s\n", (const void*)this, S.getBuffer());
+    std::free(S.getBuffer());
   }
-  return first;
-}
+#endif
+};
 
-// <CV-qualifiers> ::= [r] [V] [K]
+class NodeArray {
+  Node **Elements;
+  size_t NumElements;
 
-static const char *parse_cv_qualifiers(const char *first, const char *last,
-                                       unsigned &cv) {
-  cv = 0;
-  if (first != last) {
-    if (*first == 'r') {
-      cv |= CV_restrict;
-      ++first;
-    }
-    if (*first == 'V') {
-      cv |= CV_volatile;
-      ++first;
-    }
-    if (*first == 'K') {
-      cv |= CV_const;
-      ++first;
+public:
+  NodeArray() : Elements(nullptr), NumElements(0) {}
+  NodeArray(Node **Elements_, size_t NumElements_)
+      : Elements(Elements_), NumElements(NumElements_) {}
+
+  bool empty() const { return NumElements == 0; }
+  size_t size() const { return NumElements; }
+
+  Node **begin() const { return Elements; }
+  Node **end() const { return Elements + NumElements; }
+
+  Node *operator[](size_t Idx) const { return Elements[Idx]; }
+
+  void printWithComma(OutputStream &S) const {
+    bool FirstElement = true;
+    for (size_t Idx = 0; Idx != NumElements; ++Idx) {
+      if (Elements[Idx]->isEmptyPackExpansion())
+        continue;
+      if (!FirstElement)
+        S += ", ";
+      FirstElement = false;
+      Elements[Idx]->print(S);
     }
   }
-  return first;
-}
+};
 
-// <template-param> ::= T_    # first template parameter
-//                  ::= T <parameter-2 non-negative number> _
+class DotSuffix final : public Node {
+  const Node *Prefix;
+  const StringView Suffix;
 
-template <class C>
-static const char *parse_template_param(const char *first, const char *last,
-                                        C &db) {
-  if (last - first >= 2) {
-    if (*first == 'T') {
-      if (first[1] == '_') {
-        if (db.template_param.empty())
-          return first;
-        if (!db.template_param.back().empty()) {
-          for (auto &t : db.template_param.back().front())
-            db.names.push_back(t);
-          first += 2;
-        } else {
-          db.names.push_back("T_");
-          first += 2;
-          db.fix_forward_references = true;
-        }
-      } else if (isdigit(first[1])) {
-        const char *t = first + 1;
-        size_t sub = static_cast<size_t>(*t - '0');
-        for (++t; t != last && isdigit(*t); ++t) {
-          sub *= 10;
-          sub += static_cast<size_t>(*t - '0');
-        }
-        if (t == last || *t != '_' || db.template_param.empty())
-          return first;
-        ++sub;
-        if (sub < db.template_param.back().size()) {
-          for (auto &temp : db.template_param.back()[sub])
-            db.names.push_back(temp);
-          first = t + 1;
-        } else {
-          db.names.push_back(std::string(first, t + 1));
-          first = t + 1;
-          db.fix_forward_references = true;
-        }
-      }
-    }
+public:
+  DotSuffix(Node *Prefix_, StringView Suffix_)
+      : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {}
+
+  void printLeft(OutputStream &s) const override {
+    Prefix->print(s);
+    s += " (";
+    s += Suffix;
+    s += ")";
   }
-  return first;
-}
+};
 
-// cc <type> <expression>                               # const_cast<type>
-// (expression)
+class VendorExtQualType final : public Node {
+  const Node *Ty;
+  StringView Ext;
 
-template <class C>
-static const char *parse_const_cast_expr(const char *first, const char *last,
-                                         C &db) {
-  if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') {
-    const char *t = parse_type(first + 2, last, db);
-    if (t != first + 2) {
-      const char *t1 = parse_expression(t, last, db);
-      if (t1 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto expr = db.names.back().move_full();
-        db.names.pop_back();
-        if (db.names.empty())
-          return first;
-        db.names.back() =
-            "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
-        first = t1;
-      }
-    }
+public:
+  VendorExtQualType(Node *Ty_, StringView Ext_)
+      : Node(KVendorExtQualType, Ty_->ParameterPackSize),
+        Ty(Ty_), Ext(Ext_) {}
+
+  void printLeft(OutputStream &S) const override {
+    Ty->print(S);
+    S += " ";
+    S += Ext;
   }
-  return first;
+};
+
+enum FunctionRefQual : unsigned char {
+  FrefQualNone,
+  FrefQualLValue,
+  FrefQualRValue,
+};
+
+enum Qualifiers {
+  QualNone = 0,
+  QualConst = 0x1,
+  QualVolatile = 0x2,
+  QualRestrict = 0x4,
+};
+
+void addQualifiers(Qualifiers &Q1, Qualifiers Q2) {
+  Q1 = static_cast<Qualifiers>(Q1 | Q2);
 }
 
-// dc <type> <expression>                               # dynamic_cast<type>
-// (expression)
+class QualType : public Node {
+protected:
+  const Qualifiers Quals;
+  const Node *Child;
+
+  void printQuals(OutputStream &S) const {
+    if (Quals & QualConst)
+      S += " const";
+    if (Quals & QualVolatile)
+      S += " volatile";
+    if (Quals & QualRestrict)
+      S += " restrict";
+  }
+
+public:
+  QualType(Node *Child_, Qualifiers Quals_)
+      : Node(KQualType, Child_->ParameterPackSize, Child_->RHSComponentCache,
+             Child_->ArrayCache, Child_->FunctionCache),
+        Quals(Quals_), Child(Child_) {}
 
-template <class C>
-static const char *parse_dynamic_cast_expr(const char *first, const char *last,
-                                           C &db) {
-  if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') {
-    const char *t = parse_type(first + 2, last, db);
-    if (t != first + 2) {
-      const char *t1 = parse_expression(t, last, db);
-      if (t1 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto expr = db.names.back().move_full();
-        db.names.pop_back();
-        if (db.names.empty())
-          return first;
-        db.names.back() =
-            "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
-        first = t1;
-      }
-    }
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Child->hasRHSComponent(S);
+  }
+  bool hasArraySlow(OutputStream &S) const override {
+    return Child->hasArray(S);
+  }
+  bool hasFunctionSlow(OutputStream &S) const override {
+    return Child->hasFunction(S);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    Child->printLeft(S);
+    printQuals(S);
   }
-  return first;
-}
 
-// rc <type> <expression>                               # reinterpret_cast<type>
-// (expression)
+  void printRight(OutputStream &S) const override { Child->printRight(S); }
+};
 
-template <class C>
-static const char *parse_reinterpret_cast_expr(const char *first,
-                                               const char *last, C &db) {
-  if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') {
-    const char *t = parse_type(first + 2, last, db);
-    if (t != first + 2) {
-      const char *t1 = parse_expression(t, last, db);
-      if (t1 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto expr = db.names.back().move_full();
-        db.names.pop_back();
-        if (db.names.empty())
-          return first;
-        db.names.back() = "reinterpret_cast<" + db.names.back().move_full() +
-                          ">(" + expr + ")";
-        first = t1;
-      }
-    }
+class ConversionOperatorType final : public Node {
+  const Node *Ty;
+
+public:
+  ConversionOperatorType(Node *Ty_)
+      : Node(KConversionOperatorType, Ty_->ParameterPackSize), Ty(Ty_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += "operator ";
+    Ty->print(S);
   }
-  return first;
-}
+};
 
-// sc <type> <expression>                               # static_cast<type>
-// (expression)
+class PostfixQualifiedType final : public Node {
+  const Node *Ty;
+  const StringView Postfix;
 
-template <class C>
-static const char *parse_static_cast_expr(const char *first, const char *last,
-                                          C &db) {
-  if (last - first >= 3 && first[0] == 's' && first[1] == 'c') {
-    const char *t = parse_type(first + 2, last, db);
-    if (t != first + 2) {
-      const char *t1 = parse_expression(t, last, db);
-      if (t1 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto expr = db.names.back().move_full();
-        db.names.pop_back();
-        db.names.back() =
-            "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
-        first = t1;
-      }
-    }
+public:
+  PostfixQualifiedType(Node *Ty_, StringView Postfix_)
+      : Node(KPostfixQualifiedType, Ty_->ParameterPackSize),
+        Ty(Ty_), Postfix(Postfix_) {}
+
+  void printLeft(OutputStream &s) const override {
+    Ty->printLeft(s);
+    s += Postfix;
   }
-  return first;
-}
+};
 
-// sp <expression>                                  # pack expansion
+class NameType final : public Node {
+  const StringView Name;
 
-template <class C>
-static const char *parse_pack_expansion(const char *first, const char *last,
-                                        C &db) {
-  if (last - first >= 3 && first[0] == 's' && first[1] == 'p') {
-    const char *t = parse_expression(first + 2, last, db);
-    if (t != first + 2)
-      first = t;
-  }
-  return first;
-}
-
-// st <type>                                            # sizeof (a type)
-
-template <class C>
-static const char *parse_sizeof_type_expr(const char *first, const char *last,
-                                          C &db) {
-  if (last - first >= 3 && first[0] == 's' && first[1] == 't') {
-    const char *t = parse_type(first + 2, last, db);
-    if (t != first + 2) {
-      if (db.names.empty())
-        return first;
-      db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
-      first = t;
-    }
-  }
-  return first;
-}
-
-// sz <expr>                                            # sizeof (a expression)
-
-template <class C>
-static const char *parse_sizeof_expr_expr(const char *first, const char *last,
-                                          C &db) {
-  if (last - first >= 3 && first[0] == 's' && first[1] == 'z') {
-    const char *t = parse_expression(first + 2, last, db);
-    if (t != first + 2) {
-      if (db.names.empty())
-        return first;
-      db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
-      first = t;
-    }
-  }
-  return first;
-}
-
-// sZ <template-param>                                  # size of a parameter
-// pack
-
-template <class C>
-static const char *parse_sizeof_param_pack_expr(const char *first,
-                                                const char *last, C &db) {
-  if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' &&
-      first[2] == 'T') {
-    size_t k0 = db.names.size();
-    const char *t = parse_template_param(first + 2, last, db);
-    size_t k1 = db.names.size();
-    if (t != first + 2) {
-      std::string tmp("sizeof...(");
-      size_t k = k0;
-      if (k != k1) {
-        tmp += db.names[k].move_full();
-        for (++k; k != k1; ++k)
-          tmp += ", " + db.names[k].move_full();
-      }
-      tmp += ")";
-      for (; k1 != k0; --k1)
-        db.names.pop_back();
-      db.names.push_back(std::move(tmp));
-      first = t;
-    }
-  }
-  return first;
-}
-
-// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
-//                  ::= 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 <class C>
-static const char *parse_function_param(const char *first, const char *last,
-                                        C &db) {
-  if (last - first >= 3 && *first == 'f') {
-    if (first[1] == 'p') {
-      unsigned cv;
-      const char *t = parse_cv_qualifiers(first + 2, last, cv);
-      const char *t1 = parse_number(t, last);
-      if (t1 != last && *t1 == '_') {
-        db.names.push_back("fp" + std::string(t, t1));
-        first = t1 + 1;
-      }
-    } else if (first[1] == 'L') {
-      unsigned cv;
-      const char *t0 = parse_number(first + 2, last);
-      if (t0 != last && *t0 == 'p') {
-        ++t0;
-        const char *t = parse_cv_qualifiers(t0, last, cv);
-        const char *t1 = parse_number(t, last);
-        if (t1 != last && *t1 == '_') {
-          db.names.push_back("fp" + std::string(t, t1));
-          first = t1 + 1;
-        }
-      }
-    }
+public:
+  NameType(StringView Name_) : Node(KNameType), Name(Name_) {}
+
+  StringView getName() const { return Name; }
+  StringView getBaseName() const override { return Name; }
+
+  void printLeft(OutputStream &s) const override { s += Name; }
+};
+
+class ElaboratedTypeSpefType : public Node {
+  StringView Kind;
+  Node *Child;
+public:
+  ElaboratedTypeSpefType(StringView Kind_, Node *Child_)
+      : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {
+    ParameterPackSize = Child->ParameterPackSize;
   }
-  return first;
-}
 
-// sZ <function-param>                                  # size of a function
-// parameter pack
+  void printLeft(OutputStream &S) const override {
+    S += Kind;
+    S += ' ';
+    Child->print(S);
+  }
+};
 
-template <class C>
-static const char *parse_sizeof_function_param_pack_expr(const char *first,
-                                                         const char *last,
-                                                         C &db) {
-  if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' &&
-      first[2] == 'f') {
-    const char *t = parse_function_param(first + 2, last, db);
-    if (t != first + 2) {
-      if (db.names.empty())
-        return first;
-      db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
-      first = t;
-    }
-  }
-  return first;
-}
-
-// te <expression>                                      # typeid (expression)
-// ti <type>                                            # typeid (type)
-
-template <class C>
-static const char *parse_typeid_expr(const char *first, const char *last,
-                                     C &db) {
-  if (last - first >= 3 && first[0] == 't' &&
-      (first[1] == 'e' || first[1] == 'i')) {
-    const char *t;
-    if (first[1] == 'e')
-      t = parse_expression(first + 2, last, db);
-    else
-      t = parse_type(first + 2, last, db);
-    if (t != first + 2) {
-      if (db.names.empty())
-        return first;
-      db.names.back() = "typeid(" + db.names.back().move_full() + ")";
-      first = t;
-    }
-  }
-  return first;
-}
-
-// tw <expression>                                      # throw expression
-
-template <class C>
-static const char *parse_throw_expr(const char *first, const char *last,
-                                    C &db) {
-  if (last - first >= 3 && first[0] == 't' && first[1] == 'w') {
-    const char *t = parse_expression(first + 2, last, db);
-    if (t != first + 2) {
-      if (db.names.empty())
-        return first;
-      db.names.back() = "throw " + db.names.back().move_full();
-      first = t;
-    }
-  }
-  return first;
-}
-
-// ds <expression> <expression>                         # expr.*expr
-
-template <class C>
-static const char *parse_dot_star_expr(const char *first, const char *last,
-                                       C &db) {
-  if (last - first >= 3 && first[0] == 'd' && first[1] == 's') {
-    const char *t = parse_expression(first + 2, last, db);
-    if (t != first + 2) {
-      const char *t1 = parse_expression(t, last, db);
-      if (t1 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto expr = db.names.back().move_full();
-        db.names.pop_back();
-        db.names.back().first += ".*" + expr;
-        first = t1;
-      }
-    }
+class AbiTagAttr final : public Node {
+  const Node* Base;
+  StringView Tag;
+public:
+  AbiTagAttr(const Node* Base_, StringView Tag_)
+      : Node(KAbiTagAttr, Base_->ParameterPackSize, Base_->RHSComponentCache,
+             Base_->ArrayCache, Base_->FunctionCache),
+        Base(Base_), Tag(Tag_) {}
+
+  void printLeft(OutputStream &S) const override {
+    Base->printLeft(S);
+    S += "[abi:";
+    S += Tag;
+    S += "]";
   }
-  return first;
-}
+};
 
-// <simple-id> ::= <source-name> [ <template-args> ]
+class ObjCProtoName : public Node {
+  Node *Ty;
+  StringView Protocol;
 
-template <class C>
-static const char *parse_simple_id(const char *first, const char *last, C &db) {
-  if (first != last) {
-    const char *t = parse_source_name(first, last, db);
-    if (t != first) {
-      const char *t1 = parse_template_args(t, last, db);
-      if (t1 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto args = db.names.back().move_full();
-        db.names.pop_back();
-        db.names.back().first += std::move(args);
-      }
-      first = t1;
-    } else
-      first = t;
+  friend class PointerType;
+
+public:
+  ObjCProtoName(Node *Ty_, StringView Protocol_)
+      : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
+
+  bool isObjCObject() const {
+    return Ty->getKind() == KNameType &&
+           static_cast<NameType *>(Ty)->getName() == "objc_object";
   }
-  return first;
-}
 
-// <unresolved-type> ::= <template-param>
-//                   ::= <decltype>
-//                   ::= <substitution>
+  void printLeft(OutputStream &S) const override {
+    Ty->print(S);
+    S += "<";
+    S += Protocol;
+    S += ">";
+  }
+};
 
-template <class C>
-static const char *parse_unresolved_type(const char *first, const char *last,
-                                         C &db) {
-  if (first != last) {
-    const char *t = first;
-    switch (*first) {
-    case 'T': {
-      size_t k0 = db.names.size();
-      t = parse_template_param(first, last, db);
-      size_t k1 = db.names.size();
-      if (t != first && k1 == k0 + 1) {
-        db.subs.push_back(typename C::sub_type(1, db.names.back()));
-        first = t;
-      } else {
-        for (; k1 != k0; --k1)
-          db.names.pop_back();
-      }
-      break;
-    }
-    case 'D':
-      t = parse_decltype(first, last, db);
-      if (t != first) {
-        if (db.names.empty())
-          return first;
-        db.subs.push_back(typename C::sub_type(1, db.names.back()));
-        first = t;
-      }
-      break;
-    case 'S':
-      t = parse_substitution(first, last, db);
-      if (t != first)
-        first = t;
-      else {
-        if (last - first > 2 && first[1] == 't') {
-          t = parse_unqualified_name(first + 2, last, db);
-          if (t != first + 2) {
-            if (db.names.empty())
-              return first;
-            db.names.back().first.insert(0, "std::");
-            db.subs.push_back(typename C::sub_type(1, db.names.back()));
-            first = t;
-          }
-        }
-      }
-      break;
+class PointerType final : public Node {
+  const Node *Pointee;
+
+public:
+  PointerType(Node *Pointee_)
+      : Node(KPointerType, Pointee_->ParameterPackSize,
+             Pointee_->RHSComponentCache),
+        Pointee(Pointee_) {}
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
+  }
+
+  void printLeft(OutputStream &s) const override {
+    // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
+    if (Pointee->getKind() != KObjCProtoName ||
+        !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
+      Pointee->printLeft(s);
+      if (Pointee->hasArray(s))
+        s += " ";
+      if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+        s += "(";
+      s += "*";
+    } else {
+      const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
+      s += "id<";
+      s += objcProto->Protocol;
+      s += ">";
     }
   }
-  return first;
-}
 
-// <destructor-name> ::= <unresolved-type>                               # e.g.,
-// ~T or ~decltype(f())
-//                   ::= <simple-id>                                     # e.g.,
-//                   ~A<2*N>
-
-template <class C>
-static const char *parse_destructor_name(const char *first, const char *last,
-                                         C &db) {
-  if (first != last) {
-    const char *t = parse_unresolved_type(first, last, db);
-    if (t == first)
-      t = parse_simple_id(first, last, db);
-    if (t != first) {
-      if (db.names.empty())
-        return first;
-      db.names.back().first.insert(0, "~");
-      first = t;
-    }
-  }
-  return first;
-}
-
-// <base-unresolved-name> ::= <simple-id>                                #
-// unresolved name
-//          extension     ::= <operator-name>                            #
-//          unresolved operator-function-id
-//          extension     ::= <operator-name> <template-args>            #
-//          unresolved operator template-id
-//                        ::= on <operator-name>                         #
-//                        unresolved operator-function-id
-//                        ::= on <operator-name> <template-args>         #
-//                        unresolved operator template-id
-//                        ::= dn <destructor-name>                       #
-//                        destructor or pseudo-destructor;
-//                                                                         #
-//                                                                         e.g.
-//                                                                         ~X or
-//                                                                         ~X<N-1>
-
-template <class C>
-static const char *parse_base_unresolved_name(const char *first,
-                                              const char *last, C &db) {
-  if (last - first >= 2) {
-    if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') {
-      if (first[0] == 'o') {
-        const char *t = parse_operator_name(first + 2, last, db);
-        if (t != first + 2) {
-          first = parse_template_args(t, last, db);
-          if (first != t) {
-            if (db.names.size() < 2)
-              return first;
-            auto args = db.names.back().move_full();
-            db.names.pop_back();
-            db.names.back().first += std::move(args);
-          }
-        }
-      } else {
-        const char *t = parse_destructor_name(first + 2, last, db);
-        if (t != first + 2)
-          first = t;
-      }
-    } else {
-      const char *t = parse_simple_id(first, last, db);
-      if (t == first) {
-        t = parse_operator_name(first, last, db);
-        if (t != first) {
-          first = parse_template_args(t, last, db);
-          if (first != t) {
-            if (db.names.size() < 2)
-              return first;
-            auto args = db.names.back().move_full();
-            db.names.pop_back();
-            db.names.back().first += std::move(args);
-          }
-        }
-      } else
-        first = t;
+  void printRight(OutputStream &s) const override {
+    if (Pointee->getKind() != KObjCProtoName ||
+        !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
+      if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+        s += ")";
+      Pointee->printRight(s);
     }
   }
-  return first;
-}
+};
 
-// <unresolved-qualifier-level> ::= <simple-id>
+class LValueReferenceType final : public Node {
+  const Node *Pointee;
 
-template <class C>
-static const char *parse_unresolved_qualifier_level(const char *first,
-                                                    const char *last, C &db) {
-  return parse_simple_id(first, last, db);
-}
+public:
+  LValueReferenceType(Node *Pointee_)
+      : Node(KLValueReferenceType, Pointee_->ParameterPackSize,
+             Pointee_->RHSComponentCache),
+        Pointee(Pointee_) {}
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
+  }
 
-// <unresolved-name>
-//  extension        ::= srN <unresolved-type> [<template-args>]
-//  <unresolved-qualifier-level>* E <base-unresolved-name>
-//                   ::= [gs] <base-unresolved-name>                     # x or
-//                   (with "gs") ::x
-//                   ::= [gs] sr <unresolved-qualifier-level>+ E
-//                   <base-unresolved-name>
-//                                                                       # A::x,
-//                                                                       N::y,
-//                                                                       A<T>::z;
-//                                                                       "gs"
-//                                                                       means
-//                                                                       leading
-//                                                                       "::"
-//                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x
-//                   / decltype(p)::x
-//  extension        ::= sr <unresolved-type> <template-args>
-//  <base-unresolved-name>
-//                                                                       #
-//                                                                       T::N::x
-//                                                                       /decltype(p)::N::x
-//  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E
-//  <base-unresolved-name>
-
-template <class C>
-static const char *parse_unresolved_name(const char *first, const char *last,
-                                         C &db) {
-  if (last - first > 2) {
-    const char *t = first;
-    bool global = false;
-    if (t[0] == 'g' && t[1] == 's') {
-      global = true;
-      t += 2;
-    }
-    const char *t2 = parse_base_unresolved_name(t, last, db);
-    if (t2 != t) {
-      if (global) {
-        if (db.names.empty())
-          return first;
-        db.names.back().first.insert(0, "::");
-      }
-      first = t2;
-    } else if (last - t > 2 && t[0] == 's' && t[1] == 'r') {
-      if (t[2] == 'N') {
-        t += 3;
-        const char *t1 = parse_unresolved_type(t, last, db);
-        if (t1 == t || t1 == last)
-          return first;
-        t = t1;
-        t1 = parse_template_args(t, last, db);
-        if (t1 != t) {
-          if (db.names.size() < 2)
-            return first;
-          auto args = db.names.back().move_full();
-          db.names.pop_back();
-          db.names.back().first += std::move(args);
-          t = t1;
-          if (t == last) {
-            db.names.pop_back();
-            return first;
-          }
-        }
-        while (*t != 'E') {
-          t1 = parse_unresolved_qualifier_level(t, last, db);
-          if (t1 == t || t1 == last || db.names.size() < 2)
-            return first;
-          auto s = db.names.back().move_full();
-          db.names.pop_back();
-          db.names.back().first += "::" + std::move(s);
-          t = t1;
-        }
-        ++t;
-        t1 = parse_base_unresolved_name(t, last, db);
-        if (t1 == t) {
-          if (!db.names.empty())
-            db.names.pop_back();
-          return first;
-        }
-        if (db.names.size() < 2)
-          return first;
-        auto s = db.names.back().move_full();
-        db.names.pop_back();
-        db.names.back().first += "::" + std::move(s);
-        first = t1;
-      } else {
-        t += 2;
-        const char *t1 = parse_unresolved_type(t, last, db);
-        if (t1 != t) {
-          t = t1;
-          t1 = parse_template_args(t, last, db);
-          if (t1 != t) {
-            if (db.names.size() < 2)
-              return first;
-            auto args = db.names.back().move_full();
-            db.names.pop_back();
-            db.names.back().first += std::move(args);
-            t = t1;
-          }
-          t1 = parse_base_unresolved_name(t, last, db);
-          if (t1 == t) {
-            if (!db.names.empty())
-              db.names.pop_back();
-            return first;
-          }
-          if (db.names.size() < 2)
-            return first;
-          auto s = db.names.back().move_full();
-          db.names.pop_back();
-          db.names.back().first += "::" + std::move(s);
-          first = t1;
-        } else {
-          t1 = parse_unresolved_qualifier_level(t, last, db);
-          if (t1 == t || t1 == last)
-            return first;
-          t = t1;
-          if (global) {
-            if (db.names.empty())
-              return first;
-            db.names.back().first.insert(0, "::");
-          }
-          while (*t != 'E') {
-            t1 = parse_unresolved_qualifier_level(t, last, db);
-            if (t1 == t || t1 == last || db.names.size() < 2)
-              return first;
-            auto s = db.names.back().move_full();
-            db.names.pop_back();
-            db.names.back().first += "::" + std::move(s);
-            t = t1;
-          }
-          ++t;
-          t1 = parse_base_unresolved_name(t, last, db);
-          if (t1 == t) {
-            if (!db.names.empty())
-              db.names.pop_back();
-            return first;
-          }
-          if (db.names.size() < 2)
-            return first;
-          auto s = db.names.back().move_full();
-          db.names.pop_back();
-          db.names.back().first += "::" + std::move(s);
-          first = t1;
-        }
-      }
-    }
+  void printLeft(OutputStream &s) const override {
+    Pointee->printLeft(s);
+    if (Pointee->hasArray(s))
+      s += " ";
+    if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+      s += "(&";
+    else
+      s += "&";
   }
-  return first;
-}
+  void printRight(OutputStream &s) const override {
+    if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+      s += ")";
+    Pointee->printRight(s);
+  }
+};
 
-// dt <expression> <unresolved-name>                    # expr.name
+class RValueReferenceType final : public Node {
+  const Node *Pointee;
 
-template <class C>
-static const char *parse_dot_expr(const char *first, const char *last, C &db) {
-  if (last - first >= 3 && first[0] == 'd' && first[1] == 't') {
-    const char *t = parse_expression(first + 2, last, db);
-    if (t != first + 2) {
-      const char *t1 = parse_unresolved_name(t, last, db);
-      if (t1 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto name = db.names.back().move_full();
-        db.names.pop_back();
-        if (db.names.empty())
-          return first;
-        db.names.back().first += "." + name;
-        first = t1;
-      }
-    }
+public:
+  RValueReferenceType(Node *Pointee_)
+      : Node(KRValueReferenceType, Pointee_->ParameterPackSize,
+             Pointee_->RHSComponentCache),
+        Pointee(Pointee_) {}
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
   }
-  return first;
-}
 
-// cl <expression>+ E                                   # call
+  void printLeft(OutputStream &s) const override {
+    Pointee->printLeft(s);
+    if (Pointee->hasArray(s))
+      s += " ";
+    if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+      s += "(&&";
+    else
+      s += "&&";
+  }
 
-template <class C>
-static const char *parse_call_expr(const char *first, const char *last, C &db) {
-  if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') {
-    const char *t = parse_expression(first + 2, last, db);
-    if (t != first + 2) {
-      if (t == last)
-        return first;
-      if (db.names.empty())
-        return first;
-      db.names.back().first += db.names.back().second;
-      db.names.back().second = std::string();
-      db.names.back().first.append("(");
-      bool first_expr = true;
-      while (*t != 'E') {
-        const char *t1 = parse_expression(t, last, db);
-        if (t1 == t || t1 == last)
-          return first;
-        if (db.names.empty())
-          return first;
-        auto tmp = db.names.back().move_full();
-        db.names.pop_back();
-        if (!tmp.empty()) {
-          if (db.names.empty())
-            return first;
-          if (!first_expr) {
-            db.names.back().first.append(", ");
-            first_expr = false;
-          }
-          db.names.back().first.append(tmp);
-        }
-        t = t1;
-      }
-      ++t;
-      if (db.names.empty())
-        return first;
-      db.names.back().first.append(")");
-      first = t;
-    }
+  void printRight(OutputStream &s) const override {
+    if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+      s += ")";
+    Pointee->printRight(s);
   }
-  return first;
-}
+};
 
-// [gs] nw <expression>* _ <type> E                     # new (expr-list) type
-// [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type
-// (init)
-// [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 <class C>
-static const char *parse_new_expr(const char *first, const char *last, C &db) {
-  if (last - first >= 4) {
-    const char *t = first;
-    bool parsed_gs = false;
-    if (t[0] == 'g' && t[1] == 's') {
-      t += 2;
-      parsed_gs = true;
-    }
-    if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a')) {
-      bool is_array = t[1] == 'a';
-      t += 2;
-      if (t == last)
-        return first;
-      bool has_expr_list = false;
-      bool first_expr = true;
-      while (*t != '_') {
-        const char *t1 = parse_expression(t, last, db);
-        if (t1 == t || t1 == last)
-          return first;
-        has_expr_list = true;
-        if (!first_expr) {
-          if (db.names.empty())
-            return first;
-          auto tmp = db.names.back().move_full();
-          db.names.pop_back();
-          if (!tmp.empty()) {
-            if (db.names.empty())
-              return first;
-            db.names.back().first.append(", ");
-            db.names.back().first.append(tmp);
-            first_expr = false;
-          }
-        }
-        t = t1;
-      }
-      ++t;
-      const char *t1 = parse_type(t, last, db);
-      if (t1 == t || t1 == last)
-        return first;
-      t = t1;
-      bool has_init = false;
-      if (last - t >= 3 && t[0] == 'p' && t[1] == 'i') {
-        t += 2;
-        has_init = true;
-        first_expr = true;
-        while (*t != 'E') {
-          t1 = parse_expression(t, last, db);
-          if (t1 == t || t1 == last)
-            return first;
-          if (!first_expr) {
-            if (db.names.empty())
-              return first;
-            auto tmp = db.names.back().move_full();
-            db.names.pop_back();
-            if (!tmp.empty()) {
-              if (db.names.empty())
-                return first;
-              db.names.back().first.append(", ");
-              db.names.back().first.append(tmp);
-              first_expr = false;
-            }
-          }
-          t = t1;
-        }
-      }
-      if (*t != 'E')
-        return first;
-      std::string init_list;
-      if (has_init) {
-        if (db.names.empty())
-          return first;
-        init_list = db.names.back().move_full();
-        db.names.pop_back();
-      }
-      if (db.names.empty())
-        return first;
-      auto type = db.names.back().move_full();
-      db.names.pop_back();
-      std::string expr_list;
-      if (has_expr_list) {
-        if (db.names.empty())
-          return first;
-        expr_list = db.names.back().move_full();
-        db.names.pop_back();
-      }
-      std::string r;
-      if (parsed_gs)
-        r = "::";
-      if (is_array)
-        r += "[] ";
-      else
-        r += " ";
-      if (has_expr_list)
-        r += "(" + expr_list + ") ";
-      r += type;
-      if (has_init)
-        r += " (" + init_list + ")";
-      db.names.push_back(std::move(r));
-      first = t + 1;
-    }
-  }
-  return first;
-}
-
-// cv <type> <expression>                               # conversion with one
-// argument
-// cv <type> _ <expression>* E                          # conversion with a
-// different number of arguments
-
-template <class C>
-static const char *parse_conversion_expr(const char *first, const char *last,
-                                         C &db) {
-  if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') {
-    bool try_to_parse_template_args = db.try_to_parse_template_args;
-    db.try_to_parse_template_args = false;
-    const char *t = parse_type(first + 2, last, db);
-    db.try_to_parse_template_args = try_to_parse_template_args;
-    if (t != first + 2 && t != last) {
-      if (*t != '_') {
-        const char *t1 = parse_expression(t, last, db);
-        if (t1 == t)
-          return first;
-        t = t1;
-      } else {
-        ++t;
-        if (t == last)
-          return first;
-        if (*t == 'E')
-          db.names.emplace_back();
-        else {
-          bool first_expr = true;
-          while (*t != 'E') {
-            const char *t1 = parse_expression(t, last, db);
-            if (t1 == t || t1 == last)
-              return first;
-            if (!first_expr) {
-              if (db.names.empty())
-                return first;
-              auto tmp = db.names.back().move_full();
-              db.names.pop_back();
-              if (!tmp.empty()) {
-                if (db.names.empty())
-                  return first;
-                db.names.back().first.append(", ");
-                db.names.back().first.append(tmp);
-                first_expr = false;
-              }
-            }
-            t = t1;
-          }
-        }
-        ++t;
-      }
-      if (db.names.size() < 2)
-        return first;
-      auto tmp = db.names.back().move_full();
-      db.names.pop_back();
-      db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
-      first = t;
-    }
-  }
-  return first;
-}
-
-// pt <expression> <expression>                    # expr->name
-
-template <class C>
-static const char *parse_arrow_expr(const char *first, const char *last,
-                                    C &db) {
-  if (last - first >= 3 && first[0] == 'p' && first[1] == 't') {
-    const char *t = parse_expression(first + 2, last, db);
-    if (t != first + 2) {
-      const char *t1 = parse_expression(t, last, db);
-      if (t1 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto tmp = db.names.back().move_full();
-        db.names.pop_back();
-        db.names.back().first += "->";
-        db.names.back().first += tmp;
-        first = t1;
-      }
-    }
+class PointerToMemberType final : public Node {
+  const Node *ClassType;
+  const Node *MemberType;
+
+public:
+  PointerToMemberType(Node *ClassType_, Node *MemberType_)
+      : Node(KPointerToMemberType,
+             std::min(MemberType_->ParameterPackSize,
+                      ClassType_->ParameterPackSize),
+             MemberType_->RHSComponentCache),
+        ClassType(ClassType_), MemberType(MemberType_) {}
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return MemberType->hasRHSComponent(S);
+  }
+
+  void printLeft(OutputStream &s) const override {
+    MemberType->printLeft(s);
+    if (MemberType->hasArray(s) || MemberType->hasFunction(s))
+      s += "(";
+    else
+      s += " ";
+    ClassType->print(s);
+    s += "::*";
   }
-  return first;
-}
 
-//  <ref-qualifier> ::= R                   # & ref-qualifier
-//  <ref-qualifier> ::= O                   # && ref-qualifier
+  void printRight(OutputStream &s) const override {
+    if (MemberType->hasArray(s) || MemberType->hasFunction(s))
+      s += ")";
+    MemberType->printRight(s);
+  }
+};
 
-// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+class NodeOrString {
+  const void *First;
+  const void *Second;
 
-template <class C>
-static const char *parse_function_type(const char *first, const char *last,
-                                       C &db) {
-  if (first != last && *first == 'F') {
-    const char *t = first + 1;
-    if (t != last) {
-      if (*t == 'Y') {
-        /* extern "C" */
-        if (++t == last)
-          return first;
-      }
-      const char *t1 = parse_type(t, last, db);
-      if (t1 != t) {
-        t = t1;
-        std::string sig("(");
-        int ref_qual = 0;
-        while (true) {
-          if (t == last) {
-            if (!db.names.empty())
-              db.names.pop_back();
-            return first;
-          }
-          if (*t == 'E') {
-            ++t;
-            break;
-          }
-          if (*t == 'v') {
-            ++t;
-            continue;
-          }
-          if (*t == 'R' && t + 1 != last && t[1] == 'E') {
-            ref_qual = 1;
-            ++t;
-            continue;
-          }
-          if (*t == 'O' && t + 1 != last && t[1] == 'E') {
-            ref_qual = 2;
-            ++t;
-            continue;
-          }
-          size_t k0 = db.names.size();
-          t1 = parse_type(t, last, db);
-          size_t k1 = db.names.size();
-          if (t1 == t || t1 == last)
-            return first;
-          for (size_t k = k0; k < k1; ++k) {
-            if (sig.size() > 1)
-              sig += ", ";
-            sig += db.names[k].move_full();
-          }
-          for (size_t k = k0; k < k1; ++k)
-            db.names.pop_back();
-          t = t1;
-        }
-        sig += ")";
-        switch (ref_qual) {
-        case 1:
-          sig += " &";
-          break;
-        case 2:
-          sig += " &&";
-          break;
-        }
-        if (db.names.empty())
-          return first;
-        db.names.back().first += " ";
-        db.names.back().second.insert(0, sig);
-        first = t;
-      }
-    }
+public:
+  /* implicit */ NodeOrString(StringView Str) {
+    const char *FirstChar = Str.begin();
+    const char *SecondChar = Str.end();
+    if (SecondChar == nullptr) {
+      assert(FirstChar == SecondChar);
+      ++FirstChar, ++SecondChar;
+    }
+    First = static_cast<const void *>(FirstChar);
+    Second = static_cast<const void *>(SecondChar);
+  }
+
+  /* implicit */ NodeOrString(Node *N)
+      : First(static_cast<const void *>(N)), Second(nullptr) {}
+  NodeOrString() : First(nullptr), Second(nullptr) {}
+
+  bool isString() const { return Second && First; }
+  bool isNode() const { return First && !Second; }
+  bool isEmpty() const { return !First && !Second; }
+
+  StringView asString() const {
+    assert(isString());
+    return StringView(static_cast<const char *>(First),
+                      static_cast<const char *>(Second));
+  }
+
+  const Node *asNode() const {
+    assert(isNode());
+    return static_cast<const Node *>(First);
   }
-  return first;
-}
+};
 
-// <pointer-to-member-type> ::= M <class type> <member type>
+class ArrayType final : public Node {
+  Node *Base;
+  NodeOrString Dimension;
 
-template <class C>
-static const char *parse_pointer_to_member_type(const char *first,
-                                                const char *last, C &db) {
-  if (first != last && *first == 'M') {
-    const char *t = parse_type(first + 1, last, db);
-    if (t != first + 1) {
-      const char *t2 = parse_type(t, last, db);
-      if (t2 != t) {
-        if (db.names.size() < 2)
-          return first;
-        auto func = std::move(db.names.back());
-        db.names.pop_back();
-        auto class_type = std::move(db.names.back());
-        if (!func.second.empty() && func.second.front() == '(') {
-          db.names.back().first =
-              std::move(func.first) + "(" + class_type.move_full() + "::*";
-          db.names.back().second = ")" + std::move(func.second);
-        } else {
-          db.names.back().first =
-              std::move(func.first) + " " + class_type.move_full() + "::*";
-          db.names.back().second = std::move(func.second);
-        }
-        first = t2;
-      }
+public:
+  ArrayType(Node *Base_, NodeOrString Dimension_)
+      : Node(KArrayType, Base_->ParameterPackSize,
+             /*RHSComponentCache=*/Cache::Yes,
+             /*ArrayCache=*/Cache::Yes),
+        Base(Base_), Dimension(Dimension_) {
+    if (Dimension.isNode())
+      ParameterPackSize =
+          std::min(ParameterPackSize, Dimension.asNode()->ParameterPackSize);
+  }
+
+  // Incomplete array type.
+  ArrayType(Node *Base_)
+      : Node(KArrayType, Base_->ParameterPackSize,
+             /*RHSComponentCache=*/Cache::Yes,
+             /*ArrayCache=*/Cache::Yes),
+        Base(Base_) {}
+
+  bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+  bool hasArraySlow(OutputStream &) const override { return true; }
+
+  void printLeft(OutputStream &S) const override { Base->printLeft(S); }
+
+  void printRight(OutputStream &S) const override {
+    if (S.back() != ']')
+      S += " ";
+    S += "[";
+    if (Dimension.isString())
+      S += Dimension.asString();
+    else if (Dimension.isNode())
+      Dimension.asNode()->print(S);
+    S += "]";
+    Base->printRight(S);
+  }
+};
+
+class FunctionType final : public Node {
+  Node *Ret;
+  NodeArray Params;
+  Qualifiers CVQuals;
+  FunctionRefQual RefQual;
+  Node *ExceptionSpec;
+
+public:
+  FunctionType(Node *Ret_, NodeArray Params_, Qualifiers CVQuals_,
+               FunctionRefQual RefQual_, Node *ExceptionSpec_)
+      : Node(KFunctionType, Ret_->ParameterPackSize,
+             /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
+             /*FunctionCache=*/Cache::Yes),
+        Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_),
+        ExceptionSpec(ExceptionSpec_) {
+    for (Node *P : Params)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+    if (ExceptionSpec != nullptr)
+      ParameterPackSize =
+        std::min(ParameterPackSize, ExceptionSpec->ParameterPackSize);
+  }
+
+  bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+  bool hasFunctionSlow(OutputStream &) const override { return true; }
+
+  // Handle C++'s ... quirky decl grammer by using the left & right
+  // distinction. Consider:
+  //   int (*f(float))(char) {}
+  // f is a function that takes a float and returns a pointer to a function
+  // that takes a char and returns an int. If we're trying to print f, start
+  // by printing out the return types's left, then print our parameters, then
+  // finally print right of the return type.
+  void printLeft(OutputStream &S) const override {
+    Ret->printLeft(S);
+    S += " ";
+  }
+
+  void printRight(OutputStream &S) const override {
+    S += "(";
+    Params.printWithComma(S);
+    S += ")";
+    Ret->printRight(S);
+
+    if (CVQuals & QualConst)
+      S += " const";
+    if (CVQuals & QualVolatile)
+      S += " volatile";
+    if (CVQuals & QualRestrict)
+      S += " restrict";
+
+    if (RefQual == FrefQualLValue)
+      S += " &";
+    else if (RefQual == FrefQualRValue)
+      S += " &&";
+
+    if (ExceptionSpec != nullptr) {
+      S += ' ';
+      ExceptionSpec->print(S);
     }
   }
-  return first;
-}
+};
 
-// <array-type> ::= A <positive dimension number> _ <element type>
-//              ::= A [<dimension expression>] _ <element type>
+class NoexceptSpec : public Node {
+  Node *E;
+public:
+  NoexceptSpec(Node *E_) : Node(KNoexceptSpec, E_->ParameterPackSize), E(E_) {}
 
-template <class C>
-static const char *parse_array_type(const char *first, const char *last,
-                                    C &db) {
-  if (first != last && *first == 'A' && first + 1 != last) {
-    if (first[1] == '_') {
-      const char *t = parse_type(first + 2, last, db);
-      if (t != first + 2) {
-        if (db.names.empty())
-          return first;
-        if (db.names.back().second.substr(0, 2) == " [")
-          db.names.back().second.erase(0, 1);
-        db.names.back().second.insert(0, " []");
-        first = t;
-      }
-    } else if ('1' <= first[1] && first[1] <= '9') {
-      const char *t = parse_number(first + 1, last);
-      if (t != last && *t == '_') {
-        const char *t2 = parse_type(t + 1, last, db);
-        if (t2 != t + 1) {
-          if (db.names.empty())
-            return first;
-          if (db.names.back().second.substr(0, 2) == " [")
-            db.names.back().second.erase(0, 1);
-          db.names.back().second.insert(0,
-                                        " [" + std::string(first + 1, t) + "]");
-          first = t2;
-        }
-      }
+  void printLeft(OutputStream &S) const override {
+    S += "noexcept(";
+    E->print(S);
+    S += ")";
+  }
+};
+
+class DynamicExceptionSpec : public Node {
+  NodeArray Types;
+public:
+  DynamicExceptionSpec(NodeArray Types_)
+      : Node(KDynamicExceptionSpec), Types(Types_) {
+    for (Node *T : Types)
+      ParameterPackSize = std::min(ParameterPackSize, T->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "throw(";
+    Types.printWithComma(S);
+    S += ')';
+  }
+};
+
+class FunctionEncoding final : public Node {
+  const Node *Ret;
+  const Node *Name;
+  NodeArray Params;
+  Qualifiers CVQuals;
+  FunctionRefQual RefQual;
+
+public:
+  FunctionEncoding(Node *Ret_, Node *Name_, NodeArray Params_,
+                   Qualifiers CVQuals_, FunctionRefQual RefQual_)
+      : Node(KFunctionEncoding, NoParameterPack,
+             /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
+             /*FunctionCache=*/Cache::Yes),
+        Ret(Ret_), Name(Name_), Params(Params_), CVQuals(CVQuals_),
+        RefQual(RefQual_) {
+    for (Node *P : Params)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+    if (Ret)
+      ParameterPackSize = std::min(ParameterPackSize, Ret->ParameterPackSize);
+  }
+
+  bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+  bool hasFunctionSlow(OutputStream &) const override { return true; }
+
+  Node *getName() { return const_cast<Node *>(Name); }
+
+  void printLeft(OutputStream &S) const override {
+    if (Ret) {
+      Ret->printLeft(S);
+      if (!Ret->hasRHSComponent(S))
+        S += " ";
+    }
+    Name->print(S);
+  }
+
+  void printRight(OutputStream &S) const override {
+    S += "(";
+    Params.printWithComma(S);
+    S += ")";
+    if (Ret)
+      Ret->printRight(S);
+
+    if (CVQuals & QualConst)
+      S += " const";
+    if (CVQuals & QualVolatile)
+      S += " volatile";
+    if (CVQuals & QualRestrict)
+      S += " restrict";
+
+    if (RefQual == FrefQualLValue)
+      S += " &";
+    else if (RefQual == FrefQualRValue)
+      S += " &&";
+  }
+};
+
+class LiteralOperator : public Node {
+  const Node *OpName;
+
+public:
+  LiteralOperator(Node *OpName_)
+      : Node(KLiteralOperator, OpName_->ParameterPackSize), OpName(OpName_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += "operator\"\" ";
+    OpName->print(S);
+  }
+};
+
+class SpecialName final : public Node {
+  const StringView Special;
+  const Node *Child;
+
+public:
+  SpecialName(StringView Special_, Node* Child_)
+      : Node(KSpecialName, Child_->ParameterPackSize), Special(Special_),
+        Child(Child_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += Special;
+    Child->print(S);
+  }
+};
+
+class CtorVtableSpecialName final : public Node {
+  const Node *FirstType;
+  const Node *SecondType;
+
+public:
+  CtorVtableSpecialName(Node *FirstType_, Node *SecondType_)
+      : Node(KCtorVtableSpecialName, std::min(FirstType_->ParameterPackSize,
+                                              SecondType_->ParameterPackSize)),
+        FirstType(FirstType_), SecondType(SecondType_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += "construction vtable for ";
+    FirstType->print(S);
+    S += "-in-";
+    SecondType->print(S);
+  }
+};
+
+class QualifiedName final : public Node {
+  // qualifier::name
+  const Node *Qualifier;
+  const Node *Name;
+
+public:
+  QualifiedName(Node* Qualifier_, Node* Name_)
+      : Node(KQualifiedName,
+             std::min(Qualifier_->ParameterPackSize, Name_->ParameterPackSize)),
+        Qualifier(Qualifier_), Name(Name_) {}
+
+  StringView getBaseName() const override { return Name->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    Qualifier->print(S);
+    S += "::";
+    Name->print(S);
+  }
+};
+
+class EmptyName : public Node {
+public:
+  EmptyName() : Node(KEmptyName) {}
+  void printLeft(OutputStream &) const override {}
+};
+
+class VectorType final : public Node {
+  const Node *BaseType;
+  const NodeOrString Dimension;
+  const bool IsPixel;
+
+public:
+  VectorType(NodeOrString Dimension_)
+      : Node(KVectorType), BaseType(nullptr), Dimension(Dimension_),
+        IsPixel(true) {
+    if (Dimension.isNode())
+      ParameterPackSize = Dimension.asNode()->ParameterPackSize;
+  }
+  VectorType(Node *BaseType_, NodeOrString Dimension_)
+      : Node(KVectorType, BaseType_->ParameterPackSize), BaseType(BaseType_),
+        Dimension(Dimension_), IsPixel(false) {
+    if (Dimension.isNode())
+      ParameterPackSize =
+          std::min(ParameterPackSize, Dimension.asNode()->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    if (IsPixel) {
+      S += "pixel vector[";
+      S += Dimension.asString();
+      S += "]";
     } else {
-      const char *t = parse_expression(first + 1, last, db);
-      if (t != first + 1 && t != last && *t == '_') {
-        const char *t2 = parse_type(++t, last, db);
-        if (t2 != t) {
-          if (db.names.size() < 2)
-            return first;
-          auto type = std::move(db.names.back());
-          db.names.pop_back();
-          auto expr = std::move(db.names.back());
-          db.names.back().first = std::move(type.first);
-          if (type.second.substr(0, 2) == " [")
-            type.second.erase(0, 1);
-          db.names.back().second =
-              " [" + expr.move_full() + "]" + std::move(type.second);
-          first = t2;
-        }
-      }
+      BaseType->print(S);
+      S += " vector[";
+      if (Dimension.isNode())
+        Dimension.asNode()->print(S);
+      else if (Dimension.isString())
+        S += Dimension.asString();
+      S += "]";
     }
   }
-  return first;
-}
+};
 
-// <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class
-// member access (C++0x)
-//             ::= DT <expression> E  # decltype of an expression (C++0x)
+/// An unexpanded parameter pack (either in the expression or type context). If
+/// this AST is correct, this node will have a ParameterPackExpansion node above
+/// it.
+///
+/// This node is created when some <template-args> are found that apply to an
+/// <encoding>, and is stored in the TemplateParams table. In order for this to
+/// appear in the final AST, it has to referenced via a <template-param> (ie,
+/// T_).
+class ParameterPack final : public Node {
+  NodeArray Data;
+public:
+  ParameterPack(NodeArray Data_)
+      : Node(KParameterPack, static_cast<unsigned>(Data_.size())), Data(Data_) {
+    ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown;
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->ArrayCache == Cache::No;
+        }))
+      ArrayCache = Cache::No;
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->FunctionCache == Cache::No;
+        }))
+      FunctionCache = Cache::No;
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->RHSComponentCache == Cache::No;
+        }))
+      RHSComponentCache = Cache::No;
+  }
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    size_t Idx = S.CurrentPackIndex;
+    return Idx < Data.size() && Data[Idx]->hasRHSComponent(S);
+  }
+  bool hasArraySlow(OutputStream &S) const override {
+    size_t Idx = S.CurrentPackIndex;
+    return Idx < Data.size() && Data[Idx]->hasArray(S);
+  }
+  bool hasFunctionSlow(OutputStream &S) const override {
+    size_t Idx = S.CurrentPackIndex;
+    return Idx < Data.size() && Data[Idx]->hasFunction(S);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    size_t Idx = S.CurrentPackIndex;
+    if (Idx < Data.size())
+      Data[Idx]->printLeft(S);
+  }
+  void printRight(OutputStream &S) const override {
+    size_t Idx = S.CurrentPackIndex;
+    if (Idx < Data.size())
+      Data[Idx]->printRight(S);
+  }
+};
 
-template <class C>
-static const char *parse_decltype(const char *first, const char *last, C &db) {
-  if (last - first >= 4 && first[0] == 'D') {
-    switch (first[1]) {
-    case 't':
-    case 'T': {
-      const char *t = parse_expression(first + 2, last, db);
-      if (t != first + 2 && t != last && *t == 'E') {
-        if (db.names.empty())
-          return first;
-        db.names.back() = "decltype(" + db.names.back().move_full() + ")";
-        first = t + 1;
-      }
-    } break;
-    }
+/// A variadic template argument. This node represents an occurance of
+/// J<something>E in some <template-args>. It isn't itself unexpanded, unless
+/// one of it's Elements is. The parser inserts a ParameterPack into the
+/// TemplateParams table if the <template-args> this pack belongs to apply to an
+/// <encoding>.
+class TemplateArgumentPack final : public Node {
+  NodeArray Elements;
+public:
+  TemplateArgumentPack(NodeArray Elements_)
+      : Node(KTemplateArgumentPack), Elements(Elements_) {
+    for (Node *E : Elements)
+      ParameterPackSize = std::min(E->ParameterPackSize, ParameterPackSize);
   }
-  return first;
-}
 
-// extension:
-// <vector-type>           ::= Dv <positive dimension number> _
-//                                    <extended element type>
-//                         ::= Dv [<dimension expression>] _ <element type>
-// <extended element type> ::= <element type>
-//                         ::= p # AltiVec vector pixel
+  NodeArray getElements() const { return Elements; }
 
-template <class C>
-static const char *parse_vector_type(const char *first, const char *last,
-                                     C &db) {
-  if (last - first > 3 && first[0] == 'D' && first[1] == 'v') {
-    if ('1' <= first[2] && first[2] <= '9') {
-      const char *t = parse_number(first + 2, last);
-      if (t == last || *t != '_')
-        return first;
-      const char *num = first + 2;
-      size_t sz = static_cast<size_t>(t - num);
-      if (++t != last) {
-        if (*t != 'p') {
-          const char *t1 = parse_type(t, last, db);
-          if (t1 != t) {
-            if (db.names.empty())
-              return first;
-            db.names.back().first += " vector[" + std::string(num, sz) + "]";
-            first = t1;
-          }
-        } else {
-          ++t;
-          db.names.push_back("pixel vector[" + std::string(num, sz) + "]");
-          first = t;
-        }
-      }
-    } else {
-      std::string num;
-      const char *t1 = first + 2;
-      if (*t1 != '_') {
-        const char *t = parse_expression(t1, last, db);
-        if (t != t1) {
-          if (db.names.empty())
-            return first;
-          num = db.names.back().move_full();
-          db.names.pop_back();
-          t1 = t;
-        }
-      }
-      if (t1 != last && *t1 == '_' && ++t1 != last) {
-        const char *t = parse_type(t1, last, db);
-        if (t != t1) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first += " vector[" + num + "]";
-          first = t;
-        }
-      }
+  void printLeft(OutputStream &S) const override {
+    Elements.printWithComma(S);
+  }
+};
+
+/// A pack expansion. Below this node, there are some unexpanded ParameterPacks
+/// which each have Child->ParameterPackSize elements.
+class ParameterPackExpansion final : public Node {
+  const Node *Child;
+
+public:
+  ParameterPackExpansion(Node* Child_)
+      : Node(KParameterPackExpansion), Child(Child_) {}
+
+  const Node *getChild() const { return Child; }
+
+  void printLeft(OutputStream &S) const override {
+    unsigned PackSize = Child->ParameterPackSize;
+    if (PackSize == NoParameterPack) {
+      Child->print(S);
+      S += "...";
+      return;
+    }
+
+    SwapAndRestore<unsigned> SavePackIndex(S.CurrentPackIndex, 0);
+    for (unsigned I = 0; I != PackSize; ++I) {
+      if (I != 0)
+        S += ", ";
+      S.CurrentPackIndex = I;
+      Child->print(S);
     }
   }
-  return first;
+};
+
+inline bool Node::isEmptyPackExpansion() const {
+  if (getKind() == KParameterPackExpansion) {
+    auto *AsPack = static_cast<const ParameterPackExpansion *>(this);
+    return AsPack->getChild()->isEmptyPackExpansion();
+  }
+  if (getKind() == KTemplateArgumentPack) {
+    auto *AsTemplateArg = static_cast<const TemplateArgumentPack *>(this);
+    for (Node *E : AsTemplateArg->getElements())
+      if (!E->isEmptyPackExpansion())
+        return false;
+    return true;
+  }
+  return ParameterPackSize == 0;
 }
 
-// <type> ::= <builtin-type>
-//        ::= <function-type>
-//        ::= <class-enum-type>
-//        ::= <array-type>
-//        ::= <pointer-to-member-type>
-//        ::= <template-param>
-//        ::= <template-template-param> <template-args>
-//        ::= <decltype>
-//        ::= <substitution>
-//        ::= <CV-qualifiers> <type>
-//        ::= P <type>        # pointer-to
-//        ::= R <type>        # reference-to
-//        ::= O <type>        # rvalue reference-to (C++0x)
-//        ::= C <type>        # complex pair (C 2000)
-//        ::= G <type>        # imaginary (C 2000)
-//        ::= Dp <type>       # pack expansion (C++0x)
-//        ::= U <source-name> <type>  # vendor extended type qualifier
-// extension := U <objc-name> <objc-type>  # objc-type<identifier>
-// extension := <vector-type> # <vector-type> starts with Dv
-
-// <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 <class C>
-static const char *parse_type(const char *first, const char *last, C &db) {
-  if (first != last) {
-    switch (*first) {
-    case 'r':
-    case 'V':
-    case 'K': {
-      unsigned cv = 0;
-      const char *t = parse_cv_qualifiers(first, last, cv);
-      if (t != first) {
-        bool is_function = *t == 'F';
-        size_t k0 = db.names.size();
-        const char *t1 = parse_type(t, last, db);
-        size_t k1 = db.names.size();
-        if (t1 != t) {
-          if (is_function)
-            db.subs.pop_back();
-          db.subs.emplace_back();
-          for (size_t k = k0; k < k1; ++k) {
-            if (is_function) {
-              auto &name = db.names[k].second;
-              size_t p = name.size();
-
-              if (name[p - 2] == '&' && name[p - 1] == '&')
-                p -= 2;
-              else if (name.back() == '&')
-                p -= 1;
-
-              if (cv & CV_const) {
-                name.insert(p, " const");
-                p += 6;
-              }
-              if (cv & CV_volatile) {
-                name.insert(p, " volatile");
-                p += 9;
-              }
-              if (cv & CV_restrict)
-                name.insert(p, " restrict");
-            } else {
-              if (cv & CV_const)
-                db.names[k].first.append(" const");
-              if (cv & CV_volatile)
-                db.names[k].first.append(" volatile");
-              if (cv & CV_restrict)
-                db.names[k].first.append(" restrict");
-            }
-            db.subs.back().push_back(db.names[k]);
-          }
-          first = t1;
-        }
-      }
-    } break;
-    default: {
-      const char *t = parse_builtin_type(first, last, db);
-      if (t != first) {
-        first = t;
-      } else {
-        switch (*first) {
-        case 'A':
-          t = parse_array_type(first, last, db);
-          if (t != first) {
-            if (db.names.empty())
-              return first;
-            first = t;
-            db.subs.push_back(typename C::sub_type(1, db.names.back()));
-          }
-          break;
-        case 'C':
-          t = parse_type(first + 1, last, db);
-          if (t != first + 1) {
-            if (db.names.empty())
-              return first;
-            db.names.back().first.append(" complex");
-            first = t;
-            db.subs.push_back(typename C::sub_type(1, db.names.back()));
-          }
-          break;
-        case 'F':
-          t = parse_function_type(first, last, db);
-          if (t != first) {
-            if (db.names.empty())
-              return first;
-            first = t;
-            db.subs.push_back(typename C::sub_type(1, db.names.back()));
-          }
-          break;
-        case 'G':
-          t = parse_type(first + 1, last, db);
-          if (t != first + 1) {
-            if (db.names.empty())
-              return first;
-            db.names.back().first.append(" imaginary");
-            first = t;
-            db.subs.push_back(typename C::sub_type(1, db.names.back()));
-          }
-          break;
-        case 'M':
-          t = parse_pointer_to_member_type(first, last, db);
-          if (t != first) {
-            if (db.names.empty())
-              return first;
-            first = t;
-            db.subs.push_back(typename C::sub_type(1, db.names.back()));
-          }
-          break;
-        case 'O': {
-          size_t k0 = db.names.size();
-          t = parse_type(first + 1, last, db);
-          size_t k1 = db.names.size();
-          if (t != first + 1) {
-            db.subs.emplace_back();
-            for (size_t k = k0; k < k1; ++k) {
-              if (db.names[k].second.substr(0, 2) == " [") {
-                db.names[k].first += " (";
-                db.names[k].second.insert(0, ")");
-              } else if (!db.names[k].second.empty() &&
-                         db.names[k].second.front() == '(') {
-                db.names[k].first += "(";
-                db.names[k].second.insert(0, ")");
-              }
-              db.names[k].first.append("&&");
-              db.subs.back().push_back(db.names[k]);
-            }
-            first = t;
-          }
-          break;
-        }
-        case 'P': {
-          size_t k0 = db.names.size();
-          t = parse_type(first + 1, last, db);
-          size_t k1 = db.names.size();
-          if (t != first + 1) {
-            db.subs.emplace_back();
-            for (size_t k = k0; k < k1; ++k) {
-              if (db.names[k].second.substr(0, 2) == " [") {
-                db.names[k].first += " (";
-                db.names[k].second.insert(0, ")");
-              } else if (!db.names[k].second.empty() &&
-                         db.names[k].second.front() == '(') {
-                db.names[k].first += "(";
-                db.names[k].second.insert(0, ")");
-              }
-              if (first[1] != 'U' ||
-                  db.names[k].first.substr(0, 12) != "objc_object<") {
-                db.names[k].first.append("*");
-              } else {
-                db.names[k].first.replace(0, 11, "id");
-              }
-              db.subs.back().push_back(db.names[k]);
-            }
-            first = t;
-          }
-          break;
-        }
-        case 'R': {
-          size_t k0 = db.names.size();
-          t = parse_type(first + 1, last, db);
-          size_t k1 = db.names.size();
-          if (t != first + 1) {
-            db.subs.emplace_back();
-            for (size_t k = k0; k < k1; ++k) {
-              if (db.names[k].second.substr(0, 2) == " [") {
-                db.names[k].first += " (";
-                db.names[k].second.insert(0, ")");
-              } else if (!db.names[k].second.empty() &&
-                         db.names[k].second.front() == '(') {
-                db.names[k].first += "(";
-                db.names[k].second.insert(0, ")");
-              }
-              db.names[k].first.append("&");
-              db.subs.back().push_back(db.names[k]);
-            }
-            first = t;
-          }
-          break;
-        }
-        case 'T': {
-          size_t k0 = db.names.size();
-          t = parse_template_param(first, last, db);
-          size_t k1 = db.names.size();
-          if (t != first) {
-            db.subs.emplace_back();
-            for (size_t k = k0; k < k1; ++k)
-              db.subs.back().push_back(db.names[k]);
-            if (db.try_to_parse_template_args && k1 == k0 + 1) {
-              const char *t1 = parse_template_args(t, last, db);
-              if (t1 != t) {
-                auto args = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first += std::move(args);
-                db.subs.push_back(typename C::sub_type(1, db.names.back()));
-                t = t1;
-              }
-            }
-            first = t;
-          }
-          break;
-        }
-        case 'U':
-          if (first + 1 != last) {
-            t = parse_source_name(first + 1, last, db);
-            if (t != first + 1) {
-              const char *t2 = parse_type(t, last, db);
-              if (t2 != t) {
-                if (db.names.size() < 2)
-                  return first;
-                auto type = db.names.back().move_full();
-                db.names.pop_back();
-                if (db.names.back().first.substr(0, 9) != "objcproto") {
-                  db.names.back() = type + " " + db.names.back().move_full();
-                } else {
-                  auto proto = db.names.back().move_full();
-                  db.names.pop_back();
-                  t = parse_source_name(proto.data() + 9,
-                                        proto.data() + proto.size(), db);
-                  if (t != proto.data() + 9) {
-                    db.names.back() =
-                        type + "<" + db.names.back().move_full() + ">";
-                  } else {
-                    db.names.push_back(type + " " + proto);
-                  }
-                }
-                db.subs.push_back(typename C::sub_type(1, db.names.back()));
-                first = t2;
-              }
-            }
-          }
-          break;
-        case 'S':
-          if (first + 1 != last && first[1] == 't') {
-            t = parse_name(first, last, db);
-            if (t != first) {
-              if (db.names.empty())
-                return first;
-              db.subs.push_back(typename C::sub_type(1, db.names.back()));
-              first = t;
-            }
-          } else {
-            t = parse_substitution(first, last, db);
-            if (t != first) {
-              first = t;
-              // Parsed a substitution.  If the substitution is a
-              //  <template-param> it might be followed by <template-args>.
-              t = parse_template_args(first, last, db);
-              if (t != first) {
-                if (db.names.size() < 2)
-                  return first;
-                auto template_args = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first += template_args;
-                // Need to create substitution for <template-template-param>
-                // <template-args>
-                db.subs.push_back(typename C::sub_type(1, db.names.back()));
-                first = t;
-              }
-            }
-          }
-          break;
-        case 'D':
-          if (first + 1 != last) {
-            switch (first[1]) {
-            case 'p': {
-              size_t k0 = db.names.size();
-              t = parse_type(first + 2, last, db);
-              size_t k1 = db.names.size();
-              if (t != first + 2) {
-                db.subs.emplace_back();
-                for (size_t k = k0; k < k1; ++k)
-                  db.subs.back().push_back(db.names[k]);
-                first = t;
-                return first;
-              }
-              break;
-            }
-            case 't':
-            case 'T':
-              t = parse_decltype(first, last, db);
-              if (t != first) {
-                if (db.names.empty())
-                  return first;
-                db.subs.push_back(typename C::sub_type(1, db.names.back()));
-                first = t;
-                return first;
-              }
-              break;
-            case 'v':
-              t = parse_vector_type(first, last, db);
-              if (t != first) {
-                if (db.names.empty())
-                  return first;
-                db.subs.push_back(typename C::sub_type(1, db.names.back()));
-                first = t;
-                return first;
-              }
-              break;
-            }
-          }
-          LLVM_FALLTHROUGH;
-        default:
-          // must check for builtin-types before class-enum-types to avoid
-          // ambiguities with operator-names
-          t = parse_builtin_type(first, last, db);
-          if (t != first) {
-            first = t;
-          } else {
-            t = parse_name(first, last, db);
-            if (t != first) {
-              if (db.names.empty())
-                return first;
-              db.subs.push_back(typename C::sub_type(1, db.names.back()));
-              first = t;
-            }
-          }
-          break;
-        }
-      }
+class TemplateArgs final : public Node {
+  NodeArray Params;
+
+public:
+  TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {
+    for (Node *P : Params)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+  }
+
+  NodeArray getParams() { return Params; }
+
+  void printLeft(OutputStream &S) const override {
+    S += "<";
+    bool FirstElement = true;
+    for (size_t Idx = 0, E = Params.size(); Idx != E; ++Idx) {
+      if (Params[Idx]->isEmptyPackExpansion())
+        continue;
+      if (!FirstElement)
+        S += ", ";
+      FirstElement = false;
+      Params[Idx]->print(S);
+    }
+    if (S.back() == '>')
+      S += " ";
+    S += ">";
+  }
+};
+
+class NameWithTemplateArgs final : public Node {
+  // name<template_args>
+  Node *Name;
+  Node *TemplateArgs;
+
+public:
+  NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_)
+      : Node(KNameWithTemplateArgs, std::min(Name_->ParameterPackSize,
+                                             TemplateArgs_->ParameterPackSize)),
+        Name(Name_), TemplateArgs(TemplateArgs_) {}
+
+  StringView getBaseName() const override { return Name->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    Name->print(S);
+    TemplateArgs->print(S);
+  }
+};
+
+class GlobalQualifiedName final : public Node {
+  Node *Child;
+
+public:
+  GlobalQualifiedName(Node* Child_)
+      : Node(KGlobalQualifiedName, Child_->ParameterPackSize), Child(Child_) {}
+
+  StringView getBaseName() const override { return Child->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "::";
+    Child->print(S);
+  }
+};
+
+class StdQualifiedName final : public Node {
+  Node *Child;
+
+public:
+  StdQualifiedName(Node *Child_)
+      : Node(KStdQualifiedName, Child_->ParameterPackSize), Child(Child_) {}
+
+  StringView getBaseName() const override { return Child->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "std::";
+    Child->print(S);
+  }
+};
+
+enum class SpecialSubKind {
+  allocator,
+  basic_string,
+  string,
+  istream,
+  ostream,
+  iostream,
+};
+
+class ExpandedSpecialSubstitution final : public Node {
+  SpecialSubKind SSK;
+
+public:
+  ExpandedSpecialSubstitution(SpecialSubKind SSK_)
+      : Node(KExpandedSpecialSubstitution), SSK(SSK_) {}
+
+  StringView getBaseName() const override {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      return StringView("allocator");
+    case SpecialSubKind::basic_string:
+      return StringView("basic_string");
+    case SpecialSubKind::string:
+      return StringView("basic_string");
+    case SpecialSubKind::istream:
+      return StringView("basic_istream");
+    case SpecialSubKind::ostream:
+      return StringView("basic_ostream");
+    case SpecialSubKind::iostream:
+      return StringView("basic_iostream");
+    }
+    LLVM_BUILTIN_UNREACHABLE;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      S += "std::basic_string<char, std::char_traits<char>, "
+           "std::allocator<char> >";
+      break;
+    case SpecialSubKind::basic_string:
+    case SpecialSubKind::string:
+      S += "std::basic_string<char, std::char_traits<char>, "
+           "std::allocator<char> >";
+      break;
+    case SpecialSubKind::istream:
+      S += "std::basic_istream<char, std::char_traits<char> >";
+      break;
+    case SpecialSubKind::ostream:
+      S += "std::basic_ostream<char, std::char_traits<char> >";
+      break;
+    case SpecialSubKind::iostream:
+      S += "std::basic_iostream<char, std::char_traits<char> >";
       break;
-    }
     }
   }
-  return first;
-}
+};
 
-//   <operator-name>
-//                   ::= aa    # &&
-//                   ::= ad    # & (unary)
-//                   ::= an    # &
-//                   ::= aN    # &=
-//                   ::= aS    # =
-//                   ::= cl    # ()
-//                   ::= cm    # ,
-//                   ::= co    # ~
-//                   ::= cv <type>    # (cast)
-//                   ::= da    # delete[]
-//                   ::= de    # * (unary)
-//                   ::= dl    # delete
-//                   ::= dv    # /
-//                   ::= dV    # /=
-//                   ::= eo    # ^
-//                   ::= eO    # ^=
-//                   ::= eq    # ==
-//                   ::= ge    # >=
-//                   ::= gt    # >
-//                   ::= ix    # []
-//                   ::= le    # <=
-//                   ::= li <source-name>  # operator ""
-//                   ::= ls    # <<
-//                   ::= lS    # <<=
-//                   ::= lt    # <
-//                   ::= mi    # -
-//                   ::= mI    # -=
-//                   ::= ml    # *
-//                   ::= mL    # *=
-//                   ::= mm    # -- (postfix in <expression> context)
-//                   ::= na    # new[]
-//                   ::= ne    # !=
-//                   ::= ng    # - (unary)
-//                   ::= nt    # !
-//                   ::= nw    # new
-//                   ::= oo    # ||
-//                   ::= or    # |
-//                   ::= oR    # |=
-//                   ::= pm    # ->*
-//                   ::= pl    # +
-//                   ::= pL    # +=
-//                   ::= pp    # ++ (postfix in <expression> context)
-//                   ::= ps    # + (unary)
-//                   ::= pt    # ->
-//                   ::= qu    # ?
-//                   ::= rm    # %
-//                   ::= rM    # %=
-//                   ::= rs    # >>
-//                   ::= rS    # >>=
-//                   ::= v <digit> <source-name>        # vendor extended
-//                   operator
+class SpecialSubstitution final : public Node {
+public:
+  SpecialSubKind SSK;
 
-template <class C>
-static const char *parse_operator_name(const char *first, const char *last,
-                                       C &db) {
-  if (last - first >= 2) {
-    switch (first[0]) {
-    case 'a':
-      switch (first[1]) {
-      case 'a':
-        db.names.push_back("operator&&");
-        first += 2;
-        break;
-      case 'd':
-      case 'n':
-        db.names.push_back("operator&");
-        first += 2;
-        break;
-      case 'N':
-        db.names.push_back("operator&=");
-        first += 2;
-        break;
-      case 'S':
-        db.names.push_back("operator=");
-        first += 2;
-        break;
-      }
-      break;
-    case 'c':
-      switch (first[1]) {
-      case 'l':
-        db.names.push_back("operator()");
-        first += 2;
-        break;
-      case 'm':
-        db.names.push_back("operator,");
-        first += 2;
-        break;
-      case 'o':
-        db.names.push_back("operator~");
-        first += 2;
-        break;
-      case 'v': {
-        bool try_to_parse_template_args = db.try_to_parse_template_args;
-        db.try_to_parse_template_args = false;
-        const char *t = parse_type(first + 2, last, db);
-        db.try_to_parse_template_args = try_to_parse_template_args;
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "operator ");
-          db.parsed_ctor_dtor_cv = true;
-          first = t;
-        }
-      } break;
-      }
+  SpecialSubstitution(SpecialSubKind SSK_)
+      : Node(KSpecialSubstitution), SSK(SSK_) {}
+
+  StringView getBaseName() const override {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      return StringView("allocator");
+    case SpecialSubKind::basic_string:
+      return StringView("basic_string");
+    case SpecialSubKind::string:
+      return StringView("string");
+    case SpecialSubKind::istream:
+      return StringView("istream");
+    case SpecialSubKind::ostream:
+      return StringView("ostream");
+    case SpecialSubKind::iostream:
+      return StringView("iostream");
+    }
+    LLVM_BUILTIN_UNREACHABLE;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      S += "std::allocator";
+      break;
+    case SpecialSubKind::basic_string:
+      S += "std::basic_string";
+      break;
+    case SpecialSubKind::string:
+      S += "std::string";
       break;
-    case 'd':
-      switch (first[1]) {
-      case 'a':
-        db.names.push_back("operator delete[]");
-        first += 2;
-        break;
-      case 'e':
-        db.names.push_back("operator*");
-        first += 2;
-        break;
-      case 'l':
-        db.names.push_back("operator delete");
-        first += 2;
-        break;
-      case 'v':
-        db.names.push_back("operator/");
-        first += 2;
-        break;
-      case 'V':
-        db.names.push_back("operator/=");
-        first += 2;
-        break;
-      }
+    case SpecialSubKind::istream:
+      S += "std::istream";
       break;
-    case 'e':
-      switch (first[1]) {
-      case 'o':
-        db.names.push_back("operator^");
-        first += 2;
-        break;
-      case 'O':
-        db.names.push_back("operator^=");
-        first += 2;
-        break;
-      case 'q':
-        db.names.push_back("operator==");
-        first += 2;
-        break;
-      }
+    case SpecialSubKind::ostream:
+      S += "std::ostream";
       break;
-    case 'g':
-      switch (first[1]) {
-      case 'e':
-        db.names.push_back("operator>=");
-        first += 2;
-        break;
-      case 't':
-        db.names.push_back("operator>");
-        first += 2;
-        break;
-      }
+    case SpecialSubKind::iostream:
+      S += "std::iostream";
       break;
+    }
+  }
+};
+
+class CtorDtorName final : public Node {
+  const Node *Basename;
+  const bool IsDtor;
+
+public:
+  CtorDtorName(Node *Basename_, bool IsDtor_)
+      : Node(KCtorDtorName, Basename_->ParameterPackSize),
+        Basename(Basename_), IsDtor(IsDtor_) {}
+
+  void printLeft(OutputStream &S) const override {
+    if (IsDtor)
+      S += "~";
+    S += Basename->getBaseName();
+  }
+};
+
+class DtorName : public Node {
+  const Node *Base;
+
+public:
+  DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {
+    ParameterPackSize = Base->ParameterPackSize;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "~";
+    Base->printLeft(S);
+  }
+};
+
+class UnnamedTypeName : public Node {
+  const StringView Count;
+
+public:
+  UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += "'unnamed";
+    S += Count;
+    S += "\'";
+  }
+};
+
+class ClosureTypeName : public Node {
+  NodeArray Params;
+  StringView Count;
+
+public:
+  ClosureTypeName(NodeArray Params_, StringView Count_)
+      : Node(KClosureTypeName), Params(Params_), Count(Count_) {
+    for (Node *P : Params)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "\'lambda";
+    S += Count;
+    S += "\'(";
+    Params.printWithComma(S);
+    S += ")";
+  }
+};
+
+class StructuredBindingName : public Node {
+  NodeArray Bindings;
+public:
+  StructuredBindingName(NodeArray Bindings_)
+      : Node(KStructuredBindingName), Bindings(Bindings_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += '[';
+    Bindings.printWithComma(S);
+    S += ']';
+  }
+};
+
+// -- Expression Nodes --
+
+struct Expr : public Node {
+  Expr(Kind K = KExpr) : Node(K) {}
+};
+
+class BinaryExpr : public Expr {
+  const Node *LHS;
+  const StringView InfixOperator;
+  const Node *RHS;
+
+public:
+  BinaryExpr(Node *LHS_, StringView InfixOperator_, Node *RHS_)
+      : LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {
+    ParameterPackSize =
+      std::min(LHS->ParameterPackSize, RHS->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    // might be a template argument expression, then we need to disambiguate
+    // with parens.
+    if (InfixOperator == ">")
+      S += "(";
+
+    S += "(";
+    LHS->print(S);
+    S += ") ";
+    S += InfixOperator;
+    S += " (";
+    RHS->print(S);
+    S += ")";
+
+    if (InfixOperator == ">")
+      S += ")";
+  }
+};
+
+class ArraySubscriptExpr : public Expr {
+  const Node *Op1;
+  const Node *Op2;
+
+public:
+  ArraySubscriptExpr(Node *Op1_, Node *Op2_) : Op1(Op1_), Op2(Op2_) {
+    ParameterPackSize =
+      std::min(Op1->ParameterPackSize, Op2->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Op1->print(S);
+    S += ")[";
+    Op2->print(S);
+    S += "]";
+  }
+};
+
+class PostfixExpr : public Expr {
+  const Node *Child;
+  const StringView Operand;
+
+public:
+  PostfixExpr(Node *Child_, StringView Operand_)
+      : Child(Child_), Operand(Operand_) {
+    ParameterPackSize = Child->ParameterPackSize;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Child->print(S);
+    S += ")";
+    S += Operand;
+  }
+};
+
+class ConditionalExpr : public Expr {
+  const Node *Cond;
+  const Node *Then;
+  const Node *Else;
+
+public:
+  ConditionalExpr(Node *Cond_, Node *Then_, Node *Else_)
+      : Cond(Cond_), Then(Then_), Else(Else_) {
+    ParameterPackSize =
+        std::min(Cond->ParameterPackSize,
+                 std::min(Then->ParameterPackSize, Else->ParameterPackSize));
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Cond->print(S);
+    S += ") ? (";
+    Then->print(S);
+    S += ") : (";
+    Else->print(S);
+    S += ")";
+  }
+};
+
+class MemberExpr : public Expr {
+  const Node *LHS;
+  const StringView Kind;
+  const Node *RHS;
+
+public:
+  MemberExpr(Node *LHS_, StringView Kind_, Node *RHS_)
+      : LHS(LHS_), Kind(Kind_), RHS(RHS_) {
+    ParameterPackSize =
+      std::min(LHS->ParameterPackSize, RHS->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    LHS->print(S);
+    S += Kind;
+    RHS->print(S);
+  }
+};
+
+class EnclosingExpr : public Expr {
+  const StringView Prefix;
+  const Node *Infix;
+  const StringView Postfix;
+
+public:
+  EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_)
+      : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {
+    ParameterPackSize = Infix->ParameterPackSize;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += Prefix;
+    Infix->print(S);
+    S += Postfix;
+  }
+};
+
+class CastExpr : public Expr {
+  // cast_kind<to>(from)
+  const StringView CastKind;
+  const Node *To;
+  const Node *From;
+
+public:
+  CastExpr(StringView CastKind_, Node *To_, Node *From_)
+      : CastKind(CastKind_), To(To_), From(From_) {
+    ParameterPackSize =
+      std::min(To->ParameterPackSize, From->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += CastKind;
+    S += "<";
+    To->printLeft(S);
+    S += ">(";
+    From->printLeft(S);
+    S += ")";
+  }
+};
+
+class SizeofParamPackExpr : public Expr {
+  Node *Pack;
+
+public:
+  SizeofParamPackExpr(Node *Pack_) : Pack(Pack_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += "sizeof...(";
+    ParameterPackExpansion PPE(Pack);
+    PPE.printLeft(S);
+    S += ")";
+  }
+};
+
+class CallExpr : public Expr {
+  const Node *Callee;
+  NodeArray Args;
+
+public:
+  CallExpr(Node *Callee_, NodeArray Args_) : Callee(Callee_), Args(Args_) {
+    for (Node *P : Args)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+    ParameterPackSize = std::min(ParameterPackSize, Callee->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    Callee->print(S);
+    S += "(";
+    Args.printWithComma(S);
+    S += ")";
+  }
+};
+
+class NewExpr : public Expr {
+  // new (expr_list) type(init_list)
+  NodeArray ExprList;
+  Node *Type;
+  NodeArray InitList;
+  bool IsGlobal; // ::operator new ?
+  bool IsArray;  // new[] ?
+public:
+  NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
+          bool IsArray_)
+      : ExprList(ExprList_), Type(Type_), InitList(InitList_),
+        IsGlobal(IsGlobal_), IsArray(IsArray_) {
+    for (Node *E : ExprList)
+      ParameterPackSize = std::min(ParameterPackSize, E->ParameterPackSize);
+    for (Node *I : InitList)
+      ParameterPackSize = std::min(ParameterPackSize, I->ParameterPackSize);
+    if (Type)
+      ParameterPackSize = std::min(ParameterPackSize, Type->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    if (IsGlobal)
+      S += "::operator ";
+    S += "new";
+    if (IsArray)
+      S += "[]";
+    S += ' ';
+    if (!ExprList.empty()) {
+      S += "(";
+      ExprList.printWithComma(S);
+      S += ")";
+    }
+    Type->print(S);
+    if (!InitList.empty()) {
+      S += "(";
+      InitList.printWithComma(S);
+      S += ")";
+    }
+
+  }
+};
+
+class DeleteExpr : public Expr {
+  Node *Op;
+  bool IsGlobal;
+  bool IsArray;
+
+public:
+  DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_)
+      : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {
+    ParameterPackSize = Op->ParameterPackSize;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    if (IsGlobal)
+      S += "::";
+    S += "delete";
+    if (IsArray)
+      S += "[] ";
+    Op->print(S);
+  }
+};
+
+class PrefixExpr : public Expr {
+  StringView Prefix;
+  Node *Child;
+
+public:
+  PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {
+    ParameterPackSize = Child->ParameterPackSize;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += Prefix;
+    S += "(";
+    Child->print(S);
+    S += ")";
+  }
+};
+
+class FunctionParam : public Expr {
+  StringView Number;
+
+public:
+  FunctionParam(StringView Number_) : Number(Number_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += "fp";
+    S += Number;
+  }
+};
+
+class ConversionExpr : public Expr {
+  const Node *Type;
+  NodeArray Expressions;
+
+public:
+  ConversionExpr(const Node *Type_, NodeArray Expressions_)
+      : Type(Type_), Expressions(Expressions_) {
+    for (Node *E : Expressions)
+      ParameterPackSize = std::min(ParameterPackSize, E->ParameterPackSize);
+    ParameterPackSize = std::min(ParameterPackSize, Type->ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Type->print(S);
+    S += ")(";
+    Expressions.printWithComma(S);
+    S += ")";
+  }
+};
+
+class InitListExpr : public Expr {
+  Node *Ty;
+  NodeArray Inits;
+public:
+  InitListExpr(Node *Ty_, NodeArray Inits_)
+      : Ty(Ty_), Inits(Inits_) {
+    if (Ty)
+      ParameterPackSize = Ty->ParameterPackSize;
+    for (Node *I : Inits)
+      ParameterPackSize = std::min(I->ParameterPackSize, ParameterPackSize);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    if (Ty)
+      Ty->print(S);
+    S += '{';
+    Inits.printWithComma(S);
+    S += '}';
+  }
+};
+
+class BracedExpr : public Expr {
+  Node *Elem;
+  Node *Init;
+  bool IsArray;
+public:
+  BracedExpr(Node *Elem_, Node *Init_, bool IsArray_)
+      : Expr(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {}
+
+  void printLeft(OutputStream &S) const override {
+    if (IsArray) {
+      S += '[';
+      Elem->print(S);
+      S += ']';
+    } else {
+      S += '.';
+      Elem->print(S);
+    }
+    if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+      S += " = ";
+    Init->print(S);
+  }
+};
+
+class BracedRangeExpr : public Expr {
+  Node *First;
+  Node *Last;
+  Node *Init;
+public:
+  BracedRangeExpr(Node *First_, Node *Last_, Node *Init_)
+      : Expr(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += '[';
+    First->print(S);
+    S += " ... ";
+    Last->print(S);
+    S += ']';
+    if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+      S += " = ";
+    Init->print(S);
+  }
+};
+
+class ThrowExpr : public Expr {
+  const Node *Op;
+
+public:
+  ThrowExpr(Node *Op_) : Op(Op_) {
+    ParameterPackSize = Op->ParameterPackSize;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "throw ";
+    Op->print(S);
+  }
+};
+
+class BoolExpr : public Expr {
+  bool Value;
+
+public:
+  BoolExpr(bool Value_) : Value(Value_) {}
+
+  void printLeft(OutputStream &S) const override {
+    S += Value ? StringView("true") : StringView("false");
+  }
+};
+
+class IntegerCastExpr : public Expr {
+  // ty(integer)
+  Node *Ty;
+  StringView Integer;
+
+public:
+  IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {
+    ParameterPackSize = Ty->ParameterPackSize;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Ty->print(S);
+    S += ")";
+    S += Integer;
+  }
+};
+
+class IntegerExpr : public Expr {
+  StringView Type;
+  StringView Value;
+
+public:
+  IntegerExpr(StringView Type_, StringView Value_) : Type(Type_), Value(Value_) {}
+
+  void printLeft(OutputStream &S) const override {
+    if (Type.size() > 3) {
+      S += "(";
+      S += Type;
+      S += ")";
+    }
+
+    if (Value[0] == 'n') {
+      S += "-";
+      S += Value.dropFront(1);
+    } else
+      S += Value;
+
+    if (Type.size() <= 3)
+      S += Type;
+  }
+};
+
+template <class Float> struct FloatData;
+
+template <class Float> class FloatExpr : public Expr {
+  const StringView Contents;
+
+public:
+  FloatExpr(StringView Contents_) : Contents(Contents_) {}
+
+  void printLeft(OutputStream &s) const override {
+    const char *first = Contents.begin();
+    const char *last = Contents.end() + 1;
+
+    const size_t N = FloatData<Float>::mangled_size;
+    if (static_cast<std::size_t>(last - first) > N) {
+      last = first + N;
+      union {
+        Float value;
+        char buf[sizeof(Float)];
+      };
+      const char *t = first;
+      char *e = buf;
+      for (; t != last; ++t, ++e) {
+        unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
+                                  : static_cast<unsigned>(*t - 'a' + 10);
+        ++t;
+        unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
+                                  : static_cast<unsigned>(*t - 'a' + 10);
+        *e = static_cast<char>((d1 << 4) + d0);
+      }
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+      std::reverse(buf, e);
+#endif
+      char num[FloatData<Float>::max_demangled_size] = {0};
+      int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value);
+      s += StringView(num, num + n);
+    }
+  }
+};
+
+class BumpPointerAllocator {
+  struct BlockMeta {
+    BlockMeta* Next;
+    size_t Current;
+  };
+
+  static constexpr size_t AllocSize = 4096;
+  static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
+
+  alignas(16) char InitialBuffer[AllocSize];
+  BlockMeta* BlockList = nullptr;
+
+  void grow() {
+    char* NewMeta = new char[AllocSize];
+    BlockList = new (NewMeta) BlockMeta{BlockList, 0};
+  }
+
+  void* allocateMassive(size_t NBytes) {
+    NBytes += sizeof(BlockMeta);
+    BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(new char[NBytes]);
+    BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
+    return static_cast<void*>(NewMeta + 1);
+  }
+
+public:
+  BumpPointerAllocator()
+      : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
+
+  void* allocate(size_t N) {
+    N = (N + 15u) & ~15u;
+    if (N + BlockList->Current >= UsableAllocSize) {
+      if (N > UsableAllocSize)
+        return allocateMassive(N);
+      grow();
+    }
+    BlockList->Current += N;
+    return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
+                              BlockList->Current - N);
+  }
+
+  ~BumpPointerAllocator() {
+    while (BlockList) {
+      BlockMeta* Tmp = BlockList;
+      BlockList = BlockList->Next;
+      if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
+        delete[] reinterpret_cast<char*>(Tmp);
+    }
+  }
+};
+
+template <class T, size_t N>
+class PODSmallVector {
+  static_assert(std::is_pod<T>::value,
+                "T is required to be a plain old data type");
+
+  T* First;
+  T* Last;
+  T* Cap;
+  T Inline[N];
+
+  bool isInline() const { return First == Inline; }
+
+  void clearInline() {
+    First = Inline;
+    Last = Inline;
+    Cap = Inline + N;
+  }
+
+  void reserve(size_t NewCap) {
+    size_t S = size();
+    if (isInline()) {
+      auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));
+      std::copy(First, Last, Tmp);
+      First = Tmp;
+    } else
+      First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));
+    Last = First + S;
+    Cap = First + NewCap;
+  }
+
+public:
+  PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
+
+  PODSmallVector(const PODSmallVector&) = delete;
+  PODSmallVector& operator=(const PODSmallVector&) = delete;
+
+  PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {
+    if (Other.isInline()) {
+      std::copy(Other.begin(), Other.end(), First);
+      Last = First + Other.size();
+      Other.clear();
+      return;
+    }
+
+    First = Other.First;
+    Last = Other.Last;
+    Cap = Other.Cap;
+    Other.clearInline();
+  }
+
+  PODSmallVector& operator=(PODSmallVector&& Other) {
+    if (Other.isInline()) {
+      if (!isInline()) {
+        std::free(First);
+        clearInline();
+      }
+      std::copy(Other.begin(), Other.end(), First);
+      Last = First + Other.size();
+      Other.clear();
+      return *this;
+    }
+
+    if (isInline()) {
+      First = Other.First;
+      Last = Other.Last;
+      Cap = Other.Cap;
+      Other.clearInline();
+      return *this;
+    }
+
+    std::swap(First, Other.First);
+    std::swap(Last, Other.Last);
+    std::swap(Cap, Other.Cap);
+    Other.clear();
+    return *this;
+  }
+
+  void push_back(const T& Elem) {
+    if (Last == Cap)
+      reserve(size() * 2);
+    *Last++ = Elem;
+  }
+
+  void pop_back() {
+    assert(Last != First && "Popping empty vector!");
+    --Last;
+  }
+
+  void dropBack(size_t Index) {
+    assert(Index <= size() && "dropBack() can't expand!");
+    Last = First + Index;
+  }
+
+  T* begin() { return First; }
+  T* end() { return Last; }
+
+  bool empty() const { return First == Last; }
+  size_t size() const { return static_cast<size_t>(Last - First); }
+  T& back() {
+    assert(Last != First && "Calling back() on empty vector!");
+    return *(Last - 1);
+  }
+  T& operator[](size_t Index) {
+    assert(Index < size() && "Invalid access!");
+    return *(begin() + Index);
+  }
+  void clear() { Last = First; }
+
+  ~PODSmallVector() {
+    if (!isInline())
+      std::free(First);
+  }
+};
+
+struct Db {
+  const char *First;
+  const char *Last;
+
+  // Name stack, this is used by the parser to hold temporary names that were
+  // parsed. The parser colapses multiple names into new nodes to construct
+  // the AST. Once the parser is finished, names.size() == 1.
+  PODSmallVector<Node *, 32> Names;
+
+  // Substitution table. Itanium supports name substitutions as a means of
+  // compression. The string "S42_" refers to the 44nd entry (base-36) in this
+  // table.
+  PODSmallVector<Node *, 32> Subs;
+
+  // Template parameter table. Like the above, but referenced like "T42_".
+  // This has a smaller size compared to Subs and Names because it can be
+  // stored on the stack.
+  PODSmallVector<Node *, 8> TemplateParams;
+
+  unsigned EncodingDepth = 0;
+  bool TagTemplates = true;
+  bool FixForwardReferences = false;
+  bool TryToParseTemplateArgs = true;
+  bool ParsingLambdaParams = false;
+
+  BumpPointerAllocator ASTAllocator;
+
+  Db(const char *First_, const char *Last_) : First(First_), Last(Last_) {}
+
+  template <class T, class... Args> T *make(Args &&... args) {
+    return new (ASTAllocator.allocate(sizeof(T)))
+        T(std::forward<Args>(args)...);
+  }
+
+  template <class It> NodeArray makeNodeArray(It begin, It end) {
+    size_t sz = static_cast<size_t>(end - begin);
+    void *mem = ASTAllocator.allocate(sizeof(Node *) * sz);
+    Node **data = new (mem) Node *[sz];
+    std::copy(begin, end, data);
+    return NodeArray(data, sz);
+  }
+
+  NodeArray popTrailingNodeArray(size_t FromPosition) {
+    assert(FromPosition <= Names.size());
+    NodeArray res =
+        makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
+    Names.dropBack(FromPosition);
+    return res;
+  }
+
+  bool consumeIf(StringView S) {
+    if (StringView(First, Last).startsWith(S)) {
+      First += S.size();
+      return true;
+    }
+    return false;
+  }
+
+  bool consumeIf(char C) {
+    if (First != Last && *First == C) {
+      ++First;
+      return true;
+    }
+    return false;
+  }
+
+  char consume() { return First != Last ? *First++ : '\0'; }
+
+  char look(unsigned Lookahead = 0) {
+    if (static_cast<size_t>(Last - First) <= Lookahead)
+      return '\0';
+    return First[Lookahead];
+  }
+
+  size_t numLeft() const { return static_cast<size_t>(Last - First); }
+
+  StringView parseNumber(bool AllowNegative = false);
+  Qualifiers parseCVQualifiers();
+  bool parsePositiveInteger(size_t *Out);
+  StringView parseBareSourceName();
+
+  bool parseSeqId(size_t *Out);
+  Node *parseSubstitution();
+  Node *parseTemplateParam();
+  Node *parseTemplateArgs();
+  Node *parseTemplateArg();
+
+  /// Parse the <expr> production.
+  Node *parseExpr();
+  Node *parsePrefixExpr(StringView Kind);
+  Node *parseBinaryExpr(StringView Kind);
+  Node *parseIntegerLiteral(StringView Lit);
+  Node *parseExprPrimary();
+  template <class Float> Node *parseFloatingLiteral();
+  Node *parseFunctionParam();
+  Node *parseNewExpr();
+  Node *parseConversionExpr();
+  Node *parseBracedExpr();
+
+  /// Parse the <type> production.
+  Node *parseType();
+  Node *parseFunctionType();
+  Node *parseVectorType();
+  Node *parseDecltype();
+  Node *parseArrayType();
+  Node *parsePointerToMemberType();
+  Node *parseClassEnumType();
+  Node *parseQualifiedType();
+
+  Node *parseEncoding();
+  bool parseCallOffset();
+  Node *parseSpecialName();
+
+  /// Holds some extra information about a <name> that is being parsed. This
+  /// information is only pertinent if the <name> refers to an <encoding>.
+  struct NameState {
+    bool CtorDtorConversion = false;
+    bool EndsWithTemplateArgs = false;
+    Qualifiers CVQualifiers = QualNone;
+    FunctionRefQual ReferenceQualifier = FrefQualNone;
+  };
+
+  /// Parse the <name> production>
+  Node *parseName(NameState *State = nullptr);
+  Node *parseLocalName(NameState *State);
+  Node *parseOperatorName(NameState *State);
+  Node *parseUnqualifiedName(NameState *State);
+  Node *parseUnnamedTypeName(NameState *State);
+  Node *parseSourceName(NameState *State);
+  Node *parseUnscopedName(NameState *State);
+  Node *parseNestedName(NameState *State);
+  Node *parseCtorDtorName(Node *&SoFar, NameState *State);
+
+  Node *parseAbiTags(Node *N);
+
+  /// Parse the <unresolved-name> production.
+  Node *parseUnresolvedName();
+  Node *parseSimpleId();
+  Node *parseBaseUnresolvedName();
+  Node *parseUnresolvedType();
+  Node *parseDestructorName();
+
+  /// Top-level entry point into the parser.
+  Node *parse();
+};
+
+const char* parse_discriminator(const char* first, const char* last);
+
+// <name> ::= <nested-name> // N
+//        ::= <local-name> # See Scope Encoding below  // Z
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <unscoped-name>
+//
+// <unscoped-template-name> ::= <unscoped-name>
+//                          ::= <substitution>
+Node *Db::parseName(NameState *State) {
+  consumeIf('L'); // extension
+
+  if (look() == 'N')
+    return parseNestedName(State);
+  if (look() == 'Z')
+    return parseLocalName(State);
+
+  //        ::= <unscoped-template-name> <template-args>
+  if (look() == 'S' && look(1) != 't') {
+    Node *S = parseSubstitution();
+    if (S == nullptr)
+      return nullptr;
+    if (look() != 'I')
+      return nullptr;
+    Node *TA = parseTemplateArgs();
+    if (TA == nullptr)
+      return nullptr;
+    if (State) State->EndsWithTemplateArgs = true;
+    return make<NameWithTemplateArgs>(S, TA);
+  }
+
+  Node *N = parseUnscopedName(State);
+  if (N == nullptr)
+    return nullptr;
+  //        ::= <unscoped-template-name> <template-args>
+  if (look() == 'I') {
+    Subs.push_back(N);
+    Node *TA = parseTemplateArgs();
+    if (TA == nullptr)
+      return nullptr;
+    if (State) State->EndsWithTemplateArgs = true;
+    return make<NameWithTemplateArgs>(N, TA);
+  }
+  //        ::= <unscoped-name>
+  return N;
+}
+
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+//              := Z <function encoding> E s [<discriminator>]
+//              := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+Node *Db::parseLocalName(NameState *State) {
+  if (!consumeIf('Z'))
+    return nullptr;
+  Node *Encoding = parseEncoding();
+  if (Encoding == nullptr || !consumeIf('E'))
+    return nullptr;
+
+  if (consumeIf('s')) {
+    First = parse_discriminator(First, Last);
+    return make<QualifiedName>(Encoding, make<NameType>("string literal"));
+  }
+
+  if (consumeIf('d')) {
+    parseNumber(true);
+    if (!consumeIf('_'))
+      return nullptr;
+    Node *N = parseName(State);
+    if (N == nullptr)
+      return nullptr;
+    return make<QualifiedName>(Encoding, N);
+  }
+
+  Node *Entity = parseName(State);
+  if (Entity == nullptr)
+    return nullptr;
+  First = parse_discriminator(First, Last);
+  return make<QualifiedName>(Encoding, Entity);
+}
+
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>   # ::std::
+// extension       ::= StL<unqualified-name>
+Node *Db::parseUnscopedName(NameState *State) {
+ if (consumeIf("StL") || consumeIf("St")) {
+   Node *R = parseUnqualifiedName(State);
+   if (R == nullptr)
+     return nullptr;
+   return make<StdQualifiedName>(R);
+ }
+ return parseUnqualifiedName(State);
+}
+
+// <unqualified-name> ::= <operator-name> [abi-tags]
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <unnamed-type-name>
+//                    ::= DC <source-name>+ E      # structured binding declaration
+Node *Db::parseUnqualifiedName(NameState *State) {
+ // <ctor-dtor-name>s are special-cased in parseNestedName().
+ Node *Result;
+ if (look() == 'U')
+   Result = parseUnnamedTypeName(State);
+ else if (look() >= '1' && look() <= '9')
+   Result = parseSourceName(State);
+ else if (consumeIf("DC")) {
+   size_t BindingsBegin = Names.size();
+   do {
+     Node *Binding = parseSourceName(State);
+     if (Binding == nullptr)
+       return nullptr;
+     Names.push_back(Binding);
+   } while (!consumeIf('E'));
+   Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));
+ } else
+   Result = parseOperatorName(State);
+ if (Result != nullptr)
+   Result = parseAbiTags(Result);
+ return Result;
+}
+
+// <unnamed-type-name> ::= Ut [<nonnegative number>] _
+//                     ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters
+Node *Db::parseUnnamedTypeName(NameState *) {
+  if (consumeIf("Ut")) {
+    StringView Count = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<UnnamedTypeName>(Count);
+  }
+  if (consumeIf("Ul")) {
+    NodeArray Params;
+    SwapAndRestore<bool> SwapParams(ParsingLambdaParams, true);
+    if (!consumeIf("vE")) {
+      size_t ParamsBegin = Names.size();
+      do {
+        Node *P = parseType();
+        if (P == nullptr)
+          return nullptr;
+        Names.push_back(P);
+      } while (!consumeIf('E'));
+      Params = popTrailingNodeArray(ParamsBegin);
+    }
+    StringView Count = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<ClosureTypeName>(Params, Count);
+  }
+  return nullptr;
+}
+
+// <source-name> ::= <positive length number> <identifier>
+Node *Db::parseSourceName(NameState *) {
+  size_t Length = 0;
+  if (parsePositiveInteger(&Length))
+    return nullptr;
+  if (numLeft() < Length || Length == 0)
+    return nullptr;
+  StringView Name(First, First + Length);
+  First += Length;
+  if (Name.startsWith("_GLOBAL__N"))
+    return make<NameType>("(anonymous namespace)");
+  return make<NameType>(Name);
+}
+
+//   <operator-name> ::= aa    # &&
+//                   ::= ad    # & (unary)
+//                   ::= an    # &
+//                   ::= aN    # &=
+//                   ::= aS    # =
+//                   ::= cl    # ()
+//                   ::= cm    # ,
+//                   ::= co    # ~
+//                   ::= cv <type>    # (cast)
+//                   ::= da    # delete[]
+//                   ::= de    # * (unary)
+//                   ::= dl    # delete
+//                   ::= dv    # /
+//                   ::= dV    # /=
+//                   ::= eo    # ^
+//                   ::= eO    # ^=
+//                   ::= eq    # ==
+//                   ::= ge    # >=
+//                   ::= gt    # >
+//                   ::= ix    # []
+//                   ::= le    # <=
+//                   ::= li <source-name>  # operator ""
+//                   ::= ls    # <<
+//                   ::= lS    # <<=
+//                   ::= lt    # <
+//                   ::= mi    # -
+//                   ::= mI    # -=
+//                   ::= ml    # *
+//                   ::= mL    # *=
+//                   ::= mm    # -- (postfix in <expression> context)
+//                   ::= na    # new[]
+//                   ::= ne    # !=
+//                   ::= ng    # - (unary)
+//                   ::= nt    # !
+//                   ::= nw    # new
+//                   ::= oo    # ||
+//                   ::= or    # |
+//                   ::= oR    # |=
+//                   ::= pm    # ->*
+//                   ::= pl    # +
+//                   ::= pL    # +=
+//                   ::= pp    # ++ (postfix in <expression> context)
+//                   ::= ps    # + (unary)
+//                   ::= pt    # ->
+//                   ::= qu    # ?
+//                   ::= rm    # %
+//                   ::= rM    # %=
+//                   ::= rs    # >>
+//                   ::= rS    # >>=
+//                   ::= ss    # <=> C++2a
+//                   ::= v <digit> <source-name>        # vendor extended operator
+Node *Db::parseOperatorName(NameState *State) {
+  switch (look()) {
+  case 'a':
+    switch (look(1)) {
+    case 'a':
+      First += 2;
+      return make<NameType>("operator&&");
+    case 'd':
+    case 'n':
+      First += 2;
+      return make<NameType>("operator&");
+    case 'N':
+      First += 2;
+      return make<NameType>("operator&=");
+    case 'S':
+      First += 2;
+      return make<NameType>("operator=");
+    }
+    return nullptr;
+  case 'c':
+    switch (look(1)) {
+    case 'l':
+      First += 2;
+      return make<NameType>("operator()");
+    case 'm':
+      First += 2;
+      return make<NameType>("operator,");
+    case 'o':
+      First += 2;
+      return make<NameType>("operator~");
+    //                   ::= cv <type>    # (cast)
+    case 'v': {
+      SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      if (State) State->CtorDtorConversion = true;
+      return make<ConversionOperatorType>(Ty);
+    }
+    }
+    return nullptr;
+  case 'd':
+    switch (look(1)) {
+    case 'a':
+      First += 2;
+      return make<NameType>("operator delete[]");
+    case 'e':
+      First += 2;
+      return make<NameType>("operator*");
+    case 'l':
+      First += 2;
+      return make<NameType>("operator delete");
+    case 'v':
+      First += 2;
+      return make<NameType>("operator/");
+    case 'V':
+      First += 2;
+      return make<NameType>("operator/=");
+    }
+    return nullptr;
+  case 'e':
+    switch (look(1)) {
+    case 'o':
+      First += 2;
+      return make<NameType>("operator^");
+    case 'O':
+      First += 2;
+      return make<NameType>("operator^=");
+    case 'q':
+      First += 2;
+      return make<NameType>("operator==");
+    }
+    return nullptr;
+  case 'g':
+    switch (look(1)) {
+    case 'e':
+      First += 2;
+      return make<NameType>("operator>=");
+    case 't':
+      First += 2;
+      return make<NameType>("operator>");
+    }
+    return nullptr;
+  case 'i':
+    if (look(1) == 'x') {
+      First += 2;
+      return make<NameType>("operator[]");
+    }
+    return nullptr;
+  case 'l':
+    switch (look(1)) {
+    case 'e':
+      First += 2;
+      return make<NameType>("operator<=");
+    //                   ::= li <source-name>  # operator ""
+    case 'i': {
+      First += 2;
+      Node *SN = parseSourceName(State);
+      if (SN == nullptr)
+        return nullptr;
+      return make<LiteralOperator>(SN);
+    }
+    case 's':
+      First += 2;
+      return make<NameType>("operator<<");
+    case 'S':
+      First += 2;
+      return make<NameType>("operator<<=");
+    case 't':
+      First += 2;
+      return make<NameType>("operator<");
+    }
+    return nullptr;
+  case 'm':
+    switch (look(1)) {
     case 'i':
-      if (first[1] == 'x') {
-        db.names.push_back("operator[]");
-        first += 2;
-      }
-      break;
+      First += 2;
+      return make<NameType>("operator-");
+    case 'I':
+      First += 2;
+      return make<NameType>("operator-=");
     case 'l':
-      switch (first[1]) {
-      case 'e':
-        db.names.push_back("operator<=");
-        first += 2;
-        break;
-      case 'i': {
-        const char *t = parse_source_name(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "operator\"\" ");
-          first = t;
-        }
-      } break;
-      case 's':
-        db.names.push_back("operator<<");
-        first += 2;
-        break;
-      case 'S':
-        db.names.push_back("operator<<=");
-        first += 2;
-        break;
-      case 't':
-        db.names.push_back("operator<");
-        first += 2;
-        break;
-      }
-      break;
+      First += 2;
+      return make<NameType>("operator*");
+    case 'L':
+      First += 2;
+      return make<NameType>("operator*=");
     case 'm':
-      switch (first[1]) {
-      case 'i':
-        db.names.push_back("operator-");
-        first += 2;
-        break;
-      case 'I':
-        db.names.push_back("operator-=");
-        first += 2;
-        break;
-      case 'l':
-        db.names.push_back("operator*");
-        first += 2;
-        break;
-      case 'L':
-        db.names.push_back("operator*=");
-        first += 2;
-        break;
-      case 'm':
-        db.names.push_back("operator--");
-        first += 2;
-        break;
-      }
-      break;
-    case 'n':
-      switch (first[1]) {
-      case 'a':
-        db.names.push_back("operator new[]");
-        first += 2;
-        break;
-      case 'e':
-        db.names.push_back("operator!=");
-        first += 2;
-        break;
-      case 'g':
-        db.names.push_back("operator-");
-        first += 2;
-        break;
-      case 't':
-        db.names.push_back("operator!");
-        first += 2;
-        break;
-      case 'w':
-        db.names.push_back("operator new");
-        first += 2;
-        break;
-      }
-      break;
+      First += 2;
+      return make<NameType>("operator--");
+    }
+    return nullptr;
+  case 'n':
+    switch (look(1)) {
+    case 'a':
+      First += 2;
+      return make<NameType>("operator new[]");
+    case 'e':
+      First += 2;
+      return make<NameType>("operator!=");
+    case 'g':
+      First += 2;
+      return make<NameType>("operator-");
+    case 't':
+      First += 2;
+      return make<NameType>("operator!");
+    case 'w':
+      First += 2;
+      return make<NameType>("operator new");
+    }
+    return nullptr;
+  case 'o':
+    switch (look(1)) {
     case 'o':
-      switch (first[1]) {
-      case 'o':
-        db.names.push_back("operator||");
-        first += 2;
-        break;
-      case 'r':
-        db.names.push_back("operator|");
-        first += 2;
-        break;
-      case 'R':
-        db.names.push_back("operator|=");
-        first += 2;
-        break;
-      }
-      break;
+      First += 2;
+      return make<NameType>("operator||");
+    case 'r':
+      First += 2;
+      return make<NameType>("operator|");
+    case 'R':
+      First += 2;
+      return make<NameType>("operator|=");
+    }
+    return nullptr;
+  case 'p':
+    switch (look(1)) {
+    case 'm':
+      First += 2;
+      return make<NameType>("operator->*");
+    case 'l':
+      First += 2;
+      return make<NameType>("operator+");
+    case 'L':
+      First += 2;
+      return make<NameType>("operator+=");
     case 'p':
-      switch (first[1]) {
-      case 'm':
-        db.names.push_back("operator->*");
-        first += 2;
-        break;
-      case 'l':
-        db.names.push_back("operator+");
-        first += 2;
-        break;
-      case 'L':
-        db.names.push_back("operator+=");
-        first += 2;
-        break;
-      case 'p':
-        db.names.push_back("operator++");
-        first += 2;
-        break;
-      case 's':
-        db.names.push_back("operator+");
-        first += 2;
-        break;
-      case 't':
-        db.names.push_back("operator->");
-        first += 2;
-        break;
-      }
+      First += 2;
+      return make<NameType>("operator++");
+    case 's':
+      First += 2;
+      return make<NameType>("operator+");
+    case 't':
+      First += 2;
+      return make<NameType>("operator->");
+    }
+    return nullptr;
+  case 'q':
+    if (look(1) == 'u') {
+      First += 2;
+      return make<NameType>("operator?");
+    }
+    return nullptr;
+  case 'r':
+    switch (look(1)) {
+    case 'm':
+      First += 2;
+      return make<NameType>("operator%");
+    case 'M':
+      First += 2;
+      return make<NameType>("operator%=");
+    case 's':
+      First += 2;
+      return make<NameType>("operator>>");
+    case 'S':
+      First += 2;
+      return make<NameType>("operator>>=");
+    }
+    return nullptr;
+  case 's':
+    if (look(1) == 's') {
+      First += 2;
+      return make<NameType>("operator<=>");
+    }
+    return nullptr;
+  // ::= v <digit> <source-name>        # vendor extended operator
+  case 'v':
+    if (std::isdigit(look(1))) {
+      First += 2;
+      Node *SN = parseSourceName(State);
+      if (SN == nullptr)
+        return nullptr;
+      return make<ConversionOperatorType>(SN);
+    }
+    return nullptr;
+  }
+  return nullptr;
+}
+
+// <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, NameState *State) {
+  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;
-    case 'q':
-      if (first[1] == 'u') {
-        db.names.push_back("operator?");
-        first += 2;
-      }
+    }
+  }
+
+  if (consumeIf('C')) {
+    bool IsInherited = consumeIf('I');
+    if (look() != '1' && look() != '2' && look() != '3' && look() != '5')
+      return nullptr;
+    ++First;
+    if (State) State->CtorDtorConversion = true;
+    if (IsInherited) {
+      if (parseName() == nullptr)
+        return nullptr;
+    }
+    return make<CtorDtorName>(SoFar, false);
+  }
+
+  if (look() == 'D' &&
+      (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) {
+    First += 2;
+    if (State) State->CtorDtorConversion = 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(NameState *State) {
+  if (!consumeIf('N'))
+    return nullptr;
+
+  Qualifiers CVTmp = parseCVQualifiers();
+  if (State) State->CVQualifiers = CVTmp;
+
+  if (consumeIf('O')) {
+    if (State) State->ReferenceQualifier = FrefQualRValue;
+  } else if (consumeIf('R')) {
+    if (State) State->ReferenceQualifier = FrefQualLValue;
+  } else
+    if (State) State->ReferenceQualifier = FrefQualNone;
+
+  Node *SoFar = nullptr;
+  auto PushComponent = [&](Node *Comp) {
+    if (SoFar) SoFar = make<QualifiedName>(SoFar, Comp);
+    else       SoFar = Comp;
+    if (State) State->EndsWithTemplateArgs = false;
+  };
+
+  if (consumeIf("St"))
+    SoFar = make<NameType>("std");
+
+  while (!consumeIf('E')) {
+    consumeIf('L'); // extension
+
+    //          ::= <template-param>
+    if (look() == 'T') {
+      Node *TP = parseTemplateParam();
+      if (TP == nullptr)
+        return nullptr;
+      PushComponent(TP);
+      Subs.push_back(SoFar);
+      continue;
+    }
+
+    //          ::= <template-prefix> <template-args>
+    if (look() == 'I') {
+      Node *TA = parseTemplateArgs();
+      if (TA == nullptr || SoFar == nullptr)
+        return nullptr;
+      SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+      if (State) State->EndsWithTemplateArgs = true;
+      Subs.push_back(SoFar);
+      continue;
+    }
+
+    //          ::= <decltype>
+    if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
+      Node *DT = parseDecltype();
+      if (DT == nullptr)
+        return nullptr;
+      PushComponent(DT);
+      Subs.push_back(SoFar);
+      continue;
+    }
+
+    //          ::= <substitution>
+    if (look() == 'S' && look(1) != 't') {
+      Node *S = parseSubstitution();
+      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' && look(1) != 'C')) {
+      if (SoFar == nullptr)
+        return nullptr;
+      Node *CtorDtor = parseCtorDtorName(SoFar, State);
+      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 = parseUnqualifiedName(State);
+    if (N == nullptr)
+      return nullptr;
+    PushComponent(N);
+    Subs.push_back(SoFar);
+  }
+
+  if (SoFar == nullptr || Subs.empty())
+    return nullptr;
+
+  Subs.pop_back();
+  return SoFar;
+}
+
+// <simple-id> ::= <source-name> [ <template-args> ]
+Node *Db::parseSimpleId() {
+  Node *SN = parseSourceName(/*NameState=*/nullptr);
+  if (SN == nullptr)
+    return nullptr;
+  if (look() == 'I') {
+    Node *TA = parseTemplateArgs();
+    if (TA == nullptr)
+      return nullptr;
+    return make<NameWithTemplateArgs>(SN, TA);
+  }
+  return SN;
+}
+
+// <destructor-name> ::= <unresolved-type>  # e.g., ~T or ~decltype(f())
+//                   ::= <simple-id>        # e.g., ~A<2*N>
+Node *Db::parseDestructorName() {
+  Node *Result;
+  if (std::isdigit(look()))
+    Result = parseSimpleId();
+  else
+    Result = parseUnresolvedType();
+  if (Result == nullptr)
+    return nullptr;
+  return make<DtorName>(Result);
+}
+
+// <unresolved-type> ::= <template-param>
+//                   ::= <decltype>
+//                   ::= <substitution>
+Node *Db::parseUnresolvedType() {
+  if (look() == 'T') {
+    Node *TP = parseTemplateParam();
+    if (TP == nullptr)
+      return nullptr;
+    Subs.push_back(TP);
+    return TP;
+  }
+  if (look() == 'D') {
+    Node *DT = parseDecltype();
+    if (DT == nullptr)
+      return nullptr;
+    Subs.push_back(DT);
+    return DT;
+  }
+  return parseSubstitution();
+}
+
+// <base-unresolved-name> ::= <simple-id>                                # unresolved name
+//          extension     ::= <operator-name>                            # unresolved operator-function-id
+//          extension     ::= <operator-name> <template-args>            # unresolved operator template-id
+//                        ::= on <operator-name>                         # unresolved operator-function-id
+//                        ::= on <operator-name> <template-args>         # unresolved operator template-id
+//                        ::= dn <destructor-name>                       # destructor or pseudo-destructor;
+//                                                                         # e.g. ~X or ~X<N-1>
+Node *Db::parseBaseUnresolvedName() {
+  if (std::isdigit(look()))
+    return parseSimpleId();
+
+  if (consumeIf("dn"))
+    return parseDestructorName();
+
+  consumeIf("on");
+
+  Node *Oper = parseOperatorName(/*NameState=*/nullptr);
+  if (Oper == nullptr)
+    return nullptr;
+  if (look() == 'I') {
+    Node *TA = parseTemplateArgs();
+    if (TA == nullptr)
+      return nullptr;
+    return make<NameWithTemplateArgs>(Oper, TA);
+  }
+  return Oper;
+}
+
+// <unresolved-name>
+//  extension        ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+//                   ::= [gs] <base-unresolved-name>                     # x or (with "gs") ::x
+//                   ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>  
+//                                                                       # A::x, N::y, A<T>::z; "gs" means leading "::"
+//                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x / decltype(p)::x
+//  extension        ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+//                                                                       # T::N::x /decltype(p)::N::x
+//  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name>
+//
+// <unresolved-qualifier-level> ::= <simple-id>
+Node *Db::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();
+    if (SoFar == nullptr)
+      return nullptr;
+
+    if (look() == 'I') {
+      Node *TA = parseTemplateArgs();
+      if (TA == nullptr)
+        return nullptr;
+      SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+    }
+
+    while (!consumeIf('E')) {
+      Node *Qual = parseSimpleId();
+      if (Qual == nullptr)
+        return nullptr;
+      SoFar = make<QualifiedName>(SoFar, Qual);
+    }
+
+    Node *Base = parseBaseUnresolvedName();
+    if (Base == nullptr)
+      return nullptr;
+    return make<QualifiedName>(SoFar, Base);
+  }
+
+  bool Global = consumeIf("gs");
+
+  // [gs] <base-unresolved-name>                     # x or (with "gs") ::x
+  if (!consumeIf("sr")) {
+    SoFar = parseBaseUnresolvedName();
+    if (SoFar == nullptr)
+      return nullptr;
+    if (Global)
+      SoFar = make<GlobalQualifiedName>(SoFar);
+    return SoFar;
+  }
+
+  // [gs] sr <unresolved-qualifier-level>+ E   <base-unresolved-name>  
+  if (std::isdigit(look())) {
+    do {
+      Node *Qual = parseSimpleId();
+      if (Qual == nullptr)
+        return nullptr;
+      if (SoFar)
+        SoFar = make<QualifiedName>(SoFar, Qual);
+      else if (Global)
+        SoFar = make<GlobalQualifiedName>(Qual);
+      else
+        SoFar = Qual;
+    } while (!consumeIf('E'));
+  }
+  //      sr <unresolved-type>                 <base-unresolved-name>
+  //      sr <unresolved-type> <template-args> <base-unresolved-name>
+  else {
+    SoFar = parseUnresolvedType();
+    if (SoFar == nullptr)
+      return nullptr;
+
+    if (look() == 'I') {
+      Node *TA = parseTemplateArgs();
+      if (TA == nullptr)
+        return nullptr;
+      SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+    }
+  }
+
+  assert(SoFar != nullptr);
+
+  Node *Base = parseBaseUnresolvedName();
+  if (Base == nullptr)
+    return nullptr;
+  return make<QualifiedName>(SoFar, Base);
+}
+
+// <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;
+  if (AllowNegative)
+    consumeIf('n');
+  if (numLeft() == 0 || !std::isdigit(*First))
+    return StringView();
+  while (numLeft() != 0 && std::isdigit(*First))
+    ++First;
+  return StringView(Tmp, First);
+}
+
+// <positive length number> ::= [0-9]*
+bool Db::parsePositiveInteger(size_t *Out) {
+  *Out = 0;
+  if (look() < '0' || look() > '9')
+    return true;
+  while (look() >= '0' && look() <= '9') {
+    *Out *= 10;
+    *Out += static_cast<size_t>(consume() - '0');
+  }
+  return false;
+}
+
+StringView Db::parseBareSourceName() {
+  size_t Int = 0;
+  if (parsePositiveInteger(&Int) || numLeft() < Int)
+    return StringView();
+  StringView R(First, First + Int);
+  First += Int;
+  return R;
+}
+
+// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
+//
+// <exception-spec> ::= Do                # non-throwing exception-specification (e.g., noexcept, throw())
+//                  ::= DO <expression> E # computed (instantiation-dependent) noexcept
+//                  ::= Dw <type>+ E      # dynamic exception specification with instantiation-dependent types
+//
+// <ref-qualifier> ::= R                   # & ref-qualifier
+// <ref-qualifier> ::= O                   # && ref-qualifier
+Node *Db::parseFunctionType() {
+  Qualifiers CVQuals = parseCVQualifiers();
+
+  Node *ExceptionSpec = nullptr;
+  if (consumeIf("Do")) {
+    ExceptionSpec = make<NameType>("noexcept");
+  } else if (consumeIf("DO")) {
+    Node *E = parseExpr();
+    if (E == nullptr || !consumeIf('E'))
+      return nullptr;
+    ExceptionSpec = make<NoexceptSpec>(E);
+  } else if (consumeIf("Dw")) {
+    size_t SpecsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *T = parseType();
+      if (T == nullptr)
+        return nullptr;
+      Names.push_back(T);
+    }
+    ExceptionSpec =
+      make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));
+  }
+
+  consumeIf("Dx"); // transaction safe
+
+  if (!consumeIf('F'))
+    return nullptr;
+  consumeIf('Y'); // extern "C"
+  Node *ReturnType = parseType();
+  if (ReturnType == nullptr)
+    return nullptr;
+
+  FunctionRefQual ReferenceQualifier = FrefQualNone;
+  size_t ParamsBegin = Names.size();
+  while (true) {
+    if (consumeIf('E'))
       break;
-    case 'r':
-      switch (first[1]) {
-      case 'm':
-        db.names.push_back("operator%");
-        first += 2;
-        break;
-      case 'M':
-        db.names.push_back("operator%=");
-        first += 2;
-        break;
-      case 's':
-        db.names.push_back("operator>>");
-        first += 2;
-        break;
-      case 'S':
-        db.names.push_back("operator>>=");
-        first += 2;
-        break;
-      }
+    if (consumeIf('v'))
+      continue;
+    if (consumeIf("RE")) {
+      ReferenceQualifier = FrefQualLValue;
       break;
-    case 'v':
-      if (std::isdigit(first[1])) {
-        const char *t = parse_source_name(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "operator ");
-          first = t;
-        }
-      }
+    }
+    if (consumeIf("OE")) {
+      ReferenceQualifier = FrefQualRValue;
       break;
     }
+    Node *T = parseType();
+    if (T == nullptr)
+      return nullptr;
+    Names.push_back(T);
   }
-  return first;
+
+  NodeArray Params = popTrailingNodeArray(ParamsBegin);
+  return make<FunctionType>(ReturnType, Params, CVQuals,
+                            ReferenceQualifier, ExceptionSpec);
 }
 
-template <class C>
-static const char *parse_integer_literal(const char *first, const char *last,
-                                         const std::string &lit, C &db) {
-  const char *t = parse_number(first, last);
-  if (t != first && t != last && *t == 'E') {
-    if (lit.size() > 3)
-      db.names.push_back("(" + lit + ")");
-    else
-      db.names.emplace_back();
-    if (*first == 'n') {
-      db.names.back().first += '-';
-      ++first;
-    }
-    db.names.back().first.append(first, t);
-    if (lit.size() <= 3)
-      db.names.back().first += lit;
-    first = t + 1;
-  }
-  return first;
-}
-
-// <expr-primary> ::= L <type> <value number> E                          #
-// integer literal
-//                ::= L <type> <value float> E                           #
-//                floating literal
-//                ::= L <string type> E                                  #
-//                string literal
-//                ::= L <nullptr type> E                                 #
-//                nullptr literal (i.e., "LDnE")
-//                ::= L <type> <real-part float> _ <imag-part float> E   #
-//                complex floating point literal (C 2000)
-//                ::= L <mangled-name> E                                 #
-//                external name
-
-template <class C>
-static const char *parse_expr_primary(const char *first, const char *last,
-                                      C &db) {
-  if (last - first >= 4 && *first == 'L') {
-    switch (first[1]) {
-    case 'w': {
-      const char *t = parse_integer_literal(first + 2, last, "wchar_t", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'b':
-      if (first[3] == 'E') {
-        switch (first[2]) {
-        case '0':
-          db.names.push_back("false");
-          first += 4;
-          break;
-        case '1':
-          db.names.push_back("true");
-          first += 4;
-          break;
-        }
-      }
-      break;
-    case 'c': {
-      const char *t = parse_integer_literal(first + 2, last, "char", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'a': {
-      const char *t = parse_integer_literal(first + 2, last, "signed char", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'h': {
-      const char *t =
-          parse_integer_literal(first + 2, last, "unsigned char", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 's': {
-      const char *t = parse_integer_literal(first + 2, last, "short", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 't': {
-      const char *t =
-          parse_integer_literal(first + 2, last, "unsigned short", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'i': {
-      const char *t = parse_integer_literal(first + 2, last, "", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'j': {
-      const char *t = parse_integer_literal(first + 2, last, "u", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'l': {
-      const char *t = parse_integer_literal(first + 2, last, "l", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'm': {
-      const char *t = parse_integer_literal(first + 2, last, "ul", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'x': {
-      const char *t = parse_integer_literal(first + 2, last, "ll", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'y': {
-      const char *t = parse_integer_literal(first + 2, last, "ull", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'n': {
-      const char *t = parse_integer_literal(first + 2, last, "__int128", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'o': {
-      const char *t =
-          parse_integer_literal(first + 2, last, "unsigned __int128", db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'f': {
-      const char *t = parse_floating_number<float>(first + 2, last, db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'd': {
-      const char *t = parse_floating_number<double>(first + 2, last, db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case 'e': {
-      const char *t = parse_floating_number<long double>(first + 2, last, db);
-      if (t != first + 2)
-        first = t;
-    } break;
-    case '_':
-      if (first[2] == 'Z') {
-        const char *t = parse_encoding(first + 3, last, db);
-        if (t != first + 3 && t != last && *t == 'E')
-          first = t + 1;
-      }
-      break;
-    case 'T':
-      // Invalid mangled name per
-      //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+// extension:
+// <vector-type>           ::= Dv <positive dimension number> _ <extended element type>
+//                         ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+//                         ::= p # AltiVec vector pixel
+Node *Db::parseVectorType() {
+  if (!consumeIf("Dv"))
+    return nullptr;
+  if (look() >= '1' && look() <= '9') {
+    StringView DimensionNumber = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    if (consumeIf('p'))
+      return make<VectorType>(DimensionNumber);
+    Node *ElemType = parseType();
+    if (ElemType == nullptr)
+      return nullptr;
+    return make<VectorType>(ElemType, DimensionNumber);
+  }
+
+  if (!consumeIf('_')) {
+    Node *DimExpr = parseExpr();
+    if (!DimExpr)
+      return nullptr;
+    if (!consumeIf('_'))
+      return nullptr;
+    Node *ElemType = parseType();
+    if (!ElemType)
+      return nullptr;
+    return make<VectorType>(ElemType, DimExpr);
+  }
+  Node *ElemType = parseType();
+  if (!ElemType)
+    return nullptr;
+  return make<VectorType>(ElemType, StringView());
+}
+
+// <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x)
+//             ::= DT <expression> E  # decltype of an expression (C++0x)
+Node *Db::parseDecltype() {
+  if (!consumeIf('D'))
+    return nullptr;
+  if (!consumeIf('t') && !consumeIf('T'))
+    return nullptr;
+  Node *E = parseExpr();
+  if (E == nullptr)
+    return nullptr;
+  if (!consumeIf('E'))
+    return nullptr;
+  return make<EnclosingExpr>("decltype(", E, ")");
+}
+
+// <array-type> ::= A <positive dimension number> _ <element type>
+//              ::= A [<dimension expression>] _ <element type>
+Node *Db::parseArrayType() {
+  if (!consumeIf('A'))
+    return nullptr;
+
+  if (std::isdigit(look())) {
+    StringView Dimension = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    Node *Ty = parseType();
+    if (Ty == nullptr)
+      return nullptr;
+    return make<ArrayType>(Ty, Dimension);
+  }
+
+  if (!consumeIf('_')) {
+    Node *DimExpr = parseExpr();
+    if (DimExpr == nullptr)
+      return nullptr;
+    if (!consumeIf('_'))
+      return nullptr;
+    Node *ElementType = parseType();
+    if (ElementType == nullptr)
+      return nullptr;
+    return make<ArrayType>(ElementType, DimExpr);
+  }
+
+  Node *Ty = parseType();
+  if (Ty == nullptr)
+    return nullptr;
+  return make<ArrayType>(Ty);
+}
+
+// <pointer-to-member-type> ::= M <class type> <member type>
+Node *Db::parsePointerToMemberType() {
+  if (!consumeIf('M'))
+    return nullptr;
+  Node *ClassType = parseType();
+  if (ClassType == nullptr)
+    return nullptr;
+  Node *MemberType = parseType();
+  if (MemberType == nullptr)
+    return nullptr;
+  return make<PointerToMemberType>(ClassType, MemberType);
+}
+
+// <class-enum-type> ::= <name>     # non-dependent type name, dependent type name, or dependent typename-specifier
+//                   ::= 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'
+Node *Db::parseClassEnumType() {
+  StringView ElabSpef;
+  if (consumeIf("Ts"))
+    ElabSpef = "struct";
+  else if (consumeIf("Tu"))
+    ElabSpef = "union";
+  else if (consumeIf("Te"))
+    ElabSpef = "enum";
+
+  Node *Name = parseName();
+  if (Name == nullptr)
+    return nullptr;
+
+  if (!ElabSpef.empty())
+    return make<ElaboratedTypeSpefType>(ElabSpef, Name);
+
+  return Name;
+}
+
+// <qualified-type>     ::= <qualifiers> <type>
+// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers>
+// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier
+Node *Db::parseQualifiedType() {
+  if (consumeIf('U')) {
+    StringView Qual = parseBareSourceName();
+    if (Qual.empty())
+      return nullptr;
+
+    // FIXME parse the optional <template-args> here!
+
+    // extension            ::= U <objc-name> <objc-type>  # objc-type<identifier>
+    if (Qual.startsWith("objcproto")) {
+      StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
+      StringView Proto;
+      {
+        SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()),
+                                     SaveLast(Last, ProtoSourceName.end());
+        Proto = parseBareSourceName();
+      }
+      if (Proto.empty())
+        return nullptr;
+      Node *Child = parseQualifiedType();
+      if (Child == nullptr)
+        return nullptr;
+      return make<ObjCProtoName>(Child, Proto);
+    }
+
+    Node *Child = parseQualifiedType();
+    if (Child == nullptr)
+      return nullptr;
+    return make<VendorExtQualType>(Child, Qual);
+  }
+
+  Qualifiers Quals = parseCVQualifiers();
+  Node *Ty = parseType();
+  if (Ty == nullptr)
+    return nullptr;
+  if (Quals != QualNone)
+    Ty = make<QualType>(Ty, Quals);
+  return Ty;
+}
+
+// <type>      ::= <builtin-type>
+//             ::= <qualified-type>
+//             ::= <function-type>
+//             ::= <class-enum-type>
+//             ::= <array-type>
+//             ::= <pointer-to-member-type>
+//             ::= <template-param>
+//             ::= <template-template-param> <template-args>
+//             ::= <decltype>
+//             ::= P <type>        # pointer
+//             ::= R <type>        # l-value reference
+//             ::= O <type>        # r-value reference (C++11)
+//             ::= C <type>        # complex pair (C99)
+//             ::= G <type>        # imaginary (C99)
+//             ::= <substitution>  # See Compression below
+// extension   ::= U <objc-name> <objc-type>  # objc-type<identifier>
+// extension   ::= <vector-type> # <vector-type> starts with Dv
+//
+// <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>
+Node *Db::parseType() {
+  Node *Result = nullptr;
+
+  switch (look()) {
+  //             ::= <qualified-type>
+  case 'r':
+  case 'V':
+  case 'K': {
+    unsigned AfterQuals = 0;
+    if (look(AfterQuals) == 'r') ++AfterQuals;
+    if (look(AfterQuals) == 'V') ++AfterQuals;
+    if (look(AfterQuals) == 'K') ++AfterQuals;
+
+    if (look(AfterQuals) == 'F' ||
+        (look(AfterQuals) == 'D' &&
+         (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' ||
+          look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) {
+      Result = parseFunctionType();
+      break;
+    }
+    LLVM_FALLTHROUGH;
+  }
+  case 'U': {
+    Result = parseQualifiedType();
+    break;
+  }
+  // <builtin-type> ::= v    # void
+  case 'v':
+    ++First;
+    return make<NameType>("void");
+  //                ::= w    # wchar_t
+  case 'w':
+    ++First;
+    return make<NameType>("wchar_t");
+  //                ::= b    # bool
+  case 'b':
+    ++First;
+    return make<NameType>("bool");
+  //                ::= c    # char
+  case 'c':
+    ++First;
+    return make<NameType>("char");
+  //                ::= a    # signed char
+  case 'a':
+    ++First;
+    return make<NameType>("signed char");
+  //                ::= h    # unsigned char
+  case 'h':
+    ++First;
+    return make<NameType>("unsigned char");
+  //                ::= s    # short
+  case 's':
+    ++First;
+    return make<NameType>("short");
+  //                ::= t    # unsigned short
+  case 't':
+    ++First;
+    return make<NameType>("unsigned short");
+  //                ::= i    # int
+  case 'i':
+    ++First;
+    return make<NameType>("int");
+  //                ::= j    # unsigned int
+  case 'j':
+    ++First;
+    return make<NameType>("unsigned int");
+  //                ::= l    # long
+  case 'l':
+    ++First;
+    return make<NameType>("long");
+  //                ::= m    # unsigned long
+  case 'm':
+    ++First;
+    return make<NameType>("unsigned long");
+  //                ::= x    # long long, __int64
+  case 'x':
+    ++First;
+    return make<NameType>("long long");
+  //                ::= y    # unsigned long long, __int64
+  case 'y':
+    ++First;
+    return make<NameType>("unsigned long long");
+  //                ::= n    # __int128
+  case 'n':
+    ++First;
+    return make<NameType>("__int128");
+  //                ::= o    # unsigned __int128
+  case 'o':
+    ++First;
+    return make<NameType>("unsigned __int128");
+  //                ::= f    # float
+  case 'f':
+    ++First;
+    return make<NameType>("float");
+  //                ::= d    # double
+  case 'd':
+    ++First;
+    return make<NameType>("double");
+  //                ::= e    # long double, __float80
+  case 'e':
+    ++First;
+    return make<NameType>("long double");
+  //                ::= g    # __float128
+  case 'g':
+    ++First;
+    return make<NameType>("__float128");
+  //                ::= z    # ellipsis
+  case 'z':
+    ++First;
+    return make<NameType>("...");
+
+  // <builtin-type> ::= u <source-name>    # vendor extended type
+  case 'u': {
+    ++First;
+    StringView Res = parseBareSourceName();
+    if (Res.empty())
+      return nullptr;
+    return make<NameType>(Res);
+  }
+  case 'D':
+    switch (look(1)) {
+    //                ::= Dd   # IEEE 754r decimal floating point (64 bits)
+    case 'd':
+      First += 2;
+      return make<NameType>("decimal64");
+    //                ::= De   # IEEE 754r decimal floating point (128 bits)
+    case 'e':
+      First += 2;
+      return make<NameType>("decimal128");
+    //                ::= Df   # IEEE 754r decimal floating point (32 bits)
+    case 'f':
+      First += 2;
+      return make<NameType>("decimal32");
+    //                ::= Dh   # IEEE 754r half-precision floating point (16 bits)
+    case 'h':
+      First += 2;
+      return make<NameType>("decimal16");
+    //                ::= Di   # char32_t
+    case 'i':
+      First += 2;
+      return make<NameType>("char32_t");
+    //                ::= Ds   # char16_t
+    case 's':
+      First += 2;
+      return make<NameType>("char16_t");
+    //                ::= Da   # auto (in dependent new-expressions)
+    case 'a':
+      First += 2;
+      return make<NameType>("auto");
+    //                ::= Dc   # decltype(auto)
+    case 'c':
+      First += 2;
+      return make<NameType>("decltype(auto)");
+    //                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr))
+    case 'n':
+      First += 2;
+      return make<NameType>("std::nullptr_t");
+
+    //             ::= <decltype>
+    case 't':
+    case 'T': {
+      Result = parseDecltype();
       break;
-    default: {
-      // might be named type
-      const char *t = parse_type(first + 1, last, db);
-      if (t != first + 1 && t != last) {
-        if (*t != 'E') {
-          const char *n = t;
-          for (; n != last && isdigit(*n); ++n)
-            ;
-          if (n != t && n != last && *n == 'E') {
-            if (db.names.empty())
-              return first;
-            db.names.back() =
-                "(" + db.names.back().move_full() + ")" + std::string(t, n);
-            first = n + 1;
-            break;
-          }
-        } else {
-          first = t + 1;
-          break;
-        }
-      }
-    }
     }
-  }
-  return first;
-}
-
-static std::string base_name(std::string &s) {
-  if (s.empty())
-    return s;
-  if (s == "std::string") {
-    s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> "
-        ">";
-    return "basic_string";
-  }
-  if (s == "std::istream") {
-    s = "std::basic_istream<char, std::char_traits<char> >";
-    return "basic_istream";
-  }
-  if (s == "std::ostream") {
-    s = "std::basic_ostream<char, std::char_traits<char> >";
-    return "basic_ostream";
-  }
-  if (s == "std::iostream") {
-    s = "std::basic_iostream<char, std::char_traits<char> >";
-    return "basic_iostream";
-  }
-  const char *const pf = s.data();
-  const char *pe = pf + s.size();
-  if (pe[-1] == '>') {
-    unsigned c = 1;
-    while (true) {
-      if (--pe == pf)
-        return std::string();
-      if (pe[-1] == '<') {
-        if (--c == 0) {
-          --pe;
-          break;
-        }
-      } else if (pe[-1] == '>')
-        ++c;
+    // extension   ::= <vector-type> # <vector-type> starts with Dv
+    case 'v': {
+      Result = parseVectorType();
+      break;
     }
-  }
-  if (pe - pf <= 1)
-    return std::string();
-  const char *p0 = pe - 1;
-  for (; p0 != pf; --p0) {
-    if (*p0 == ':') {
-      ++p0;
+    //           ::= Dp <type>       # pack expansion (C++0x)
+    case 'p': {
+      First += 2;
+      Node *Child = parseType();
+      if (!Child)
+        return nullptr;
+      Result = make<ParameterPackExpansion>(Child);
       break;
     }
-    if (!isalpha(*p0) && !isdigit(*p0) && *p0 != '_') {
-      return std::string();
+    // Exception specifier on a function type.
+    case 'o':
+    case 'O':
+    case 'w':
+    // Transaction safe function type.
+    case 'x':
+      Result = parseFunctionType();
+      break;
     }
-  }
-  return std::string(p0, pe);
+    break;
+  //             ::= <function-type>
+  case 'F': {
+    Result = parseFunctionType();
+    break;
+  }
+  //             ::= <array-type>
+  case 'A': {
+    Result = parseArrayType();
+    break;
+  }
+  //             ::= <pointer-to-member-type>
+  case 'M': {
+    Result = 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();
+      break;
+    }
+
+    Result = parseTemplateParam();
+    if (Result == nullptr)
+      return nullptr;
+
+    // Result could be either of:
+    //   <type>        ::= <template-param>
+    //   <type>        ::= <template-template-param> <template-args>
+    //
+    //   <template-template-param> ::= <template-param>
+    //                             ::= <substitution>
+    //
+    // If this is followed by some <template-args>, and we're permitted to
+    // parse them, take the second production.
+
+    if (TryToParseTemplateArgs && look() == 'I') {
+      Node *TA = parseTemplateArgs();
+      if (TA == nullptr)
+        return nullptr;
+      Result = make<NameWithTemplateArgs>(Result, TA);
+    }
+    break;
+  }
+  //             ::= P <type>        # pointer
+  case 'P': {
+    ++First;
+    Node *Ptr = parseType();
+    if (Ptr == nullptr)
+      return nullptr;
+    Result = make<PointerType>(Ptr);
+    break;
+  }
+  //             ::= R <type>        # l-value reference
+  case 'R': {
+    ++First;
+    Node *Ref = parseType();
+    if (Ref == nullptr)
+      return nullptr;
+    Result = make<LValueReferenceType>(Ref);
+    break;
+  }
+  //             ::= O <type>        # r-value reference (C++11)
+  case 'O': {
+    ++First;
+    Node *Ref = parseType();
+    if (Ref == nullptr)
+      return nullptr;
+    Result = make<RValueReferenceType>(Ref);
+    break;
+  }
+  //             ::= C <type>        # complex pair (C99)
+  case 'C': {
+    ++First;
+    Node *P = parseType();
+    if (P == nullptr)
+      return nullptr;
+    Result = make<PostfixQualifiedType>(P, " complex");
+    break;
+  }
+  //             ::= G <type>        # imaginary (C99)
+  case 'G': {
+    ++First;
+    Node *P = parseType();
+    if (P == nullptr)
+      return P;
+    Result = make<PostfixQualifiedType>(P, " imaginary");
+    break;
+  }
+  //             ::= <substitution>  # See Compression below
+  case 'S': {
+    if (look(1) && look(1) != 't') {
+      Node *Sub = parseSubstitution();
+      if (Sub == nullptr)
+        return nullptr;
+
+      // Sub could be either of:
+      //   <type>        ::= <substitution>
+      //   <type>        ::= <template-template-param> <template-args>
+      //
+      //   <template-template-param> ::= <template-param>
+      //                             ::= <substitution>
+      //
+      // If this is followed by some <template-args>, and we're permitted to
+      // parse them, take the second production.
+
+      if (TryToParseTemplateArgs && look() == 'I') {
+        Node *TA = parseTemplateArgs();
+        if (TA == nullptr)
+          return nullptr;
+        Result = make<NameWithTemplateArgs>(Sub, TA);
+        break;
+      }
+
+      // If all we parsed was a substitution, don't re-insert into the
+      // substitution table.
+      return Sub;
+    }
+    LLVM_FALLTHROUGH;
+  }
+  //        ::= <class-enum-type>
+  default: {
+    Result = parseClassEnumType();
+    break;
+  }
+  }
+
+  // If we parsed a type, insert it into the substitution table. Note that all
+  // <builtin-type>s and <substitution>s have already bailed out, because they
+  // don't get substitutions.
+  if (Result != nullptr)
+    Subs.push_back(Result);
+  return Result;
+}
+
+Node *Db::parsePrefixExpr(StringView Kind) {
+  Node *E = parseExpr();
+  if (E == nullptr)
+    return nullptr;
+  return make<PrefixExpr>(Kind, E);
 }
 
-// <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::parseBinaryExpr(StringView Kind) {
+  Node *LHS = parseExpr();
+  if (LHS == nullptr)
+    return nullptr;
+  Node *RHS = parseExpr();
+  if (RHS == nullptr)
+    return nullptr;
+  return make<BinaryExpr>(LHS, Kind, RHS);
+}
 
-template <class C>
-static const char *parse_ctor_dtor_name(const char *first, const char *last,
-                                        C &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.push_back(base_name(db.names.back().first));
-        first += 2;
-        db.parsed_ctor_dtor_cv = 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("~" + base_name(db.names.back().first));
-        first += 2;
-        db.parsed_ctor_dtor_cv = true;
-        break;
-      }
-      break;
-    }
+Node *Db::parseIntegerLiteral(StringView Lit) {
+  StringView Tmp = parseNumber(true);
+  if (!Tmp.empty() && consumeIf('E'))
+    return make<IntegerExpr>(Lit, Tmp);
+  return nullptr;
+}
+
+// <CV-Qualifiers> ::= [r] [V] [K]
+Qualifiers Db::parseCVQualifiers() {
+  Qualifiers CVR = QualNone;
+  if (consumeIf('r'))
+    addQualifiers(CVR, QualRestrict);
+  if (consumeIf('V'))
+    addQualifiers(CVR, QualVolatile);
+  if (consumeIf('K'))
+    addQualifiers(CVR, QualConst);
+  return CVR;
+}
+
+// <function-param> ::= fp <top-level CV-Qualifiers> _                                     # L == 0, first parameter
+//                  ::= 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
+Node *Db::parseFunctionParam() {
+  if (consumeIf("fp")) {
+    parseCVQualifiers();
+    StringView Num = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<FunctionParam>(Num);
+  }
+  if (consumeIf("fL")) {
+    if (parseNumber().empty())
+      return nullptr;
+    if (!consumeIf('p'))
+      return nullptr;
+    parseCVQualifiers();
+    StringView Num = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<FunctionParam>(Num);
   }
-  return first;
+  return nullptr;
 }
 
-// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
-//                     ::= <closure-type-name>
-//
-// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
-//
-// <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda
-// has no parameters
+// [gs] nw <expression>* _ <type> E                     # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
+// [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
+Node *Db::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();
+    if (Ex == nullptr)
+      return nullptr;
+    Names.push_back(Ex);
+  }
+  NodeArray ExprList = popTrailingNodeArray(Exprs);
+  Node *Ty = parseType();
+  if (Ty == nullptr)
+    return Ty;
+  if (consumeIf("pi")) {
+    size_t InitsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *Init = parseExpr();
+      if (Init == nullptr)
+        return Init;
+      Names.push_back(Init);
+    }
+    NodeArray Inits = popTrailingNodeArray(InitsBegin);
+    return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
+  } else if (!consumeIf('E'))
+    return nullptr;
+  return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
+}
 
-template <class C>
-static const char *parse_unnamed_type_name(const char *first, const char *last,
-                                           C &db) {
-  if (last - first > 2 && first[0] == 'U') {
-    char type = first[1];
-    switch (type) {
-    case 't': {
-      db.names.push_back(std::string("'unnamed"));
-      const char *t0 = first + 2;
-      if (t0 == last) {
-        db.names.pop_back();
-        return first;
-      }
-      if (std::isdigit(*t0)) {
-        const char *t1 = t0 + 1;
-        while (t1 != last && std::isdigit(*t1))
-          ++t1;
-        db.names.back().first.append(t0, t1);
-        t0 = t1;
-      }
-      db.names.back().first.push_back('\'');
-      if (t0 == last || *t0 != '_') {
-        db.names.pop_back();
-        return first;
-      }
-      first = t0 + 1;
-    } break;
-    case 'l': {
-      size_t lambda_pos = db.names.size();
-      db.names.push_back(std::string("'lambda'("));
-      const char *t0 = first + 2;
-      if (first[2] == 'v') {
-        db.names.back().first += ')';
-        ++t0;
-      } else {
-        bool is_first_it = true;
-        while (true) {
-          long k0 = static_cast<long>(db.names.size());
-          const char *t1 = parse_type(t0, last, db);
-          long k1 = static_cast<long>(db.names.size());
-          if (t1 == t0)
-            break;
-          if (k0 >= k1)
-            return first;
-          // If the call to parse_type above found a pack expansion
-          // substitution, then multiple names could have been
-          // inserted into the name table. Walk through the names,
-          // appending each onto the lambda's parameter list.
-          std::for_each(db.names.begin() + k0, db.names.begin() + k1,
-                        [&](typename C::sub_type::value_type &pair) {
-                          if (pair.empty())
-                            return;
-                          auto &lambda = db.names[lambda_pos].first;
-                          if (!is_first_it)
-                            lambda.append(", ");
-                          is_first_it = false;
-                          lambda.append(pair.move_full());
-                        });
-          db.names.erase(db.names.begin() + k0, db.names.end());
-          t0 = t1;
-        }
-        if (is_first_it) {
-          if (!db.names.empty())
-            db.names.pop_back();
-          return first;
-        }
-        if (db.names.empty() || db.names.size() - 1 != lambda_pos)
-          return first;
-        db.names.back().first.append(")");
-      }
-      if (t0 == last || *t0 != 'E') {
-        if (!db.names.empty())
-          db.names.pop_back();
-        return first;
-      }
-      ++t0;
-      if (t0 == last) {
-        if (!db.names.empty())
-          db.names.pop_back();
-        return first;
-      }
-      if (std::isdigit(*t0)) {
-        const char *t1 = t0 + 1;
-        while (t1 != last && std::isdigit(*t1))
-          ++t1;
-        db.names.back().first.insert(db.names.back().first.begin() + 7, t0, t1);
-        t0 = t1;
-      }
-      if (t0 == last || *t0 != '_') {
-        if (!db.names.empty())
-          db.names.pop_back();
-        return first;
-      }
-      first = t0 + 1;
-    } break;
-    }
+// cv <type> <expression>                               # conversion with one argument
+// cv <type> _ <expression>* E                          # conversion with a different number of arguments
+Node *Db::parseConversionExpr() {
+  if (!consumeIf("cv"))
+    return nullptr;
+  Node *Ty;
+  {
+    SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
+    Ty = parseType();
   }
-  return first;
-}
 
-// <unqualified-name> ::= <operator-name>
-//                    ::= <ctor-dtor-name>
-//                    ::= <source-name>
-//                    ::= <unnamed-type-name>
+  if (Ty == nullptr)
+    return nullptr;
 
-template <class C>
-static const char *parse_unqualified_name(const char *first, const char *last,
-                                          C &db) {
-  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)
-        first = t;
-      break;
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      t = parse_source_name(first, last, db);
-      if (t != first)
-        first = t;
-      break;
-    default:
-      t = parse_operator_name(first, last, db);
-      if (t != first)
-        first = t;
-      break;
-    };
+  if (consumeIf('_')) {
+    size_t ExprsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *E = parseExpr();
+      if (E == nullptr)
+        return E;
+      Names.push_back(E);
+    }
+    NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+    return make<ConversionExpr>(Ty, Exprs);
   }
-  return first;
-}
 
-// <unscoped-name> ::= <unqualified-name>
-//                 ::= St <unqualified-name>   # ::std::
-// extension       ::= StL<unqualified-name>
+  Node *E[1] = {parseExpr()};
+  if (E[0] == nullptr)
+    return nullptr;
+  return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
+}
 
-template <class C>
-static const char *parse_unscoped_name(const char *first, const char *last,
-                                       C &db) {
-  if (last - first >= 2) {
-    const char *t0 = first;
-    bool St = false;
-    if (first[0] == 'S' && first[1] == 't') {
-      t0 += 2;
-      St = true;
-      if (t0 != last && *t0 == 'L')
-        ++t0;
-    }
-    const char *t1 = parse_unqualified_name(t0, last, db);
-    if (t1 != t0) {
-      if (St) {
-        if (db.names.empty())
-          return first;
-        db.names.back().first.insert(0, "std::");
-      }
-      first = t1;
+// <expr-primary> ::= L <type> <value number> E                          # integer literal
+//                ::= L <type> <value float> E                           # floating literal
+//                ::= L <string type> E                                  # string literal
+//                ::= 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
+Node *Db::parseExprPrimary() {
+  if (!consumeIf('L'))
+    return nullptr;
+  switch (look()) {
+  case 'w':
+    ++First;
+    return parseIntegerLiteral("wchar_t");
+  case 'b':
+    if (consumeIf("b0E"))
+      return make<BoolExpr>(0);
+    if (consumeIf("b1E"))
+      return make<BoolExpr>(1);
+    return nullptr;
+  case 'c':
+    ++First;
+    return parseIntegerLiteral("char");
+  case 'a':
+    ++First;
+    return parseIntegerLiteral("signed char");
+  case 'h':
+    ++First;
+    return parseIntegerLiteral("unsigned char");
+  case 's':
+    ++First;
+    return parseIntegerLiteral("short");
+  case 't':
+    ++First;
+    return parseIntegerLiteral("unsigned short");
+  case 'i':
+    ++First;
+    return parseIntegerLiteral("");
+  case 'j':
+    ++First;
+    return parseIntegerLiteral("u");
+  case 'l':
+    ++First;
+    return parseIntegerLiteral("l");
+  case 'm':
+    ++First;
+    return parseIntegerLiteral("ul");
+  case 'x':
+    ++First;
+    return parseIntegerLiteral("ll");
+  case 'y':
+    ++First;
+    return parseIntegerLiteral("ull");
+  case 'n':
+    ++First;
+    return parseIntegerLiteral("__int128");
+  case 'o':
+    ++First;
+    return parseIntegerLiteral("unsigned __int128");
+  case 'f':
+    ++First;
+    return parseFloatingLiteral<float>();
+  case 'd':
+    ++First;
+    return parseFloatingLiteral<double>();
+  case 'e':
+    ++First;
+    return parseFloatingLiteral<long double>();
+  case '_':
+    if (consumeIf("_Z")) {
+      Node *R = parseEncoding();
+      if (R != nullptr && consumeIf('E'))
+        return R;
+    }
+    return nullptr;
+  case 'T':
+    // Invalid mangled name per
+    //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+    return nullptr;
+  default: {
+    // might be named type
+    Node *T = parseType();
+    if (T == nullptr)
+      return nullptr;
+    StringView N = parseNumber();
+    if (!N.empty()) {
+      if (!consumeIf('E'))
+        return nullptr;
+      return make<IntegerCastExpr>(T, N);
     }
+    if (consumeIf('E'))
+      return T;
+    return nullptr;
+  }
   }
-  return first;
 }
 
-// at <type>                                            # alignof (a type)
-
-template <class C>
-static const char *parse_alignof_type(const char *first, const char *last,
-                                      C &db) {
-  if (last - first >= 3 && first[0] == 'a' && first[1] == 't') {
-    const char *t = parse_type(first + 2, last, db);
-    if (t != first + 2) {
-      if (db.names.empty())
-        return first;
-      db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
-      first = t;
-    }
-  }
-  return first;
-}
-
-// az <expression>                                            # alignof (a
-// expression)
-
-template <class C>
-static const char *parse_alignof_expr(const char *first, const char *last,
-                                      C &db) {
-  if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') {
-    const char *t = parse_expression(first + 2, last, db);
-    if (t != first + 2) {
-      if (db.names.empty())
-        return first;
-      db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
-      first = t;
-    }
-  }
-  return first;
-}
-
-template <class C>
-static const char *parse_noexcept_expression(const char *first,
-                                             const char *last, C &db) {
-  const char *t1 = parse_expression(first, last, db);
-  if (t1 != first) {
-    if (db.names.empty())
-      return first;
-    db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
-    first = t1;
-  }
-  return first;
-}
-
-template <class C>
-static const char *parse_prefix_expression(const char *first, const char *last,
-                                           const std::string &op,
-                                           C &db) {
-  const char *t1 = parse_expression(first, last, db);
-  if (t1 != first) {
-    if (db.names.empty())
-      return first;
-    db.names.back().first = op + "(" + db.names.back().move_full() + ")";
-    first = t1;
-  }
-  return first;
-}
-
-template <class C>
-static const char *parse_binary_expression(const char *first, const char *last,
-                                           const std::string &op,
-                                           C &db) {
-  const char *t1 = parse_expression(first, last, db);
-  if (t1 != first) {
-    const char *t2 = parse_expression(t1, last, db);
-    if (t2 != t1) {
-      if (db.names.size() < 2)
-        return first;
-      auto op2 = db.names.back().move_full();
-      db.names.pop_back();
-      auto op1 = db.names.back().move_full();
-      auto &nm = db.names.back().first;
-      nm.clear();
-      if (op == ">")
-        nm += '(';
-      nm += "(" + op1 + ") " + op + " (" + op2 + ")";
-      if (op == ">")
-        nm += ')';
-      first = t2;
-    } else if (!db.names.empty())
-      db.names.pop_back();
+// <braced-expression> ::= <expression>
+//                     ::= di <field source-name> <braced-expression>    # .name = expr
+//                     ::= dx <index expression> <braced-expression>     # [expr] = expr
+//                     ::= dX <range begin expression> <range end expression> <braced-expression>
+Node *Db::parseBracedExpr() {
+  if (look() == 'd') {
+    switch (look(1)) {
+    case 'i': {
+      First += 2;
+      Node *Field = parseSourceName(/*NameState=*/nullptr);
+      if (Field == nullptr)
+        return nullptr;
+      Node *Init = parseBracedExpr();
+      if (Init == nullptr)
+        return nullptr;
+      return make<BracedExpr>(Field, Init, /*isArray=*/false);
+    }
+    case 'x': {
+      First += 2;
+      Node *Index = parseExpr();
+      if (Index == nullptr)
+        return nullptr;
+      Node *Init = parseBracedExpr();
+      if (Init == nullptr)
+        return nullptr;
+      return make<BracedExpr>(Index, Init, /*isArray=*/true);
+    }
+    case 'X': {
+      First += 2;
+      Node *RangeBegin = parseExpr();
+      if (RangeBegin == nullptr)
+        return nullptr;
+      Node *RangeEnd = parseExpr();
+      if (RangeEnd == nullptr)
+        return nullptr;
+      Node *Init = parseBracedExpr();
+      if (Init == nullptr)
+        return nullptr;
+      return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init);
+    }
+    }
   }
-  return first;
+  return parseExpr();
 }
 
 // <expression> ::= <unary operator-name> <expression>
 //              ::= <binary operator-name> <expression> <expression>
-//              ::= <ternary operator-name> <expression> <expression>
-//              <expression>
+//              ::= <ternary operator-name> <expression> <expression> <expression>
 //              ::= cl <expression>+ E                                   # call
-//              ::= cv <type> <expression>                               #
-//              conversion with one argument
-//              ::= cv <type> _ <expression>* E                          #
-//              conversion with a different number of arguments
-//              ::= [gs] nw <expression>* _ <type> E                     # new
-//              (expr-list) type
-//              ::= [gs] nw <expression>* _ <type> <initializer>         # new
-//              (expr-list) type (init)
-//              ::= [gs] na <expression>* _ <type> E                     # new[]
-//              (expr-list) type
-//              ::= [gs] na <expression>* _ <type> <initializer>         # new[]
-//              (expr-list) type (init)
-//              ::= [gs] dl <expression>                                 #
-//              delete expression
-//              ::= [gs] da <expression>                                 #
-//              delete[] expression
-//              ::= pp_ <expression>                                     #
-//              prefix ++
-//              ::= mm_ <expression>                                     #
-//              prefix --
-//              ::= ti <type>                                            #
-//              typeid (type)
-//              ::= te <expression>                                      #
-//              typeid (expression)
-//              ::= dc <type> <expression>                               #
-//              dynamic_cast<type> (expression)
-//              ::= sc <type> <expression>                               #
-//              static_cast<type> (expression)
-//              ::= cc <type> <expression>                               #
-//              const_cast<type> (expression)
-//              ::= rc <type> <expression>                               #
-//              reinterpret_cast<type> (expression)
-//              ::= st <type>                                            #
-//              sizeof (a type)
-//              ::= sz <expression>                                      #
-//              sizeof (an expression)
-//              ::= at <type>                                            #
-//              alignof (a type)
-//              ::= az <expression>                                      #
-//              alignof (an expression)
-//              ::= nx <expression>                                      #
-//              noexcept (expression)
+//              ::= cv <type> <expression>                               # conversion with one argument
+//              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments
+//              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type
+//              ::= [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
+//              ::= [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
+//              ::= [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
+//              ::= [gs] dl <expression>                                 # delete expression
+//              ::= [gs] da <expression>                                 # delete[] expression
+//              ::= pp_ <expression>                                     # prefix ++
+//              ::= mm_ <expression>                                     # prefix --
+//              ::= ti <type>                                            # typeid (type)
+//              ::= te <expression>                                      # typeid (expression)
+//              ::= dc <type> <expression>                               # dynamic_cast<type> (expression)
+//              ::= sc <type> <expression>                               # static_cast<type> (expression)
+//              ::= cc <type> <expression>                               # const_cast<type> (expression)
+//              ::= rc <type> <expression>                               # reinterpret_cast<type> (expression)
+//              ::= st <type>                                            # sizeof (a type)
+//              ::= sz <expression>                                      # sizeof (an expression)
+//              ::= at <type>                                            # alignof (a type)
+//              ::= az <expression>                                      # alignof (an expression)
+//              ::= nx <expression>                                      # noexcept (expression)
 //              ::= <template-param>
 //              ::= <function-param>
-//              ::= dt <expression> <unresolved-name>                    #
-//              expr.name
-//              ::= pt <expression> <unresolved-name>                    #
-//              expr->name
-//              ::= ds <expression> <expression>                         #
-//              expr.*expr
-//              ::= sZ <template-param>                                  # size
-//              of a parameter pack
-//              ::= sZ <function-param>                                  # size
-//              of a function parameter pack
-//              ::= sp <expression>                                      # pack
-//              expansion
-//              ::= tw <expression>                                      # throw
-//              expression
-//              ::= tr                                                   # throw
-//              with no operand (rethrow)
-//              ::= <unresolved-name>                                    # f(p),
-//              N::f(p), ::f(p),
-//                                                                       #
-//                                                                       freestanding
-//                                                                       dependent
-//                                                                       name
-//                                                                       (e.g.,
-//                                                                       T::x),
-//                                                                       #
-//                                                                       objectless
-//                                                                       nonstatic
-//                                                                       member
-//                                                                       reference
+//              ::= dt <expression> <unresolved-name>                    # expr.name
+//              ::= pt <expression> <unresolved-name>                    # expr->name
+//              ::= ds <expression> <expression>                         # expr.*expr
+//              ::= sZ <template-param>                                  # size of a parameter pack
+//              ::= sZ <function-param>                                  # size of a function parameter pack
+//              ::= sp <expression>                                      # pack expansion
+//              ::= tw <expression>                                      # throw expression
+//              ::= tr                                                   # throw with no operand (rethrow)
+//              ::= <unresolved-name>                                    # f(p), N::f(p), ::f(p),
+//                                                                       # freestanding dependent name (e.g., T::x),
+//                                                                       # objectless nonstatic member reference
+//              ::= fL <binary-operator-name> <expression> <expression>
+//              ::= fR <binary-operator-name> <expression> <expression>
+//              ::= fl <binary-operator-name> <expression>
+//              ::= fr <binary-operator-name> <expression>
 //              ::= <expr-primary>
+Node *Db::parseExpr() {
+  bool Global = consumeIf("gs");
+  if (numLeft() < 2)
+    return nullptr;
 
-template <class C>
-static const char *parse_expression(const char *first, const char *last,
-                                    C &db) {
-  if (last - first >= 2) {
-    const char *t = first;
-    bool parsed_gs = false;
-    if (last - first >= 4 && t[0] == 'g' && t[1] == 's') {
-      t += 2;
-      parsed_gs = true;
-    }
-    switch (*t) {
-    case 'L':
-      first = parse_expr_primary(first, last, db);
-      break;
-    case 'T':
-      first = parse_template_param(first, last, db);
-      break;
-    case 'f':
-      first = parse_function_param(first, last, db);
-      break;
+  switch (*First) {
+  case 'L':
+    return parseExprPrimary();
+  case 'T':
+    return parseTemplateParam();
+  case 'f':
+    return parseFunctionParam();
+  case 'a':
+    switch (First[1]) {
     case 'a':
-      switch (t[1]) {
-      case 'a':
-        t = parse_binary_expression(first + 2, last, "&&", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'd':
-        t = parse_prefix_expression(first + 2, last, "&", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'n':
-        t = parse_binary_expression(first + 2, last, "&", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'N':
-        t = parse_binary_expression(first + 2, last, "&=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'S':
-        t = parse_binary_expression(first + 2, last, "=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 't':
-        first = parse_alignof_type(first, last, db);
-        break;
-      case 'z':
-        first = parse_alignof_expr(first, last, db);
-        break;
-      }
-      break;
-    case 'c':
-      switch (t[1]) {
-      case 'c':
-        first = parse_const_cast_expr(first, last, db);
-        break;
-      case 'l':
-        first = parse_call_expr(first, last, db);
-        break;
-      case 'm':
-        t = parse_binary_expression(first + 2, last, ",", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'o':
-        t = parse_prefix_expression(first + 2, last, "~", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'v':
-        first = parse_conversion_expr(first, last, db);
-        break;
-      }
-      break;
+      First += 2;
+      return parseBinaryExpr("&&");
     case 'd':
-      switch (t[1]) {
-      case 'a': {
-        const char *t1 = parse_expression(t + 2, last, db);
-        if (t1 != t + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first =
-              (parsed_gs ? std::string("::") : std::string()) + "delete[] " +
-              db.names.back().move_full();
-          first = t1;
-        }
-      } break;
-      case 'c':
-        first = parse_dynamic_cast_expr(first, last, db);
-        break;
-      case 'e':
-        t = parse_prefix_expression(first + 2, last, "*", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'l': {
-        const char *t1 = parse_expression(t + 2, last, db);
-        if (t1 != t + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first =
-              (parsed_gs ? std::string("::") : std::string()) + "delete " +
-              db.names.back().move_full();
-          first = t1;
-        }
-      } break;
-      case 'n':
-        return parse_unresolved_name(first, last, db);
-      case 's':
-        first = parse_dot_star_expr(first, last, db);
-        break;
-      case 't':
-        first = parse_dot_expr(first, last, db);
-        break;
-      case 'v':
-        t = parse_binary_expression(first + 2, last, "/", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'V':
-        t = parse_binary_expression(first + 2, last, "/=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      }
-      break;
-    case 'e':
-      switch (t[1]) {
-      case 'o':
-        t = parse_binary_expression(first + 2, last, "^", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'O':
-        t = parse_binary_expression(first + 2, last, "^=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'q':
-        t = parse_binary_expression(first + 2, last, "==", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      }
-      break;
-    case 'g':
-      switch (t[1]) {
-      case 'e':
-        t = parse_binary_expression(first + 2, last, ">=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 't':
-        t = parse_binary_expression(first + 2, last, ">", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      }
-      break;
-    case 'i':
-      if (t[1] == 'x') {
-        const char *t1 = parse_expression(first + 2, last, db);
-        if (t1 != first + 2) {
-          const char *t2 = parse_expression(t1, last, db);
-          if (t2 != t1) {
-            if (db.names.size() < 2)
-              return first;
-            auto op2 = db.names.back().move_full();
-            db.names.pop_back();
-            auto op1 = db.names.back().move_full();
-            db.names.back() = "(" + op1 + ")[" + op2 + "]";
-            first = t2;
-          } else if (!db.names.empty())
-            db.names.pop_back();
-        }
-      }
-      break;
-    case 'l':
-      switch (t[1]) {
-      case 'e':
-        t = parse_binary_expression(first + 2, last, "<=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 's':
-        t = parse_binary_expression(first + 2, last, "<<", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'S':
-        t = parse_binary_expression(first + 2, last, "<<=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 't':
-        t = parse_binary_expression(first + 2, last, "<", db);
-        if (t != first + 2)
-          first = t;
-        break;
+      First += 2;
+      return parsePrefixExpr("&");
+    case 'n':
+      First += 2;
+      return parseBinaryExpr("&");
+    case 'N':
+      First += 2;
+      return parseBinaryExpr("&=");
+    case 'S':
+      First += 2;
+      return parseBinaryExpr("=");
+    case 't': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<EnclosingExpr>("alignof (", Ty, ")");
+    }
+    case 'z': {
+      First += 2;
+      Node *Ty = parseExpr();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<EnclosingExpr>("alignof (", Ty, ")");
+    }
+    }
+    return nullptr;
+  case 'c':
+    switch (First[1]) {
+    // cc <type> <expression>                               # const_cast<type>(expression)
+    case 'c': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return Ty;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<CastExpr>("const_cast", Ty, Ex);
+    }
+    // cl <expression>+ E                                   # call
+    case 'l': {
+      First += 2;
+      Node *Callee = parseExpr();
+      if (Callee == nullptr)
+        return Callee;
+      size_t ExprsBegin = Names.size();
+      while (!consumeIf('E')) {
+        Node *E = parseExpr();
+        if (E == nullptr)
+          return E;
+        Names.push_back(E);
       }
-      break;
+      return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
+    }
     case 'm':
-      switch (t[1]) {
-      case 'i':
-        t = parse_binary_expression(first + 2, last, "-", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'I':
-        t = parse_binary_expression(first + 2, last, "-=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'l':
-        t = parse_binary_expression(first + 2, last, "*", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'L':
-        t = parse_binary_expression(first + 2, last, "*=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'm':
-        if (first + 2 != last && first[2] == '_') {
-          t = parse_prefix_expression(first + 3, last, "--", db);
-          if (t != first + 3)
-            first = t;
-        } else {
-          const char *t1 = parse_expression(first + 2, last, db);
-          if (t1 != first + 2) {
-            if (db.names.empty())
-              return first;
-            db.names.back() = "(" + db.names.back().move_full() + ")--";
-            first = t1;
-          }
-        }
-        break;
-      }
-      break;
+      First += 2;
+      return parseBinaryExpr(",");
+    case 'o':
+      First += 2;
+      return parsePrefixExpr("~");
+    case 'v':
+      return parseConversionExpr();
+    }
+    return nullptr;
+  case 'd':
+    switch (First[1]) {
+    case 'a': {
+      First += 2;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
+    }
+    case 'c': {
+      First += 2;
+      Node *T = parseType();
+      if (T == nullptr)
+        return T;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<CastExpr>("dynamic_cast", T, Ex);
+    }
+    case 'e':
+      First += 2;
+      return parsePrefixExpr("*");
+    case 'l': {
+      First += 2;
+      Node *E = parseExpr();
+      if (E == nullptr)
+        return E;
+      return make<DeleteExpr>(E, Global, /*is_array=*/false);
+    }
     case 'n':
-      switch (t[1]) {
-      case 'a':
-      case 'w':
-        first = parse_new_expr(first, last, db);
-        break;
-      case 'e':
-        t = parse_binary_expression(first + 2, last, "!=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'g':
-        t = parse_prefix_expression(first + 2, last, "-", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 't':
-        t = parse_prefix_expression(first + 2, last, "!", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'x':
-        t = parse_noexcept_expression(first + 2, last, db);
-        if (t != first + 2)
-          first = t;
-        break;
-      }
-      break;
+      return parseUnresolvedName();
+    case 's': {
+      First += 2;
+      Node *LHS = parseExpr();
+      if (LHS == nullptr)
+        return nullptr;
+      Node *RHS = parseExpr();
+      if (RHS == nullptr)
+        return nullptr;
+      return make<MemberExpr>(LHS, ".*", RHS);
+    }
+    case 't': {
+      First += 2;
+      Node *LHS = parseExpr();
+      if (LHS == nullptr)
+        return LHS;
+      Node *RHS = parseExpr();
+      if (RHS == nullptr)
+        return nullptr;
+      return make<MemberExpr>(LHS, ".", RHS);
+    }
+    case 'v':
+      First += 2;
+      return parseBinaryExpr("/");
+    case 'V':
+      First += 2;
+      return parseBinaryExpr("/=");
+    }
+    return nullptr;
+  case 'e':
+    switch (First[1]) {
     case 'o':
-      switch (t[1]) {
-      case 'n':
-        return parse_unresolved_name(first, last, db);
-      case 'o':
-        t = parse_binary_expression(first + 2, last, "||", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'r':
-        t = parse_binary_expression(first + 2, last, "|", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'R':
-        t = parse_binary_expression(first + 2, last, "|=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      }
-      break;
-    case 'p':
-      switch (t[1]) {
-      case 'm':
-        t = parse_binary_expression(first + 2, last, "->*", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'l':
-        t = parse_binary_expression(first + 2, last, "+", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'L':
-        t = parse_binary_expression(first + 2, last, "+=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'p':
-        if (first + 2 != last && first[2] == '_') {
-          t = parse_prefix_expression(first + 3, last, "++", db);
-          if (t != first + 3)
-            first = t;
-        } else {
-          const char *t1 = parse_expression(first + 2, last, db);
-          if (t1 != first + 2) {
-            if (db.names.empty())
-              return first;
-            db.names.back() = "(" + db.names.back().move_full() + ")++";
-            first = t1;
-          }
-        }
-        break;
-      case 's':
-        t = parse_prefix_expression(first + 2, last, "+", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 't':
-        first = parse_arrow_expr(first, last, db);
-        break;
-      }
-      break;
+      First += 2;
+      return parseBinaryExpr("^");
+    case 'O':
+      First += 2;
+      return parseBinaryExpr("^=");
     case 'q':
-      if (t[1] == 'u') {
-        const char *t1 = parse_expression(first + 2, last, db);
-        if (t1 != first + 2) {
-          const char *t2 = parse_expression(t1, last, db);
-          if (t2 != t1) {
-            const char *t3 = parse_expression(t2, last, db);
-            if (t3 != t2) {
-              if (db.names.size() < 3)
-                return first;
-              auto op3 = db.names.back().move_full();
-              db.names.pop_back();
-              auto op2 = db.names.back().move_full();
-              db.names.pop_back();
-              auto op1 = db.names.back().move_full();
-              db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
-              first = t3;
-            } else {
-              if (db.names.size() < 2)
-                return first;
-              db.names.pop_back();
-              db.names.pop_back();
-            }
-          } else if (!db.names.empty())
-            db.names.pop_back();
-        }
-      }
-      break;
-    case 'r':
-      switch (t[1]) {
-      case 'c':
-        first = parse_reinterpret_cast_expr(first, last, db);
-        break;
-      case 'm':
-        t = parse_binary_expression(first + 2, last, "%", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'M':
-        t = parse_binary_expression(first + 2, last, "%=", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 's':
-        t = parse_binary_expression(first + 2, last, ">>", db);
-        if (t != first + 2)
-          first = t;
-        break;
-      case 'S':
-        t = parse_binary_expression(first + 2, last, ">>=", db);
-        if (t != first + 2)
-          first = t;
-        break;
+      First += 2;
+      return parseBinaryExpr("==");
+    }
+    return nullptr;
+  case 'g':
+    switch (First[1]) {
+    case 'e':
+      First += 2;
+      return parseBinaryExpr(">=");
+    case 't':
+      First += 2;
+      return parseBinaryExpr(">");
+    }
+    return nullptr;
+  case 'i':
+    switch (First[1]) {
+    case 'x': {
+      First += 2;
+      Node *Base = parseExpr();
+      if (Base == nullptr)
+        return nullptr;
+      Node *Index = parseExpr();
+      if (Index == nullptr)
+        return Index;
+      return make<ArraySubscriptExpr>(Base, Index);
+    }
+    case 'l': {
+      First += 2;
+      size_t InitsBegin = Names.size();
+      while (!consumeIf('E')) {
+        Node *E = parseBracedExpr();
+        if (E == nullptr)
+          return nullptr;
+        Names.push_back(E);
       }
-      break;
+      return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
+    }
+    }
+    return nullptr;
+  case 'l':
+    switch (First[1]) {
+    case 'e':
+      First += 2;
+      return parseBinaryExpr("<=");
     case 's':
-      switch (t[1]) {
-      case 'c':
-        first = parse_static_cast_expr(first, last, db);
-        break;
-      case 'p':
-        first = parse_pack_expansion(first, last, db);
-        break;
-      case 'r':
-        return parse_unresolved_name(first, last, db);
-      case 't':
-        first = parse_sizeof_type_expr(first, last, db);
-        break;
-      case 'z':
-        first = parse_sizeof_expr_expr(first, last, db);
-        break;
-      case 'Z':
-        if (last - t >= 3) {
-          switch (t[2]) {
-          case 'T':
-            first = parse_sizeof_param_pack_expr(first, last, db);
-            break;
-          case 'f':
-            first = parse_sizeof_function_param_pack_expr(first, last, db);
-            break;
-          }
-        }
-        break;
-      }
-      break;
+      First += 2;
+      return parseBinaryExpr("<<");
+    case 'S':
+      First += 2;
+      return parseBinaryExpr("<<=");
     case 't':
-      switch (t[1]) {
-      case 'e':
-      case 'i':
-        first = parse_typeid_expr(first, last, db);
-        break;
-      case 'r':
-        db.names.push_back("throw");
-        first += 2;
-        break;
-      case 'w':
-        first = parse_throw_expr(first, last, db);
-        break;
-      }
-      break;
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      return parse_unresolved_name(first, last, db);
-    }
-  }
-  return first;
-}
-
-// <template-arg> ::= <type>                                             # type
-// or template
-//                ::= X <expression> E                                   #
-//                expression
-//                ::= <expr-primary>                                     #
-//                simple expressions
-//                ::= J <template-arg>* E                                #
-//                argument pack
-//                ::= LZ <encoding> E                                    #
-//                extension
-
-template <class C>
-static const char *parse_template_arg(const char *first, const char *last,
-                                      C &db) {
-  if (first != last) {
-    const char *t;
-    switch (*first) {
-    case 'X':
-      t = parse_expression(first + 1, last, db);
-      if (t != first + 1) {
-        if (t != last && *t == 'E')
-          first = t + 1;
-      }
-      break;
-    case 'J':
-      t = first + 1;
-      if (t == last)
-        return first;
-      while (*t != 'E') {
-        const char *t1 = parse_template_arg(t, last, db);
-        if (t1 == t)
-          return first;
-        t = t1;
-      }
-      first = t + 1;
-      break;
+      First += 2;
+      return parseBinaryExpr("<");
+    }
+    return nullptr;
+  case 'm':
+    switch (First[1]) {
+    case 'i':
+      First += 2;
+      return parseBinaryExpr("-");
+    case 'I':
+      First += 2;
+      return parseBinaryExpr("-=");
+    case 'l':
+      First += 2;
+      return parseBinaryExpr("*");
+    case 'L':
+      First += 2;
+      return parseBinaryExpr("*=");
+    case 'm':
+      First += 2;
+      if (consumeIf('_'))
+        return parsePrefixExpr("--");
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return nullptr;
+      return make<PostfixExpr>(Ex, "--");
+    }
+    return nullptr;
+  case 'n':
+    switch (First[1]) {
+    case 'a':
+    case 'w':
+      return parseNewExpr();
+    case 'e':
+      First += 2;
+      return parseBinaryExpr("!=");
+    case 'g':
+      First += 2;
+      return parsePrefixExpr("-");
+    case 't':
+      First += 2;
+      return parsePrefixExpr("!");
+    case 'x':
+      First += 2;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<EnclosingExpr>("noexcept (", Ex, ")");
+    }
+    return nullptr;
+  case 'o':
+    switch (First[1]) {
+    case 'n':
+      return parseUnresolvedName();
+    case 'o':
+      First += 2;
+      return parseBinaryExpr("||");
+    case 'r':
+      First += 2;
+      return parseBinaryExpr("|");
+    case 'R':
+      First += 2;
+      return parseBinaryExpr("|=");
+    }
+    return nullptr;
+  case 'p':
+    switch (First[1]) {
+    case 'm':
+      First += 2;
+      return parseBinaryExpr("->*");
+    case 'l':
+      First += 2;
+      return parseBinaryExpr("+");
     case 'L':
-      // <expr-primary> or LZ <encoding> E
-      if (first + 1 != last && first[1] == 'Z') {
-        t = parse_encoding(first + 2, last, db);
-        if (t != first + 2 && t != last && *t == 'E')
-          first = t + 1;
-      } else
-        first = parse_expr_primary(first, last, db);
-      break;
-    default:
-      // <type>
-      first = parse_type(first, last, db);
-      break;
+      First += 2;
+      return parseBinaryExpr("+=");
+    case 'p': {
+      First += 2;
+      if (consumeIf('_'))
+        return parsePrefixExpr("++");
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<PostfixExpr>(Ex, "++");
     }
-  }
-  return first;
-}
-
-// <template-args> ::= I <template-arg>* E
-//     extension, the abi says <template-arg>+
-
-template <class C>
-static const char *parse_template_args(const char *first, const char *last,
-                                       C &db) {
-  if (last - first >= 2 && *first == 'I') {
-    if (db.tag_templates)
-      db.template_param.back().clear();
-    const char *t = first + 1;
-    std::string args("<");
-    while (*t != 'E') {
-      if (db.tag_templates)
-        db.template_param.emplace_back();
-      size_t k0 = db.names.size();
-      const char *t1 = parse_template_arg(t, last, db);
-      size_t k1 = db.names.size();
-      if (db.tag_templates)
-        db.template_param.pop_back();
-      if (t1 == t || t1 == last)
-        return first;
-      if (db.tag_templates) {
-        db.template_param.back().emplace_back();
-        for (size_t k = k0; k < k1; ++k)
-          db.template_param.back().back().push_back(db.names[k]);
-      }
-      for (size_t k = k0; k < k1; ++k) {
-        if (args.size() > 1)
-          args += ", ";
-        args += db.names[k].move_full();
-      }
-      for (; k1 > k0; --k1)
-        if (!db.names.empty())
-          db.names.pop_back();
-      t = t1;
-    }
-    first = t + 1;
-    if (args.back() != '>')
-      args += ">";
-    else
-      args += " >";
-    db.names.push_back(std::move(args));
-  }
-  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>
-
-template <class C>
-static const char *parse_nested_name(const char *first, const char *last, C &db,
-                                     bool *ends_with_template_args) {
-  if (first != last && *first == 'N') {
-    unsigned cv;
-    const char *t0 = parse_cv_qualifiers(first + 1, last, cv);
-    if (t0 == last)
-      return first;
-    db.ref = 0;
-    if (*t0 == 'R') {
-      db.ref = 1;
-      ++t0;
-    } else if (*t0 == 'O') {
-      db.ref = 2;
-      ++t0;
-    }
-    db.names.emplace_back();
-    if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't') {
-      t0 += 2;
-      db.names.back().first = "std";
-    }
-    if (t0 == last) {
-      db.names.pop_back();
-      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) {
-          auto name = db.names.back().move_full();
-          db.names.pop_back();
-          if (db.names.empty())
-            return first;
-          if (!db.names.back().first.empty()) {
-            db.names.back().first += "::" + name;
-            db.subs.push_back(typename C::sub_type(1, db.names.back()));
-          } else
-            db.names.back().first = name;
-          pop_subs = true;
-          t0 = t1;
-        } else
-          return first;
-        break;
-      case 'T':
-        t1 = parse_template_param(t0, last, db);
-        if (t1 != t0 && t1 != last) {
-          auto name = db.names.back().move_full();
-          db.names.pop_back();
-          if (db.names.empty())
-            return first;
-          if (!db.names.back().first.empty())
-            db.names.back().first += "::" + name;
-          else
-            db.names.back().first = name;
-          db.subs.push_back(typename C::sub_type(1, 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) {
-          auto name = db.names.back().move_full();
-          db.names.pop_back();
-          if (db.names.empty())
-            return first;
-          if (!db.names.back().first.empty())
-            db.names.back().first += "::" + name;
-          else
-            db.names.back().first = name;
-          db.subs.push_back(typename C::sub_type(1, 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) {
-          auto name = db.names.back().move_full();
-          db.names.pop_back();
-          if (db.names.empty())
-            return first;
-          db.names.back().first += name;
-          db.subs.push_back(typename C::sub_type(1, 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) {
-          auto name = db.names.back().move_full();
-          db.names.pop_back();
-          if (db.names.empty())
-            return first;
-          if (!db.names.back().first.empty())
-            db.names.back().first += "::" + name;
-          else
-            db.names.back().first = name;
-          db.subs.push_back(typename C::sub_type(1, db.names.back()));
-          pop_subs = true;
-          t0 = t1;
-        } else
-          return first;
-      }
+    case 's':
+      First += 2;
+      return parsePrefixExpr("+");
+    case 't': {
+      First += 2;
+      Node *L = parseExpr();
+      if (L == nullptr)
+        return nullptr;
+      Node *R = parseExpr();
+      if (R == nullptr)
+        return nullptr;
+      return make<MemberExpr>(L, "->", R);
     }
-    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
-
-static const char *parse_discriminator(const char *first, const char *last) {
-  // parse but ignore discriminator
-  if (first != last) {
-    if (*first == '_') {
-      const char *t1 = first + 1;
-      if (t1 != last) {
-        if (std::isdigit(*t1))
-          first = t1 + 1;
-        else if (*t1 == '_') {
-          for (++t1; t1 != last && std::isdigit(*t1); ++t1)
-            ;
-          if (t1 != last && *t1 == '_')
-            first = t1 + 1;
-        }
-      }
-    } else if (std::isdigit(*first)) {
-      const char *t1 = first + 1;
-      for (; t1 != last && std::isdigit(*t1); ++t1)
-        ;
-      if (t1 == last)
-        first = last;
     }
-  }
-  return first;
-}
-
-// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
-//              := Z <function encoding> E s [<discriminator>]
-//              := Z <function encoding> Ed [ <parameter number> ] _ <entity
-//              name>
-
-template <class C>
-static const char *parse_local_name(const char *first, const char *last, C &db,
-                                    bool *ends_with_template_args) {
-  if (first != last && *first == 'Z') {
-    const char *t = parse_encoding(first + 1, last, db);
-    if (t != first + 1 && t != last && *t == 'E' && ++t != last) {
-      switch (*t) {
-      case 's':
-        first = parse_discriminator(t + 1, last);
-        if (db.names.empty())
-          return first;
-        db.names.back().first.append("::string literal");
-        break;
-      case 'd':
-        if (++t != last) {
-          const char *t1 = parse_number(t, last);
-          if (t1 != last && *t1 == '_') {
-            t = t1 + 1;
-            t1 = parse_name(t, last, db, ends_with_template_args);
-            if (t1 != t) {
-              if (db.names.size() < 2)
-                return first;
-              auto name = db.names.back().move_full();
-              db.names.pop_back();
-              if (db.names.empty())
-                return first;
-              db.names.back().first.append("::");
-              db.names.back().first.append(name);
-              first = t1;
-            } else if (!db.names.empty())
-              db.names.pop_back();
-          }
-        }
-        break;
-      default: {
-        const char *t1 = parse_name(t, last, db, ends_with_template_args);
-        if (t1 != t) {
-          // parse but ignore discriminator
-          first = parse_discriminator(t1, last);
-          if (db.names.size() < 2)
-            return first;
-          auto name = db.names.back().move_full();
-          db.names.pop_back();
-          if (db.names.empty())
-            return first;
-          db.names.back().first.append("::");
-          db.names.back().first.append(name);
-        } else if (!db.names.empty())
-          db.names.pop_back();
-      } break;
+    return nullptr;
+  case 'q':
+    if (First[1] == 'u') {
+      First += 2;
+      Node *Cond = parseExpr();
+      if (Cond == nullptr)
+        return nullptr;
+      Node *LHS = parseExpr();
+      if (LHS == nullptr)
+        return nullptr;
+      Node *RHS = parseExpr();
+      if (RHS == nullptr)
+        return nullptr;
+      return make<ConditionalExpr>(Cond, LHS, RHS);
+    }
+    return nullptr;
+  case 'r':
+    switch (First[1]) {
+    case 'c': {
+      First += 2;
+      Node *T = parseType();
+      if (T == nullptr)
+        return T;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<CastExpr>("reinterpret_cast", T, Ex);
+    }
+    case 'm':
+      First += 2;
+      return parseBinaryExpr("%");
+    case 'M':
+      First += 2;
+      return parseBinaryExpr("%=");
+    case 's':
+      First += 2;
+      return parseBinaryExpr(">>");
+    case 'S':
+      First += 2;
+      return parseBinaryExpr(">>=");
+    }
+    return nullptr;
+  case 's':
+    switch (First[1]) {
+    case 'c': {
+      First += 2;
+      Node *T = parseType();
+      if (T == nullptr)
+        return T;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<CastExpr>("static_cast", T, Ex);
+    }
+    case 'p': {
+      First += 2;
+      Node *Child = parseExpr();
+      if (Child == nullptr)
+        return nullptr;
+      return make<ParameterPackExpansion>(Child);
+    }
+    case 'r':
+      return parseUnresolvedName();
+    case 't': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return Ty;
+      return make<EnclosingExpr>("sizeof (", Ty, ")");
+    }
+    case 'z': {
+      First += 2;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<EnclosingExpr>("sizeof (", Ex, ")");
+    }
+    case 'Z':
+      First += 2;
+      if (look() == 'T') {
+        Node *R = parseTemplateParam();
+        if (R == nullptr)
+          return nullptr;
+        return make<SizeofParamPackExpr>(R);
+      } else if (look() == 'f') {
+        Node *FP = parseFunctionParam();
+        if (FP == nullptr)
+          return nullptr;
+        return make<EnclosingExpr>("sizeof...", FP, ")");
       }
+      return nullptr;
     }
-  }
-  return first;
-}
-
-// <name> ::= <nested-name> // N
-//        ::= <local-name> # See Scope Encoding below  // Z
-//        ::= <unscoped-template-name> <template-args>
-//        ::= <unscoped-name>
-
-// <unscoped-template-name> ::= <unscoped-name>
-//                          ::= <substitution>
-
-template <class C>
-static const char *parse_name(const char *first, const char *last, C &db,
-                              bool *ends_with_template_args) {
-  if (last - first >= 2) {
-    const char *t0 = first;
-    // extension: ignore L here
-    if (*t0 == 'L')
-      ++t0;
-    switch (*t0) {
-    case 'N': {
-      const char *t1 = parse_nested_name(t0, last, db, ends_with_template_args);
-      if (t1 != t0)
-        first = t1;
-      break;
+    return nullptr;
+  case 't':
+    switch (First[1]) {
+    case 'e': {
+      First += 2;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<EnclosingExpr>("typeid (", Ex, ")");
     }
-    case 'Z': {
-      const char *t1 = parse_local_name(t0, last, db, ends_with_template_args);
-      if (t1 != t0)
-        first = t1;
-      break;
+    case 'i': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return Ty;
+      return make<EnclosingExpr>("typeid (", Ty, ")");
     }
-    default: {
-      const char *t1 = parse_unscoped_name(t0, last, db);
-      if (t1 != t0) {
-        if (t1 != last &&
-            *t1 == 'I') // <unscoped-template-name> <template-args>
-        {
-          if (db.names.empty())
-            return first;
-          db.subs.push_back(typename C::sub_type(1, db.names.back()));
-          t0 = t1;
-          t1 = parse_template_args(t0, last, db);
-          if (t1 != t0) {
-            if (db.names.size() < 2)
-              return first;
-            auto tmp = db.names.back().move_full();
-            db.names.pop_back();
-            if (db.names.empty())
-              return first;
-            db.names.back().first += tmp;
-            first = t1;
-            if (ends_with_template_args)
-              *ends_with_template_args = true;
-          }
-        } else // <unscoped-name>
-          first = t1;
-      } else { // try <substitution> <template-args>
-        t1 = parse_substitution(t0, last, db);
-        if (t1 != t0 && t1 != last && *t1 == 'I') {
-          t0 = t1;
-          t1 = parse_template_args(t0, last, db);
-          if (t1 != t0) {
-            if (db.names.size() < 2)
-              return first;
-            auto tmp = db.names.back().move_full();
-            db.names.pop_back();
-            if (db.names.empty())
-              return first;
-            db.names.back().first += tmp;
-            first = t1;
-            if (ends_with_template_args)
-              *ends_with_template_args = true;
-          }
-        }
+    case 'l': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      size_t InitsBegin = Names.size();
+      while (!consumeIf('E')) {
+        Node *E = parseBracedExpr();
+        if (E == nullptr)
+          return nullptr;
+        Names.push_back(E);
       }
-      break;
+      return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
+    }
+    case 'r':
+      First += 2;
+      return make<NameType>("throw");
+    case 'w': {
+      First += 2;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return nullptr;
+      return make<ThrowExpr>(Ex);
     }
     }
+    return nullptr;
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+    return parseUnresolvedName();
   }
-  return first;
+  return nullptr;
 }
 
 // <call-offset> ::= h <nv-offset> _
@@ -3811,26 +4291,15 @@ static const char *parse_name(const char
 //
 // <v-offset>  ::= <offset number> _ <virtual offset number>
 //               # virtual base override, with vcall offset
-
-static const char *parse_call_offset(const char *first, const char *last) {
-  if (first != last) {
-    switch (*first) {
-    case 'h': {
-      const char *t = parse_number(first + 1, last);
-      if (t != first + 1 && t != last && *t == '_')
-        first = t + 1;
-    } break;
-    case 'v': {
-      const char *t = parse_number(first + 1, last);
-      if (t != first + 1 && t != last && *t == '_') {
-        const char *t2 = parse_number(++t, last);
-        if (t2 != t && t2 != last && *t2 == '_')
-          first = t2 + 1;
-      }
-    } break;
-    }
-  }
-  return first;
+bool Db::parseCallOffset() {
+  // Just scan through the call offset, we never add this information into the
+  // output.
+  if (consumeIf('h'))
+    return parseNumber(true).empty() || !consumeIf('_');
+  if (consumeIf('v'))
+    return parseNumber(true).empty() || !consumeIf('_') ||
+           parseNumber(true).empty() || !consumeIf('_');
+  return true;
 }
 
 // <special-name> ::= TV <type>    # virtual table
@@ -3843,471 +4312,580 @@ static const char *parse_call_offset(con
 //                    # second call-offset is result adjustment
 //                ::= T <call-offset> <base encoding>
 //                    # base is the nominal target function of thunk
-//                ::= GV <object name> # Guard variable for one-time
-//                initialization
+//                ::= GV <object name> # Guard variable for one-time initialization
 //                                     # No <type>
 //                ::= TW <object name> # Thread-local wrapper
 //                ::= TH <object name> # Thread-local initialization
-//      extension ::= TC <first type> <number> _ <second type> # construction
-//      vtable for second-in-first
+//                ::= GR <object name> _             # First temporary
+//                ::= 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 <class C>
-static const char *parse_special_name(const char *first, const char *last,
-                                      C &db) {
-  if (last - first > 2) {
-    const char *t;
-    switch (*first) {
-    case 'T':
-      switch (first[1]) {
-      case 'V':
-        // TV <type>    # virtual table
-        t = parse_type(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "vtable for ");
-          first = t;
-        }
-        break;
-      case 'T':
-        // TT <type>    # VTT structure (construction vtable index)
-        t = parse_type(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "VTT for ");
-          first = t;
-        }
-        break;
-      case 'I':
-        // TI <type>    # typeinfo structure
-        t = parse_type(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "typeinfo for ");
-          first = t;
-        }
-        break;
-      case 'S':
-        // TS <type>    # typeinfo name (null-terminated byte string)
-        t = parse_type(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "typeinfo name for ");
-          first = t;
-        }
-        break;
-      case 'c':
-        // Tc <call-offset> <call-offset> <base encoding>
-        {
-          const char *t0 = parse_call_offset(first + 2, last);
-          if (t0 == first + 2)
-            break;
-          const char *t1 = parse_call_offset(t0, last);
-          if (t1 == t0)
-            break;
-          t = parse_encoding(t1, last, db);
-          if (t != t1) {
-            if (db.names.empty())
-              return first;
-            db.names.back().first.insert(0, "covariant return thunk to ");
-            first = t;
-          }
-        }
-        break;
-      case 'C':
-        // extension ::= TC <first type> <number> _ <second type> # construction
-        // vtable for second-in-first
-        t = parse_type(first + 2, last, db);
-        if (t != first + 2) {
-          const char *t0 = parse_number(t, last);
-          if (t0 != t && t0 != last && *t0 == '_') {
-            const char *t1 = parse_type(++t0, last, db);
-            if (t1 != t0) {
-              if (db.names.size() < 2)
-                return first;
-              auto left = db.names.back().move_full();
-              db.names.pop_back();
-              if (db.names.empty())
-                return first;
-              db.names.back().first = "construction vtable for " +
-                                      std::move(left) + "-in-" +
-                                      db.names.back().move_full();
-              first = t1;
-            }
-          }
-        }
-        break;
-      case 'W':
-        // TW <object name> # Thread-local wrapper
-        t = parse_name(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "thread-local wrapper routine for ");
-          first = t;
-        }
-        break;
-      case 'H':
-        // TH <object name> # Thread-local initialization
-        t = parse_name(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(
-              0, "thread-local initialization routine for ");
-          first = t;
-        }
-        break;
-      default:
-        // T <call-offset> <base encoding>
-        {
-          const char *t0 = parse_call_offset(first + 1, last);
-          if (t0 == first + 1)
-            break;
-          t = parse_encoding(t0, last, db);
-          if (t != t0) {
-            if (db.names.empty())
-              return first;
-            if (first[1] == 'v') {
-              db.names.back().first.insert(0, "virtual thunk to ");
-              first = t;
-            } else {
-              db.names.back().first.insert(0, "non-virtual thunk to ");
-              first = t;
-            }
-          }
-        }
-        break;
-      }
-      break;
-    case 'G':
-      switch (first[1]) {
-      case 'V':
-        // GV <object name> # Guard variable for one-time initialization
-        t = parse_name(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "guard variable for ");
-          first = t;
-        }
-        break;
-      case 'R':
-        // extension ::= GR <object name> # reference temporary for object
-        t = parse_name(first + 2, last, db);
-        if (t != first + 2) {
-          if (db.names.empty())
-            return first;
-          db.names.back().first.insert(0, "reference temporary for ");
-          first = t;
-        }
-        break;
-      }
-      break;
+Node *Db::parseSpecialName() {
+  switch (look()) {
+  case 'T':
+    switch (look(1)) {
+    // TV <type>    # virtual table
+    case 'V': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<SpecialName>("vtable for ", Ty);
+    }
+    // TT <type>    # VTT structure (construction vtable index)
+    case 'T': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<SpecialName>("VTT for ", Ty);
+    }
+    // TI <type>    # typeinfo structure
+    case 'I': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<SpecialName>("typeinfo for ", Ty);
+    }
+    // TS <type>    # typeinfo name (null-terminated byte string)
+    case 'S': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<SpecialName>("typeinfo name for ", Ty);
+    }
+    // Tc <call-offset> <call-offset> <base encoding>
+    case 'c': {
+      First += 2;
+      if (parseCallOffset() || parseCallOffset())
+        return nullptr;
+      Node *Encoding = parseEncoding();
+      if (Encoding == nullptr)
+        return nullptr;
+      return make<SpecialName>("covariant return thunk to ", Encoding);
+    }
+    // extension ::= TC <first type> <number> _ <second type>
+    //               # construction vtable for second-in-first
+    case 'C': {
+      First += 2;
+      Node *FirstType = parseType();
+      if (FirstType == nullptr)
+        return nullptr;
+      if (parseNumber(true).empty() || !consumeIf('_'))
+        return nullptr;
+      Node *SecondType = parseType();
+      if (SecondType == nullptr)
+        return nullptr;
+      return make<CtorVtableSpecialName>(SecondType, FirstType);
+    }
+    // TW <object name> # Thread-local wrapper
+    case 'W': {
+      First += 2;
+      Node *Name = parseName();
+      if (Name == nullptr)
+        return nullptr;
+      return make<SpecialName>("thread-local wrapper routine for ", Name);
+    }
+    // TH <object name> # Thread-local initialization
+    case 'H': {
+      First += 2;
+      Node *Name = parseName();
+      if (Name == nullptr)
+        return nullptr;
+      return make<SpecialName>("thread-local initialization routine for ", Name);
+    }
+    // T <call-offset> <base encoding>
+    default: {
+      ++First;
+      bool IsVirt = look() == 'v';
+      if (parseCallOffset())
+        return nullptr;
+      Node *BaseEncoding = parseEncoding();
+      if (BaseEncoding == nullptr)
+        return nullptr;
+      if (IsVirt)
+        return make<SpecialName>("virtual thunk to ", BaseEncoding);
+      else
+        return make<SpecialName>("non-virtual thunk to ", BaseEncoding);
+    }
+    }
+  case 'G':
+    switch (look(1)) {
+    // GV <object name> # Guard variable for one-time initialization
+    case 'V': {
+      First += 2;
+      Node *Name = parseName();
+      if (Name == nullptr)
+        return nullptr;
+      return make<SpecialName>("guard variable for ", Name);
+    }
+    // GR <object name> # reference temporary for object
+    // GR <object name> _             # First temporary
+    // GR <object name> <seq-id> _    # Subsequent temporaries
+    case 'R': {
+      First += 2;
+      Node *Name = parseName();
+      if (Name == nullptr)
+        return nullptr;
+      size_t Count;
+      bool ParsedSeqId = !parseSeqId(&Count);
+      if (!consumeIf('_') && ParsedSeqId)
+        return nullptr;
+      return make<SpecialName>("reference temporary for ", Name);
+    }
     }
   }
-  return first;
+  return nullptr;
 }
 
-namespace {
-template <class T> class save_value {
-  T &restore_;
-  T original_value_;
+// <encoding> ::= <function name> <bare-function-type>
+//            ::= <data name>
+//            ::= <special-name>
+Node *Db::parseEncoding() {
+  // Always "tag" templates (insert them into Db::TemplateParams) unless we're
+  // doing a second parse to resolve a forward template reference, in which case
+  // we only tag templates if EncodingDepth > 1.
+  // FIXME: This is kinda broken; it would be better to make a forward reference
+  // and patch it all in one pass.
+  SwapAndRestore<bool> SaveTagTemplates(TagTemplates,
+                                        TagTemplates || EncodingDepth);
+  SwapAndRestore<unsigned> SaveEncodingDepth(EncodingDepth, EncodingDepth + 1);
+
+  if (look() == 'G' || look() == 'T')
+    return parseSpecialName();
+
+  auto IsEndOfEncoding = [&] {
+    // The set of chars that can potentially follow an <encoding> (none of which
+    // can start a <type>). Enumerating these allows us to avoid speculative
+    // parsing.
+    return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_';
+  };
+
+  NameState NameInfo;
+  Node *Name = parseName(&NameInfo);
+  if (Name == nullptr || IsEndOfEncoding())
+    return Name;
+
+  TagTemplates = false;
+
+  Node *ReturnType = nullptr;
+  if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) {
+    ReturnType = parseType();
+    if (ReturnType == nullptr)
+      return nullptr;
+  }
+
+  if (consumeIf('v'))
+    return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
+                                  NameInfo.CVQualifiers,
+                                  NameInfo.ReferenceQualifier);
+
+  size_t ParamsBegin = Names.size();
+  do {
+    Node *Ty = parseType();
+    if (Ty == nullptr)
+      return nullptr;
+    Names.push_back(Ty);
+  } while (!IsEndOfEncoding());
+
+  return make<FunctionEncoding>(ReturnType, Name,
+                                popTrailingNodeArray(ParamsBegin),
+                                NameInfo.CVQualifiers,
+                                NameInfo.ReferenceQualifier);
+}
+
+template <class Float>
+struct FloatData;
+
+template <>
+struct FloatData<float>
+{
+    static const size_t mangled_size = 8;
+    static const size_t max_demangled_size = 24;
+    static constexpr const char* spec = "%af";
+};
 
-public:
-  save_value(T &restore) : restore_(restore), original_value_(restore) {}
+constexpr const char* FloatData<float>::spec;
+
+template <>
+struct FloatData<double>
+{
+    static const size_t mangled_size = 16;
+    static const size_t max_demangled_size = 32;
+    static constexpr const char* spec = "%a";
+};
 
-  ~save_value() { restore_ = std::move(original_value_); }
+constexpr const char* FloatData<double>::spec;
 
-  save_value(const save_value &) = delete;
-  save_value &operator=(const save_value &) = delete;
+template <>
+struct FloatData<long double>
+{
+#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
+    defined(__wasm__)
+    static const size_t mangled_size = 32;
+#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
+    static const size_t mangled_size = 16;
+#else
+    static const size_t mangled_size = 20;  // May need to be adjusted to 16 or 24 on other platforms
+#endif
+    static const size_t max_demangled_size = 40;
+    static constexpr const char *spec = "%LaL";
 };
+
+constexpr const char *FloatData<long double>::spec;
+
+template <class Float> Node *Db::parseFloatingLiteral() {
+  const size_t N = FloatData<Float>::mangled_size;
+  if (numLeft() <= N)
+    return nullptr;
+  StringView Data(First, First + N);
+  for (char C : Data)
+    if (!std::isxdigit(C))
+      return nullptr;
+  First += N;
+  if (!consumeIf('E'))
+    return nullptr;
+  return make<FloatExpr<Float>>(Data);
 }
 
-// <encoding> ::= <function name> <bare-function-type>
-//            ::= <data name>
-//            ::= <special-name>
+// <seq-id> ::= <0-9A-Z>+
+bool Db::parseSeqId(size_t *Out) {
+  if (!(look() >= '0' && look() <= '9') &&
+      !(look() >= 'A' && look() <= 'Z'))
+    return true;
+
+  size_t Id = 0;
+  while (true) {
+    if (look() >= '0' && look() <= '9') {
+      Id *= 36;
+      Id += static_cast<size_t>(look() - '0');
+    } else if (look() >= 'A' && look() <= 'Z') {
+      Id *= 36;
+      Id += static_cast<size_t>(look() - 'A') + 10;
+    } else {
+      *Out = Id;
+      return false;
+    }
+    ++First;
+  }
+}
+
+// <substitution> ::= S <seq-id> _
+//                ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+//                                               ::std::char_traits<char>,
+//                                               ::std::allocator<char> >
+// <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> >
+Node *Db::parseSubstitution() {
+  if (!consumeIf('S'))
+    return nullptr;
 
-template <class C>
-static const char *parse_encoding(const char *first, const char *last, C &db) {
-  if (first != last) {
-    save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
-    ++db.encoding_depth;
-    save_value<decltype(db.tag_templates)> sb(db.tag_templates);
-    if (db.encoding_depth > 1)
-      db.tag_templates = true;
-    save_value<decltype(db.parsed_ctor_dtor_cv)> sp(db.parsed_ctor_dtor_cv);
-    db.parsed_ctor_dtor_cv = false;
-    switch (*first) {
-    case 'G':
-    case 'T':
-      first = parse_special_name(first, last, db);
+  if (std::islower(look())) {
+    Node *SpecialSub;
+    switch (look()) {
+    case 'a':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);
       break;
-    default: {
-      bool ends_with_template_args = false;
-      const char *t = parse_name(first, last, db, &ends_with_template_args);
-      unsigned cv = db.cv;
-      unsigned ref = db.ref;
-      if (t != first) {
-        if (t != last && *t != 'E' && *t != '.') {
-          save_value<bool> sb2(db.tag_templates);
-          db.tag_templates = false;
-          const char *t2;
-          std::string ret2;
-          if (db.names.empty())
-            return first;
-          const std::string &nm = db.names.back().first;
-          if (nm.empty())
-            return first;
-          if (!db.parsed_ctor_dtor_cv && ends_with_template_args) {
-            t2 = parse_type(t, last, db);
-            if (t2 == t)
-              return first;
-            if (db.names.size() < 2)
-              return first;
-            auto ret1 = std::move(db.names.back().first);
-            ret2 = std::move(db.names.back().second);
-            if (ret2.empty())
-              ret1 += ' ';
-            db.names.pop_back();
-            if (db.names.empty())
-              return first;
-
-            db.names.back().first.insert(0, ret1);
-            t = t2;
-          }
-          db.names.back().first += '(';
-          if (t != last && *t == 'v') {
-            ++t;
-          } else {
-            bool first_arg = true;
-            while (true) {
-              size_t k0 = db.names.size();
-              t2 = parse_type(t, last, db);
-              size_t k1 = db.names.size();
-              if (t2 == t)
-                break;
-              if (k1 > k0) {
-                std::string tmp;
-                for (size_t k = k0; k < k1; ++k) {
-                  if (!tmp.empty())
-                    tmp += ", ";
-                  tmp += db.names[k].move_full();
-                }
-                for (size_t k = k0; k < k1; ++k) {
-                  if (db.names.empty())
-                    return first;
-                  db.names.pop_back();
-                }
-                if (!tmp.empty()) {
-                  if (db.names.empty())
-                    return first;
-                  if (!first_arg)
-                    db.names.back().first += ", ";
-                  else
-                    first_arg = false;
-                  db.names.back().first += tmp;
-                }
-              }
-              t = t2;
-            }
-          }
-          if (db.names.empty())
-            return first;
-          db.names.back().first += ')';
-          if (cv & CV_const)
-            db.names.back().first.append(" const");
-          if (cv & CV_volatile)
-            db.names.back().first.append(" volatile");
-          if (cv & CV_restrict)
-            db.names.back().first.append(" restrict");
-          if (ref == 1)
-            db.names.back().first.append(" &");
-          else if (ref == 2)
-            db.names.back().first.append(" &&");
-          db.names.back().first += ret2;
-          first = t;
-        } else
-          first = t;
-      }
+    case 'b':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string);
+      break;
+    case 's':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);
+      break;
+    case 'i':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);
+      break;
+    case 'o':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);
+      break;
+    case 'd':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);
       break;
+    default:
+      return nullptr;
     }
+    // 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);
+    if (WithTags != SpecialSub) {
+      Subs.push_back(WithTags);
+      SpecialSub = WithTags;
     }
+    return SpecialSub;
   }
-  return first;
+
+  //                ::= S_
+  if (consumeIf('_')) {
+    if (Subs.empty())
+      return nullptr;
+    return Subs[0];
+  }
+
+  //                ::= S <seq-id> _
+  size_t Index = 0;
+  if (parseSeqId(&Index))
+    return nullptr;
+  ++Index;
+  if (!consumeIf('_') || Index >= Subs.size())
+    return nullptr;
+  return Subs[Index];
 }
 
-// _block_invoke
-// _block_invoke<decimal-digit>+
-// _block_invoke_<decimal-digit>+
-
-template <class C>
-static const char *parse_block_invoke(const char *first, const char *last,
-                                      C &db) {
-  if (last - first >= 13) {
-    const char test[] = "_block_invoke";
-    const char *t = first;
-    for (int i = 0; i < 13; ++i, ++t) {
-      if (*t != test[i])
-        return first;
-    }
-    if (t != last) {
-      if (*t == '_') {
-        // must have at least 1 decimal digit
-        if (++t == last || !std::isdigit(*t))
-          return first;
-        ++t;
-      }
-      // parse zero or more digits
-      while (t != last && isdigit(*t))
-        ++t;
+// <template-param> ::= T_    # first template parameter
+//                  ::= T <parameter-2 non-negative number> _
+Node *Db::parseTemplateParam() {
+  if (!consumeIf('T'))
+    return nullptr;
+
+  size_t Index = 0;
+  if (!consumeIf('_')) {
+    if (parsePositiveInteger(&Index))
+      return nullptr;
+    ++Index;
+    if (!consumeIf('_'))
+      return nullptr;
+  }
+
+  // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter list
+  // are mangled as the corresponding artificial template type parameter.
+  if (ParsingLambdaParams)
+    return make<NameType>("auto");
+
+  if (Index >= TemplateParams.size()) {
+    FixForwardReferences = true;
+    return make<NameType>("FORWARD_REFERENCE");
+  }
+  return TemplateParams[Index];
+}
+
+// <template-arg> ::= <type>                    # type or template
+//                ::= X <expression> E          # expression
+//                ::= <expr-primary>            # simple expressions
+//                ::= J <template-arg>* E       # argument pack
+//                ::= LZ <encoding> E           # extension
+Node *Db::parseTemplateArg() {
+  switch (look()) {
+  case 'X': {
+    ++First;
+    Node *Arg = parseExpr();
+    if (Arg == nullptr || !consumeIf('E'))
+      return nullptr;
+    return Arg;
+  }
+  case 'J': {
+    ++First;
+    size_t ArgsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *Arg = parseTemplateArg();
+      if (Arg == nullptr)
+        return nullptr;
+      Names.push_back(Arg);
+    }
+    NodeArray Args = popTrailingNodeArray(ArgsBegin);
+    return make<TemplateArgumentPack>(Args);
+  }
+  case 'L': {
+    //                ::= LZ <encoding> E           # extension
+    if (look(1) == 'Z') {
+      First += 2;
+      Node *Arg = parseEncoding();
+      if (Arg == nullptr || !consumeIf('E'))
+        return nullptr;
+      return Arg;
     }
-    if (db.names.empty())
-      return first;
-    db.names.back().first.insert(0, "invocation function for block in ");
-    first = t;
+    //                ::= <expr-primary>            # simple expressions
+    return parseExprPrimary();
+  }
+  default:
+    return parseType();
   }
-  return first;
 }
 
-// extension
-// <dot-suffix> := .<anything and everything>
+// <template-args> ::= I <template-arg>* E
+//     extension, the abi says <template-arg>+
+Node *Db::parseTemplateArgs() {
+  if (!consumeIf('I'))
+    return nullptr;
 
-template <class C>
-static const char *parse_dot_suffix(const char *first, const char *last,
-                                    C &db) {
-  if (first != last && *first == '.') {
-    if (db.names.empty())
-      return first;
-    db.names.back().first += " (" + std::string(first, last) + ")";
-    first = last;
+  // <template-params> refer to the innermost <template-args>. Clear out any
+  // outer args that we may have inserted into TemplateParams.
+  if (TagTemplates)
+    TemplateParams.clear();
+
+  size_t ArgsBegin = Names.size();
+  while (!consumeIf('E')) {
+    if (TagTemplates) {
+      auto OldParams = std::move(TemplateParams);
+      Node *Arg = parseTemplateArg();
+      TemplateParams = std::move(OldParams);
+      if (Arg == nullptr)
+        return nullptr;
+      Names.push_back(Arg);
+      Node *TableEntry = Arg;
+      if (Arg->getKind() == Node::KTemplateArgumentPack) {
+        TableEntry = make<ParameterPack>(
+            static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
+      }
+      TemplateParams.push_back(TableEntry);
+    } else {
+      Node *Arg = parseTemplateArg();
+      if (Arg == nullptr)
+        return nullptr;
+      Names.push_back(Arg);
+    }
   }
-  return first;
+  return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
 }
 
-// <block-involcaton-function> ___Z<encoding>_block_invoke
-// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
-// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
-// <mangled-name> ::= _Z<encoding>
-//                ::= <type>
+// <discriminator> := _ <non-negative number>      # when number < 10
+//                 := __ <non-negative number> _   # when number >= 10
+//  extension      := decimal-digit+               # at the end of string
 
-template <class C>
-static void demangle(const char *first, const char *last, C &db, int &status) {
-  if (first >= last) {
-    status = invalid_mangled_name;
-    return;
-  }
-  if (*first == '_') {
-    if (last - first >= 4) {
-      if (first[1] == 'Z') {
-        const char *t = parse_encoding(first + 2, last, db);
-        if (t != first + 2 && t != last && *t == '.')
-          t = parse_dot_suffix(t, last, db);
-        if (t != last)
-          status = invalid_mangled_name;
-      } else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z') {
-        const char *t = parse_encoding(first + 4, last, db);
-        if (t != first + 4 && t != last) {
-          const char *t1 = parse_block_invoke(t, last, db);
-          if (t1 != last)
-            status = invalid_mangled_name;
-        } else
-          status = invalid_mangled_name;
-      } else
-        status = invalid_mangled_name;
-    } else
-      status = invalid_mangled_name;
-  } else {
-    const char *t = parse_type(first, last, db);
-    if (t != last)
-      status = invalid_mangled_name;
+const char*
+parse_discriminator(const char* first, const char* last)
+{
+    // parse but ignore discriminator
+    if (first != last)
+    {
+        if (*first == '_')
+        {
+            const char* t1 = first+1;
+            if (t1 != last)
+            {
+                if (std::isdigit(*t1))
+                    first = t1+1;
+                else if (*t1 == '_')
+                {
+                    for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+                        ;
+                    if (t1 != last && *t1 == '_')
+                        first = t1 + 1;
+                }
+            }
+        }
+        else if (std::isdigit(*first))
+        {
+            const char* t1 = first+1;
+            for (; t1 != last && std::isdigit(*t1); ++t1)
+                ;
+            if (t1 == last)
+                first = last;
+        }
+    }
+    return first;
+}
+
+// <mangled-name> ::= _Z <encoding>
+//                ::= <type>
+// extension      ::= ___Z <encoding> _block_invoke
+// extension      ::= ___Z <encoding> _block_invoke<decimal-digit>+
+// extension      ::= ___Z <encoding> _block_invoke_<decimal-digit>+
+Node *Db::parse() {
+  if (consumeIf("_Z")) {
+    Node *Encoding = parseEncoding();
+    if (Encoding == nullptr)
+      return nullptr;
+    if (look() == '.') {
+      Encoding = make<DotSuffix>(Encoding, StringView(First, Last));
+      First = Last;
+    }
+    if (numLeft() != 0)
+      return nullptr;
+    return Encoding;
+  }
+
+  if (consumeIf("___Z")) {
+    Node *Encoding = parseEncoding();
+    if (Encoding == nullptr || !consumeIf("_block_invoke"))
+      return nullptr;
+    bool RequireNumber = consumeIf('_');
+    if (parseNumber().empty() && RequireNumber)
+      return nullptr;
+    if (numLeft() != 0)
+      return nullptr;
+    return make<SpecialName>("invocation function for block in ", Encoding);
   }
-  if (status == success && db.names.empty())
-    status = invalid_mangled_name;
+
+  Node *Ty = parseType();
+  if (numLeft() != 0)
+    return nullptr;
+  return Ty;
 }
+}  // unnamed namespace
 
-namespace {
-template <class StrT> struct string_pair {
-  StrT first;
-  StrT second;
-
-  string_pair() = default;
-  string_pair(StrT f) : first(std::move(f)) {}
-  string_pair(StrT f, StrT s) : first(std::move(f)), second(std::move(s)) {}
-  template <size_t N> string_pair(const char (&s)[N]) : first(s, N - 1) {}
-
-  size_t size() const { return first.size() + second.size(); }
-  bool empty() const { return first.empty() && second.empty(); }
-  StrT full() const { return first + second; }
-  StrT move_full() { return std::move(first) + std::move(second); }
+enum {
+  unknown_error = -4,
+  invalid_args = -3,
+  invalid_mangled_name = -2,
+  memory_alloc_failure = -1,
+  success = 0,
 };
 
-struct Db {
-  typedef std::vector<string_pair<std::string>> sub_type;
-  typedef std::vector<sub_type> template_param_type;
-  sub_type names;
-  template_param_type subs;
-  std::vector<template_param_type> template_param;
-  unsigned cv = 0;
-  unsigned ref = 0;
-  unsigned encoding_depth = 0;
-  bool parsed_ctor_dtor_cv = false;
-  bool tag_templates = true;
-  bool fix_forward_references = false;
-  bool try_to_parse_template_args = true;
-
-  Db() : subs(0, names), template_param(0, subs) {}
-};
-}
+char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
+                            size_t *N, int *Status) {
+  if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
+    if (Status)
+      *Status = invalid_args;
+    return nullptr;
+  }
 
-char *llvm::itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
-                            int *status) {
-  if (mangled_name == nullptr || (buf != nullptr && n == nullptr)) {
-    if (status)
-      *status = invalid_args;
-    return nullptr;
-  }
-  size_t internal_size = buf != nullptr ? *n : 0;
-  Db db;
-  db.template_param.emplace_back();
-  int internal_status = success;
-  size_t len = std::strlen(mangled_name);
-  demangle(mangled_name, mangled_name + len, db, internal_status);
-  if (internal_status == success && db.fix_forward_references &&
-      !db.template_param.empty() && !db.template_param.front().empty()) {
-    db.fix_forward_references = false;
-    db.tag_templates = false;
-    db.names.clear();
-    db.subs.clear();
-    demangle(mangled_name, mangled_name + len, db, internal_status);
-    if (db.fix_forward_references)
-      internal_status = invalid_mangled_name;
-  }
-  if (internal_status == success) {
-    size_t sz = db.names.back().size() + 1;
-    if (sz > internal_size) {
-      char *newbuf = static_cast<char *>(std::realloc(buf, sz));
-      if (newbuf == nullptr) {
-        internal_status = memory_alloc_failure;
-        buf = nullptr;
-      } else {
-        buf = newbuf;
-        if (n != nullptr)
-          *n = sz;
-      }
-    }
-    if (buf != nullptr) {
-      db.names.back().first += db.names.back().second;
-      std::memcpy(buf, db.names.back().first.data(), sz - 1);
-      buf[sz - 1] = char(0);
-    }
-  } else
-    buf = nullptr;
-  if (status)
-    *status = internal_status;
-  return buf;
+  size_t BufSize = Buf != nullptr ? *N : 0;
+  int InternalStatus = success;
+  size_t MangledNameLength = std::strlen(MangledName);
+
+  Db Parser(MangledName, MangledName + MangledNameLength);
+  Node *AST = Parser.parse();
+
+  if (AST == nullptr)
+    InternalStatus = invalid_mangled_name;
+
+  if (InternalStatus == success && Parser.FixForwardReferences &&
+      !Parser.TemplateParams.empty()) {
+    Parser.FixForwardReferences = false;
+    Parser.TagTemplates = false;
+    Parser.Names.clear();
+    Parser.Subs.clear();
+    Parser.First = MangledName;
+    Parser.Last = MangledName + MangledNameLength;
+    AST = Parser.parse();
+    if (AST == nullptr || Parser.FixForwardReferences)
+      InternalStatus = invalid_mangled_name;
+  }
+
+  if (InternalStatus == success && AST->containsUnexpandedParameterPack())
+    InternalStatus = invalid_mangled_name;
+
+  if (InternalStatus == success) {
+    if (Buf == nullptr) {
+      BufSize = 1024;
+      Buf = static_cast<char*>(std::malloc(BufSize));
+    }
+
+    if (Buf) {
+      OutputStream Stream(Buf, BufSize);
+      AST->print(Stream);
+      Stream += '\0';
+      if (N != nullptr)
+        *N = Stream.getCurrentPosition();
+      Buf = Stream.getBuffer();
+    } else
+      InternalStatus = memory_alloc_failure;
+  }
+
+  if (Status)
+    *Status = InternalStatus;
+  return InternalStatus == success ? Buf : nullptr;
 }




More information about the llvm-commits mailing list