erik.pilkington created this revision.
erik.pilkington added reviewers: EricWF, mclow.lists, dexonsmith.

This patch fixes some longstanding bugs in the demangler to do with it's 
handling of variadic templates.

Currently the demangler handles variadic templates by expanding them into the 
Names stack. A parse_* function can succeed and add 0 or more Node*s to the 
stack. Each production that can consume a variadic template was responsible for 
looping over all the names it parsed, and transforming the stack. Although its 
possible for a pack to appear in almost every production, most productions 
didn't implement this loop (all but pointer and reference types). The current 
demangler also doesn't respect "Dp" and "sp" productions, which correspond to 
pack expansions in type and expression contexts. It ignores these pack 
expansions, and just eagerly expands the pack in the nearest context where it 
would be possible. For example, we misdemangle the following:

  template <class> struct unary {};
  template <class... Ts> void f(unary<Ts>...) {}
  template void f<int, char, float>(unary<int>, unary<char>, unary<float>);
  // clang mangles to _Z1fIJicfEEvDp5unaryIT_E

The demangler misdemangles this symbol into:

  void f<int, char, float>(unary<int, char, float>)

I think the best way to handle the Dp & sp productions is to parse an 
unexpanded AST, then expand it whenever we encounter the Dp/sp. One way of 
implementing this might be to do a recursive TreeTransform-like traversal of 
the AST, but we would have to do a bunch of allocations for all the expanded 
nodes and it would be pretty complex. This patch does the expanding during 
printing, by reusing the unexpanded AST. This also automatically gives us 
support for PackExpansions everywhere in the grammar. Most of the churn in this 
patch has to do with propagating up the the pack size and some other metadata 
as the AST is being constructed.

This patch also introduces a nice feature: Every parse_* function now either 
fails, or returns exactly 1 Node. I'm going to use this to clean up the parser 
a bit.

Thanks for taking a look!
Erik


Repository:
  rCXXA libc++abi

https://reviews.llvm.org/D41885

Files:
  src/cxa_demangle.cpp
  test/test_demangle.pass.cpp
  test/unittest_demangle.pass.cpp

Index: test/unittest_demangle.pass.cpp
===================================================================
--- test/unittest_demangle.pass.cpp
+++ 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();
 }
Index: test/test_demangle.pass.cpp
===================================================================
--- test/test_demangle.pass.cpp
+++ 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,13 +29604,19 @@
     {"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>)"},
 };
 
 const unsigned N = sizeof(cases) / sizeof(cases[0]);
Index: src/cxa_demangle.cpp
===================================================================
--- src/cxa_demangle.cpp
+++ src/cxa_demangle.cpp
@@ -10,16 +10,17 @@
 // FIXME: (possibly) incomplete list of features that clang mangles that this
 // file does not yet support:
 //   - enable_if attribute
-//   - decomposition declarations
 //   - C++ modules TS
+//   - All C++14 and C++17 features
 
 #define _LIBCPP_NO_EXCEPTIONS
 
 #include "__cxxabi_config.h"
 
 #include <vector>
 #include <algorithm>
 #include <numeric>
+#include <cassert>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
@@ -32,20 +33,7 @@
 #endif
 #endif
 
-namespace __cxxabiv1
-{
-
-namespace
-{
-
-enum
-{
-    unknown_error = -4,
-    invalid_args = -3,
-    invalid_mangled_name,
-    memory_alloc_failure,
-    success
-};
+namespace {
 
 class StringView {
   const char *First;
@@ -82,6 +70,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) {
@@ -110,6 +99,12 @@
   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();
+
+  bool PrintingFailed = false;
+
   OutputStream &operator+=(StringView R) {
     size_t Size = R.size();
     if (Size == 0)
@@ -126,41 +121,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';
@@ -173,69 +134,113 @@
   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 {
 public:
   enum Kind : unsigned char {
-    KDotSuffix,
-    KVendorExtQualType,
-    KQualType,
-    KConversionOperatorType,
-    KPostfixQualifiedType,
-    KNameType,
-    KAbiTagAttr,
+    KUnknown,
+    KParameterPackExpansion,
     KObjCProtoName,
-    KPointerType,
-    KLValueReferenceType,
-    KRValueReferenceType,
-    KPointerToMemberType,
-    KArrayType,
-    KFunctionType,
-    KTopLevelFunctionDecl,
-    KFunctionQualType,
+    KNameType,
+    KVendorExtQualType,
     KFunctionRefQualType,
-    KLiteralOperator,
-    KSpecialName,
-    KCtorVtableSpecialName,
-    KQualifiedName,
-    KEmptyName,
-    KVectorType,
-    KTemplateParams,
-    KNameWithTemplateArgs,
-    KGlobalQualifiedName,
-    KStdQualifiedName,
-    KExpandedSpecialSubstitution,
+    KFunctionType,
+    KParameterPack,
+    KTemplateArgumentPack,
     KSpecialSubstitution,
-    KCtorDtorName,
-    KDtorName,
-    KUnnamedTypeName,
-    KLambdaTypeName,
-    KExpr,
+    KFunctionEncoding,
+    KEmptyName,
   };
 
-  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_) {}
+  mutable unsigned HasCachedRHSComponent : 1;
+  mutable unsigned CachedRHSComponent : 1;
+
+  mutable unsigned HasCachedArray : 1;
+  mutable unsigned CachedArray : 1;
+
+  mutable unsigned HasCachedFunction : 1;
+  mutable unsigned CachedFunction : 1;
 
-  bool hasRHSComponent() const { return HasRHSComponent; }
-  bool hasArray() const { return HasArray; }
-  bool hasFunction() const { return HasFunction; }
+  Node(Kind K_ = KUnknown) : K(K_) {
+    HasCachedRHSComponent = HasCachedArray = HasCachedFunction = 0;
+  }
+
+  bool containsUnexpandedParameterPack() const {
+    return ParameterPackSize != NoParameterPack;
+  }
+
+  void setCachedRHSComponent(bool Val) {
+    HasCachedRHSComponent = 1;
+    CachedRHSComponent = Val;
+  }
+
+  void setCachedArray(bool Val) {
+    HasCachedArray = 1;
+    CachedArray = Val;
+  }
+
+  void setCachedFunction(bool Val) {
+    HasCachedFunction = 1;
+    CachedFunction = Val;
+  }
 
-  void print(OutputStream &s) const {
-    printLeft(s);
-    if (hasRHSComponent())
-      printRight(s);
+  bool hasRHSComponent(OutputStream &S) const {
+    if (HasCachedRHSComponent)
+      return CachedRHSComponent;
+    HasCachedRHSComponent = 1;
+    return CachedRHSComponent = hasRHSComponentSlow(S);
+  }
+
+  bool hasArray(OutputStream &S) const {
+    if (HasCachedArray)
+      return CachedArray;
+    HasCachedArray = 1;
+    return CachedArray = hasArraySlow(S);
+  }
+
+  bool hasFunction(OutputStream &S) const {
+    if (HasCachedFunction)
+      return CachedFunction;
+    HasCachedFunction = 1;
+    return CachedFunction = 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 (!HasCachedRHSComponent || CachedRHSComponent)
+      printRight(S);
   }
 
   // Print the "left" side of this Node into OutputStream.
@@ -251,24 +256,47 @@
 
   // Silence compiler warnings, this dtor will never be called.
   virtual ~Node() = default;
+
+#if 0
+  void dump() const {
+    char *Buffer = static_cast<char*>(std::malloc(1024));
+    OutputStream S(Buffer, 1024);
+    print(S);
+    S += '\0';
+    if (S.PrintingFailed)
+      printf("Failed to print %p\n", (const void*)this);
+    else
+      printf("Symbol dump for %p: %s\n", (const void*)this, S.getBuffer());
+    std::free(S.getBuffer());
+  }
+#endif
 };
 
 class NodeArray {
   Node **Elements;
   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);
     }
   }
@@ -280,31 +308,44 @@
 
 public:
   DotSuffix(Node *Prefix_, StringView Suffix_)
-      : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {}
+      : Prefix(Prefix_), Suffix(Suffix_) {
+    if (Prefix->HasCachedRHSComponent)
+      setCachedRHSComponent(Prefix->CachedRHSComponent);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
-  void printLeft(OutputStream &s) const override {
-    Prefix->print(s);
-    s += " (";
-    s += Suffix;
-    s += ")";
+  void printLeft(OutputStream &S) const override {
+    Prefix->print(S);
+    S += " (";
+    S += Suffix;
+    S += ")";
   }
 };
 
 class VendorExtQualType final : public Node {
-  const Node *Ext;
   const Node *Ty;
+  const Node *Ext;
 
 public:
-  VendorExtQualType(Node *Ext_, Node *Ty_)
-      : Node(KVendorExtQualType), Ext(Ext_), Ty(Ty_) {}
+  VendorExtQualType(Node* Ty_, Node *Ext_)
+      : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {
+    ParameterPackSize = Ty->ParameterPackSize;
+    if (Ty->HasCachedRHSComponent)
+      setCachedRHSComponent(Ty->CachedRHSComponent);
+    if (Ty->HasCachedArray)
+      setCachedArray(Ty->CachedArray);
+    if (Ty->HasCachedFunction)
+      setCachedFunction(Ty->CachedFunction);
+  }
+
+  const Node* getQual() const { return Ext; }
 
   void printLeft(OutputStream &S) const override {
-    Ext->print(S);
+    Ty->print(S);
     S += " ";
-    Ty->printLeft(S);
+    Ext->printLeft(S);
   }
-
-  void printRight(OutputStream &S) const override { Ty->printRight(S); }
 };
 
 enum Qualifiers {
@@ -334,14 +375,25 @@
 
 public:
   QualType(Node *Child_, Qualifiers Quals_)
-      : Node(KQualType, Child_->hasRHSComponent(), Child_->hasFunction(),
-             Child_->hasArray()),
-        Quals(Quals_), Child(Child_) {}
+      : Quals(Quals_), Child(Child_) {
+    ParameterPackSize = Child->ParameterPackSize;
+    if (Child->HasCachedRHSComponent)
+      setCachedRHSComponent(Child->CachedRHSComponent);
+    if (Child->HasCachedArray)
+      setCachedArray(Child->CachedArray);
+    if (Child->HasCachedFunction)
+      setCachedFunction(Child->CachedFunction);
+  }
 
-  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);
@@ -355,7 +407,12 @@
   const Node *Ty;
 
 public:
-  ConversionOperatorType(Node *Ty_) : Node(KConversionOperatorType), Ty(Ty_) {}
+  ConversionOperatorType(Node *Ty_) : Ty(Ty_) {
+    ParameterPackSize = Ty->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "operator ";
@@ -369,7 +426,13 @@
 
 public:
   PostfixQualifiedType(Node *Ty_, StringView Postfix_)
-      : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}
+      : Ty(Ty_), Postfix(Postfix_) {
+    ParameterPackSize = Ty->ParameterPackSize;
+    if (Ty->HasCachedRHSComponent)
+      setCachedRHSComponent(Ty->CachedRHSComponent);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &s) const override {
     Ty->printLeft(s);
@@ -383,7 +446,12 @@
   const StringView Name;
 
 public:
-  NameType(StringView Name_) : Node(KNameType), Name(Name_) {}
+  NameType(StringView Name_) : Node(KNameType), Name(Name_) {
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+    ParameterPackSize = NoParameterPack;
+  }
 
   StringView getName() const { return Name; }
   StringView getBaseName() const override { return Name; }
@@ -395,8 +463,15 @@
   const Node* Base;
   StringView Tag;
 public:
-  AbiTagAttr(const Node* Base_, StringView Tag_)
-      : Node(KAbiTagAttr), Base(Base_), Tag(Tag_) {}
+  AbiTagAttr(const Node* Base_, StringView Tag_) : Base(Base_), Tag(Tag_) {
+    if (Base->HasCachedRHSComponent)
+      setCachedRHSComponent(Base->CachedRHSComponent);
+    if (Base->HasCachedArray)
+      setCachedArray(Base->CachedArray);
+    if (Base->HasCachedFunction)
+      setCachedFunction(Base->CachedFunction);
+    ParameterPackSize = Base->ParameterPackSize;
+  }
 
   void printLeft(OutputStream &S) const override {
     Base->printLeft(S);
@@ -414,36 +489,50 @@
 
 public:
   ObjCProtoName(Node *Ty_, Node *Protocol_)
-      : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
+      : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+    ParameterPackSize = NoParameterPack;
+  }
 
   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);
+    Protocol->print(S);
     S += ">";
   }
 };
 
 class PointerType final : public Node {
   const Node *Pointee;
 
 public:
-  PointerType(Node *Pointee_)
-      : Node(KPointerType, Pointee_->hasRHSComponent()), Pointee(Pointee_) {}
+  PointerType(Node *Pointee_) : Pointee(Pointee_) {
+    ParameterPackSize = Pointee->ParameterPackSize;
+    if (Pointee->HasCachedRHSComponent)
+      setCachedRHSComponent(Pointee->CachedRHSComponent);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
+
+  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 {
@@ -455,9 +544,9 @@
   }
 
   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);
     }
@@ -468,48 +557,64 @@
   const Node *Pointee;
 
 public:
-  LValueReferenceType(Node *Pointee_)
-      : Node(KLValueReferenceType, Pointee_->hasRHSComponent()),
-        Pointee(Pointee_) {}
+  LValueReferenceType(Node *Pointee_) : Pointee(Pointee_) {
+    ParameterPackSize = Pointee->ParameterPackSize;
+    if (Pointee->HasCachedRHSComponent)
+      setCachedRHSComponent(Pointee->CachedRHSComponent);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
-  void printLeft(OutputStream &s) const override {
-    Pointee->printLeft(s);
-    if (Pointee->hasArray())
-      s += " ";
-    if (Pointee->hasArray() || Pointee->hasFunction())
-      s += "(&";
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    Pointee->printLeft(S);
+    if (Pointee->hasArray(S))
+      S += " ";
+    if (Pointee->hasArray(S) || Pointee->hasFunction(S))
+      S += "(&";
     else
-      s += "&";
+      S += "&";
   }
-  void printRight(OutputStream &s) const override {
-    if (Pointee->hasArray() || Pointee->hasFunction())
-      s += ")";
-    Pointee->printRight(s);
+  void printRight(OutputStream &S) const override {
+    if (Pointee->hasArray(S) || Pointee->hasFunction(S))
+      S += ")";
+    Pointee->printRight(S);
   }
 };
 
 class RValueReferenceType final : public Node {
   const Node *Pointee;
 
 public:
-  RValueReferenceType(Node *Pointee_)
-      : Node(KRValueReferenceType, Pointee_->hasRHSComponent()),
-        Pointee(Pointee_) {}
+  RValueReferenceType(Node *Pointee_) : Pointee(Pointee_) {
+    ParameterPackSize = Pointee->ParameterPackSize;
+    if (Pointee->HasCachedRHSComponent)
+      setCachedRHSComponent(Pointee->CachedRHSComponent);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
-  void printLeft(OutputStream &s) const override {
-    Pointee->printLeft(s);
-    if (Pointee->hasArray())
-      s += " ";
-    if (Pointee->hasArray() || Pointee->hasFunction())
-      s += "(&&";
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    Pointee->printLeft(S);
+    if (Pointee->hasArray(S))
+      S += " ";
+    if (Pointee->hasArray(S) || Pointee->hasFunction(S))
+      S += "(&&";
     else
-      s += "&&";
+      S += "&&";
   }
 
-  void printRight(OutputStream &s) const override {
-    if (Pointee->hasArray() || Pointee->hasFunction())
-      s += ")";
-    Pointee->printRight(s);
+  void printRight(OutputStream &S) const override {
+    if (Pointee->hasArray(S) || Pointee->hasFunction(S))
+      S += ")";
+    Pointee->printRight(S);
   }
 };
 
@@ -519,23 +624,33 @@
 
 public:
   PointerToMemberType(Node *ClassType_, Node *MemberType_)
-      : Node(KPointerToMemberType, MemberType_->hasRHSComponent()),
-        ClassType(ClassType_), MemberType(MemberType_) {}
+      : ClassType(ClassType_), MemberType(MemberType_) {
+    ParameterPackSize =
+      std::min(ClassType->ParameterPackSize, MemberType->ParameterPackSize);
+    if (MemberType->HasCachedRHSComponent)
+      setCachedRHSComponent(MemberType->CachedRHSComponent);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
-  void printLeft(OutputStream &s) const override {
-    MemberType->printLeft(s);
-    if (MemberType->hasArray() || MemberType->hasFunction())
-      s += "(";
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return MemberType->hasRHSComponent(S);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    MemberType->printLeft(S);
+    if (MemberType->hasArray(S) || MemberType->hasFunction(S))
+      S += "(";
     else
-      s += " ";
-    ClassType->print(s);
-    s += "::*";
+      S += " ";
+    ClassType->print(S);
+    S += "::*";
   }
 
-  void printRight(OutputStream &s) const override {
-    if (MemberType->hasArray() || MemberType->hasFunction())
-      s += ")";
-    MemberType->printRight(s);
+  void printRight(OutputStream &S) const override {
+    if (MemberType->hasArray(S) || MemberType->hasFunction(S))
+      S += ")";
+    MemberType->printRight(S);
   }
 };
 
@@ -581,10 +696,21 @@
 
 public:
   ArrayType(Node *Base_, NodeOrString Dimension_)
-      : Node(KArrayType, true, false, true), Base(Base_), Dimension(Dimension_) {}
+      : Base(Base_), Dimension(Dimension_) {
+    ParameterPackSize = Base->ParameterPackSize;
+    if (Dimension.isNode() &&
+        Dimension.asNode()->ParameterPackSize < ParameterPackSize)
+      ParameterPackSize = Dimension.asNode()->ParameterPackSize;
+    setCachedRHSComponent(true);
+    setCachedArray(true);
+    setCachedFunction(false);
+  }
+
+  bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+  bool hasArraySlow(OutputStream &) const override { return true; }
 
   // Incomplete array type.
-  ArrayType(Node *Base_) : Node(KArrayType, true, false, true), Base(Base_) {}
+  ArrayType(Node *Base_) : Base(Base_) {}
 
   void printLeft(OutputStream &S) const override { Base->printLeft(S); }
 
@@ -607,7 +733,17 @@
 
 public:
   FunctionType(Node *Ret_, NodeArray Params_)
-      : Node(KFunctionType, true, true), Ret(Ret_), Params(Params_) {}
+      : Node(KFunctionType), Ret(Ret_), Params(Params_) {
+    for (Node *P : Params)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+    ParameterPackSize = std::min(ParameterPackSize, Ret->ParameterPackSize);
+    setCachedRHSComponent(true);
+    setCachedArray(false);
+    setCachedFunction(true);
+  }
+
+  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:
@@ -623,34 +759,46 @@
 
   void printRight(OutputStream &S) const override {
     S += "(";
-    Params.printWithSeperator(S, ", ");
+    Params.printWithComma(S);
     S += ")";
     Ret->printRight(S);
   }
 };
 
-class TopLevelFunctionDecl final : public Node {
+class FunctionEncoding final : public Node {
   const Node *Ret;
   const Node *Name;
   NodeArray Params;
 
 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_)
+      : Node(KFunctionEncoding), Ret(Ret_), Name(Name_), Params(Params_) {
+    for (Node *P : Params)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+    if (Ret)
+      ParameterPackSize = std::min(ParameterPackSize, Ret->ParameterPackSize);
+    setCachedRHSComponent(true);
+    setCachedArray(false);
+    setCachedFunction(true);
+  }
+
+  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);
   }
 
   void printRight(OutputStream &S) const override {
     S += "(";
-    Params.printWithSeperator(S, ", ");
+    Params.printWithComma(S);
     S += ")";
     if (Ret)
       Ret->printRight(S);
@@ -671,7 +819,15 @@
 
 public:
   FunctionRefQualType(Node *Fn_, FunctionRefQual Quals_)
-      : Node(KFunctionRefQualType, true, true), Fn(Fn_), Quals(Quals_) {}
+      : Node(KFunctionRefQualType), Fn(Fn_), Quals(Quals_) {
+    ParameterPackSize = Fn->ParameterPackSize;
+    setCachedRHSComponent(true);
+    setCachedArray(false);
+    setCachedFunction(true);
+  }
+
+  bool hasFunctionSlow(OutputStream &) const override { return true; }
+  bool hasRHSComponentSlow(OutputStream &) const override { return true; }
 
   void printQuals(OutputStream &S) const {
     if (Quals == FrefQualLValue)
@@ -691,12 +847,12 @@
 class FunctionQualType final : public QualType {
 public:
   FunctionQualType(Node *Child_, Qualifiers Quals_)
-      : QualType(KFunctionQualType, Child_, Quals_) {}
+      : QualType(Child_, Quals_) {}
 
   void printLeft(OutputStream &S) const override { Child->printLeft(S); }
 
   void printRight(OutputStream &S) const override {
-    if (Child->K == KFunctionRefQualType) {
+    if (Child->getKind() == KFunctionRefQualType) {
       auto *RefQuals = static_cast<const FunctionRefQualType *>(Child);
       RefQuals->Fn->printRight(S);
       printQuals(S);
@@ -712,7 +868,12 @@
   const Node *OpName;
 
 public:
-  LiteralOperator(Node *OpName_) : Node(KLiteralOperator), OpName(OpName_) {}
+  LiteralOperator(Node *OpName_) : OpName(OpName_) {
+    ParameterPackSize = OpName->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedFunction(false);
+    setCachedArray(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "operator\"\" ";
@@ -726,7 +887,12 @@
 
 public:
   SpecialName(StringView Special_, Node *Child_)
-      : Node(KSpecialName), Special(Special_), Child(Child_) {}
+      : Special(Special_), Child(Child_) {
+    ParameterPackSize = Child->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedFunction(false);
+    setCachedArray(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += Special;
@@ -740,8 +906,13 @@
 
 public:
   CtorVtableSpecialName(Node *FirstType_, Node *SecondType_)
-      : Node(KCtorVtableSpecialName), FirstType(FirstType_),
-        SecondType(SecondType_) {}
+      : FirstType(FirstType_), SecondType(SecondType_) {
+    ParameterPackSize =
+      std::min(FirstType->ParameterPackSize, SecondType->ParameterPackSize);
+    setCachedRHSComponent(false);
+    setCachedFunction(false);
+    setCachedArray(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "construction vtable for ";
@@ -756,48 +927,61 @@
   const Node *Qualifier;
   const Node *Name;
 
-  mutable OutputStream::StreamStringView Cache;
-
 public:
   QualifiedName(Node *Qualifier_, Node *Name_)
-      : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {}
+      : Qualifier(Qualifier_), Name(Name_) {
+    ParameterPackSize =
+      std::min(Qualifier->ParameterPackSize, Name->ParameterPackSize);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   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);
   }
 };
 
 class EmptyName : public Node {
 public:
-  EmptyName() : Node(KEmptyName) {}
+  EmptyName() : Node(KEmptyName) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
   void printLeft(OutputStream &) const override {}
 };
 
 class VectorType final : public Node {
   const Node *BaseType;
   const NodeOrString Dimension;
   const bool IsPixel;
 
+  void setupCache() {
+    if (BaseType)
+      ParameterPackSize = BaseType->ParameterPackSize;
+    if (Dimension.isNode() &&
+        Dimension.asNode()->ParameterPackSize < ParameterPackSize)
+      ParameterPackSize = Dimension.asNode()->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
+
 public:
   VectorType(NodeOrString Dimension_)
-      : Node(KVectorType), BaseType(nullptr), Dimension(Dimension_),
-        IsPixel(true) {}
+      : BaseType(nullptr), Dimension(Dimension_), IsPixel(true) {
+    setupCache();
+  }
   VectorType(Node *BaseType_, NodeOrString Dimension_)
-      : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_),
-        IsPixel(false) {}
+      : BaseType(BaseType_), Dimension(Dimension_), IsPixel(false) {
+    setupCache();
+  }
 
   void printLeft(OutputStream &S) const override {
     if (IsPixel) {
@@ -816,29 +1000,172 @@
   }
 };
 
-class TemplateParams final : public Node {
-  NodeArray Params;
+/// An unexpanded parameter pack (either in the expression or type context). If
+/// this AST is correct, this node will have a ParameterPackExpansion node above
+/// it.
+///
+/// This node is created when some <template-args> are found that apply to an
+/// <encoding>, and is stored in the TemplateParams table. In order for this to
+/// appear in the final AST, it has to referenced via a <template-param> (ie,
+/// T_).
+class ParameterPack final : public Node {
+  NodeArray Data;
+public:
+  ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) {
+    ParameterPackSize = static_cast<unsigned>(Data.size());
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->HasCachedArray && !P->CachedArray;
+        }))
+      setCachedArray(false);
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->HasCachedFunction && !P->CachedFunction;
+        }))
+      setCachedFunction(false);
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->HasCachedRHSComponent && !P->CachedRHSComponent;
+        }))
+      setCachedRHSComponent(false);
+  }
+
+  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);
+  }
+
+  size_t getSize() const { return Data.size(); }
+  NodeArray getNodes() { return Data; }
+
+  void printLeft(OutputStream &S) const override {
+    size_t Idx = S.CurrentPackIndex;
+    // If this index is out of range, or UINT_MAX (in which case we're not even
+    // expanding a pack) then this is an invalid mangled name.
+    if (Idx >= Data.size()) {
+      S.PrintingFailed = true;
+      return;
+    }
+    Data[Idx]->printLeft(S);
+  }
+  void printRight(OutputStream &S) const override {
+    size_t Idx = S.CurrentPackIndex;
+    // If this index is out of range, or UINT_MAX (in which case we're not even
+    // expanding a pack) then this is an invalid mangled name.
+    if (Idx >= Data.size()) {
+      S.PrintingFailed = true;
+      return;
+    }
+    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);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
-  mutable OutputStream::StreamStringView Cache;
+  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:
-  TemplateParams(NodeArray Params_) : Node(KTemplateParams), Params(Params_) {}
+  ParameterPackExpansion(Node* Child_)
+      : Node(KParameterPackExpansion), Child(Child_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
+
+  const Node *getChild() const { return Child; }
 
   void printLeft(OutputStream &S) const override {
-    if (!Cache.empty()) {
-      S += Cache;
+    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_) : Params(Params_) {
+    for (Node *P : Params)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
+
+  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);
   }
 };
 
@@ -849,7 +1176,13 @@
 
 public:
   NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_)
-      : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {}
+      : Name(Name_), TemplateArgs(TemplateArgs_) {
+    ParameterPackSize =
+      std::min(Name->ParameterPackSize, TemplateArgs->ParameterPackSize);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   StringView getBaseName() const override { return Name->getBaseName(); }
 
@@ -863,7 +1196,12 @@
   Node *Child;
 
 public:
-  GlobalQualifiedName(Node *Child_) : Node(KGlobalQualifiedName), Child(Child_) {}
+  GlobalQualifiedName(Node *Child_) : Child(Child_) {
+    ParameterPackSize = Child->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   StringView getBaseName() const override { return Child->getBaseName(); }
 
@@ -877,7 +1215,12 @@
   Node *Child;
 
 public:
-  StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
+  StdQualifiedName(Node *Child_) : Child(Child_) {
+    ParameterPackSize = Child->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   StringView getBaseName() const override { return Child->getBaseName(); }
 
@@ -900,8 +1243,12 @@
   SpecialSubKind SSK;
 
 public:
-  ExpandedSpecialSubstitution(SpecialSubKind SSK_)
-      : Node(KExpandedSpecialSubstitution), SSK(SSK_) {}
+  ExpandedSpecialSubstitution(SpecialSubKind SSK_) : SSK(SSK_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   StringView getBaseName() const override {
     switch (SSK) {
@@ -949,8 +1296,12 @@
 public:
   SpecialSubKind SSK;
 
-  SpecialSubstitution(SpecialSubKind SSK_)
-      : Node(KSpecialSubstitution), SSK(SSK_) {}
+  SpecialSubstitution(SpecialSubKind SSK_) : Node(KSpecialSubstitution), SSK(SSK_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   StringView getBaseName() const override {
     switch (SSK) {
@@ -1000,7 +1351,12 @@
 
 public:
   CtorDtorName(Node *Basename_, bool IsDtor_)
-      : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_) {}
+      : Basename(Basename_), IsDtor(IsDtor_) {
+    ParameterPackSize = Basename->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     if (IsDtor)
@@ -1013,7 +1369,12 @@
   const Node *Base;
 
 public:
-  DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {}
+  DtorName(Node *Base_) : Base(Base_) {
+    ParameterPackSize = Base->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "~";
@@ -1025,7 +1386,12 @@
   const StringView Count;
 
 public:
-  UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {}
+  UnnamedTypeName(StringView Count_) : Count(Count_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "'unnamed";
@@ -1040,31 +1406,39 @@
 
 public:
   LambdaTypeName(NodeArray Params_, StringView Count_)
-      : Node(KLambdaTypeName), Params(Params_), Count(Count_) {}
+      : Params(Params_), Count(Count_) {
+    for (Node *P : Params)
+      ParameterPackSize = std::min(ParameterPackSize, P->ParameterPackSize);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "\'lambda";
     S += Count;
     S += "\'(";
-    Params.printWithSeperator(S, ", ");
+    Params.printWithComma(S);
     S += ")";
   }
 };
 
 // -- Expression Nodes --
 
-struct Expr : public Node {
-  Expr() : Node(KExpr) {}
-};
-
-class BinaryExpr : public Expr {
+class BinaryExpr : public Node {
   const Node *LHS;
   const StringView InfixOperator;
   const Node *RHS;
 
 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);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     // might be a template argument expression, then we need to disambiguate
@@ -1085,12 +1459,18 @@
   }
 };
 
-class ArraySubscriptExpr : public Expr {
+class ArraySubscriptExpr : public Node {
   const Node *Op1;
   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);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "(";
@@ -1101,13 +1481,18 @@
   }
 };
 
-class PostfixExpr : public Expr {
+class PostfixExpr : public Node {
   const Node *Child;
   const StringView Operand;
 
 public:
   PostfixExpr(Node *Child_, StringView Operand_)
-      : Child(Child_), Operand(Operand_) {}
+      : Child(Child_), Operand(Operand_) {
+    ParameterPackSize = Child->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "(";
@@ -1117,14 +1502,21 @@
   }
 };
 
-class ConditionalExpr : public Expr {
+class ConditionalExpr : public Node {
   const Node *Cond;
   const Node *Then;
   const Node *Else;
 
 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));
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "(";
@@ -1137,47 +1529,64 @@
   }
 };
 
-class MemberExpr : public Expr {
+class MemberExpr : public Node {
   const Node *LHS;
   const StringView Kind;
   const Node *RHS;
 
 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);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     LHS->print(S);
     S += Kind;
     RHS->print(S);
   }
 };
 
-class EnclosingExpr : public Expr {
+class EnclosingExpr : public Node {
   const StringView Prefix;
   const Node *Infix;
   const StringView Postfix;
 
 public:
   EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_)
-      : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {}
+      : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {
+    ParameterPackSize = Infix->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += Prefix;
     Infix->print(S);
     S += Postfix;
   }
 };
 
-class CastExpr : public Expr {
+class CastExpr : public Node {
   // cast_kind<to>(from)
   const StringView CastKind;
   const Node *To;
   const Node *From;
 
 public:
   CastExpr(StringView CastKind_, Node *To_, Node *From_)
-      : CastKind(CastKind_), To(To_), From(From_) {}
+      : CastKind(CastKind_), To(To_), From(From_) {
+    ParameterPackSize =
+      std::min(To->ParameterPackSize, From->ParameterPackSize);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += CastKind;
@@ -1189,46 +1598,69 @@
   }
 };
 
-class SizeofParamPackExpr : public Expr {
-  NodeArray Args;
+class SizeofParamPackExpr : public Node {
+  Node *Pack;
 
 public:
-  SizeofParamPackExpr(NodeArray Args_) : Args(Args_) {}
+  SizeofParamPackExpr(Node *Pack_) : Pack(Pack_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "sizeof...(";
-    Args.printWithSeperator(S, ", ");
+    ParameterPackExpansion PPE(Pack);
+    PPE.printLeft(S);
     S += ")";
   }
 };
 
-class CallExpr : public Expr {
+class CallExpr : public Node {
   const Node *Callee;
   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);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     Callee->print(S);
     S += "(";
-    Args.printWithSeperator(S, ", ");
+    Args.printWithComma(S);
     S += ")";
   }
 };
 
-class NewExpr : public Expr {
+class NewExpr : public Node {
   // new (expr_list) type(init_list)
   NodeArray ExprList;
   Node *Type;
   NodeArray InitList;
   bool IsGlobal; // ::operator new ?
   bool IsArray;  // new[] ?
 public:
-  NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
+  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);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     if (IsGlobal)
@@ -1238,26 +1670,32 @@
       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 += ")";
     }
+
   }
 };
 
-class DeleteExpr : public Expr {
+class DeleteExpr : public Node {
   Node *Op;
   bool IsGlobal;
   bool IsArray;
 
 public:
   DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_)
-      : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+      : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {
+    ParameterPackSize = Op->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     if (IsGlobal)
@@ -1269,12 +1707,17 @@
   }
 };
 
-class PrefixExpr : public Expr {
+class PrefixExpr : public Node {
   StringView Prefix;
   Node *Child;
 
 public:
-  PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {}
+  PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {
+    ParameterPackSize = Child->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += Prefix;
@@ -1284,78 +1727,92 @@
   }
 };
 
-class FunctionParam : public Expr {
+class FunctionParam : public Node {
   StringView Number;
 
 public:
-  FunctionParam(StringView Number_) : Number(Number_) {}
+  FunctionParam(StringView Number_) : Number(Number_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "fp";
     S += Number;
   }
 };
 
-class ExprList : public Expr {
-  NodeArray SubExprs;
-
-public:
-  ExprList(NodeArray SubExprs_) : SubExprs(SubExprs_) {}
-
-  void printLeft(OutputStream &S) const override {
-    S += "(";
-    SubExprs.printWithSeperator(S, ", ");
-    S += ")";
-  }
-};
-
-class ConversionExpr : public Expr {
+class ConversionExpr : public Node {
+  const Node *Type;
   NodeArray Expressions;
-  NodeArray Types;
 
 public:
-  ConversionExpr(NodeArray Expressions_, NodeArray Types_)
-      : Expressions(Expressions_), Types(Types_) {}
+  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);
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "(";
-    Expressions.printWithSeperator(S, ", ");
+    Type->print(S);
     S += ")(";
-    Types.printWithSeperator(S, ", ");
+    Expressions.printWithComma(S);
     S += ")";
   }
 };
 
-class ThrowExpr : public Expr {
+class ThrowExpr : public Node {
   const Node *Op;
 
 public:
-  ThrowExpr(Node *Op_) : Op(Op_) {}
+  ThrowExpr(Node *Op_) : Op(Op_) {
+    ParameterPackSize = Op->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "throw ";
     Op->print(S);
   }
 };
 
-class BoolExpr : public Expr {
+class BoolExpr : public Node {
   bool Value;
 
 public:
-  BoolExpr(bool Value_) : Value(Value_) {}
+  BoolExpr(bool Value_) : Value(Value_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += Value ? StringView("true") : StringView("false");
   }
 };
 
-class IntegerCastExpr : public Expr {
+class IntegerCastExpr : public Node {
   // ty(integer)
   Node *Ty;
   StringView Integer;
 
 public:
-  IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {}
+  IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {
+    ParameterPackSize = Ty->ParameterPackSize;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "(";
@@ -1365,12 +1822,17 @@
   }
 };
 
-class IntegerExpr : public Expr {
+class IntegerExpr : public Node {
   StringView Type;
   StringView Value;
 
 public:
-  IntegerExpr(StringView Type_, StringView Value_) : Type(Type_), Value(Value_) {}
+  IntegerExpr(StringView Type_, StringView Value_) : Type(Type_), Value(Value_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &S) const override {
     if (Type.size() > 3) {
@@ -1392,11 +1854,16 @@
 
 template <class Float> struct FloatData;
 
-template <class Float> class FloatExpr : public Expr {
+template <class Float> class FloatExpr : public Node {
   const StringView Contents;
 
 public:
-  FloatExpr(StringView Contents_) : Contents(Contents_) {}
+  FloatExpr(StringView Contents_) : Contents(Contents_) {
+    ParameterPackSize = NoParameterPack;
+    setCachedRHSComponent(false);
+    setCachedArray(false);
+    setCachedFunction(false);
+  }
 
   void printLeft(OutputStream &s) const override {
     const char *first = Contents.begin();
@@ -1593,94 +2060,22 @@
   }
 };
 
-// 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;
-
-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);
-  }
-
-  // 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);
-  }
-
-  // Remove the last pack from the table.
-  void popPack() {
-    unsigned Last = PackIndices.back();
-    PackIndices.pop_back();
-    Substitutions.dropBack(Last);
-  }
-
-  // For use in a range-for loop.
-  struct NodeRange {
-    Node** First;
-    Node** Last;
-    Node** begin() { return First; }
-    Node** end() { return Last; }
-  };
-
-  // 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};
-  }
-
-  size_t size() const { return PackIndices.size(); }
-  bool empty() const { return PackIndices.empty(); }
-  void clear() {
-    Substitutions.clear();
-    PackIndices.clear();
-  }
-};
-
 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;
 
     // 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;
+    // 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.
-    SubstitutionTable<4> TemplateParams;
+    PODSmallVector<Node *, 8> TemplateParams;
 
     Qualifiers CV = QualNone;
     FunctionRefQual RefQuals = FrefQualNone;
@@ -1938,8 +2333,7 @@
             case '_':
                 if (!db.Subs.empty())
                 {
-                    for (Node* n : db.Subs.nthSubstitution(0))
-                        db.Names.push_back(n);
+                    db.Names.push_back(db.Subs[0]);
                     first += 2;
                 }
                 break;
@@ -1965,8 +2359,7 @@
                     ++sub;
                     if (sub < db.Subs.size())
                     {
-                        for (Node* n : db.Subs.nthSubstitution(sub))
-                            db.Names.push_back(n);
+                        db.Names.push_back(db.Subs[sub]);
                         first = t+1;
                     }
                 }
@@ -2197,8 +2590,7 @@
             {
                 if (!db.TemplateParams.empty())
                 {
-                    for (Node *t : db.TemplateParams.nthSubstitution(0))
-                        db.Names.push_back(t);
+                    db.Names.push_back(db.TemplateParams[0]);
                     first += 2;
                 }
                 else
@@ -2222,8 +2614,7 @@
                 ++sub;
                 if (sub < db.TemplateParams.size())
                 {
-                    for (Node *temp : db.TemplateParams.nthSubstitution(sub))
-                        db.Names.push_back(temp);
+                    db.Names.push_back(db.TemplateParams[sub]);
                     first = t+1;
                 }
                 else
@@ -2356,9 +2747,13 @@
 {
     if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
     {
+        size_t before = db.Names.size();
         const char* t = parse_expression(first+2, last, db);
+        if (before + 1 != db.Names.size())
+            return first;
         if (t != first+2)
             first = t;
+        db.Names.back() = db.make<ParameterPackExpansion>(db.Names.back());
     }
     return first;
 }
@@ -2413,11 +2808,9 @@
         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)
+        if (t != first+2 && k0 + 1 == k1)
         {
-            Node* sizeof_expr = db.make<SizeofParamPackExpr>(
-                db.popTrailingNodeArray(k0));
-            db.Names.push_back(sizeof_expr);
+            db.Names.back() = db.make<SizeofParamPackExpr>(db.Names.back());
             first = t;
         }
     }
@@ -2604,7 +2997,7 @@
             size_t k1 = db.Names.size();
             if (t != first && k1 == k0 + 1)
             {
-                db.Subs.pushSubstitution(db.Names.back());
+                db.Subs.push_back(db.Names.back());
                 first = t;
             }
             else
@@ -2620,7 +3013,7 @@
             {
                 if (db.Names.empty())
                     return first;
-                db.Subs.pushSubstitution(db.Names.back());
+                db.Subs.push_back(db.Names.back());
                 first = t;
             }
             break;
@@ -2639,7 +3032,7 @@
                             return first;
                         db.Names.back() =
                             db.make<StdQualifiedName>(db.Names.back());
-                        db.Subs.pushSubstitution(db.Names.back());
+                        db.Subs.push_back(db.Names.back());
                         first = t;
                     }
                 }
@@ -3054,7 +3447,7 @@
     {
         bool TryToParseTemplateArgs = db.TryToParseTemplateArgs;
         db.TryToParseTemplateArgs = false;
-        size_t type_begin = db.Names.size();
+        size_t type_index = db.Names.size();
         const char* t = parse_type(first+2, last, db);
         db.TryToParseTemplateArgs = TryToParseTemplateArgs;
         if (t != first+2 && t != last)
@@ -3085,16 +3478,13 @@
                 ++t;
             }
             if (db.Names.size() < expr_list_begin ||
-                type_begin > expr_list_begin)
+                type_index + 1 != 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[type_index], expressions);
+            db.Names.dropBack(type_index);
             db.Names.push_back(conv_expr);
             first = t;
         }
@@ -3444,23 +3834,20 @@
                     size_t k0 = db.Names.size();
                     const char* t1 = parse_type(t, last, db);
                     size_t k1 = db.Names.size();
-                    if (t1 != t)
+                    if (t1 != t && k0 + 1 == k1)
                     {
                         if (is_function)
-                            db.Subs.popPack();
-                        db.Subs.pushPack();
-                        for (size_t k = k0; k < k1; ++k)
+                            db.Subs.pop_back();
+                        if (cv)
                         {
-                            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]);
+                            if (is_function)
+                                db.Names.back() = db.make<FunctionQualType>(
+                                    db.Names.back(), cv);
+                            else
+                                db.Names.back() =
+                                    db.make<QualType>(db.Names.back(), cv);
                         }
+                        db.Subs.push_back(db.Names.back());
                         first = t1;
                     }
                 }
@@ -3484,7 +3871,7 @@
                             if (db.Names.empty())
                                 return first;
                             first = t;
-                            db.Subs.pushSubstitution(db.Names.back());
+                            db.Subs.push_back(db.Names.back());
                         }
                         break;
                     case 'C':
@@ -3496,7 +3883,7 @@
                             db.Names.back() = db.make<PostfixQualifiedType>(
                                 db.Names.back(), " complex");
                             first = t;
-                            db.Subs.pushSubstitution(db.Names.back());
+                            db.Subs.push_back(db.Names.back());
                         }
                         break;
                     case 'F':
@@ -3506,7 +3893,7 @@
                             if (db.Names.empty())
                                 return first;
                             first = t;
-                            db.Subs.pushSubstitution(db.Names.back());
+                            db.Subs.push_back(db.Names.back());
                         }
                         break;
                     case 'G':
@@ -3518,7 +3905,7 @@
                             db.Names.back() = db.make<PostfixQualifiedType>(
                                 db.Names.back(), " imaginary");
                             first = t;
-                            db.Subs.pushSubstitution(db.Names.back());
+                            db.Subs.push_back(db.Names.back());
                         }
                         break;
                     case 'M':
@@ -3528,23 +3915,19 @@
                             if (db.Names.empty())
                                 return first;
                             first = t;
-                            db.Subs.pushSubstitution(db.Names.back());
+                            db.Subs.push_back(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)
+                        if (t != first+1 || k0 + 1 == k1)
                         {
-                            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]);
-                            }
+                            db.Names.back() =
+                                db.make<RValueReferenceType>(db.Names.back());
+                            db.Subs.push_back(db.Names.back());
                             first = t;
                         }
                         break;
@@ -3554,14 +3937,10 @@
                         size_t k0 = db.Names.size();
                         t = parse_type(first+1, last, db);
                         size_t k1 = db.Names.size();
-                        if (t != first+1)
+                        if (t != first+1 && k0 + 1 == k1)
                         {
-                            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]);
-                            }
+                            db.Names.back() = db.make<PointerType>(db.Names.back());
+                            db.Subs.push_back(db.Names.back());
                             first = t;
                         }
                         break;
@@ -3571,15 +3950,11 @@
                         size_t k0 = db.Names.size();
                         t = parse_type(first+1, last, db);
                         size_t k1 = db.Names.size();
-                        if (t != first+1)
+                        if (t != first+1 && k0 + 1 == k1)
                         {
-                            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]);
-                            }
+                            db.Names.back() =
+                                db.make<LValueReferenceType>(db.Names.back());
+                            db.Subs.push_back(db.Names.back());
                             first = t;
                         }
                         break;
@@ -3589,11 +3964,9 @@
                         size_t k0 = db.Names.size();
                         t = parse_template_param(first, last, db);
                         size_t k1 = db.Names.size();
-                        if (t != first)
+                        if (t != first && k0 + 1 == k1)
                         {
-                            db.Subs.pushPack();
-                            for (size_t k = k0; k < k1; ++k)
-                                db.Subs.pushSubstitutionIntoPack(db.Names[k]);
+                            db.Subs.push_back(db.Names.back());
                             if (db.TryToParseTemplateArgs && k1 == k0+1)
                             {
                                 const char* t1 = parse_template_args(t, last, db);
@@ -3604,7 +3977,7 @@
                                     db.Names.back() = db.make<
                                         NameWithTemplateArgs>(
                                         db.Names.back(), args);
-                                    db.Subs.pushSubstitution(db.Names.back());
+                                    db.Subs.push_back(db.Names.back());
                                     t = t1;
                                 }
                             }
@@ -3644,7 +4017,7 @@
                                             db.Names.push_back(db.make<VendorExtQualType>(type, proto));
                                         }
                                     }
-                                    db.Subs.pushSubstitution(db.Names.back());
+                                    db.Subs.push_back(db.Names.back());
                                     first = t2;
                                 }
                             }
@@ -3658,7 +4031,7 @@
                             {
                                 if (db.Names.empty())
                                     return first;
-                                db.Subs.pushSubstitution(db.Names.back());
+                                db.Subs.push_back(db.Names.back());
                                 first = t;
                             }
                         }
@@ -3683,7 +4056,7 @@
                                           NameWithTemplateArgs>(
                                               db.Names.back(), template_args);
                                         // Need to create substitution for <template-template-param> <template-args>
-                                        db.Subs.pushSubstitution(db.Names.back());
+                                        db.Subs.push_back(db.Names.back());
                                         first = t;
                                     }
                                 }
@@ -3700,11 +4073,12 @@
                                 size_t k0 = db.Names.size();
                                 t = parse_type(first+2, last, db);
                                 size_t k1 = db.Names.size();
-                                if (t != first+2)
+                                if (t != first+2 && k0 + 1 == k1)
                                 {
-                                    db.Subs.pushPack();
-                                    for (size_t k = k0; k < k1; ++k)
-                                        db.Subs.pushSubstitutionIntoPack(db.Names[k]);
+                                    db.Names.back() =
+                                        db.make<ParameterPackExpansion>(
+                                            db.Names.back());
+                                    db.Subs.push_back(db.Names.back());
                                     first = t;
                                     return first;
                                 }
@@ -3717,7 +4091,7 @@
                                 {
                                     if (db.Names.empty())
                                         return first;
-                                    db.Subs.pushSubstitution(db.Names.back());
+                                    db.Subs.push_back(db.Names.back());
                                     first = t;
                                     return first;
                                 }
@@ -3728,7 +4102,7 @@
                                 {
                                     if (db.Names.empty())
                                         return first;
-                                    db.Subs.pushSubstitution(db.Names.back());
+                                    db.Subs.push_back(db.Names.back());
                                     first = t;
                                     return first;
                                 }
@@ -3751,7 +4125,7 @@
                             {
                                 if (db.Names.empty())
                                     return first;
-                                db.Subs.pushSubstitution(db.Names.back());
+                                db.Subs.push_back(db.Names.back());
                                 first = t;
                             }
                         }
@@ -5199,7 +5573,6 @@
 //                ::= <expr-primary>                                     # simple expressions
 //                ::= J <template-arg>* E                                # argument pack
 //                ::= LZ <encoding> E                                    # extension
-
 const char*
 parse_template_arg(const char* first, const char* last, Db& db)
 {
@@ -5216,19 +5589,23 @@
                     first = t+1;
             }
             break;
-        case 'J':
+        case 'J': {
             t = first+1;
             if (t == last)
                 return first;
+            size_t ArgsBegin = db.Names.size();
             while (*t != 'E')
             {
                 const char* t1 = parse_template_arg(t, last, db);
                 if (t1 == t)
                     return first;
                 t = t1;
             }
+            NodeArray Args = db.popTrailingNodeArray(ArgsBegin);
+            db.Names.push_back(db.make<TemplateArgumentPack>(Args));
             first = t+1;
             break;
+        }
         case 'L':
             // <expr-primary> or LZ <encoding> E
             if (first+1 != last && first[1] == 'Z')
@@ -5251,7 +5628,6 @@
 
 // <template-args> ::= I <template-arg>* E
 //     extension, the abi says <template-arg>+
-
 const char*
 parse_template_args(const char* first, const char* last, Db& db)
 {
@@ -5270,12 +5646,14 @@
                 const char* t1 = parse_template_arg(t, last, db);
                 size_t k1 = db.Names.size();
                 db.TemplateParams = std::move(TmpParams);
-
-                if (t1 == t || t1 == last || k0 > k1)
+                if (t1 == t || t1 == last || k0 + 1 != k1)
                     return first;
-                db.TemplateParams.pushPack();
-                for (size_t k = k0; k < k1; ++k)
-                    db.TemplateParams.pushSubstitutionIntoPack(db.Names[k]);
+                Node *TableEntry = db.Names.back();
+                if (TableEntry->getKind() == Node::KTemplateArgumentPack)
+                  TableEntry = db.make<ParameterPack>(
+                      static_cast<TemplateArgumentPack*>(TableEntry)
+                          ->getElements());
+                db.TemplateParams.push_back(TableEntry);
                 t = t1;
                 continue;
             }
@@ -5289,7 +5667,7 @@
         if (begin_idx > db.Names.size())
             return first;
         first = t + 1;
-        TemplateParams* tp = db.make<TemplateParams>(
+        auto *tp = db.make<TemplateArgs>(
             db.popTrailingNodeArray(begin_idx));
         db.Names.push_back(tp);
     }
@@ -5363,7 +5741,7 @@
                     {
                         db.Names.back() = db.make<QualifiedName>(
                             db.Names.back(), name);
-                        db.Subs.pushSubstitution(db.Names.back());
+                        db.Subs.push_back(db.Names.back());
                     }
                     else
                         db.Names.back() = name;
@@ -5386,7 +5764,7 @@
                             db.make<QualifiedName>(db.Names.back(), name);
                     else
                         db.Names.back() = name;
-                    db.Subs.pushSubstitution(db.Names.back());
+                    db.Subs.push_back(db.Names.back());
                     pop_subs = true;
                     t0 = t1;
                 }
@@ -5408,7 +5786,7 @@
                             db.make<QualifiedName>(db.Names.back(), name);
                     else
                         db.Names.back() = name;
-                    db.Subs.pushSubstitution(db.Names.back());
+                    db.Subs.push_back(db.Names.back());
                     pop_subs = true;
                     t0 = t1;
                 }
@@ -5425,7 +5803,7 @@
                     db.Names.pop_back();
                     db.Names.back() = db.make<NameWithTemplateArgs>(
                         db.Names.back(), name);
-                    db.Subs.pushSubstitution(db.Names.back());
+                    db.Subs.push_back(db.Names.back());
                     t0 = t1;
                     component_ends_with_template_args = true;
                 }
@@ -5450,7 +5828,7 @@
                             db.make<QualifiedName>(db.Names.back(), name);
                     else
                         db.Names.back() = name;
-                    db.Subs.pushSubstitution(db.Names.back());
+                    db.Subs.push_back(db.Names.back());
                     pop_subs = true;
                     t0 = t1;
                 }
@@ -5461,7 +5839,7 @@
         first = t0 + 1;
         db.CV = cv;
         if (pop_subs && !db.Subs.empty())
-            db.Subs.popPack();
+            db.Subs.pop_back();
         if (ends_with_template_args)
             *ends_with_template_args = component_ends_with_template_args;
     }
@@ -5626,7 +6004,7 @@
                 {
                     if (db.Names.empty())
                         return first;
-                    db.Subs.pushSubstitution(db.Names.back());
+                    db.Subs.push_back(db.Names.back());
                     t0 = t1;
                     t1 = parse_template_args(t0, last, db);
                     if (t1 != t0)
@@ -6013,7 +6391,7 @@
                             return first;
                         Node* name = db.Names.back();
                         db.Names.pop_back();
-                        result = db.make<TopLevelFunctionDecl>(
+                        result = db.make<FunctionEncoding>(
                             return_type, name, NodeArray());
                     }
                     else
@@ -6034,7 +6412,7 @@
                             return first;
                         Node* name = db.Names.back();
                         db.Names.pop_back();
-                        result = db.make<TopLevelFunctionDecl>(
+                        result = db.make<FunctionEncoding>(
                             return_type, name, params);
                     }
                     if (ref != FrefQualNone)
@@ -6111,12 +6489,19 @@
     return first;
 }
 
+enum {
+    unknown_error = -4,
+    invalid_args = -3,
+    invalid_mangled_name,
+    memory_alloc_failure,
+    success
+};
+
 // <block-involcaton-function> ___Z<encoding>_block_invoke
 // <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
 // <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
 // <mangled-name> ::= _Z<encoding>
 //                ::= <type>
-
 void
 demangle(const char* first, const char* last, Db& db, int& status)
 {
@@ -6167,6 +6552,8 @@
 
 }  // unnamed namespace
 
+
+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))
@@ -6195,6 +6582,10 @@
             internal_status = invalid_mangled_name;
     }
 
+    if (internal_status == success &&
+        db.Names.back()->containsUnexpandedParameterPack())
+        internal_status = invalid_mangled_name;
+
     if (internal_status == success)
     {
         if (!buf)
@@ -6210,6 +6601,10 @@
             s += '\0';
             if (n) *n = s.getCurrentPosition();
             buf = s.getBuffer();
+            if (s.PrintingFailed) {
+              internal_status = invalid_mangled_name;
+              buf = nullptr;
+            }
         }
         else
             internal_status = memory_alloc_failure;
@@ -6220,5 +6615,4 @@
         *status = internal_status;
     return buf;
 }
-
 }  // __cxxabiv1
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to