[demangler] Support for dependent elaborate type specifiers.

git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@324969 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index 49b3e12..5faf0ae 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -165,6 +165,7 @@
     KQualType,
     KConversionOperatorType,
     KPostfixQualifiedType,
+    KElaboratedTypeSpefType,
     KNameType,
     KAbiTagAttr,
     KObjCProtoName,
@@ -443,6 +444,22 @@
   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;
@@ -2235,8 +2252,22 @@
 //                   ::= Tu <name>  # dependent elaborated type specifier using 'union'
 //                   ::= Te <name>  # dependent elaborated type specifier using 'enum'
 Node *Db::parseClassEnumType() {
-  // FIXME: try to parse the elaborated type specifiers here!
-  return legacyParse<parse_name>();
+  StringView ElabSpef;
+  if (consumeIf("Ts"))
+    ElabSpef = "struct";
+  else if (consumeIf("Tu"))
+    ElabSpef = "union";
+  else if (consumeIf("Te"))
+    ElabSpef = "enum";
+
+  Node *Name = legacyParse<parse_name>();
+  if (Name == nullptr)
+    return nullptr;
+
+  if (!ElabSpef.empty())
+    return make<ElaboratedTypeSpefType>(ElabSpef, Name);
+
+  return Name;
 }
 
 // <qualified-type>     ::= <qualifiers> <type>
@@ -2495,6 +2526,12 @@
   }
   //             ::= <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 = legacyParse<parse_template_param>();
     if (Result == nullptr)
       return nullptr;
diff --git a/test/test_demangle.pass.cpp b/test/test_demangle.pass.cpp
index c66161d..e28f1ec 100644
--- a/test/test_demangle.pass.cpp
+++ b/test/test_demangle.pass.cpp
@@ -29658,7 +29658,11 @@
     {"_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*)"}
+    {"_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*)"},
 };
 
 const unsigned N = sizeof(cases) / sizeof(cases[0]);