Merge commit f26c8d18976

* upstream svn@323906

Test: git diff f26c8d18976 ==  git diff 05ba328 c9dec13
Change-Id: If992e433888af8b631b54abd4dc81258d9462e89
diff --git a/.arcconfig b/.arcconfig
index 0c5cf4e..08cd16e 100644
--- a/.arcconfig
+++ b/.arcconfig
@@ -1,4 +1,4 @@
 {
-  "project_id" : "libcxxabi",
+  "repository.callsign" : "CXXA",
   "conduit_uri" : "https://reviews.llvm.org/"
 }
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 456250e..35eb130 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,7 +21,7 @@
   project(libcxxabi CXX C)
 
   set(PACKAGE_NAME libcxxabi)
-  set(PACKAGE_VERSION 6.0.0svn)
+  set(PACKAGE_VERSION 7.0.0svn)
   set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
   set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org")
 
@@ -69,6 +69,7 @@
 option(LIBCXXABI_INCLUDE_TESTS "Generate build targets for the libc++abi unit tests." ${LLVM_INCLUDE_TESTS})
 set(LIBCXXABI_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
     "Define suffix of library directory name (32/64)")
+option(LIBCXXABI_INSTALL_LIBRARY "Install the libc++abi library." ON)
 set(LIBCXXABI_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.")
 set(LIBCXXABI_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.")
 set(LIBCXXABI_SYSROOT "" CACHE PATH "Sysroot for cross compiling.")
@@ -114,6 +115,7 @@
         ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBCXX_INCLUDES}
         ${LIBCXXABI_LIBCXX_INCLUDE_DIRS}
         ${LLVM_INCLUDE_DIR}/c++/v1
+  NO_CMAKE_FIND_ROOT_PATH
   )
 
 set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXXABI_LIBCXX_INCLUDES}" CACHE PATH
@@ -126,6 +128,7 @@
         ${LIBCXXABI_LIBCXX_INCLUDES}/../
         ${LIBCXXABI_LIBCXX_SRC_DIRS}
   NO_DEFAULT_PATH
+  NO_CMAKE_FIND_ROOT_PATH
   )
 
 if (LIBCXXABI_LIBCXX_PATH STREQUAL "LIBCXXABI_LIBCXX_PATH-NOTFOUND")
@@ -424,6 +427,7 @@
           ${LLVM_MAIN_SRC_DIR}/projects/libunwind/include
           ${LLVM_MAIN_SRC_DIR}/runtimes/libunwind/include
     NO_DEFAULT_PATH
+    NO_CMAKE_FIND_ROOT_PATH
   )
 
   if (LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL-NOTFOUND")
@@ -439,18 +443,21 @@
 # soname, etc...
 add_subdirectory(src)
 
-if (NOT LIBCXXABI_INCLUDE_TESTS OR (LIBCXXABI_STANDALONE_BUILD AND NOT LIBCXXABI_ENABLE_SHARED))
-  # We can't reasonably test the system C++ library with a static libc++abi.
-  # We either need to be able to replace libc++abi at run time (with a shared
-  # libc++abi), or we need to be able to replace the C++ runtime (with a non-
-  # standalone build).
-  message(WARNING "The libc++abi tests aren't valid when libc++abi is built "
-                  "standalone (i.e. outside of llvm/projects/libcxxabi ) and "
-                  "is built without a shared library.  Either build a shared "
-                  "library, build libc++abi at the same time as you build "
-                  "libc++, or do without testing.  No check target will be "
-                  "available!")
-else()
-  add_subdirectory(test)
-  add_subdirectory(fuzz)
+if (LIBCXXABI_INCLUDE_TESTS)
+  if (LIBCXXABI_STANDALONE_BUILD AND NOT LIBCXXABI_ENABLE_SHARED)
+    # We can't reasonably test the system C++ library with a static
+    # libc++abi.  We either need to be able to replace libc++abi at
+    # run time (with a shared libc++abi), or we need to be able to
+    # replace the C++ runtime (with a non- standalone build).
+    message(WARNING "The libc++abi tests aren't valid when libc++abi "
+                    "is built standalone (i.e. outside of "
+                    "llvm/projects/libcxxabi ) and is built without "
+                    "a shared library.  Either build a shared "
+                    "library, build libc++abi at the same time as "
+                    "you build libc++, or do without testing.  No "
+                    "check target will be available!")
+  else()
+    add_subdirectory(test)
+    add_subdirectory(fuzz)
+  endif()
 endif()
diff --git a/CREDITS.TXT b/CREDITS.TXT
index 9c910fc..fbb6cbf 100644
--- a/CREDITS.TXT
+++ b/CREDITS.TXT
@@ -58,7 +58,7 @@
 D: Minor patches and fixes
 
 N: Jon Roelofs
-E: jonathan@codesourcery.com
+E: jroelofs@jroelofs.com
 D: ARM EHABI Unwind & Exception Handling, Bare-metal
 
 N: Nico Weber
diff --git a/cmake/Modules/HandleOutOfTreeLLVM.cmake b/cmake/Modules/HandleOutOfTreeLLVM.cmake
index 8e74208..ed0b527 100644
--- a/cmake/Modules/HandleOutOfTreeLLVM.cmake
+++ b/cmake/Modules/HandleOutOfTreeLLVM.cmake
@@ -107,14 +107,22 @@
     set(LLVM_ENABLE_SPHINX OFF)
   endif()
 
-  # Required LIT Configuration ------------------------------------------------
-  # Define the default arguments to use with 'lit', and an option for the user
-  # to override.
-  set(LIT_ARGS_DEFAULT "-sv --show-xfail --show-unsupported")
-  if (MSVC OR XCODE)
-    set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+  # In a standalone build, we don't have llvm to automatically generate the
+  # llvm-lit script for us.  So we need to provide an explicit directory that
+  # the configurator should write the script into.
+  set(LLVM_LIT_OUTPUT_DIR "${libcxxabi_BINARY_DIR}/bin")
+
+  if (LLVM_INCLUDE_TESTS)
+    # Required LIT Configuration ------------------------------------------------
+    # Define the default arguments to use with 'lit', and an option for the user
+    # to override.
+    set(LLVM_EXTERNAL_LIT "${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py")
+    set(LIT_ARGS_DEFAULT "-sv --show-xfail --show-unsupported")
+    if (MSVC OR XCODE)
+      set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+    endif()
+    set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
   endif()
-  set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
 
   # Required doc configuration
   if (LLVM_ENABLE_SPHINX)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index adcc412..5a929cf 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -127,6 +127,9 @@
 # Build the shared library.
 if (LIBCXXABI_ENABLE_SHARED)
   add_library(cxxabi_shared SHARED $<TARGET_OBJECTS:cxxabi_objects>)
+  if(COMMAND llvm_setup_rpath)
+    llvm_setup_rpath(cxxabi_shared)
+  endif()
   target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES})
   set_target_properties(cxxabi_shared
                         PROPERTIES
@@ -151,7 +154,13 @@
 
 # Build the static library.
 if (LIBCXXABI_ENABLE_STATIC)
-  add_library(cxxabi_static STATIC $<TARGET_OBJECTS:cxxabi_objects>)
+  set(cxxabi_static_sources $<TARGET_OBJECTS:cxxabi_objects>)
+  if (LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_ENABLE_STATIC_UNWINDER)
+    if (TARGET unwind_static OR HAVE_LIBUNWIND)
+      list(APPEND cxxabi_static_sources $<TARGET_OBJECTS:unwind_objects>)
+    endif()
+  endif()
+  add_library(cxxabi_static STATIC ${cxxabi_static_sources})
   target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES})
   set_target_properties(cxxabi_static
                         PROPERTIES
@@ -173,17 +182,25 @@
 # Add a meta-target for both libraries.
 add_custom_target(cxxabi DEPENDS ${LIBCXXABI_TARGETS})
 
-install(TARGETS ${LIBCXXABI_TARGETS}
-  LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi
-  ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi
-  )
+if (LIBCXXABI_INSTALL_LIBRARY)
+  install(TARGETS ${LIBCXXABI_TARGETS}
+    LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi
+    ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi
+    )
+endif()
 
-if (NOT CMAKE_CONFIGURATION_TYPES)
+if (NOT CMAKE_CONFIGURATION_TYPES AND LIBCXXABI_INSTALL_LIBRARY)
   add_custom_target(install-cxxabi
     DEPENDS cxxabi
     COMMAND "${CMAKE_COMMAND}"
             -DCMAKE_INSTALL_COMPONENT=cxxabi
             -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake")
+  add_custom_target(install-cxxabi-stripped
+    DEPENDS cxxabi
+    COMMAND "${CMAKE_COMMAND}"
+            -DCMAKE_INSTALL_COMPONENT=cxxabi
+            -DCMAKE_INSTALL_DO_STRIP=1
+            -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake")
 
   # TODO: This is a legacy target name and should be removed at some point.
   add_custom_target(install-libcxxabi DEPENDS install-cxxabi)
diff --git a/src/cxa_default_handlers.cpp b/src/cxa_default_handlers.cpp
index f2e36b4..8231139 100644
--- a/src/cxa_default_handlers.cpp
+++ b/src/cxa_default_handlers.cpp
@@ -19,6 +19,7 @@
 #include "cxa_exception.hpp"
 #include "private_typeinfo.h"
 
+#if !defined(LIBCXXABI_SILENT_TERMINATE)
 static const char* cause = "uncaught";
 
 __attribute__((noreturn))
@@ -84,7 +85,6 @@
     std::terminate();
 }
 
-#if !defined(LIBCXXABI_SILENT_TERMINATE)
 static std::terminate_handler default_terminate_handler = demangling_terminate_handler;
 static std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
 #else
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index 7d17318..d0362dc 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -7,6 +7,12 @@
 //
 //===----------------------------------------------------------------------===//
 
+// 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
+
 #define _LIBCPP_NO_EXCEPTIONS
 
 #include "__cxxabi_config.h"
@@ -14,6 +20,7 @@
 #include <vector>
 #include <algorithm>
 #include <numeric>
+#include <cassert>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
@@ -26,20 +33,15 @@
 #endif
 #endif
 
-namespace __cxxabiv1
-{
+#ifndef NDEBUG
+#if __has_attribute(noinline) && __has_attribute(used)
+#define DUMP_METHOD __attribute__((noinline,used))
+#else
+#define DUMP_METHOD
+#endif
+#endif
 
-namespace
-{
-
-enum
-{
-    unknown_error = -4,
-    invalid_args = -3,
-    invalid_mangled_name,
-    memory_alloc_failure,
-    success
-};
+namespace {
 
 class StringView {
   const char *First;
@@ -76,6 +78,7 @@
   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; }
 };
 
 bool operator==(const StringView &LHS, const StringView &RHS) {
@@ -104,6 +107,10 @@
   OutputStream(char *StartBuf, size_t Size)
       : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
 
+  /// 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();
+
   OutputStream &operator+=(StringView R) {
     size_t Size = R.size();
     if (Size == 0)
@@ -120,41 +127,7 @@
     return *this;
   }
 
-  // Offset of position in buffer, used for building stream_string_view.
-  typedef unsigned StreamPosition;
-
-  // StringView into a stream, used for caching the ast nodes.
-  class StreamStringView {
-    StreamPosition First, Last;
-
-    friend class OutputStream;
-
-  public:
-    StreamStringView() : First(0), Last(0) {}
-
-    StreamStringView(StreamPosition First_, StreamPosition Last_)
-        : First(First_), Last(Last_) {}
-
-    bool empty() const { return First == Last; }
-  };
-
-  OutputStream &operator+=(StreamStringView &s) {
-    size_t Sz = static_cast<size_t>(s.Last - s.First);
-    if (Sz == 0)
-      return *this;
-    grow(Sz);
-    memmove(Buffer + CurrentPosition, Buffer + s.First, Sz);
-    CurrentPosition += Sz;
-    return *this;
-  }
-
-  StreamPosition getCurrentPosition() const {
-    return static_cast<StreamPosition>(CurrentPosition);
-  }
-
-  StreamStringView makeStringViewFromPastPosition(StreamPosition Pos) {
-    return StreamStringView(Pos, getCurrentPosition());
-  }
+  size_t getCurrentPosition() const { return CurrentPosition; };
 
   char back() const {
     return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
@@ -167,6 +140,21 @@
   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);
+  }
+  ~SwapAndRestore() { Restore = std::move(OriginalValue); }
+
+  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 {
@@ -177,7 +165,9 @@
     KQualType,
     KConversionOperatorType,
     KPostfixQualifiedType,
+    KElaboratedTypeSpefType,
     KNameType,
+    KAbiTagAttr,
     KObjCProtoName,
     KPointerType,
     KLValueReferenceType,
@@ -185,16 +175,19 @@
     KPointerToMemberType,
     KArrayType,
     KFunctionType,
-    KTopLevelFunctionDecl,
-    KFunctionQualType,
-    KFunctionRefQualType,
+    KNoexceptSpec,
+    KDynamicExceptionSpec,
+    KFunctionEncoding,
     KLiteralOperator,
     KSpecialName,
     KCtorVtableSpecialName,
     KQualifiedName,
     KEmptyName,
     KVectorType,
-    KTemplateParams,
+    KParameterPack,
+    KTemplateArgumentPack,
+    KParameterPackExpansion,
+    KTemplateArgs,
     KNameWithTemplateArgs,
     KGlobalQualifiedName,
     KStdQualifiedName,
@@ -203,32 +196,77 @@
     KCtorDtorName,
     KDtorName,
     KUnnamedTypeName,
-    KLambdaTypeName,
+    KClosureTypeName,
     KExpr,
+    KBracedExpr,
+    KBracedRangeExpr,
   };
 
-  const Kind K;
+  static constexpr unsigned NoParameterPack =
+    std::numeric_limits<unsigned>::max();
+  unsigned ParameterPackSize = NoParameterPack;
 
-private:
-  // If this Node has any RHS part, potentally many Nodes further down.
-  const unsigned HasRHSComponent : 1;
-  const unsigned HasFunction : 1;
-  const unsigned HasArray : 1;
+  Kind K;
 
-public:
-  Node(Kind K_, bool HasRHS_ = false, bool HasFunction_ = false,
-       bool HasArray_ = false)
-      : K(K_), HasRHSComponent(HasRHS_), HasFunction(HasFunction_),
-        HasArray(HasArray_) {}
+  /// 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, };
 
-  bool hasRHSComponent() const { return HasRHSComponent; }
-  bool hasArray() const { return HasArray; }
-  bool hasFunction() const { return HasFunction; }
+  /// Tracks if this node has a component on its right side, in which case we
+  /// need to call printRight.
+  Cache RHSComponentCache;
 
-  void print(OutputStream &s) const {
-    printLeft(s);
-    if (hasRHSComponent())
-      printRight(s);
+  /// 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.
@@ -244,6 +282,17 @@
 
   // Silence compiler warnings, this dtor will never be called.
   virtual ~Node() = default;
+
+#ifndef NDEBUG
+  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());
+  }
+#endif
 };
 
 class NodeArray {
@@ -251,17 +300,26 @@
   size_t NumElements;
 
 public:
-  NodeArray() : NumElements(0) {}
+  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; }
 
-  void printWithSeperator(OutputStream &S, StringView Seperator) const {
+  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 (Idx)
-        S += Seperator;
+      if (Elements[Idx]->isEmptyPackExpansion())
+        continue;
+      if (!FirstElement)
+        S += ", ";
+      FirstElement = false;
       Elements[Idx]->print(S);
     }
   }
@@ -284,20 +342,25 @@
 };
 
 class VendorExtQualType final : public Node {
-  const Node *Ext;
   const Node *Ty;
+  StringView Ext;
 
 public:
-  VendorExtQualType(Node *Ext_, Node *Ty_)
-      : Node(KVendorExtQualType), Ext(Ext_), Ty(Ty_) {}
+  VendorExtQualType(Node *Ty_, StringView Ext_)
+      : Node(KVendorExtQualType, Ty_->ParameterPackSize),
+        Ty(Ty_), Ext(Ext_) {}
 
   void printLeft(OutputStream &S) const override {
-    Ext->print(S);
+    Ty->print(S);
     S += " ";
-    Ty->printLeft(S);
+    S += Ext;
   }
+};
 
-  void printRight(OutputStream &S) const override { Ty->printRight(S); }
+enum FunctionRefQual : unsigned char {
+  FrefQualNone,
+  FrefQualLValue,
+  FrefQualRValue,
 };
 
 enum Qualifiers {
@@ -327,14 +390,19 @@
 
 public:
   QualType(Node *Child_, Qualifiers Quals_)
-      : Node(KQualType, Child_->hasRHSComponent(), Child_->hasFunction(),
-             Child_->hasArray()),
+      : Node(KQualType, Child_->ParameterPackSize, Child_->RHSComponentCache,
+             Child_->ArrayCache, Child_->FunctionCache),
         Quals(Quals_), Child(Child_) {}
 
-  QualType(Node::Kind ChildKind_, Node *Child_, Qualifiers Quals_)
-      : Node(ChildKind_, Child_->hasRHSComponent(), Child_->hasFunction(),
-             Child_->hasArray()),
-        Quals(Quals_), Child(Child_) {}
+  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);
@@ -348,7 +416,8 @@
   const Node *Ty;
 
 public:
-  ConversionOperatorType(Node *Ty_) : Node(KConversionOperatorType), Ty(Ty_) {}
+  ConversionOperatorType(Node *Ty_)
+      : Node(KConversionOperatorType, Ty_->ParameterPackSize), Ty(Ty_) {}
 
   void printLeft(OutputStream &S) const override {
     S += "operator ";
@@ -362,14 +431,13 @@
 
 public:
   PostfixQualifiedType(Node *Ty_, StringView Postfix_)
-      : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}
+      : Node(KPostfixQualifiedType, Ty_->ParameterPackSize),
+        Ty(Ty_), Postfix(Postfix_) {}
 
   void printLeft(OutputStream &s) const override {
     Ty->printLeft(s);
     s += Postfix;
   }
-
-  void printRight(OutputStream &S) const override { Ty->printRight(S); }
 };
 
 class NameType final : public Node {
@@ -384,25 +452,58 @@
   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;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    S += Kind;
+    S += ' ';
+    Child->print(S);
+  }
+};
+
+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 += "]";
+  }
+};
+
 class ObjCProtoName : public Node {
   Node *Ty;
-  Node *Protocol;
+  StringView Protocol;
 
   friend class PointerType;
 
 public:
-  ObjCProtoName(Node *Ty_, Node *Protocol_)
+  ObjCProtoName(Node *Ty_, StringView Protocol_)
       : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
 
   bool isObjCObject() const {
-    return Ty->K == KNameType &&
+    return Ty->getKind() == KNameType &&
            static_cast<NameType *>(Ty)->getName() == "objc_object";
   }
 
   void printLeft(OutputStream &S) const override {
-    Ty->printLeft(S);
+    Ty->print(S);
     S += "<";
-    Protocol->printLeft(S);
+    S += Protocol;
     S += ">";
   }
 };
@@ -412,30 +513,36 @@
 
 public:
   PointerType(Node *Pointee_)
-      : Node(KPointerType, Pointee_->hasRHSComponent()), Pointee(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->K != KObjCProtoName ||
+    if (Pointee->getKind() != KObjCProtoName ||
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
       Pointee->printLeft(s);
-      if (Pointee->hasArray())
+      if (Pointee->hasArray(s))
         s += " ";
-      if (Pointee->hasArray() || Pointee->hasFunction())
+      if (Pointee->hasArray(s) || Pointee->hasFunction(s))
         s += "(";
       s += "*";
     } else {
       const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
       s += "id<";
-      objcProto->Protocol->print(s);
+      s += objcProto->Protocol;
       s += ">";
     }
   }
 
   void printRight(OutputStream &s) const override {
-    if (Pointee->K != KObjCProtoName ||
+    if (Pointee->getKind() != KObjCProtoName ||
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
-      if (Pointee->hasArray() || Pointee->hasFunction())
+      if (Pointee->hasArray(s) || Pointee->hasFunction(s))
         s += ")";
       Pointee->printRight(s);
     }
@@ -447,20 +554,25 @@
 
 public:
   LValueReferenceType(Node *Pointee_)
-      : Node(KLValueReferenceType, Pointee_->hasRHSComponent()),
+      : Node(KLValueReferenceType, Pointee_->ParameterPackSize,
+             Pointee_->RHSComponentCache),
         Pointee(Pointee_) {}
 
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
+  }
+
   void printLeft(OutputStream &s) const override {
     Pointee->printLeft(s);
-    if (Pointee->hasArray())
+    if (Pointee->hasArray(s))
       s += " ";
-    if (Pointee->hasArray() || Pointee->hasFunction())
+    if (Pointee->hasArray(s) || Pointee->hasFunction(s))
       s += "(&";
     else
       s += "&";
   }
   void printRight(OutputStream &s) const override {
-    if (Pointee->hasArray() || Pointee->hasFunction())
+    if (Pointee->hasArray(s) || Pointee->hasFunction(s))
       s += ")";
     Pointee->printRight(s);
   }
@@ -471,21 +583,26 @@
 
 public:
   RValueReferenceType(Node *Pointee_)
-      : Node(KRValueReferenceType, Pointee_->hasRHSComponent()),
+      : Node(KRValueReferenceType, Pointee_->ParameterPackSize,
+             Pointee_->RHSComponentCache),
         Pointee(Pointee_) {}
 
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
+  }
+
   void printLeft(OutputStream &s) const override {
     Pointee->printLeft(s);
-    if (Pointee->hasArray())
+    if (Pointee->hasArray(s))
       s += " ";
-    if (Pointee->hasArray() || Pointee->hasFunction())
+    if (Pointee->hasArray(s) || Pointee->hasFunction(s))
       s += "(&&";
     else
       s += "&&";
   }
 
   void printRight(OutputStream &s) const override {
-    if (Pointee->hasArray() || Pointee->hasFunction())
+    if (Pointee->hasArray(s) || Pointee->hasFunction(s))
       s += ")";
     Pointee->printRight(s);
   }
@@ -497,12 +614,19 @@
 
 public:
   PointerToMemberType(Node *ClassType_, Node *MemberType_)
-      : Node(KPointerToMemberType, MemberType_->hasRHSComponent()),
+      : 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() || MemberType->hasFunction())
+    if (MemberType->hasArray(s) || MemberType->hasFunction(s))
       s += "(";
     else
       s += " ";
@@ -511,7 +635,7 @@
   }
 
   void printRight(OutputStream &s) const override {
-    if (MemberType->hasArray() || MemberType->hasFunction())
+    if (MemberType->hasArray(s) || MemberType->hasFunction(s))
       s += ")";
     MemberType->printRight(s);
   }
@@ -559,10 +683,24 @@
 
 public:
   ArrayType(Node *Base_, NodeOrString Dimension_)
-      : Node(KArrayType, true, false, true), Base(Base_), Dimension(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, true, false, true), Base(Base_) {}
+  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); }
 
@@ -582,10 +720,27 @@
 class FunctionType final : public Node {
   Node *Ret;
   NodeArray Params;
+  Qualifiers CVQuals;
+  FunctionRefQual RefQual;
+  Node *ExceptionSpec;
 
 public:
-  FunctionType(Node *Ret_, NodeArray Params_)
-      : Node(KFunctionType, true, true), Ret(Ret_), Params(Params_) {}
+  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:
@@ -601,26 +756,87 @@
 
   void printRight(OutputStream &S) const override {
     S += "(";
-    Params.printWithSeperator(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);
+    }
   }
 };
 
-class TopLevelFunctionDecl final : public Node {
+class NoexceptSpec : public Node {
+  Node *E;
+public:
+  NoexceptSpec(Node *E_) : Node(KNoexceptSpec, E_->ParameterPackSize), E(E_) {}
+
+  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:
-  TopLevelFunctionDecl(Node *Ret_, Node *Name_, NodeArray Params_)
-      : Node(KTopLevelFunctionDecl, true, true), Ret(Ret_), Name(Name_),
-        Params(Params_) {}
+  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())
+      if (!Ret->hasRHSComponent(S))
         S += " ";
     }
     Name->print(S);
@@ -628,69 +844,31 @@
 
   void printRight(OutputStream &S) const override {
     S += "(";
-    Params.printWithSeperator(S, ", ");
+    Params.printWithComma(S);
     S += ")";
     if (Ret)
       Ret->printRight(S);
-  }
-};
 
-enum FunctionRefQual : unsigned char {
-  FrefQualNone,
-  FrefQualLValue,
-  FrefQualRValue,
-};
+    if (CVQuals & QualConst)
+      S += " const";
+    if (CVQuals & QualVolatile)
+      S += " volatile";
+    if (CVQuals & QualRestrict)
+      S += " restrict";
 
-class FunctionRefQualType : public Node {
-  Node *Fn;
-  FunctionRefQual Quals;
-
-  friend class FunctionQualType;
-
-public:
-  FunctionRefQualType(Node *Fn_, FunctionRefQual Quals_)
-      : Node(KFunctionRefQualType, true, true), Fn(Fn_), Quals(Quals_) {}
-
-  void printQuals(OutputStream &S) const {
-    if (Quals == FrefQualLValue)
+    if (RefQual == FrefQualLValue)
       S += " &";
-    else
+    else if (RefQual == FrefQualRValue)
       S += " &&";
   }
-
-  void printLeft(OutputStream &S) const override { Fn->printLeft(S); }
-
-  void printRight(OutputStream &S) const override {
-    Fn->printRight(S);
-    printQuals(S);
-  }
-};
-
-class FunctionQualType final : public QualType {
-public:
-  FunctionQualType(Node *Child_, Qualifiers Quals_)
-      : QualType(KFunctionQualType, Child_, Quals_) {}
-
-  void printLeft(OutputStream &S) const override { Child->printLeft(S); }
-
-  void printRight(OutputStream &S) const override {
-    if (Child->K == KFunctionRefQualType) {
-      auto *RefQuals = static_cast<const FunctionRefQualType *>(Child);
-      RefQuals->Fn->printRight(S);
-      printQuals(S);
-      RefQuals->printQuals(S);
-    } else {
-      Child->printRight(S);
-      printQuals(S);
-    }
-  }
 };
 
 class LiteralOperator : public Node {
   const Node *OpName;
 
 public:
-  LiteralOperator(Node *OpName_) : Node(KLiteralOperator), OpName(OpName_) {}
+  LiteralOperator(Node *OpName_)
+      : Node(KLiteralOperator, OpName_->ParameterPackSize), OpName(OpName_) {}
 
   void printLeft(OutputStream &S) const override {
     S += "operator\"\" ";
@@ -703,8 +881,9 @@
   const Node *Child;
 
 public:
-  SpecialName(StringView Special_, Node *Child_)
-      : Node(KSpecialName), Special(Special_), Child(Child_) {}
+  SpecialName(StringView Special_, Node* Child_)
+      : Node(KSpecialName, Child_->ParameterPackSize), Special(Special_),
+        Child(Child_) {}
 
   void printLeft(OutputStream &S) const override {
     S += Special;
@@ -718,8 +897,9 @@
 
 public:
   CtorVtableSpecialName(Node *FirstType_, Node *SecondType_)
-      : Node(KCtorVtableSpecialName), FirstType(FirstType_),
-        SecondType(SecondType_) {}
+      : Node(KCtorVtableSpecialName, std::min(FirstType_->ParameterPackSize,
+                                              SecondType_->ParameterPackSize)),
+        FirstType(FirstType_), SecondType(SecondType_) {}
 
   void printLeft(OutputStream &S) const override {
     S += "construction vtable for ";
@@ -734,27 +914,18 @@
   const Node *Qualifier;
   const Node *Name;
 
-  mutable OutputStream::StreamStringView Cache;
-
 public:
-  QualifiedName(Node *Qualifier_, Node *Name_)
-      : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {}
+  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 {
-    if (!Cache.empty()) {
-      S += Cache;
-      return;
-    }
-
-    OutputStream::StreamPosition Start = S.getCurrentPosition();
-    if (Qualifier->K != KEmptyName) {
-      Qualifier->print(S);
-      S += "::";
-    }
+    Qualifier->print(S);
+    S += "::";
     Name->print(S);
-    Cache = S.makeStringViewFromPastPosition(Start);
   }
 };
 
@@ -772,10 +943,17 @@
 public:
   VectorType(NodeOrString Dimension_)
       : Node(KVectorType), BaseType(nullptr), Dimension(Dimension_),
-        IsPixel(true) {}
+        IsPixel(true) {
+    if (Dimension.isNode())
+      ParameterPackSize = Dimension.asNode()->ParameterPackSize;
+  }
   VectorType(Node *BaseType_, NodeOrString Dimension_)
-      : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_),
-        IsPixel(false) {}
+      : 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) {
@@ -794,29 +972,149 @@
   }
 };
 
-class TemplateParams final : public Node {
-  NodeArray Params;
-
-  mutable OutputStream::StreamStringView Cache;
-
+/// 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:
-  TemplateParams(NodeArray Params_) : Node(KTemplateParams), Params(Params_) {}
+  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 {
-    if (!Cache.empty()) {
-      S += Cache;
+    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);
+  }
+};
+
+/// 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);
+  }
+
+  NodeArray getElements() const { return Elements; }
+
+  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;
     }
 
-    OutputStream::StreamPosition Start = S.getCurrentPosition();
+    SwapAndRestore<unsigned> SavePackIndex(S.CurrentPackIndex, 0);
+    for (unsigned I = 0; I != PackSize; ++I) {
+      if (I != 0)
+        S += ", ";
+      S.CurrentPackIndex = I;
+      Child->print(S);
+    }
+  }
+};
 
+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;
+}
+
+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 += "<";
-    Params.printWithSeperator(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 += ">";
-
-    Cache = S.makeStringViewFromPastPosition(Start);
   }
 };
 
@@ -827,7 +1125,9 @@
 
 public:
   NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_)
-      : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {}
+      : Node(KNameWithTemplateArgs, std::min(Name_->ParameterPackSize,
+                                             TemplateArgs_->ParameterPackSize)),
+        Name(Name_), TemplateArgs(TemplateArgs_) {}
 
   StringView getBaseName() const override { return Name->getBaseName(); }
 
@@ -841,7 +1141,8 @@
   Node *Child;
 
 public:
-  GlobalQualifiedName(Node *Child_) : Node(KGlobalQualifiedName), Child(Child_) {}
+  GlobalQualifiedName(Node* Child_)
+      : Node(KGlobalQualifiedName, Child_->ParameterPackSize), Child(Child_) {}
 
   StringView getBaseName() const override { return Child->getBaseName(); }
 
@@ -855,7 +1156,8 @@
   Node *Child;
 
 public:
-  StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
+  StdQualifiedName(Node *Child_)
+      : Node(KStdQualifiedName, Child_->ParameterPackSize), Child(Child_) {}
 
   StringView getBaseName() const override { return Child->getBaseName(); }
 
@@ -978,7 +1280,8 @@
 
 public:
   CtorDtorName(Node *Basename_, bool IsDtor_)
-      : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_) {}
+      : Node(KCtorDtorName, Basename_->ParameterPackSize),
+        Basename(Basename_), IsDtor(IsDtor_) {}
 
   void printLeft(OutputStream &S) const override {
     if (IsDtor)
@@ -991,7 +1294,9 @@
   const Node *Base;
 
 public:
-  DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {}
+  DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {
+    ParameterPackSize = Base->ParameterPackSize;
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "~";
@@ -1012,19 +1317,22 @@
   }
 };
 
-class LambdaTypeName : public Node {
+class ClosureTypeName : public Node {
   NodeArray Params;
   StringView Count;
 
 public:
-  LambdaTypeName(NodeArray Params_, StringView Count_)
-      : Node(KLambdaTypeName), Params(Params_), Count(Count_) {}
+  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.printWithSeperator(S, ", ");
+    Params.printWithComma(S);
     S += ")";
   }
 };
@@ -1032,7 +1340,7 @@
 // -- Expression Nodes --
 
 struct Expr : public Node {
-  Expr() : Node(KExpr) {}
+  Expr(Kind K = KExpr) : Node(K) {}
 };
 
 class BinaryExpr : public Expr {
@@ -1042,7 +1350,10 @@
 
 public:
   BinaryExpr(Node *LHS_, StringView InfixOperator_, Node *RHS_)
-      : LHS(LHS_), InfixOperator(InfixOperator_), RHS(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
@@ -1068,7 +1379,10 @@
   const Node *Op2;
 
 public:
-  ArraySubscriptExpr(Node *Op1_, Node *Op2_) : Op1(Op1_), Op2(Op2_) {}
+  ArraySubscriptExpr(Node *Op1_, Node *Op2_) : Op1(Op1_), Op2(Op2_) {
+    ParameterPackSize =
+      std::min(Op1->ParameterPackSize, Op2->ParameterPackSize);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "(";
@@ -1085,7 +1399,9 @@
 
 public:
   PostfixExpr(Node *Child_, StringView Operand_)
-      : Child(Child_), Operand(Operand_) {}
+      : Child(Child_), Operand(Operand_) {
+    ParameterPackSize = Child->ParameterPackSize;
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "(";
@@ -1102,7 +1418,11 @@
 
 public:
   ConditionalExpr(Node *Cond_, Node *Then_, Node *Else_)
-      : Cond(Cond_), Then(Then_), Else(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 += "(";
@@ -1122,7 +1442,10 @@
 
 public:
   MemberExpr(Node *LHS_, StringView Kind_, Node *RHS_)
-      : LHS(LHS_), Kind(Kind_), RHS(RHS_) {}
+      : LHS(LHS_), Kind(Kind_), RHS(RHS_) {
+    ParameterPackSize =
+      std::min(LHS->ParameterPackSize, RHS->ParameterPackSize);
+  }
 
   void printLeft(OutputStream &S) const override {
     LHS->print(S);
@@ -1138,7 +1461,9 @@
 
 public:
   EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_)
-      : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {}
+      : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {
+    ParameterPackSize = Infix->ParameterPackSize;
+  }
 
   void printLeft(OutputStream &S) const override {
     S += Prefix;
@@ -1155,7 +1480,10 @@
 
 public:
   CastExpr(StringView CastKind_, Node *To_, Node *From_)
-      : CastKind(CastKind_), To(To_), From(From_) {}
+      : CastKind(CastKind_), To(To_), From(From_) {
+    ParameterPackSize =
+      std::min(To->ParameterPackSize, From->ParameterPackSize);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += CastKind;
@@ -1168,14 +1496,15 @@
 };
 
 class SizeofParamPackExpr : public Expr {
-  NodeArray Args;
+  Node *Pack;
 
 public:
-  SizeofParamPackExpr(NodeArray Args_) : Args(Args_) {}
+  SizeofParamPackExpr(Node *Pack_) : Pack(Pack_) {}
 
   void printLeft(OutputStream &S) const override {
     S += "sizeof...(";
-    Args.printWithSeperator(S, ", ");
+    ParameterPackExpansion PPE(Pack);
+    PPE.printLeft(S);
     S += ")";
   }
 };
@@ -1185,12 +1514,16 @@
   NodeArray Args;
 
 public:
-  CallExpr(Node *Callee_, NodeArray Args_) : Callee(Callee_), Args(Args_) {}
+  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.printWithSeperator(S, ", ");
+    Args.printWithComma(S);
     S += ")";
   }
 };
@@ -1205,8 +1538,15 @@
 public:
   NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
           bool IsArray_)
-      : ExprList(ExprList_), Type(Type_), InitList(InitList_), IsGlobal(IsGlobal_),
-        IsArray(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)
@@ -1214,17 +1554,19 @@
     S += "new";
     if (IsArray)
       S += "[]";
+    S += ' ';
     if (!ExprList.empty()) {
       S += "(";
-      ExprList.printWithSeperator(S, ", ");
+      ExprList.printWithComma(S);
       S += ")";
     }
     Type->print(S);
     if (!InitList.empty()) {
       S += "(";
-      InitList.printWithSeperator(S, ", ");
+      InitList.printWithComma(S);
       S += ")";
     }
+
   }
 };
 
@@ -1235,7 +1577,9 @@
 
 public:
   DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_)
-      : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+      : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {
+    ParameterPackSize = Op->ParameterPackSize;
+  }
 
   void printLeft(OutputStream &S) const override {
     if (IsGlobal)
@@ -1252,7 +1596,9 @@
   Node *Child;
 
 public:
-  PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {}
+  PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {
+    ParameterPackSize = Child->ParameterPackSize;
+  }
 
   void printLeft(OutputStream &S) const override {
     S += Prefix;
@@ -1274,33 +1620,88 @@
   }
 };
 
-class ExprList : public Expr {
-  NodeArray SubExprs;
+class ConversionExpr : public Expr {
+  const Node *Type;
+  NodeArray Expressions;
 
 public:
-  ExprList(NodeArray SubExprs_) : SubExprs(SubExprs_) {}
+  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 += "(";
-    SubExprs.printWithSeperator(S, ", ");
+    Type->print(S);
+    S += ")(";
+    Expressions.printWithComma(S);
     S += ")";
   }
 };
 
-class ConversionExpr : public Expr {
-  NodeArray Expressions;
-  NodeArray Types;
-
+class InitListExpr : public Expr {
+  Node *Ty;
+  NodeArray Inits;
 public:
-  ConversionExpr(NodeArray Expressions_, NodeArray Types_)
-      : Expressions(Expressions_), Types(Types_) {}
+  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 {
-    S += "(";
-    Expressions.printWithSeperator(S, ", ");
-    S += ")(";
-    Types.printWithSeperator(S, ", ");
-    S += ")";
+    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);
   }
 };
 
@@ -1308,7 +1709,9 @@
   const Node *Op;
 
 public:
-  ThrowExpr(Node *Op_) : Op(Op_) {}
+  ThrowExpr(Node *Op_) : Op(Op_) {
+    ParameterPackSize = Op->ParameterPackSize;
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "throw ";
@@ -1333,7 +1736,9 @@
   StringView Integer;
 
 public:
-  IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {}
+  IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {
+    ParameterPackSize = Ty->ParameterPackSize;
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "(";
@@ -1571,1046 +1976,794 @@
   }
 };
 
-// Substitution table. This type is used to track the substitutions that are
-// known by the parser.
-template <size_t Size>
-class SubstitutionTable {
-  // Substitutions hold the actual entries in the table, and PackIndices tells
-  // us which entries are members of which pack. For example, if the
-  // substitutions we're tracking are: {int, {float, FooBar}, char}, with
-  // {float, FooBar} being a parameter pack, we represent the substitutions as:
-  // Substitutions: int, float, FooBar, char
-  // PackIndices:     0,             1,    3
-  // So, PackIndicies[I] holds the offset of the begin of the Ith pack, and
-  // PackIndices[I + 1] holds the offset of the end.
-  PODSmallVector<Node*, Size> Substitutions;
-  PODSmallVector<unsigned, Size> PackIndices;
+struct Db {
+  const char *First;
+  const char *Last;
 
-public:
-  // Add a substitution that represents a single name to the table. This is
-  // modeled as a parameter pack with just one element.
-  void pushSubstitution(Node* Entry) {
-    pushPack();
-    pushSubstitutionIntoPack(Entry);
+  // 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;
+
+  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)...);
   }
 
-  // Add a new empty pack to the table. Subsequent calls to
-  // pushSubstitutionIntoPack() will add to this pack.
-  void pushPack() {
-    PackIndices.push_back(static_cast<unsigned>(Substitutions.size()));
-  }
-  void pushSubstitutionIntoPack(Node* Entry) {
-    assert(!PackIndices.empty() && "No pack to push substitution into!");
-    Substitutions.push_back(Entry);
+  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);
   }
 
-  // Remove the last pack from the table.
-  void popPack() {
-    unsigned Last = PackIndices.back();
-    PackIndices.pop_back();
-    Substitutions.dropBack(Last);
+  NodeArray popTrailingNodeArray(size_t FromPosition) {
+    assert(FromPosition <= Names.size());
+    NodeArray res =
+        makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
+    Names.dropBack(FromPosition);
+    return res;
   }
 
-  // For use in a range-for loop.
-  struct NodeRange {
-    Node** First;
-    Node** Last;
-    Node** begin() { return First; }
-    Node** end() { return Last; }
+  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;
   };
 
-  // Retrieve the Nth substitution. This is represented as a range, as the
-  // substitution could be referring to a parameter pack.
-  NodeRange nthSubstitution(size_t N) {
-    assert(PackIndices[N] <= Substitutions.size());
-    // The Nth parameter pack starts at offset PackIndices[N], and ends at
-    // PackIndices[N + 1].
-    Node** Begin = Substitutions.begin() + PackIndices[N];
-    Node** End;
-    if (N + 1 != PackIndices.size()) {
-      assert(PackIndices[N + 1] <= Substitutions.size());
-      End = Substitutions.begin() + PackIndices[N + 1];
-    } else
-      End = Substitutions.end();
-    assert(Begin <= End);
-    return NodeRange{Begin, End};
-  }
+  /// 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);
 
-  size_t size() const { return PackIndices.size(); }
-  bool empty() const { return PackIndices.empty(); }
-  void clear() {
-    Substitutions.clear();
-    PackIndices.clear();
-  }
+  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();
 };
 
-struct Db
-{
-    // 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;
+const char* parse_discriminator(const char* first, const char* last);
 
-    // Substitution table. Itanium supports name substitutions as a means of
-    // compression. The string "S42_" refers to the 42nd entry in this table.
-    SubstitutionTable<32> Subs;
+// <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
 
-    // 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.
-    SubstitutionTable<4> TemplateParams;
+  if (look() == 'N')
+    return parseNestedName(State);
+  if (look() == 'Z')
+    return parseLocalName(State);
 
-    Qualifiers CV = QualNone;
-    FunctionRefQual RefQuals = FrefQualNone;
-    unsigned EncodingDepth = 0;
-    bool ParsedCtorDtorCV = false;
-    bool TagTemplates = true;
-    bool FixForwardReferences = false;
-    bool TryToParseTemplateArgs = true;
+  //        ::= <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);
+  }
 
-    BumpPointerAllocator ASTAllocator;
-
-    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;
-    }
-};
-
-const char* parse_type(const char* first, const char* last, Db& db);
-const char* parse_encoding(const char* first, const char* last, Db& db);
-const char* parse_name(const char* first, const char* last, Db& db,
-                       bool* ends_with_template_args = 0);
-const char* parse_expression(const char* first, const char* last, Db& db);
-const char* parse_template_args(const char* first, const char* last, Db& db);
-const char* parse_operator_name(const char* first, const char* last, Db& db);
-const char* parse_unqualified_name(const char* first, const char* last, Db& db);
-const char* parse_decltype(const char* first, const char* last, Db& db);
-
-// <number> ::= [n] <non-negative decimal integer>
-
-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;
-            }
-        }
-    }
-    return first;
+  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;
 }
 
-template <class Float>
-struct FloatData;
+// <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;
 
-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";
-};
+  if (consumeIf('s')) {
+    First = parse_discriminator(First, Last);
+    return make<QualifiedName>(Encoding, make<NameType>("string literal"));
+  }
 
-constexpr const char* FloatData<float>::spec;
+  if (consumeIf('d')) {
+    parseNumber(true);
+    if (!consumeIf('_'))
+      return nullptr;
+    Node *N = parseName(State);
+    if (N == nullptr)
+      return nullptr;
+    return make<QualifiedName>(Encoding, N);
+  }
 
-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";
-};
+  Node *Entity = parseName(State);
+  if (Entity == nullptr)
+    return nullptr;
+  First = parse_discriminator(First, Last);
+  return make<QualifiedName>(Encoding, Entity);
+}
 
-constexpr const char* FloatData<double>::spec;
+// <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);
+}
 
-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";
-};
+// <unqualified-name> ::= <operator-name> [abi-tags]
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <unnamed-type-name>
+// FIXME:             ::= 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
+   Result = parseOperatorName(State);
+ if (Result != nullptr)
+   Result = parseAbiTags(Result);
+ return Result;
+}
 
-constexpr const char* FloatData<long double>::spec;
-
-template <class Float>
-const char*
-parse_floating_number(const char* first, const char* last, Db& db)
-{
-    const size_t N = FloatData<Float>::mangled_size;
-    if (static_cast<std::size_t>(last - first) <= N)
-        return first;
-    last = first + N;
-    const char* t = first;
-    for (; t != last; ++t)
-    {
-        if (!isxdigit(*t))
-            return first;
+// <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;
+    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);
     }
-    if (*t == 'E')
-    {
-        db.Names.push_back(
-            db.make<FloatExpr<Float>>(StringView(first, t)));
-        first = t + 1;
-    }
-    return first;
+    StringView Count = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<ClosureTypeName>(Params, Count);
+  }
+  return nullptr;
 }
 
 // <source-name> ::= <positive length number> <identifier>
-
-const char*
-parse_source_name(const char* first, const char* last, Db& 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)
-            {
-                StringView r(t, t + n);
-                if (r.substr(0, 10) == "_GLOBAL__N")
-                    db.Names.push_back(db.make<NameType>("(anonymous namespace)"));
-                else
-                    db.Names.push_back(db.make<NameType>(r));
-                first = t + n;
-            }
-        }
-    }
-    return first;
+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);
 }
 
-// <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> >
-
-const char*
-parse_substitution(const char* first, const char* last, Db& db)
-{
-    if (last - first >= 2)
-    {
-        if (*first == 'S')
-        {
-            switch (first[1])
-            {
-            case 'a':
-                db.Names.push_back(
-                    db.make<SpecialSubstitution>(
-                        SpecialSubKind::allocator));
-                first += 2;
-                break;
-            case 'b':
-                db.Names.push_back(
-                    db.make<SpecialSubstitution>(SpecialSubKind::basic_string));
-                first += 2;
-                break;
-            case 's':
-                db.Names.push_back(
-                    db.make<SpecialSubstitution>(
-                        SpecialSubKind::string));
-                first += 2;
-                break;
-            case 'i':
-                db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::istream));
-                first += 2;
-                break;
-            case 'o':
-                db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::ostream));
-                first += 2;
-                break;
-            case 'd':
-                db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::iostream));
-                first += 2;
-                break;
-            case '_':
-                if (!db.Subs.empty())
-                {
-                    for (Node* n : db.Subs.nthSubstitution(0))
-                        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 (Node* n : db.Subs.nthSubstitution(sub))
-                            db.Names.push_back(n);
-                        first = t+1;
-                    }
-                }
-                break;
-            }
-        }
+//   <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 first;
+    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':
+      First += 2;
+      return make<NameType>("operator-");
+    case 'I':
+      First += 2;
+      return make<NameType>("operator-=");
+    case 'l':
+      First += 2;
+      return make<NameType>("operator*");
+    case 'L':
+      First += 2;
+      return make<NameType>("operator*=");
+    case 'm':
+      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':
+      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':
+      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;
 }
 
-// <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
-
-const char*
-parse_builtin_type(const char* first, const char* last, Db& db)
-{
-    if (first != last)
-    {
-        switch (*first)
-        {
-        case 'v':
-            db.Names.push_back(db.make<NameType>("void"));
-            ++first;
-            break;
-        case 'w':
-            db.Names.push_back(db.make<NameType>("wchar_t"));
-            ++first;
-            break;
-        case 'b':
-            db.Names.push_back(db.make<NameType>("bool"));
-            ++first;
-            break;
-        case 'c':
-            db.Names.push_back(db.make<NameType>("char"));
-            ++first;
-            break;
-        case 'a':
-            db.Names.push_back(db.make<NameType>("signed char"));
-            ++first;
-            break;
-        case 'h':
-            db.Names.push_back(db.make<NameType>("unsigned char"));
-            ++first;
-            break;
-        case 's':
-            db.Names.push_back(db.make<NameType>("short"));
-            ++first;
-            break;
-        case 't':
-            db.Names.push_back(db.make<NameType>("unsigned short"));
-            ++first;
-            break;
-        case 'i':
-            db.Names.push_back(db.make<NameType>("int"));
-            ++first;
-            break;
-        case 'j':
-            db.Names.push_back(db.make<NameType>("unsigned int"));
-            ++first;
-            break;
-        case 'l':
-            db.Names.push_back(db.make<NameType>("long"));
-            ++first;
-            break;
-        case 'm':
-            db.Names.push_back(db.make<NameType>("unsigned long"));
-            ++first;
-            break;
-        case 'x':
-            db.Names.push_back(db.make<NameType>("long long"));
-            ++first;
-            break;
-        case 'y':
-            db.Names.push_back(db.make<NameType>("unsigned long long"));
-            ++first;
-            break;
-        case 'n':
-            db.Names.push_back(db.make<NameType>("__int128"));
-            ++first;
-            break;
-        case 'o':
-            db.Names.push_back(db.make<NameType>("unsigned __int128"));
-            ++first;
-            break;
-        case 'f':
-            db.Names.push_back(db.make<NameType>("float"));
-            ++first;
-            break;
-        case 'd':
-            db.Names.push_back(db.make<NameType>("double"));
-            ++first;
-            break;
-        case 'e':
-            db.Names.push_back(db.make<NameType>("long double"));
-            ++first;
-            break;
-        case 'g':
-            db.Names.push_back(db.make<NameType>("__float128"));
-            ++first;
-            break;
-        case 'z':
-            db.Names.push_back(db.make<NameType>("..."));
-            ++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(db.make<NameType>("decimal64"));
-                    first += 2;
-                    break;
-                case 'e':
-                    db.Names.push_back(db.make<NameType>("decimal128"));
-                    first += 2;
-                    break;
-                case 'f':
-                    db.Names.push_back(db.make<NameType>("decimal32"));
-                    first += 2;
-                    break;
-                case 'h':
-                    db.Names.push_back(db.make<NameType>("decimal16"));
-                    first += 2;
-                    break;
-                case 'i':
-                    db.Names.push_back(db.make<NameType>("char32_t"));
-                    first += 2;
-                    break;
-                case 's':
-                    db.Names.push_back(db.make<NameType>("char16_t"));
-                    first += 2;
-                    break;
-                case 'a':
-                    db.Names.push_back(db.make<NameType>("auto"));
-                    first += 2;
-                    break;
-                case 'c':
-                    db.Names.push_back(db.make<NameType>("decltype(auto)"));
-                    first += 2;
-                    break;
-                case 'n':
-                    db.Names.push_back(db.make<NameType>("std::nullptr_t"));
-                    first += 2;
-                    break;
-                }
-            }
-            break;
-        }
+// <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;
     }
-    return first;
+  }
+
+  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;
 }
 
-// <CV-Qualifiers> ::= [r] [V] [K]
+// <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;
 
-const char*
-parse_cv_qualifiers(const char* first, const char* last, Qualifiers& cv)
-{
-    cv = QualNone;
-    if (first != last)
-    {
-        if (*first == 'r')
-        {
-            addQualifiers(cv, QualRestrict);
-            ++first;
-        }
-        if (*first == 'V')
-        {
-            addQualifiers(cv, QualVolatile);
-            ++first;
-        }
-        if (*first == 'K')
-        {
-            addQualifiers(cv, QualConst);
-            ++first;
-        }
+  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;
     }
-    return first;
-}
 
-// <template-param> ::= T_    # first template parameter
-//                  ::= T <parameter-2 non-negative number> _
-
-const char*
-parse_template_param(const char* first, const char* last, Db& db)
-{
-    if (last - first >= 2)
-    {
-        if (*first == 'T')
-        {
-            if (first[1] == '_')
-            {
-                if (!db.TemplateParams.empty())
-                {
-                    for (Node *t : db.TemplateParams.nthSubstitution(0))
-                        db.Names.push_back(t);
-                    first += 2;
-                }
-                else
-                {
-                    db.Names.push_back(db.make<NameType>("T_"));
-                    first += 2;
-                    db.FixForwardReferences = 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 != '_')
-                    return first;
-                ++sub;
-                if (sub < db.TemplateParams.size())
-                {
-                    for (Node *temp : db.TemplateParams.nthSubstitution(sub))
-                        db.Names.push_back(temp);
-                    first = t+1;
-                }
-                else
-                {
-                    db.Names.push_back(
-                        db.make<NameType>(StringView(first, t + 1)));
-                    first = t+1;
-                    db.FixForwardReferences = true;
-                }
-            }
-        }
+    //          ::= <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;
     }
-    return first;
-}
 
-// cc <type> <expression>                               # const_cast<type> (expression)
-
-const char*
-parse_const_cast_expr(const char* first, const char* last, Db& 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 from_expr = db.Names.back();
-                db.Names.pop_back();
-                if (db.Names.empty())
-                    return first;
-                db.Names.back() = db.make<CastExpr>(
-                    "const_cast", db.Names.back(), from_expr);
-                first = t1;
-            }
-        }
+    //          ::= <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;
     }
-    return first;
-}
 
-// dc <type> <expression>                               # dynamic_cast<type> (expression)
-
-const char*
-parse_dynamic_cast_expr(const char* first, const char* last, Db& 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 from_expr = db.Names.back();
-                db.Names.pop_back();
-                if (db.Names.empty())
-                    return first;
-                db.Names.back() = db.make<CastExpr>(
-                    "dynamic_cast", db.Names.back(), from_expr);
-                first = t1;
-            }
-        }
+    //          ::= <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;
     }
-    return first;
-}
 
-// rc <type> <expression>                               # reinterpret_cast<type> (expression)
-
-const char*
-parse_reinterpret_cast_expr(const char* first, const char* last, Db& 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 from_expr = db.Names.back();
-                db.Names.pop_back();
-                if (db.Names.empty())
-                    return first;
-                db.Names.back() = db.make<CastExpr>(
-                    "reinterpret_cast", db.Names.back(), from_expr);
-                first = t1;
-            }
-        }
+    // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.
+    if (look() == 'C' || look() == 'D') {
+      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;
     }
-    return first;
-}
 
-// sc <type> <expression>                               # static_cast<type> (expression)
+    //          ::= <prefix> <unqualified-name>
+    Node *N = parseUnqualifiedName(State);
+    if (N == nullptr)
+      return nullptr;
+    PushComponent(N);
+    Subs.push_back(SoFar);
+  }
 
-const char*
-parse_static_cast_expr(const char* first, const char* last, Db& 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 from_expr = db.Names.back();
-                db.Names.pop_back();
-                db.Names.back() = db.make<CastExpr>(
-                    "static_cast", db.Names.back(), from_expr);
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
+  if (SoFar == nullptr || Subs.empty())
+    return nullptr;
 
-// sp <expression>                                  # pack expansion
-
-const char*
-parse_pack_expansion(const char* first, const char* last, Db& 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)
-
-const char*
-parse_sizeof_type_expr(const char* first, const char* last, Db& 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() = db.make<EnclosingExpr>(
-                "sizeof (", db.Names.back(), ")");
-            first = t;
-        }
-    }
-    return first;
-}
-
-// sz <expr>                                            # sizeof (a expression)
-
-const char*
-parse_sizeof_expr_expr(const char* first, const char* last, Db& 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() = db.make<EnclosingExpr>(
-                "sizeof (", db.Names.back(), ")");
-            first = t;
-        }
-    }
-    return first;
-}
-
-// sZ <template-param>                                  # size of a parameter pack
-
-const char*
-parse_sizeof_param_pack_expr(const char* first, const char* last, Db& 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 && k0 <= k1)
-        {
-            Node* sizeof_expr = db.make<SizeofParamPackExpr>(
-                db.popTrailingNodeArray(k0));
-            db.Names.push_back(sizeof_expr);
-            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
-
-const char*
-parse_function_param(const char* first, const char* last, Db& db)
-{
-    if (last - first >= 3 && *first == 'f')
-    {
-        if (first[1] == 'p')
-        {
-            Qualifiers 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(
-                    db.make<FunctionParam>(StringView(t, t1)));
-                first = t1+1;
-            }
-        }
-        else if (first[1] == 'L')
-        {
-            Qualifiers 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(
-                        db.make<FunctionParam>(StringView(t, t1)));
-                    first = t1+1;
-                }
-            }
-        }
-    }
-    return first;
-}
-
-// sZ <function-param>                                  # size of a function parameter pack
-
-const char*
-parse_sizeof_function_param_pack_expr(const char* first, const char* last, Db& 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() = db.make<EnclosingExpr>(
-                "sizeof...(", db.Names.back(), ")");
-            first = t;
-        }
-    }
-    return first;
-}
-
-// te <expression>                                      # typeid (expression)
-// ti <type>                                            # typeid (type)
-
-const char*
-parse_typeid_expr(const char* first, const char* last, Db& 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() = db.make<EnclosingExpr>(
-                "typeid(", db.Names.back(), ")");
-            first = t;
-        }
-    }
-    return first;
-}
-
-// tw <expression>                                      # throw expression
-
-const char*
-parse_throw_expr(const char* first, const char* last, Db& 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() = db.make<ThrowExpr>(db.Names.back());
-            first = t;
-        }
-    }
-    return first;
-}
-
-// ds <expression> <expression>                         # expr.*expr
-
-const char*
-parse_dot_star_expr(const char* first, const char* last, Db& 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 rhs_expr = db.Names.back();
-                db.Names.pop_back();
-                db.Names.back() = db.make<MemberExpr>(
-                    db.Names.back(), ".*", rhs_expr);
-                first = t1;
-            }
-        }
-    }
-    return first;
+  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;
+}
 
-const char*
-parse_simple_id(const char* first, const char* last, Db& 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();
-                db.Names.pop_back();
-                db.Names.back() =
-                    db.make<NameWithTemplateArgs>(db.Names.back(), args);
-            }
-            first = t1;
-        }
-        else
-            first = t;
-    }
-    return first;
+// <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>
-
-const char*
-parse_unresolved_type(const char* first, const char* last, Db& 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.pushSubstitution(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.pushSubstitution(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() =
-                            db.make<StdQualifiedName>(db.Names.back());
-                        db.Subs.pushSubstitution(db.Names.back());
-                        first = t;
-                    }
-                }
-            }
-            break;
-       }
-    }
-    return first;
-}
-
-// <destructor-name> ::= <unresolved-type>                               # e.g., ~T or ~decltype(f())
-//                   ::= <simple-id>                                     # e.g., ~A<2*N>
-
-const char*
-parse_destructor_name(const char* first, const char* last, Db& 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() = db.make<DtorName>(db.Names.back());
-            first = t;
-        }
-    }
-    return first;
+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
@@ -2620,73 +2773,25 @@
 //                        ::= 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();
 
-const char*
-parse_base_unresolved_name(const char* first, const char* last, Db& 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();
-                        db.Names.pop_back();
-                        db.Names.back() =
-                            db.make<NameWithTemplateArgs>(
-                                db.Names.back(), 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();
-                        db.Names.pop_back();
-                        db.Names.back() =
-                            db.make<NameWithTemplateArgs>(
-                                db.Names.back(), args);
-                    }
-                }
-            }
-            else
-                first = t;
-        }
-    }
-    return first;
-}
+  if (consumeIf("dn"))
+    return parseDestructorName();
 
-// <unresolved-qualifier-level> ::= <simple-id>
+  consumeIf("on");
 
-const char*
-parse_unresolved_qualifier_level(const char* first, const char* last, Db& db)
-{
-    return parse_simple_id(first, last, db);
+  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>
@@ -2698,220 +2803,767 @@
 //  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;
 
-const char*
-parse_unresolved_name(const char* first, const char* last, Db& 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() =
-                    db.make<GlobalQualifiedName>(db.Names.back());
-            }
-            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();
-                    db.Names.pop_back();
-                    db.Names.back() = db.make<NameWithTemplateArgs>(
-                        db.Names.back(), 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();
-                    db.Names.pop_back();
-                    db.Names.back() =
-                        db.make<QualifiedName>(db.Names.back(), 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();
-                db.Names.pop_back();
-                db.Names.back() =
-                    db.make<QualifiedName>(db.Names.back(), 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();
-                        db.Names.pop_back();
-                        db.Names.back() =
-                            db.make<NameWithTemplateArgs>(
-                                db.Names.back(), 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();
-                    db.Names.pop_back();
-                    db.Names.back() =
-                        db.make<QualifiedName>(db.Names.back(), 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() =
-                            db.make<GlobalQualifiedName>(
-                                db.Names.back());
-                    }
-                    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();
-                        db.Names.pop_back();
-                        db.Names.back() = db.make<QualifiedName>(
-                            db.Names.back(), 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();
-                    db.Names.pop_back();
-                    db.Names.back() =
-                        db.make<QualifiedName>(db.Names.back(), s);
-                    first = t1;
-                }
-            }
-        }
+  // 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);
     }
-    return first;
+
+    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);
 }
 
-// dt <expression> <unresolved-name>                    # expr.name
-
-const char*
-parse_dot_expr(const char* first, const char* last, Db& 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();
-                db.Names.pop_back();
-                if (db.Names.empty())
-                    return first;
-                db.Names.back() = db.make<MemberExpr>(db.Names.back(), ".", name);
-                first = t1;
-            }
-        }
-    }
-    return first;
+// <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;
 }
 
-// cl <expression>+ E                                   # call
+// <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);
+}
 
-const char*
-parse_call_expr(const char* first, const char* last, Db& db)
-{
-    if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t == last || t == first + 2 || db.Names.empty())
-            return first;
-        Node* callee = db.Names.back();
-        db.Names.pop_back();
-        size_t args_begin = db.Names.size();
-        while (*t != 'E')
-        {
-            const char* t1 = parse_expression(t, last, db);
-            if (t1 == last || t1 == t)
-                return first;
-            t = t1;
-        }
-        if (db.Names.size() < args_begin)
-            return first;
-        ++t;
-        CallExpr* the_call = db.make<CallExpr>(
-            callee, db.popTrailingNodeArray(args_begin));
-        db.Names.push_back(the_call);
-        first = t;
+// <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);
     }
-    return first;
+    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;
+    if (consumeIf('v'))
+      continue;
+    if (consumeIf("RE")) {
+      ReferenceQualifier = FrefQualLValue;
+      break;
+    }
+    if (consumeIf("OE")) {
+      ReferenceQualifier = FrefQualRValue;
+      break;
+    }
+    Node *T = parseType();
+    if (T == nullptr)
+      return nullptr;
+    Names.push_back(T);
+  }
+
+  NodeArray Params = popTrailingNodeArray(ParamsBegin);
+  return make<FunctionType>(ReturnType, Params, CVQuals,
+                            ReferenceQualifier, ExceptionSpec);
+}
+
+// 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;
+    }
+    _LIBCPP_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;
+    }
+    // extension   ::= <vector-type> # <vector-type> starts with Dv
+    case 'v': {
+      Result = parseVectorType();
+      break;
+    }
+    //           ::= Dp <type>       # pack expansion (C++0x)
+    case 'p': {
+      First += 2;
+      Node *Child = parseType();
+      if (!Child)
+        return nullptr;
+      Result = make<ParameterPackExpansion>(Child);
+      break;
+    }
+    // Exception specifier on a function type.
+    case 'o':
+    case 'O':
+    case 'w':
+    // Transaction safe function type.
+    case 'x':
+      Result = parseFunctionType();
+      break;
+    }
+    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;
+    }
+    _LIBCPP_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);
+}
+
+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);
+}
+
+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 nullptr;
 }
 
 // [gs] nw <expression>* _ <type> E                     # new (expr-list) type
@@ -2919,1678 +3571,208 @@
 // [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
-
-const char*
-parse_new_expr(const char* first, const char* last, Db& 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;
-            size_t first_expr_in_list = db.Names.size();
-            NodeArray ExprList, init_list;
-            while (*t != '_')
-            {
-                const char* t1 = parse_expression(t, last, db);
-                if (t1 == t || t1 == last)
-                    return first;
-                t = t1;
-            }
-            if (first_expr_in_list > db.Names.size())
-                return first;
-            ExprList = db.popTrailingNodeArray(first_expr_in_list);
-            ++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;
-                size_t init_list_begin = db.Names.size();
-                while (*t != 'E')
-                {
-                    t1 = parse_expression(t, last, db);
-                    if (t1 == t || t1 == last)
-                        return first;
-                    t = t1;
-                }
-                if (init_list_begin > db.Names.size())
-                    return first;
-                init_list = db.popTrailingNodeArray(init_list_begin);
-            }
-            if (*t != 'E' || db.Names.empty())
-                return first;
-            auto type = db.Names.back();
-            db.Names.pop_back();
-            db.Names.push_back(
-                db.make<NewExpr>(ExprList, type, init_list,
-                                  parsed_gs, is_array));
-            first = t+1;
-        }
+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);
     }
-    return first;
+    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);
 }
 
 // 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();
+  }
 
-const char*
-parse_conversion_expr(const char* first, const char* last, Db& db)
-{
-    if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
-    {
-        bool TryToParseTemplateArgs = db.TryToParseTemplateArgs;
-        db.TryToParseTemplateArgs = false;
-        size_t type_begin = db.Names.size();
-        const char* t = parse_type(first+2, last, db);
-        db.TryToParseTemplateArgs = TryToParseTemplateArgs;
-        if (t != first+2 && t != last)
-        {
-            size_t expr_list_begin = db.Names.size();
-            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')
-                {
-                    while (*t != 'E')
-                    {
-                        const char* t1 = parse_expression(t, last, db);
-                        if (t1 == t || t1 == last)
-                            return first;
-                        t = t1;
-                    }
-                }
-                ++t;
-            }
-            if (db.Names.size() < expr_list_begin ||
-                type_begin > expr_list_begin)
-                return first;
-            NodeArray expressions = db.makeNodeArray(
-                db.Names.begin() + (long)expr_list_begin, db.Names.end());
-            NodeArray types = db.makeNodeArray(
-                db.Names.begin() + (long)type_begin,
-                db.Names.begin() + (long)expr_list_begin);
-            auto* conv_expr = db.make<ConversionExpr>(
-                types, expressions);
-            db.Names.dropBack(type_begin);
-            db.Names.push_back(conv_expr);
-            first = t;
-        }
+  if (Ty == nullptr)
+    return nullptr;
+
+  if (consumeIf('_')) {
+    size_t ExprsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *E = parseExpr();
+      if (E == nullptr)
+        return E;
+      Names.push_back(E);
     }
-    return first;
-}
+    NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+    return make<ConversionExpr>(Ty, Exprs);
+  }
 
-// pt <expression> <expression>                    # expr->name
-
-const char*
-parse_arrow_expr(const char* first, const char* last, Db& 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();
-                db.Names.pop_back();
-                db.Names.back() = db.make<MemberExpr>(
-                    db.Names.back(), "->", tmp);
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
-
-//  <ref-qualifier> ::= R                   # & ref-qualifier
-//  <ref-qualifier> ::= O                   # && ref-qualifier
-
-// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
-
-const char*
-parse_function_type(const char* first, const char* last, Db& 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 && !db.Names.empty())
-            {
-                Node* ret_type = db.Names.back();
-                db.Names.pop_back();
-                size_t params_begin = db.Names.size();
-                t = t1;
-                FunctionRefQual RefQuals = FrefQualNone;
-                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')
-                    {
-                        RefQuals = FrefQualLValue;
-                        ++t;
-                        continue;
-                    }
-                    if (*t == 'O' && t+1 != last && t[1] == 'E')
-                    {
-                        RefQuals = FrefQualRValue;
-                        ++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 || k1 < k0)
-                        return first;
-                    t = t1;
-                }
-                if (db.Names.empty() || params_begin > db.Names.size())
-                    return first;
-                Node* fty = db.make<FunctionType>(
-                    ret_type, db.popTrailingNodeArray(params_begin));
-                if (RefQuals)
-                    fty = db.make<FunctionRefQualType>(fty, RefQuals);
-                db.Names.push_back(fty);
-                first = t;
-            }
-        }
-    }
-    return first;
-}
-
-// <pointer-to-member-type> ::= M <class type> <member type>
-
-const char*
-parse_pointer_to_member_type(const char* first, const char* last, Db& 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 ClassType = std::move(db.Names.back());
-                db.Names.back() =
-                    db.make<PointerToMemberType>(ClassType, func);
-                first = t2;
-            }
-        }
-    }
-    return first;
-}
-
-// <array-type> ::= A <positive dimension number> _ <element type>
-//              ::= A [<dimension expression>] _ <element type>
-
-const char*
-parse_array_type(const char* first, const char* last, Db& 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;
-                db.Names.back() = db.make<ArrayType>(db.Names.back());
-                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;
-                    db.Names.back() =
-                        db.make<ArrayType>(db.Names.back(),
-                                            StringView(first + 1, t));
-                    first = t2;
-                }
-            }
-        }
-        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 base_type = std::move(db.Names.back());
-                    db.Names.pop_back();
-                    auto dimension_expr = std::move(db.Names.back());
-                    db.Names.back() =
-                        db.make<ArrayType>(base_type, dimension_expr);
-                    first = t2;
-                }
-            }
-        }
-    }
-    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)
-
-const char*
-parse_decltype(const char* first, const char* last, Db& 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() = db.make<EnclosingExpr>(
-                        "decltype(", db.Names.back(), ")");
-                    first = t+1;
-                }
-            }
-            break;
-        }
-    }
-    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
-
-const char*
-parse_vector_type(const char* first, const char* last, Db& 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() =
-                            db.make<VectorType>(db.Names.back(),
-                                                 StringView(num, num + sz));
-                        first = t1;
-                    }
-                }
-                else
-                {
-                    ++t;
-                    db.Names.push_back(
-                        db.make<VectorType>(StringView(num, num + sz)));
-                    first = t;
-                }
-            }
-        }
-        else
-        {
-            Node* num = nullptr;
-            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();
-                    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;
-                    if (num)
-                        db.Names.back() =
-                            db.make<VectorType>(db.Names.back(), num);
-                    else
-                        db.Names.back() =
-                            db.make<VectorType>(db.Names.back(), StringView());
-                    first = t;
-                } else if (num)
-                    db.Names.push_back(num);
-            }
-        }
-    }
-    return first;
-}
-
-// <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>
-
-const char*
-parse_type(const char* first, const char* last, Db& db)
-{
-    if (first != last)
-    {
-        switch (*first)
-        {
-            case 'r':
-            case 'V':
-            case 'K':
-              {
-                Qualifiers cv = QualNone;
-                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.popPack();
-                        db.Subs.pushPack();
-                        for (size_t k = k0; k < k1; ++k)
-                        {
-                            if (cv) {
-                                if (is_function)
-                                    db.Names[k] = db.make<FunctionQualType>(
-                                        db.Names[k], cv);
-                                else
-                                    db.Names[k] =
-                                        db.make<QualType>(db.Names[k], cv);
-                            }
-                            db.Subs.pushSubstitutionIntoPack(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.pushSubstitution(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() = db.make<PostfixQualifiedType>(
-                                db.Names.back(), " complex");
-                            first = t;
-                            db.Subs.pushSubstitution(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.pushSubstitution(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() = db.make<PostfixQualifiedType>(
-                                db.Names.back(), " imaginary");
-                            first = t;
-                            db.Subs.pushSubstitution(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.pushSubstitution(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.pushPack();
-                            for (size_t k = k0; k < k1; ++k)
-                            {
-                                db.Names[k] =
-                                    db.make<RValueReferenceType>(db.Names[k]);
-                                db.Subs.pushSubstitutionIntoPack(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.pushPack();
-                            for (size_t k = k0; k < k1; ++k)
-                            {
-                                db.Names[k] = db.make<PointerType>(db.Names[k]);
-                                db.Subs.pushSubstitutionIntoPack(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.pushPack();
-                            for (size_t k = k0; k < k1; ++k)
-                            {
-                                db.Names[k] =
-                                    db.make<LValueReferenceType>(db.Names[k]);
-                                db.Subs.pushSubstitutionIntoPack(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.pushPack();
-                            for (size_t k = k0; k < k1; ++k)
-                                db.Subs.pushSubstitutionIntoPack(db.Names[k]);
-                            if (db.TryToParseTemplateArgs && k1 == k0+1)
-                            {
-                                const char* t1 = parse_template_args(t, last, db);
-                                if (t1 != t)
-                                {
-                                    auto args = db.Names.back();
-                                    db.Names.pop_back();
-                                    db.Names.back() = db.make<
-                                        NameWithTemplateArgs>(
-                                        db.Names.back(), args);
-                                    db.Subs.pushSubstitution(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();
-                                    db.Names.pop_back();
-                                    if (db.Names.back()->K != Node::KNameType ||
-                                        !static_cast<NameType*>(db.Names.back())->getName().startsWith("objcproto"))
-                                    {
-                                        db.Names.back() = db.make<VendorExtQualType>(type, db.Names.back());
-                                    }
-                                    else
-                                    {
-                                        auto* proto = static_cast<NameType*>(db.Names.back());
-                                        db.Names.pop_back();
-                                        t = parse_source_name(proto->getName().begin() + 9, proto->getName().end(), db);
-                                        if (t != proto->getName().begin() + 9)
-                                        {
-                                            db.Names.back() = db.make<ObjCProtoName>(type, db.Names.back());
-                                        }
-                                        else
-                                        {
-                                            db.Names.push_back(db.make<VendorExtQualType>(type, proto));
-                                        }
-                                    }
-                                    db.Subs.pushSubstitution(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.pushSubstitution(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>.
-                                if (db.TryToParseTemplateArgs)
-                                {
-                                    t = parse_template_args(first, last, db);
-                                    if (t != first)
-                                    {
-                                        if (db.Names.size() < 2)
-                                            return first;
-                                        auto template_args = db.Names.back();
-                                        db.Names.pop_back();
-                                        db.Names.back() = db.make<
-                                          NameWithTemplateArgs>(
-                                              db.Names.back(), template_args);
-                                        // Need to create substitution for <template-template-param> <template-args>
-                                        db.Subs.pushSubstitution(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.pushPack();
-                                    for (size_t k = k0; k < k1; ++k)
-                                        db.Subs.pushSubstitutionIntoPack(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.pushSubstitution(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.pushSubstitution(db.Names.back());
-                                    first = t;
-                                    return first;
-                                }
-                                break;
-                            }
-                        }
-                        _LIBCPP_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.pushSubstitution(db.Names.back());
-                                first = t;
-                            }
-                        }
-                        break;
-                    }
-              }
-                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
-
-const char*
-parse_operator_name(const char* first, const char* last, Db& db)
-{
-    if (last - first >= 2)
-    {
-        switch (first[0])
-        {
-        case 'a':
-            switch (first[1])
-            {
-            case 'a':
-                db.Names.push_back(db.make<NameType>("operator&&"));
-                first += 2;
-                break;
-            case 'd':
-            case 'n':
-                db.Names.push_back(db.make<NameType>("operator&"));
-                first += 2;
-                break;
-            case 'N':
-                db.Names.push_back(db.make<NameType>("operator&="));
-                first += 2;
-                break;
-            case 'S':
-                db.Names.push_back(db.make<NameType>("operator="));
-                first += 2;
-                break;
-            }
-            break;
-        case 'c':
-            switch (first[1])
-            {
-            case 'l':
-                db.Names.push_back(db.make<NameType>("operator()"));
-                first += 2;
-                break;
-            case 'm':
-                db.Names.push_back(db.make<NameType>("operator,"));
-                first += 2;
-                break;
-            case 'o':
-                db.Names.push_back(db.make<NameType>("operator~"));
-                first += 2;
-                break;
-            case 'v':
-                {
-                    bool TryToParseTemplateArgs = db.TryToParseTemplateArgs;
-                    db.TryToParseTemplateArgs = false;
-                    const char* t = parse_type(first+2, last, db);
-                    db.TryToParseTemplateArgs = TryToParseTemplateArgs;
-                    if (t != first+2)
-                    {
-                        if (db.Names.empty())
-                            return first;
-                        db.Names.back() =
-                            db.make<ConversionOperatorType>(db.Names.back());
-                        db.ParsedCtorDtorCV = true;
-                        first = t;
-                    }
-                }
-                break;
-            }
-            break;
-        case 'd':
-            switch (first[1])
-            {
-            case 'a':
-                db.Names.push_back(db.make<NameType>("operator delete[]"));
-                first += 2;
-                break;
-            case 'e':
-                db.Names.push_back(db.make<NameType>("operator*"));
-                first += 2;
-                break;
-            case 'l':
-                db.Names.push_back(db.make<NameType>("operator delete"));
-                first += 2;
-                break;
-            case 'v':
-                db.Names.push_back(db.make<NameType>("operator/"));
-                first += 2;
-                break;
-            case 'V':
-                db.Names.push_back(db.make<NameType>("operator/="));
-                first += 2;
-                break;
-            }
-            break;
-        case 'e':
-            switch (first[1])
-            {
-            case 'o':
-                db.Names.push_back(db.make<NameType>("operator^"));
-                first += 2;
-                break;
-            case 'O':
-                db.Names.push_back(db.make<NameType>("operator^="));
-                first += 2;
-                break;
-            case 'q':
-                db.Names.push_back(db.make<NameType>("operator=="));
-                first += 2;
-                break;
-            }
-            break;
-        case 'g':
-            switch (first[1])
-            {
-            case 'e':
-                db.Names.push_back(db.make<NameType>("operator>="));
-                first += 2;
-                break;
-            case 't':
-                db.Names.push_back(db.make<NameType>("operator>"));
-                first += 2;
-                break;
-            }
-            break;
-        case 'i':
-            if (first[1] == 'x')
-            {
-                db.Names.push_back(db.make<NameType>("operator[]"));
-                first += 2;
-            }
-            break;
-        case 'l':
-            switch (first[1])
-            {
-            case 'e':
-                db.Names.push_back(db.make<NameType>("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() =
-                            db.make<LiteralOperator>(db.Names.back());
-                        first = t;
-                    }
-                }
-                break;
-            case 's':
-                db.Names.push_back(db.make<NameType>("operator<<"));
-                first += 2;
-                break;
-            case 'S':
-                db.Names.push_back(db.make<NameType>("operator<<="));
-                first += 2;
-                break;
-            case 't':
-                db.Names.push_back(db.make<NameType>("operator<"));
-                first += 2;
-                break;
-            }
-            break;
-        case 'm':
-            switch (first[1])
-            {
-            case 'i':
-                db.Names.push_back(db.make<NameType>("operator-"));
-                first += 2;
-                break;
-            case 'I':
-                db.Names.push_back(db.make<NameType>("operator-="));
-                first += 2;
-                break;
-            case 'l':
-                db.Names.push_back(db.make<NameType>("operator*"));
-                first += 2;
-                break;
-            case 'L':
-                db.Names.push_back(db.make<NameType>("operator*="));
-                first += 2;
-                break;
-            case 'm':
-                db.Names.push_back(db.make<NameType>("operator--"));
-                first += 2;
-                break;
-            }
-            break;
-        case 'n':
-            switch (first[1])
-            {
-            case 'a':
-                db.Names.push_back(db.make<NameType>("operator new[]"));
-                first += 2;
-                break;
-            case 'e':
-                db.Names.push_back(db.make<NameType>("operator!="));
-                first += 2;
-                break;
-            case 'g':
-                db.Names.push_back(db.make<NameType>("operator-"));
-                first += 2;
-                break;
-            case 't':
-                db.Names.push_back(db.make<NameType>("operator!"));
-                first += 2;
-                break;
-            case 'w':
-                db.Names.push_back(db.make<NameType>("operator new"));
-                first += 2;
-                break;
-            }
-            break;
-        case 'o':
-            switch (first[1])
-            {
-            case 'o':
-                db.Names.push_back(db.make<NameType>("operator||"));
-                first += 2;
-                break;
-            case 'r':
-                db.Names.push_back(db.make<NameType>("operator|"));
-                first += 2;
-                break;
-            case 'R':
-                db.Names.push_back(db.make<NameType>("operator|="));
-                first += 2;
-                break;
-            }
-            break;
-        case 'p':
-            switch (first[1])
-            {
-            case 'm':
-                db.Names.push_back(db.make<NameType>("operator->*"));
-                first += 2;
-                break;
-            case 'l':
-                db.Names.push_back(db.make<NameType>("operator+"));
-                first += 2;
-                break;
-            case 'L':
-                db.Names.push_back(db.make<NameType>("operator+="));
-                first += 2;
-                break;
-            case 'p':
-                db.Names.push_back(db.make<NameType>("operator++"));
-                first += 2;
-                break;
-            case 's':
-                db.Names.push_back(db.make<NameType>("operator+"));
-                first += 2;
-                break;
-            case 't':
-                db.Names.push_back(db.make<NameType>("operator->"));
-                first += 2;
-                break;
-            }
-            break;
-        case 'q':
-            if (first[1] == 'u')
-            {
-                db.Names.push_back(db.make<NameType>("operator?"));
-                first += 2;
-            }
-            break;
-        case 'r':
-            switch (first[1])
-            {
-            case 'm':
-                db.Names.push_back(db.make<NameType>("operator%"));
-                first += 2;
-                break;
-            case 'M':
-                db.Names.push_back(db.make<NameType>("operator%="));
-                first += 2;
-                break;
-            case 's':
-                db.Names.push_back(db.make<NameType>("operator>>"));
-                first += 2;
-                break;
-            case 'S':
-                db.Names.push_back(db.make<NameType>("operator>>="));
-                first += 2;
-                break;
-            }
-            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() =
-                        db.make<ConversionOperatorType>(db.Names.back());
-                    first = t;
-                }
-            }
-            break;
-        }
-    }
-    return first;
-}
-
-const char*
-parse_integer_literal(const char* first, const char* last, StringView lit, Db& db)
-{
-    const char* t = parse_number(first, last);
-    if (t != first && t != last && *t == 'E')
-    {
-        db.Names.push_back(
-            db.make<IntegerExpr>(lit, StringView(first, t)));
-        first = t+1;
-    }
-    return first;
+  Node *E[1] = {parseExpr()};
+  if (E[0] == nullptr)
+    return nullptr;
+  return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
 }
 
 // <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)
+// FIXME:         ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)
 //                ::= L <mangled-name> E                                 # external name
-
-const char*
-parse_expr_primary(const char* first, const char* last, Db& 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(db.make<BoolExpr>(0));
-                    first += 4;
-                    break;
-                case '1':
-                    db.Names.push_back(db.make<BoolExpr>(1));
-                    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
-            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.make<IntegerCastExpr>(
-                                db.Names.back(), StringView(t, n));
-                            first = n+1;
-                            break;
-                        }
-                    }
-                    else
-                    {
-                        first = t+1;
-                        break;
-                    }
-                }
-            }
-        }
+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 first;
+    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;
+  }
+  }
 }
 
-Node* maybe_change_special_sub_name(Node* inp, Db& db)
-{
-    if (inp->K != Node::KSpecialSubstitution)
-        return inp;
-    auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK;
-    switch (Kind)
-    {
-    case SpecialSubKind::string:
-    case SpecialSubKind::istream:
-    case SpecialSubKind::ostream:
-    case SpecialSubKind::iostream:
-        return db.make<ExpandedSpecialSubstitution>(Kind);
-    default:
-        break;
+// <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);
     }
-    return inp;
-}
-
-// <ctor-dtor-name> ::= C1    # complete object constructor
-//                  ::= C2    # base object constructor
-//                  ::= C3    # complete object allocating constructor
-//   extension      ::= C5    # ?
-//                  ::= D0    # deleting destructor
-//                  ::= D1    # complete object destructor
-//                  ::= D2    # base object destructor
-//   extension      ::= D5    # ?
-
-const char*
-parse_ctor_dtor_name(const char* first, const char* last, Db& db)
-{
-    if (last-first >= 2 && !db.Names.empty())
-    {
-        switch (first[0])
-        {
-        case 'C':
-            switch (first[1])
-            {
-            case '1':
-            case '2':
-            case '3':
-            case '5':
-                if (db.Names.empty())
-                    return first;
-                db.Names.back() =
-                    maybe_change_special_sub_name(db.Names.back(), db);
-                db.Names.push_back(
-                    db.make<CtorDtorName>(db.Names.back(), false));
-                first += 2;
-                db.ParsedCtorDtorCV = true;
-                break;
-            }
-            break;
-        case 'D':
-            switch (first[1])
-            {
-            case '0':
-            case '1':
-            case '2':
-            case '5':
-                if (db.Names.empty())
-                    return first;
-                db.Names.push_back(
-                    db.make<CtorDtorName>(db.Names.back(), true));
-                first += 2;
-                db.ParsedCtorDtorCV = true;
-                break;
-            }
-            break;
-        }
+    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);
     }
-    return first;
-}
-
-// <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
-
-const char*
-parse_unnamed_type_name(const char* first, const char* last, Db& db)
-{
-    if (last - first > 2 && first[0] == 'U')
-    {
-        char type = first[1];
-        switch (type)
-        {
-        case 't':
-          {
-            const char* t0 = first+2;
-            if (t0 == last)
-                return first;
-            StringView count;
-            if (std::isdigit(*t0))
-            {
-                const char* t1 = t0 + 1;
-                while (t1 != last && std::isdigit(*t1))
-                    ++t1;
-                count = StringView(t0, t1);
-                t0 = t1;
-            }
-            if (t0 == last || *t0 != '_')
-                return first;
-            db.Names.push_back(db.make<UnnamedTypeName>(count));
-            first = t0 + 1;
-          }
-            break;
-        case 'l':
-          {
-            size_t begin_pos = db.Names.size();
-            const char* t0 = first+2;
-            NodeArray lambda_params;
-            if (first[2] == 'v')
-            {
-                ++t0;
-            }
-            else
-            {
-                while (true)
-                {
-                    const char* t1 = parse_type(t0, last, db);
-                    if (t1 == t0)
-                        break;
-                    t0 = t1;
-                }
-                if (db.Names.size() < begin_pos)
-                    return first;
-                lambda_params = db.popTrailingNodeArray(begin_pos);
-            }
-            if (t0 == last || *t0 != 'E')
-                return first;
-            ++t0;
-            if (t0 == last)
-                return first;
-            StringView count;
-            if (std::isdigit(*t0))
-            {
-                const char* t1 = t0 + 1;
-                while (t1 != last && std::isdigit(*t1))
-                    ++t1;
-                count = StringView(t0, t1);
-                t0 = t1;
-            }
-            if (t0 == last || *t0 != '_')
-                return first;
-            db.Names.push_back(db.make<LambdaTypeName>(lambda_params, count));
-            first = t0 + 1;
-          }
-            break;
-        }
+    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;
-}
-
-// <unqualified-name> ::= <operator-name>
-//                    ::= <ctor-dtor-name>
-//                    ::= <source-name>   
-//                    ::= <unnamed-type-name>
-
-const char*
-parse_unqualified_name(const char* first, const char* last, Db& 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;
-        };
     }
-    return first;
-}
-
-// <unscoped-name> ::= <unqualified-name>
-//                 ::= St <unqualified-name>   # ::std::
-// extension       ::= StL<unqualified-name>
-
-const char*
-parse_unscoped_name(const char* first, const char* last, Db& 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() =
-                    db.make<StdQualifiedName>(db.Names.back());
-            }
-            first = t1;
-        }
-    }
-    return first;
-}
-
-// at <type>                                            # alignof (a type)
-
-const char*
-parse_alignof_type(const char* first, const char* last, Db& 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() =
-                db.make<EnclosingExpr>("alignof (", db.Names.back(), ")");
-            first = t;
-        }
-    }
-    return first;
-}
-
-// az <expression>                                            # alignof (a expression)
-
-const char*
-parse_alignof_expr(const char* first, const char* last, Db& 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() =
-                db.make<EnclosingExpr>("alignof (", db.Names.back(), ")");
-            first = t;
-        }
-    }
-    return first;
-}
-
-const char*
-parse_noexcept_expression(const char* first, const char* last, Db& db)
-{
-    const char* t1 = parse_expression(first, last, db);
-    if (t1 != first)
-    {
-        if (db.Names.empty())
-            return first;
-        db.Names.back() =
-            db.make<EnclosingExpr>("noexcept (", db.Names.back(), ")");
-        first = t1;
-    }
-    return first;
-}
-
-const char*
-parse_prefix_expression(const char* first, const char* last, StringView op, Db& db)
-{
-    const char* t1 = parse_expression(first, last, db);
-    if (t1 != first)
-    {
-        if (db.Names.empty())
-            return first;
-        db.Names.back() = db.make<PrefixExpr>(op, db.Names.back());
-        first = t1;
-    }
-    return first;
-}
-
-const char*
-parse_binary_expression(const char* first, const char* last, StringView op, Db& 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();
-            db.Names.pop_back();
-            auto op1 = db.Names.back();
-            db.Names.back() = db.make<BinaryExpr>(op1, op, op2);
-            first = t2;
-        }
-    }
-    return first;
+  }
+  return parseExpr();
 }
 
 // <expression> ::= <unary operator-name> <expression>
@@ -4631,775 +3813,918 @@
 //              ::= <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;
 
-const char*
-parse_expression(const char* first, const char* last, Db& 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;
-        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;
-        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() = db.make<DeleteExpr>(
-                            db.Names.back(), parsed_gs, /*is_array=*/true);
-                        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() = db.make<DeleteExpr>(
-                            db.Names.back(), parsed_gs, /*is_array=*/false);
-                        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();
-                        db.Names.pop_back();
-                        auto op1 = db.Names.back();
-                        db.Names.back() =
-                            db.make<ArraySubscriptExpr>(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;
-            }
-            break;
-        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.make<PostfixExpr>(db.Names.back(), "--");
-                        first = t1;
-                    }
-                }
-                break;
-            }
-            break;
-        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;
-        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.make<PostfixExpr>(db.Names.back(), "++");
-                        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;
-        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();
-                            db.Names.pop_back();
-                            auto op2 = db.Names.back();
-                            db.Names.pop_back();
-                            auto op1 = db.Names.back();
-                            db.Names.back() =
-                                db.make<ConditionalExpr>(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;
-            }
-            break;
-        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;
-        case 't':
-            switch (t[1])
-            {
-            case 'e':
-            case 'i':
-                first = parse_typeid_expr(first, last, db);
-                break;
-            case 'r':
-                db.Names.push_back(db.make<NameType>("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);
-        }
+  switch (*First) {
+  case 'L':
+    return parseExprPrimary();
+  case 'T':
+    return parseTemplateParam();
+  case 'f':
+    return parseFunctionParam();
+  case 'a':
+    switch (First[1]) {
+    case 'a':
+      First += 2;
+      return parseBinaryExpr("&&");
+    case 'd':
+      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, ")");
     }
-    return first;
+    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);
+      }
+      return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
+    }
+    case 'm':
+      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':
+      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':
+      First += 2;
+      return parseBinaryExpr("^");
+    case 'O':
+      First += 2;
+      return parseBinaryExpr("^=");
+    case 'q':
+      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);
+      }
+      return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
+    }
+    }
+    return nullptr;
+  case 'l':
+    switch (First[1]) {
+    case 'e':
+      First += 2;
+      return parseBinaryExpr("<=");
+    case 's':
+      First += 2;
+      return parseBinaryExpr("<<");
+    case 'S':
+      First += 2;
+      return parseBinaryExpr("<<=");
+    case 't':
+      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':
+      First += 2;
+      return parseBinaryExpr("+=");
+    case 'p': {
+      First += 2;
+      if (consumeIf('_'))
+        return parsePrefixExpr("++");
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<PostfixExpr>(Ex, "++");
+    }
+    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);
+    }
+    }
+    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 nullptr;
+  case 't':
+    switch (First[1]) {
+    case 'e': {
+      First += 2;
+      Node *Ex = parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<EnclosingExpr>("typeid (", Ex, ")");
+    }
+    case 'i': {
+      First += 2;
+      Node *Ty = parseType();
+      if (Ty == nullptr)
+        return Ty;
+      return make<EnclosingExpr>("typeid (", Ty, ")");
+    }
+    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);
+      }
+      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 nullptr;
 }
 
-// <template-arg> ::= <type>                                             # type or template
-//                ::= X <expression> E                                   # expression
-//                ::= <expr-primary>                                     # simple expressions
-//                ::= J <template-arg>* E                                # argument pack
-//                ::= LZ <encoding> E                                    # extension
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+//
+// <nv-offset> ::= <offset number>
+//               # non-virtual base override
+//
+// <v-offset>  ::= <offset number> _ <virtual offset number>
+//               # virtual base override, with vcall offset
+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;
+}
 
-const char*
-parse_template_arg(const char* first, const char* last, Db& 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;
-        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;
-        }
+// <special-name> ::= TV <type>    # virtual table
+//                ::= TT <type>    # VTT structure (construction vtable index)
+//                ::= TI <type>    # typeinfo structure
+//                ::= TS <type>    # typeinfo name (null-terminated byte string)
+//                ::= Tc <call-offset> <call-offset> <base encoding>
+//                    # base is the nominal target function of thunk
+//                    # first call-offset is 'this' adjustment
+//                    # 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
+//                                     # 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
+//      extension ::= GR <object name> # reference temporary for object
+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);
     }
-    return first;
+    // 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
+    case 'R': {
+      First += 2;
+      Node *Name = parseName();
+      if (Name == nullptr)
+        return nullptr;
+      return make<SpecialName>("reference temporary for ", Name);
+    }
+    }
+  }
+  return nullptr;
+}
+
+// <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";
+};
+
+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";
+};
+
+constexpr const char* FloatData<double>::spec;
+
+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);
+}
+
+// <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;
+
+  if (std::islower(look())) {
+    Node *SpecialSub;
+    switch (look()) {
+    case 'a':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);
+      break;
+    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;
+  }
+
+  //                ::= 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];
+}
+
+// <template-param> ::= T_    # first template parameter
+//                  ::= T <parameter-2 non-negative number> _
+Node *Db::parseTemplateParam() {
+  if (!consumeIf('T'))
+    return nullptr;
+
+  if (consumeIf('_')) {
+    if (TemplateParams.empty()) {
+      FixForwardReferences = true;
+      return make<NameType>("FORWARD_REFERENCE");
+    }
+    return TemplateParams[0];
+  }
+
+  size_t Index;
+  if (parsePositiveInteger(&Index))
+    return nullptr;
+  ++Index;
+  if (!consumeIf('_'))
+    return nullptr;
+  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;
+    }
+    //                ::= <expr-primary>            # simple expressions
+    return parseExprPrimary();
+  }
+  default:
+    return parseType();
+  }
 }
 
 // <template-args> ::= I <template-arg>* E
 //     extension, the abi says <template-arg>+
+Node *Db::parseTemplateArgs() {
+  if (!consumeIf('I'))
+    return nullptr;
 
-const char*
-parse_template_args(const char* first, const char* last, Db& db)
-{
-    if (last - first >= 2 && *first == 'I')
-    {
-        if (db.TagTemplates)
-            db.TemplateParams.clear();
-        const char* t = first+1;
-        size_t begin_idx = db.Names.size();
-        while (*t != 'E')
-        {
-            if (db.TagTemplates)
-            {
-                auto TmpParams = std::move(db.TemplateParams);
-                size_t k0 = db.Names.size();
-                const char* t1 = parse_template_arg(t, last, db);
-                size_t k1 = db.Names.size();
-                db.TemplateParams = std::move(TmpParams);
+  // <template-params> refer to the innermost <template-args>. Clear out any
+  // outer args that we may have inserted into TemplateParams.
+  if (TagTemplates)
+    TemplateParams.clear();
 
-                if (t1 == t || t1 == last || k0 > k1)
-                    return first;
-                db.TemplateParams.pushPack();
-                for (size_t k = k0; k < k1; ++k)
-                    db.TemplateParams.pushSubstitutionIntoPack(db.Names[k]);
-                t = t1;
-                continue;
-            }
-            size_t k0 = db.Names.size();
-            const char* t1 = parse_template_arg(t, last, db);
-            size_t k1 = db.Names.size();
-            if (t1 == t || t1 == last || k0 > k1)
-              return first;
-            t = t1;
-        }
-        if (begin_idx > db.Names.size())
-            return first;
-        first = t + 1;
-        TemplateParams* tp = db.make<TemplateParams>(
-            db.popTrailingNodeArray(begin_idx));
-        db.Names.push_back(tp);
+  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;
-}
-
-// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
-//               ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
-// 
-// <prefix> ::= <prefix> <unqualified-name>
-//          ::= <template-prefix> <template-args>
-//          ::= <template-param>
-//          ::= <decltype>
-//          ::= # empty
-//          ::= <substitution>
-//          ::= <prefix> <data-member-prefix>
-//  extension ::= L
-// 
-// <template-prefix> ::= <prefix> <template unqualified-name>
-//                   ::= <template-param>
-//                   ::= <substitution>
-
-const char*
-parse_nested_name(const char* first, const char* last, Db& db,
-                  bool* ends_with_template_args)
-{
-    if (first != last && *first == 'N')
-    {
-        Qualifiers cv;
-        const char* t0 = parse_cv_qualifiers(first+1, last, cv);
-        if (t0 == last)
-            return first;
-        db.RefQuals = FrefQualNone;
-        if (*t0 == 'R')
-        {
-            db.RefQuals = FrefQualLValue;
-            ++t0;
-        }
-        else if (*t0 == 'O')
-        {
-            db.RefQuals = FrefQualRValue;
-            ++t0;
-        }
-        db.Names.push_back(db.make<EmptyName>());
-        if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
-        {
-            t0 += 2;
-            db.Names.back() = db.make<NameType>("std");
-        }
-        if (t0 == last)
-            return first;
-        bool pop_subs = false;
-        bool component_ends_with_template_args = false;
-        while (*t0 != 'E')
-        {
-            component_ends_with_template_args = false;
-            const char* t1;
-            switch (*t0)
-            {
-            case 'S':
-                if (t0 + 1 != last && t0[1] == 't')
-                    goto do_parse_unqualified_name;
-                t1 = parse_substitution(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    if (db.Names.size() < 2)
-                        return first;
-                    auto name = db.Names.back();
-                    db.Names.pop_back();
-                    if (db.Names.back()->K != Node::KEmptyName)
-                    {
-                        db.Names.back() = db.make<QualifiedName>(
-                            db.Names.back(), name);
-                        db.Subs.pushSubstitution(db.Names.back());
-                    }
-                    else
-                        db.Names.back() = name;
-                    pop_subs = true;
-                    t0 = t1;
-                }
-                else
-                    return first;
-                break;
-            case 'T':
-                t1 = parse_template_param(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    if (db.Names.size() < 2)
-                        return first;
-                    auto name = db.Names.back();
-                    db.Names.pop_back();
-                    if (db.Names.back()->K != Node::KEmptyName)
-                        db.Names.back() =
-                            db.make<QualifiedName>(db.Names.back(), name);
-                    else
-                        db.Names.back() = name;
-                    db.Subs.pushSubstitution(db.Names.back());
-                    pop_subs = true;
-                    t0 = t1;
-                }
-                else
-                    return first;
-                break;
-            case 'D':
-                if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
-                    goto do_parse_unqualified_name;
-                t1 = parse_decltype(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    if (db.Names.size() < 2)
-                        return first;
-                    auto name = db.Names.back();
-                    db.Names.pop_back();
-                    if (db.Names.back()->K != Node::KEmptyName)
-                        db.Names.back() =
-                            db.make<QualifiedName>(db.Names.back(), name);
-                    else
-                        db.Names.back() = name;
-                    db.Subs.pushSubstitution(db.Names.back());
-                    pop_subs = true;
-                    t0 = t1;
-                }
-                else
-                    return first;
-                break;
-            case 'I':
-                t1 = parse_template_args(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    if (db.Names.size() < 2)
-                        return first;
-                    auto name = db.Names.back();
-                    db.Names.pop_back();
-                    db.Names.back() = db.make<NameWithTemplateArgs>(
-                        db.Names.back(), name);
-                    db.Subs.pushSubstitution(db.Names.back());
-                    t0 = t1;
-                    component_ends_with_template_args = true;
-                }
-                else
-                    return first;
-                break;
-            case 'L':
-                if (++t0 == last)
-                    return first;
-                break;
-            default:
-            do_parse_unqualified_name:
-                t1 = parse_unqualified_name(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    if (db.Names.size() < 2)
-                        return first;
-                    auto name = db.Names.back();
-                    db.Names.pop_back();
-                    if (db.Names.back()->K != Node::KEmptyName)
-                        db.Names.back() =
-                            db.make<QualifiedName>(db.Names.back(), name);
-                    else
-                        db.Names.back() = name;
-                    db.Subs.pushSubstitution(db.Names.back());
-                    pop_subs = true;
-                    t0 = t1;
-                }
-                else
-                    return first;
-            }
-        }
-        first = t0 + 1;
-        db.CV = cv;
-        if (pop_subs && !db.Subs.empty())
-            db.Subs.popPack();
-        if (ends_with_template_args)
-            *ends_with_template_args = component_ends_with_template_args;
-    }
-    return first;
+  }
+  return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
 }
 
 // <discriminator> := _ <non-negative number>      # when number < 10
@@ -5440,719 +4765,106 @@
     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>
-
-const char*
-parse_local_name(const char* first, const char* last, Db& 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() = db.make<QualifiedName>(
-                    db.Names.back(), db.make<NameType>("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();
-                            db.Names.pop_back();
-                            if (db.Names.empty())
-                                return first;
-                            db.Names.back() =
-                                db.make<QualifiedName>(db.Names.back(), 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();
-                        db.Names.pop_back();
-                        if (db.Names.empty())
-                            return first;
-                        db.Names.back() =
-                            db.make<QualifiedName>(db.Names.back(), name);
-                    }
-                    else if (!db.Names.empty())
-                        db.Names.pop_back();
-                }
-                break;
-            }
-        }
-    }
-    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>
-
-const char*
-parse_name(const char* first, const char* last, Db& 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;
-          }
-        case 'Z':
-          {
-            const char* t1 = parse_local_name(t0, last, db,
-                                              ends_with_template_args);
-            if (t1 != t0)
-                first = t1;
-            break;
-          }
-        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.pushSubstitution(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();
-                        db.Names.pop_back();
-                        if (db.Names.empty())
-                            return first;
-                        db.Names.back() =
-                            db.make<NameWithTemplateArgs>(
-                                db.Names.back(), 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();
-                        db.Names.pop_back();
-                        if (db.Names.empty())
-                            return first;
-                        db.Names.back() =
-                            db.make<NameWithTemplateArgs>(
-                                db.Names.back(), tmp);
-                        first = t1;
-                        if (ends_with_template_args)
-                            *ends_with_template_args = true;
-                    }
-                }
-            }
-            break;
-          }
-        }
-    }
-    return first;
-}
-
-// <call-offset> ::= h <nv-offset> _
-//               ::= v <v-offset> _
-// 
-// <nv-offset> ::= <offset number>
-//               # non-virtual base override
-// 
-// <v-offset>  ::= <offset number> _ <virtual offset number>
-//               # virtual base override, with vcall offset
-
-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;
-}
-
-// <special-name> ::= TV <type>    # virtual table
-//                ::= TT <type>    # VTT structure (construction vtable index)
-//                ::= TI <type>    # typeinfo structure
-//                ::= TS <type>    # typeinfo name (null-terminated byte string)
-//                ::= Tc <call-offset> <call-offset> <base encoding>
-//                    # base is the nominal target function of thunk
-//                    # first call-offset is 'this' adjustment
-//                    # 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
-//                                     # 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
-//      extension ::= GR <object name> # reference temporary for object
-
-const char*
-parse_special_name(const char* first, const char* last, Db& 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() =
-                        db.make<SpecialName>("vtable for ", db.Names.back());
-                    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() =
-                        db.make<SpecialName>("VTT for ", db.Names.back());
-                    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() =
-                        db.make<SpecialName>("typeinfo for ", db.Names.back());
-                    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() =
-                        db.make<SpecialName>("typeinfo name for ", db.Names.back());
-                    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() =
-                        db.make<SpecialName>("covariant return thunk to ",
-                                              db.Names.back());
-                    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();
-                            db.Names.pop_back();
-                            if (db.Names.empty())
-                                return first;
-                            db.Names.back() = db.make<CtorVtableSpecialName>(
-                                left, db.Names.back());
-                            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() =
-                        db.make<SpecialName>("thread-local wrapper routine for ",
-                                              db.Names.back());
-                    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() = db.make<SpecialName>(
-                        "thread-local initialization routine for ", db.Names.back());
-                    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() =
-                            db.make<SpecialName>("virtual thunk to ",
-                                                  db.Names.back());
-                        first = t;
-                    }
-                    else
-                    {
-                        db.Names.back() =
-                            db.make<SpecialName>("non-virtual thunk to ",
-                                                  db.Names.back());
-                        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() =
-                        db.make<SpecialName>("guard variable for ", db.Names.back());
-                    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() =
-                        db.make<SpecialName>("reference temporary for ",
-                                              db.Names.back());
-                    first = t;
-                }
-                break;
-            }
-            break;
-        }
-    }
-    return first;
-}
-
-template <class T>
-class save_value
-{
-    T& restore_;
-    T original_value_;
-public:
-    save_value(T& restore)
-        : restore_(restore),
-          original_value_(restore)
-        {}
-
-    ~save_value()
-    {
-        restore_ = std::move(original_value_);
-    }
-
-    save_value(const save_value&) = delete;
-    save_value& operator=(const save_value&) = delete;
-};
-
-// <encoding> ::= <function name> <bare-function-type>
-//            ::= <data name>
-//            ::= <special-name>
-
-const char*
-parse_encoding(const char* first, const char* last, Db& db)
-{
-    if (first != last)
-    {
-        save_value<decltype(db.EncodingDepth)> su(db.EncodingDepth);
-        ++db.EncodingDepth;
-        save_value<decltype(db.TagTemplates)> sb(db.TagTemplates);
-        if (db.EncodingDepth > 1)
-            db.TagTemplates = true;
-        save_value<decltype(db.ParsedCtorDtorCV)> sp(db.ParsedCtorDtorCV);
-        db.ParsedCtorDtorCV = false;
-        switch (*first)
-        {
-        case 'G':
-        case 'T':
-            first = parse_special_name(first, last, db);
-            break;
-        default:
-          {
-            bool ends_with_template_args = false;
-            const char* t = parse_name(first, last, db,
-                                       &ends_with_template_args);
-            if (db.Names.empty())
-                return first;
-            Qualifiers cv = db.CV;
-            FunctionRefQual ref = db.RefQuals;
-            if (t != first)
-            {
-                if (t != last && *t != 'E' && *t != '.')
-                {
-                    save_value<bool> sb2(db.TagTemplates);
-                    db.TagTemplates = false;
-                    const char* t2;
-                    if (db.Names.empty())
-                        return first;
-                    if (!db.Names.back())
-                        return first;
-                    Node* return_type = nullptr;
-                    if (!db.ParsedCtorDtorCV && ends_with_template_args)
-                    {
-                        t2 = parse_type(t, last, db);
-                        if (t2 == t)
-                            return first;
-                        if (db.Names.size() < 1)
-                            return first;
-                        return_type = db.Names.back();
-                        db.Names.pop_back();
-                        t = t2;
-                    }
-
-                    Node* result = nullptr;
-
-                    if (t != last && *t == 'v')
-                    {
-                        ++t;
-                        if (db.Names.empty())
-                            return first;
-                        Node* name = db.Names.back();
-                        db.Names.pop_back();
-                        result = db.make<TopLevelFunctionDecl>(
-                            return_type, name, NodeArray());
-                    }
-                    else
-                    {
-                        size_t params_begin = db.Names.size();
-                        while (true)
-                        {
-                            t2 = parse_type(t, last, db);
-                            if (t2 == t)
-                                break;
-                            t = t2;
-                        }
-                        if (db.Names.size() < params_begin)
-                            return first;
-                        NodeArray params =
-                            db.popTrailingNodeArray(params_begin);
-                        if (db.Names.empty())
-                            return first;
-                        Node* name = db.Names.back();
-                        db.Names.pop_back();
-                        result = db.make<TopLevelFunctionDecl>(
-                            return_type, name, params);
-                    }
-                    if (ref != FrefQualNone)
-                        result = db.make<FunctionRefQualType>(result, ref);
-                    if (cv != QualNone)
-                        result = db.make<FunctionQualType>(result, cv);
-                    db.Names.push_back(result);
-                    first = t;
-                }
-                else
-                    first = t;
-            }
-            break;
-          }
-        }
-    }
-    return first;
-}
-
-// _block_invoke
-// _block_invoke<decimal-digit>+
-// _block_invoke_<decimal-digit>+
-
-const char*
-parse_block_invoke(const char* first, const char* last, Db& db)
-{
-    if (last - first >= 13)
-    {
-        // FIXME: strcmp?
-        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;
-        }
-        if (db.Names.empty())
-            return first;
-        db.Names.back() =
-            db.make<SpecialName>("invocation function for block in ",
-                                  db.Names.back());
-        first = t;
-    }
-    return first;
-}
-
-// extension
-// <dot-suffix> := .<anything and everything>
-
-const char*
-parse_dot_suffix(const char* first, const char* last, Db& db)
-{
-    if (first != last && *first == '.')
-    {
-        if (db.Names.empty())
-            return first;
-        db.Names.back() =
-            db.make<DotSuffix>(db.Names.back(), StringView(first, last));
-        first = last;
-    }
-    return first;
-}
-
-// <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>
+// <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;
+  }
 
-void
-demangle(const char* first, const char* last, Db& 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;
-    }
-    if (status == success && db.Names.empty())
-        status = invalid_mangled_name;
+  if (consumeIf("___Z")) {
+    Node *Encoding = parseEncoding();
+    if (Encoding == nullptr || !consumeIf("_block_invoke"))
+      return nullptr;
+    consumeIf('_');
+    if (parseNumber().empty())
+      return nullptr;
+    if (numLeft() != 0)
+      return nullptr;
+    return make<SpecialName>("invocation function for block in ", Encoding);
+  }
+
+  Node *Ty = parseType();
+  if (numLeft() != 0)
+    return nullptr;
+  return Ty;
 }
-
 }  // unnamed namespace
 
+enum {
+  unknown_error = -4,
+  invalid_args = -3,
+  invalid_mangled_name = -2,
+  memory_alloc_failure = -1,
+  success = 0,
+};
+
+namespace __cxxabiv1 {
 extern "C" _LIBCXXABI_FUNC_VIS char *
-__cxa_demangle(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;
+__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
+  if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
+    if (Status)
+      *Status = invalid_args;
+    return nullptr;
+  }
+
+  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));
     }
 
-    size_t internal_size = buf != nullptr ? *n : 0;
-    Db db;
-    int internal_status = success;
-    size_t len = std::strlen(mangled_name);
-    demangle(mangled_name, mangled_name + len, db,
-             internal_status);
+    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 (internal_status == success && db.FixForwardReferences &&
-        !db.TemplateParams.empty())
-    {
-        db.FixForwardReferences = false;
-        db.TagTemplates = false;
-        db.Names.clear();
-        db.Subs.clear();
-        demangle(mangled_name, mangled_name + len, db, internal_status);
-        if (db.FixForwardReferences)
-            internal_status = invalid_mangled_name;
-    }
-
-    if (internal_status == success)
-    {
-        if (!buf)
-        {
-            internal_size = 1024;
-            buf = static_cast<char*>(std::malloc(internal_size));
-        }
-
-        if (buf)
-        {
-            OutputStream s(buf, internal_size);
-            db.Names.back()->print(s);
-            s += '\0';
-            if (n) *n = s.getCurrentPosition();
-            buf = s.getBuffer();
-        }
-        else
-            internal_status = memory_alloc_failure;
-    }
-    else
-        buf = nullptr;
-    if (status)
-        *status = internal_status;
-    return buf;
+  if (Status)
+    *Status = InternalStatus;
+  return InternalStatus == success ? Buf : nullptr;
 }
-
 }  // __cxxabiv1
diff --git a/src/cxa_exception.cpp b/src/cxa_exception.cpp
index e6ed093..b77f3a8 100644
--- a/src/cxa_exception.cpp
+++ b/src/cxa_exception.cpp
@@ -11,6 +11,8 @@
 //  
 //===----------------------------------------------------------------------===//
 
+#define _LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS
+
 #include "cxxabi.h"
 
 #include <exception>        // for std::terminate
@@ -137,6 +139,28 @@
     std::__terminate(exception_header->terminateHandler);
 }
 
+// Return the offset of the __cxa_exception header from the start of the
+// allocated buffer. If __cxa_exception's alignment is smaller than the maximum
+// useful alignment for the target machine, padding has to be inserted before
+// the header to ensure the thrown object that follows the header is
+// sufficiently aligned. This happens if _Unwind_exception isn't double-word
+// aligned (on Darwin, for example).
+static size_t get_cxa_exception_offset() {
+  struct S {
+  } __attribute__((aligned));
+
+  // Compute the maximum alignment for the target machine.
+  constexpr size_t alignment = std::alignment_of<S>::value;
+  constexpr size_t excp_size = sizeof(__cxa_exception);
+  constexpr size_t aligned_size =
+      (excp_size + alignment - 1) / alignment * alignment;
+  constexpr size_t offset = aligned_size - excp_size;
+  static_assert((offset == 0 ||
+                 std::alignment_of<_Unwind_Exception>::value < alignment),
+                "offset is non-zero only if _Unwind_Exception isn't aligned");
+  return offset;
+}
+
 extern "C" {
 
 //  Allocate a __cxa_exception object, and zero-fill it.
@@ -146,10 +170,16 @@
 //  user's exception object.
 void *__cxa_allocate_exception(size_t thrown_size) throw() {
     size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
-    __cxa_exception *exception_header =
-        static_cast<__cxa_exception *>(__aligned_malloc_with_fallback(actual_size));
-    if (NULL == exception_header)
+
+    // Allocate extra space before the __cxa_exception header to ensure the
+    // start of the thrown object is sufficiently aligned.
+    size_t header_offset = get_cxa_exception_offset();
+    char *raw_buffer =
+        (char *)__aligned_malloc_with_fallback(header_offset + actual_size);
+    if (NULL == raw_buffer)
         std::terminate();
+    __cxa_exception *exception_header =
+        static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
     std::memset(exception_header, 0, actual_size);
     return thrown_object_from_cxa_exception(exception_header);
 }
@@ -157,7 +187,11 @@
 
 //  Free a __cxa_exception object allocated with __cxa_allocate_exception.
 void __cxa_free_exception(void *thrown_object) throw() {
-    __aligned_free_with_fallback(cxa_exception_from_thrown_object(thrown_object));
+    // Compute the size of the padding before the header.
+    size_t header_offset = get_cxa_exception_offset();
+    char *raw_buffer =
+        ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset;
+    __aligned_free_with_fallback((void *)raw_buffer);
 }
 
 
diff --git a/src/cxa_exception.hpp b/src/cxa_exception.hpp
index b9f74e3..c8b0fb1 100644
--- a/src/cxa_exception.hpp
+++ b/src/cxa_exception.hpp
@@ -60,22 +60,7 @@
     // previously adding padded to 64-bit align unwindHeader.
     size_t referenceCount;
 #endif
-
-    // This field is annotated with attribute aligned so that the exception
-    // object following the field is sufficiently aligned and there is no
-    // gap between the field and the exception object. r276215 made a change to
-    // annotate _Unwind_Exception in unwind.h with __attribute__((aligned)), but
-    // we cannot incorporate the fix on Darwin since it is an ABI-breaking
-    // change, which is why we need the attribute on this field.
-    //
-    // For ARM EHABI, we do not align this field since _Unwind_Exception is an
-    // alias of _Unwind_Control_Block, which is not annotated with
-    // __attribute__((aligned).
-#if defined(_LIBCXXABI_ARM_EHABI)
     _Unwind_Exception unwindHeader;
-#else
-    _Unwind_Exception unwindHeader __attribute__((aligned));
-#endif
 };
 
 // http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
@@ -109,14 +94,7 @@
 #if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI)
     void* primaryException;
 #endif
-
-    // See the comment in __cxa_exception as to why this field has attribute
-    // aligned.
-#if defined(_LIBCXXABI_ARM_EHABI)
     _Unwind_Exception unwindHeader;
-#else
-    _Unwind_Exception unwindHeader __attribute__((aligned));
-#endif
 };
 
 struct _LIBCXXABI_HIDDEN __cxa_eh_globals {
diff --git a/src/private_typeinfo.cpp b/src/private_typeinfo.cpp
index 08e2b45..ef9466e 100644
--- a/src/private_typeinfo.cpp
+++ b/src/private_typeinfo.cpp
@@ -673,8 +673,8 @@
             info.path_dynamic_ptr_to_static_ptr == unknown)
         {
             syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
-                            " has hidden visibility.  They should all have public visibility.  "
-                            " %s, %s, %s.\n", static_type->name(), dynamic_type->name(),
+                            "has hidden visibility.  They should all have public visibility.  "
+                            "%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
                     dst_type->name());
             // Redo the search comparing type_info's using strcmp
             info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index c1819d7..5e51c44 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -24,10 +24,6 @@
     "Executor to use when running tests.")
 
 set(AUTO_GEN_COMMENT "## Autogenerated by libcxxabi configuration.\n# Do not edit!")
-configure_file(
-  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
-  @ONLY)
 
 if (LIBCXXABI_ENABLE_SHARED)
   set(LIBCXXABI_TEST_DEPS cxxabi_shared)
@@ -46,6 +42,11 @@
   endif()
 endif()
 
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+
 add_lit_testsuite(check-cxxabi "Running libcxxabi tests"
   ${CMAKE_CURRENT_BINARY_DIR}
   DEPENDS ${LIBCXXABI_TEST_DEPS}
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
index 0e40a29..a66c9e4 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.in
@@ -20,6 +20,8 @@
 config.host_triple              = "@LLVM_HOST_TRIPLE@"
 config.target_triple            = "@TARGET_TRIPLE@"
 config.use_target               = len("@LIBCXXABI_TARGET_TRIPLE@") > 0
+config.sysroot                  = "@LIBCXXABI_SYSROOT@"
+config.gcc_toolchain            = "@LIBCXXABI_GCC_TOOLCHAIN@"
 config.cxx_ext_threads          = "@LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY@"
 
 # Let the main config do the real work.
diff --git a/test/test_demangle.pass.cpp b/test/test_demangle.pass.cpp
index 18bbbba..b54f8d3 100644
--- a/test/test_demangle.pass.cpp
+++ b/test/test_demangle.pass.cpp
@@ -29585,7 +29585,7 @@
     {"_Z1fPU11objcproto1A11objc_object", "f(id<A>)"},
     {"_Z1fPKU11objcproto1A7NSArray", "f(NSArray<A> const*)"},
     {"_ZNK1AIJ1Z1Y1XEEcv1BIJDpPT_EEIJS2_S1_S0_EEEv", "A<Z, Y, X>::operator B<X*, Y*, Z*><X, Y, Z>() const"},
-    {"_ZNK3Ncr6Silver7Utility6detail12CallOnThreadIZ53-[DeploymentSetupController handleManualServerEntry:]E3$_5EclIJEEEDTclclL_ZNS2_4getTIS4_EERT_vEEspclsr3stdE7forwardIT_Efp_EEEDpOSA_", "decltype(-[DeploymentSetupController handleManualServerEntry:]::$_5& Ncr::Silver::Utility::detail::getT<-[DeploymentSetupController handleManualServerEntry:]::$_5>()()(std::forward<-[DeploymentSetupController handleManualServerEntry:]::$_5>(fp))) Ncr::Silver::Utility::detail::CallOnThread<-[DeploymentSetupController handleManualServerEntry:]::$_5>::operator()<>(-[DeploymentSetupController handleManualServerEntry:]::$_5&&) const"},
+    {"_ZNK3Ncr6Silver7Utility6detail12CallOnThreadIZ53-[DeploymentSetupController handleManualServerEntry:]E3$_5EclIJEEEDTclclL_ZNS2_4getTIS4_EERT_vEEspclsr3stdE7forwardIT_Efp_EEEDpOSA_", "decltype(-[DeploymentSetupController handleManualServerEntry:]::$_5& Ncr::Silver::Utility::detail::getT<-[DeploymentSetupController handleManualServerEntry:]::$_5>()()(std::forward<-[DeploymentSetupController handleManualServerEntry:]::$_5>(fp)...)) Ncr::Silver::Utility::detail::CallOnThread<-[DeploymentSetupController handleManualServerEntry:]::$_5>::operator()<>(-[DeploymentSetupController handleManualServerEntry:]::$_5&&...) const"},
     {"_Zli2_xy", "operator\"\" _x(unsigned long long)"},
     {"_Z1fIiEDcT_", "decltype(auto) f<int>(int)"},
     {"_ZZ4testvEN1g3fooE5Point", "test()::g::foo(Point)"},
@@ -29604,7 +29604,118 @@
     {"PFvRmOE", "void (*)(unsigned long&) &&"},
     {"_ZTW1x", "thread-local wrapper routine for x"},
     {"_ZTHN3fooE", "thread-local initialization routine for foo"},
-    {"_Z4algoIJiiiEEvZ1gEUlT_E_", "void algo<int, int, int>(g::'lambda'(int, int, int))"},
+    {"_Z4algoIJiiiEEvZ1gEUlDpT_E_", "void algo<int, int, int>(g::'lambda'(int, int, int))"},
+    // attribute abi_tag
+    {"_Z1fB3foov", "f[abi:foo]()"},
+    {"_Z1fB3fooB3barv", "f[abi:foo][abi:bar]()"},
+    {"_ZN1SB5outer1fB5innerEv", "S[abi:outer]::f[abi:inner]()"},
+    {"_ZN1SC2B8ctor_tagEv", "S::S[abi:ctor_tag]()"},
+    {"_ZplB4MERP1SS_", "operator+[abi:MERP](S, S)"},
+
+    {"_Z1fIJifcEEvDp5unaryIT_E", "void f<int, float, char>(unary<int>, unary<float>, unary<char>)"},
+    {"_Z1fIJEJiEEvDpT_DpT0_", "void f<int>(int)"},
+    {"_Z1fIJicEEvDp7MuncherIAstT__S1_E", "void f<int, char>(Muncher<int [sizeof (int)]>, Muncher<char [sizeof (char)]>)"},
+    {"_ZN1SIJifcEE1fIJdjEEEiDp4MerpIJifcT_EE", "int S<int, float, char>::f<double, unsigned int>(Merp<int, float, char, double>, Merp<int, float, char, unsigned int>)"},
+    {"_Z1pIJicEEiDp4MerpIXsZT_EJT_EE", "int p<int, char>(Merp<sizeof...(int, char), int>, Merp<sizeof...(int, char), char>)"},
+
+    // Some expression symbols found in clang's test/CodeGenCXX/mangle-exprs.cpp
+    {"_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE", "void Casts::implicit<4u>(enable_if<(4u) <= (4), void>::type*)"},
+    {"_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE", "void Casts::cstyle<4u>(enable_if<(4u) <= ((unsigned int)(4)), void>::type*)"},
+    {"_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE", "void Casts::functional<4u>(enable_if<(4u) <= ((unsigned int)(4)), void>::type*)"},
+    {"_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_scjLi4EEvE4typeE", "void Casts::static_<4u>(enable_if<(4u) <= (static_cast<unsigned int>(4)), void>::type*)"},
+    {"_ZN5Casts12reinterpret_ILj4EiEEvPN9enable_ifIXleT_szrcPT0_Li0EEvE4typeE", "void Casts::reinterpret_<4u, int>(enable_if<(4u) <= (sizeof (reinterpret_cast<int*>(0))), void>::type*)"},
+    {"_ZN5Casts6const_IiXadL_ZNS_1iEEEEEvPN9enable_ifIXleLi0EszccPT_T0_EvE4typeE", "void Casts::const_<int, &(Casts::i)>(enable_if<(0) <= (sizeof (const_cast<int*>(&(Casts::i)))), void>::type*)"},
+    {"_ZN5Casts8dynamic_INS_1SEXadL_ZNS_1sEEEEEvPN9enable_ifIXleLi0EszdcPT_T0_EvE4typeE", "void Casts::dynamic_<Casts::S, &(Casts::s)>(enable_if<(0) <= (sizeof (dynamic_cast<Casts::S*>(&(Casts::s)))), void>::type*)"},
+    {"_ZN5Casts1fILi6EEENS_1TIXT_EEEv", "Casts::T<6> Casts::f<6>()"},
+    {"_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE", "void Casts::auto_<int>(decltype(new auto((int)())))"},
+    {"_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE", "void Casts::scalar_<int>(decltype(((int)()) , ((int)())))"},
+    {"_ZN5test11aIsEEDTcl3foocvT__EEES1_", "decltype(foo((short)())) test1::a<short>(short)"},
+    {"_ZN5test21aIPFfvEEEvT_DTclfL0p_EE", "void test2::a<float (*)()>(float (*)(), decltype(fp()))"},
+    {"_ZN5test21bIPFfvEEEDTclfp_EET_", "decltype(fp()) test2::b<float (*)()>(float (*)())"},
+    {"_ZN5test21cIPFfvEEEvT_PFvDTclfL1p_EEE", "void test2::c<float (*)()>(float (*)(), void (*)(decltype(fp())))"},
+    {"_ZN5test21dIPFfvEEEvT_PFDTclfL0p_EEvE", "void test2::d<float (*)()>(float (*)(), decltype(fp()) (*)())"},
+    {"_ZN5test21eIPFfvEEEvPFDTclfp_EET_E", "void test2::e<float (*)()>(decltype(fp()) (*)(float (*)()))"},
+    {"_ZN5test21fIPFfvEEEvPFvT_DTclfL0p_EEE", "void test2::f<float (*)()>(void (*)(float (*)(), decltype(fp())))"},
+    {"_ZN5test21gIPFfvEEEvT_DTclfL0p_EE", "void test2::g<float (*)()>(float (*)(), decltype(fp()))"},
+    {"_ZN5test21hIPFfvEEEvT_DTcvPFDTclfL0p_EEvELi0EE", "void test2::h<float (*)()>(float (*)(), decltype((decltype(fp()) (*)())(0)))"},
+    {"_ZN5test21iIPFfvEEEvDTcvPFDTclfp_EET_ELi0EE", "void test2::i<float (*)()>(decltype((decltype(fp()) (*)(float (*)()))(0)))"},
+    {"_ZZN5test21gIPFfvEEEvT_DTclfL0p_EEE8variable", "void test2::g<float (*)()>(float (*)(), decltype(fp()))::variable"},
+    {"_ZN5test31aINS_1XEMS1_PiEEvT_T0_DTdsfL0p_fL0p0_E", "void test3::a<test3::X, int* test3::X::*>(test3::X, int* test3::X::*, decltype(fp.*fp0))"},
+    {"_ZN5test43tf1INS_1XEEEvDTnw_T_piLi1EEE", "void test4::tf1<test4::X>(decltype(new test4::X(1)))"},
+    {"_ZN5test51aIiEEvDTnxcvT__EE", "void test5::a<int>(decltype(noexcept ((int)())))"},
+    {"_ZN5test62f1IiEEvDTcvT_dtdtL_ZNS_1zEE2ua1iE", "void test6::f1<int>(decltype((int)(test6::z.ua.i)))"},
+    {"_ZN5test62f2IiEEvDTcvT_dtdtL_ZNS_1zEE2ub1iE", "void test6::f2<int>(decltype((int)(test6::z.ub.i)))"},
+    {"_ZN5test62f3IiEEvDTcvT_dtdtL_ZNS_1zEE1s1iE", "void test6::f3<int>(decltype((int)(test6::z.s.i)))"},
+    {"_ZN5test62f4IiEEvDTcvT_dtdtL_ZNS_1zEE4uuss1iE", "void test6::f4<int>(decltype((int)(test6::z.uuss.i)))"},
+    {"_ZN5test62f5IiEEvDTcvT_dtptL_ZNS_2zpEE2ua1iE", "void test6::f5<int>(decltype((int)(test6::zp->ua.i)))"},
+    {"_ZN5test62f6IiEEvDTcvT_dtptL_ZNS_2zpEE2ub1iE", "void test6::f6<int>(decltype((int)(test6::zp->ub.i)))"},
+    {"_ZN5test62f7IiEEvDTcvT_dtptL_ZNS_2zpEE1s1iE", "void test6::f7<int>(decltype((int)(test6::zp->s.i)))"},
+    {"_ZN5test62f8IiEEvDTcvT_dtptL_ZNS_2zpEE4uuss1iE", "void test6::f8<int>(decltype((int)(test6::zp->uuss.i)))"},
+    {"_ZN5test73fD2IiEEDTcmcvNS_1DEL_ZNS_1bEEcvT__EES2_", "decltype(((test7::D)(test7::b)) , ((int)())) test7::fD2<int>(int)"},
+    {"_ZN5test73fT2IiEEDTcvT__EES1_", "decltype((int)()) test7::fT2<int>(int)"},
+    {"_ZN5test73fT4IiEEDTcvT_Li1EES1_", "decltype((int)(1)) test7::fT4<int>(int)"},
+    {"_ZN5test73fT6INS_1BEEEDTcvT__Li1ELi2EEES2_", "decltype((test7::B)(1, 2)) test7::fT6<test7::B>(test7::B)"},
+    {"_ZNK5test81XIiE3barIiEEDTcl3fooIT_EEEv", "decltype(foo<int>()) test8::X<int>::bar<int>() const"},
+
+    // Multiple qualifiers on the same type should all get the same entry in the substitution table.
+    {"_Z1fPU3AS1KiS0_", "f(int const AS1*, int const AS1*)"},
+
+    {"_ZN6test471fINS_1SEEEvPTsNT_1cE", "void test47::f<test47::S>(struct test47::S::c*)"},
+    {"_ZN6test481fINS_1SEEEvPTuNT_1uE", "void test48::f<test48::S>(union test48::S::u*)"},
+    {"_ZN6test451fINS_1SEEEvPTeNT_1eE", "void test45::f<test45::S>(enum test45::S::e*)"},
+
+    // Initializer list expressions
+    {"_ZN5test43tf2INS_1XEEEvDTnw_T_piilLi1EEEE", "void test4::tf2<test4::X>(decltype(new test4::X({1})))"},
+    {"_ZN5test73fA1IiEEDTcmtlNS_1AELi1ELi2EEcvT__EES2_", "decltype((test7::A{1, 2}) , ((int)())) test7::fA1<int>(int)"},
+    {"_ZN5test73fA2IiEEDTcmcvNS_1AEilLi1ELi2EEcvT__EES2_", "decltype(((test7::A)({1, 2})) , ((int)())) test7::fA2<int>(int)"},
+    {"_ZN5test73fB1IiEEDTcmtlNS_1BELi1ELi2EEcvT__EES2_", "decltype((test7::B{1, 2}) , ((int)())) test7::fB1<int>(int)"},
+    {"_ZN5test73fB2IiEEDTcmcvNS_1BEilLi1ELi2EEcvT__EES2_", "decltype(((test7::B)({1, 2})) , ((int)())) test7::fB2<int>(int)"},
+    {"_ZN5test73fC1IiEEDTcmtlNS_1CEilLi1ELi2EEEcvT__EES2_", "decltype((test7::C{{1, 2}}) , ((int)())) test7::fC1<int>(int)"},
+    {"_ZN5test73fC2IiEEDTcmcvNS_1CEilLi1ELi2EEcvT__EES2_", "decltype(((test7::C)({1, 2})) , ((int)())) test7::fC2<int>(int)"},
+    {"_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_", "decltype((test7::D{test7::b}) , ((int)())) test7::fD1<int>(int)"},
+    {"_ZN5test73fE1IiEEDTcmtlNS_1EELi1ELi2EEcvT__EES2_", "decltype((test7::E{1, 2}) , ((int)())) test7::fE1<int>(int)"},
+    {"_ZN5test73fE2IiEEDTcmcvNS_1EEilLi1ELi2EEcvT__EES2_", "decltype(((test7::E)({1, 2})) , ((int)())) test7::fE2<int>(int)"},
+    {"_ZN5test73fF1IiEEDTcmtlNS_1FEilLi1ELi2EEEcvT__EES2_", "decltype((test7::F{{1, 2}}) , ((int)())) test7::fF1<int>(int)"},
+    {"_ZN5test73fF2IiEEDTcmcvNS_1FEilLi1ELi2EEcvT__EES2_", "decltype(((test7::F)({1, 2})) , ((int)())) test7::fF2<int>(int)"},
+    {"_ZN5test73fT1IiEEDTtlT_EES1_", "decltype(int{}) test7::fT1<int>(int)"},
+    {"_ZN5test73fT3IiEEDTtlT_Li1EEES1_", "decltype(int{1}) test7::fT3<int>(int)"},
+    {"_ZN5test73fT5INS_1BEEEDTtlT_Li1ELi2EEES2_", "decltype(test7::B{1, 2}) test7::fT5<test7::B>(test7::B)"},
+    {"_ZN5test73fT7INS_1AEEEDTtlT_ilEEES2_", "decltype(test7::A{{}}) test7::fT7<test7::A>(test7::A)"},
+    {"_ZN5test73fT8INS_1AEEEDTcvT_ilEES2_", "decltype((test7::A)({})) test7::fT8<test7::A>(test7::A)"},
+    {"_ZN5test73fT9INS_1AEEEDTtlT_ilLi1EEEES2_", "decltype(test7::A{{1}}) test7::fT9<test7::A>(test7::A)"},
+    {"_ZN5test73fTAINS_1AEEEDTcvT_ilLi1EEES2_", "decltype((test7::A)({1})) test7::fTA<test7::A>(test7::A)"},
+    {"_ZN5test73fTBINS_1CEEEDTtlT_ilLi1ELi2EEEES2_", "decltype(test7::C{{1, 2}}) test7::fTB<test7::C>(test7::C)"},
+    {"_ZN5test73fTCINS_1CEEEDTcvT_ilLi1ELi2EEES2_", "decltype((test7::C)({1, 2})) test7::fTC<test7::C>(test7::C)"},
+
+    // Designated init expressions
+    {"_ZN15designated_init1fINS_1AEEEvDTtlT_di1adi1bdxLi3EdXLi1ELi4ELi9EEE", "void designated_init::f<designated_init::A>(decltype(designated_init::A{.a.b[3][1 ... 4] = 9}))"},
+    {"_Z1fIXtl1Xdi1adi1bdxLi3ELi1EEEE", "f<X{.a.b[3] = 1}>"},
+
+    // Inheriting constructors:
+    {"_ZN1BCI21AEi", "B::B(int)"},
+    {"_ZN1DCI21CIiEET_", "D::D(int)"},
+
+    // Exception specifiers:
+    {"_Z1bPDoFivE", "b(int (*)() noexcept)"},
+    {"_Z1fILb0EEvPDOT_EFivE", "void f<false>(int (*)() noexcept(false))"},
+    {"_Z1fILb1EEvPDOT_EFivE", "void f<true>(int (*)() noexcept(true))"},
+    {"_Z1gIJEEvPDwDpT_EFivE", "void g<>(int (*)() throw())"},
+    {"_Z1gIJfEEvPDwDpT_EFivE", "void g<float>(int (*)() throw(float))"},
+    {"_Z1hIJEEPDwDpT_iEFivEPDwiS1_EFivE", "int (*h<>(int (*)() throw(int)))() throw(int)"},
+    {"_Z1hIJfEEPDwDpT_iEFivEPDwiS1_EFivE", "int (*h<float>(int (*)() throw(int, float)))() throw(float, int)"},
+    {"_Z1iIJEEPDwiDpT_EFivEPS2_", "int (*i<>(int (*)() throw(int)))() throw(int)"},
+    {"_Z1iIJEEPDwiDpT_EFivES3_", "int (*i<>(int (*)() throw(int)))() throw(int)"},
+    {"_Z1iIJfEEPDwiDpT_EFivEPS2_", "int (*i<float>(int (*)() throw(int, float)))() throw(int, float)"},
+    {"_Z1iIJfEEPDwiDpT_EFivES3_", "int (*i<float>(int (*)() throw(int, float)))() throw(int, float)"},
+    {"_Z1pILb1EEiM1SKDOT_EFivRE", "int p<true>(int (S::*)() const & noexcept(true))"},
+    {"_Z1pIJicfEEiM1SVKDwDpT_EFivOE", "int p<int, char, float>(int (S::*)() const volatile && throw(int, char, float))"},
+    {"_Z1pM1SDoFivE", "p(int (S::*)() noexcept)"},
+
+    {"_ZNKR4llvm8OptionalINS_11MCFixupKindEEdeEv", "llvm::Optional<llvm::MCFixupKind>::operator*() const &"},
+    {"_ZZL23isValidCoroutineContextRN5clang4SemaENS_14SourceLocationEN4llvm9StringRefEENK3$_4clEZL23isValidCoroutineContextS1_S2_S4_E15InvalidFuncDiag", "isValidCoroutineContext(clang::Sema&, clang::SourceLocation, llvm::StringRef)::$_4::operator()(isValidCoroutineContext(clang::Sema&, clang::SourceLocation, llvm::StringRef)::InvalidFuncDiag) const"},
+
+    // ABI tags can apply to built-in substitutions.
+    {"_Z1fSsB1XS_", "f(std::string[abi:X], std::string[abi:X])"},
 };
 
 const unsigned N = sizeof(cases) / sizeof(cases[0]);
@@ -29712,7 +29823,7 @@
     free(buf);
 }
 
-void test2()
+void test_invalid_cases()
 {
     std::size_t len = 0;
     char* buf = nullptr;
@@ -29733,6 +29844,39 @@
     free(buf);
 }
 
+const char *xfail_cases[] = {
+    "_Z1fUa9enable_ifIXLi1EEEv", // enable_if attribute
+    "_ZDC2a12a2E", // decomposition decl
+    "_ZW6FooBarE2f3v", // C++ modules TS
+
+    // FIXME: Why does clang generate the "cp" expr?
+    "_ZN5test11bIsEEDTcp3foocvT__EEES1_",
+};
+
+const size_t num_xfails = sizeof(xfail_cases) / sizeof(xfail_cases[0]);
+
+void test_xfail_cases()
+{
+    std::size_t len = 0;
+    char* buf = nullptr;
+    for (std::size_t i = 0; i < num_xfails; ++i)
+    {
+        int status;
+        char* demang = __cxxabiv1::__cxa_demangle(xfail_cases[i], buf, &len, &status);
+        if (status != -2)
+        {
+            std::cout << xfail_cases[i] << " was documented as xfail but passed\n"
+                      << "got status = " << status << '\n';
+            assert(status == -2);
+        }
+        else
+        {
+            buf = demang;
+        }
+    }
+    free(buf);
+}
+
 void testFPLiterals()
 {
     std::size_t len = 0;
@@ -29769,7 +29913,8 @@
     {
         timer t;
         test();
-        test2();
+        test_invalid_cases();
+        test_xfail_cases();
         testFPLiterals();
     }
 #if 0
diff --git a/test/unittest_demangle.pass.cpp b/test/unittest_demangle.pass.cpp
index 0b4505e..3ec869c 100644
--- a/test/unittest_demangle.pass.cpp
+++ b/test/unittest_demangle.pass.cpp
@@ -82,44 +82,6 @@
   }
 }
 
-void testSubstitutionTable() {
-  {
-    SubstitutionTable<2> Tab;
-
-    NameType Names[] = {{"MERP"}, {"MARP"}, {"MAMP"}};
-    Tab.pushPack();
-    Tab.pushSubstitutionIntoPack(&Names[0]);
-    Tab.pushSubstitutionIntoPack(&Names[1]);
-    Tab.pushSubstitutionIntoPack(&Names[2]);
-
-    int Index = 0;
-    for (Node* N : Tab.nthSubstitution(0)) {
-      assert(static_cast<NameType*>(N)->getName() == Names[Index].getName());
-      ++Index;
-    }
-    assert(Index == 3);
-
-    Tab.popPack();
-    assert(Tab.empty() && Tab.size() == 0);
-    Tab.pushSubstitution(&Names[0]);
-    Tab.pushSubstitution(&Names[1]);
-    assert(!Tab.empty() && Tab.size() == 2);
-
-    int I = 0;
-    for (Node* N : Tab.nthSubstitution(0)) {
-      assert(static_cast<NameType*>(N)->getName() == "MERP");
-      assert(I == 0);
-      ++I;
-    }
-    for (Node* N : Tab.nthSubstitution(1)) {
-      assert(static_cast<NameType*>(N)->getName() == "MARP");
-      assert(I == 1);
-      ++I;
-    }
-  }
-}
-
 int main() {
   testPODSmallVector();
-  testSubstitutionTable();
 }