[llvm] r371274 - Synchronize LLVM's copy of libc++abi's demangler with the libc++abi

Richard Smith via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 6 17:11:53 PDT 2019


Author: rsmith
Date: Fri Sep  6 17:11:53 2019
New Revision: 371274

URL: http://llvm.org/viewvc/llvm-project?rev=371274&view=rev
Log:
Synchronize LLVM's copy of libc++abi's demangler with the libc++abi
version after r371273.

Also fix a minor issue in r371273 that only surfaced after template
instantiation from LLVM's use of the demangler.

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

Modified: llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h?rev=371274&r1=371273&r2=371274&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h (original)
+++ llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h Fri Sep  6 17:11:53 2019
@@ -57,6 +57,11 @@
     X(LocalName) \
     X(VectorType) \
     X(PixelVectorType) \
+    X(SyntheticTemplateParamName) \
+    X(TypeTemplateParamDecl) \
+    X(NonTypeTemplateParamDecl) \
+    X(TemplateTemplateParamDecl) \
+    X(TemplateParamPackDecl) \
     X(ParameterPack) \
     X(TemplateArgumentPack) \
     X(ParameterPackExpansion) \
@@ -91,6 +96,8 @@
     X(ThrowExpr) \
     X(UUIDOfExpr) \
     X(BoolExpr) \
+    X(StringLiteral) \
+    X(LambdaExpr) \
     X(IntegerCastExpr) \
     X(IntegerLiteral) \
     X(FloatLiteral) \
@@ -303,7 +310,7 @@ inline Qualifiers operator|=(Qualifiers
   return Q1 = static_cast<Qualifiers>(Q1 | Q2);
 }
 
-class QualType : public Node {
+class QualType final : public Node {
 protected:
   const Qualifiers Quals;
   const Node *Child;
@@ -964,6 +971,127 @@ public:
   }
 };
 
+enum class TemplateParamKind { Type, NonType, Template };
+
+/// An invented name for a template parameter for which we don't have a
+/// corresponding template argument.
+///
+/// This node is created when parsing the <lambda-sig> for a lambda with
+/// explicit template arguments, which might be referenced in the parameter
+/// types appearing later in the <lambda-sig>.
+class SyntheticTemplateParamName final : public Node {
+  TemplateParamKind Kind;
+  unsigned Index;
+
+public:
+  SyntheticTemplateParamName(TemplateParamKind Kind_, unsigned Index_)
+      : Node(KSyntheticTemplateParamName), Kind(Kind_), Index(Index_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Kind, Index); }
+
+  void printLeft(OutputStream &S) const override {
+    switch (Kind) {
+    case TemplateParamKind::Type:
+      S += "$T";
+      break;
+    case TemplateParamKind::NonType:
+      S += "$N";
+      break;
+    case TemplateParamKind::Template:
+      S += "$TT";
+      break;
+    }
+    if (Index > 0)
+      S << Index - 1;
+  }
+};
+
+/// A template type parameter declaration, 'typename T'.
+class TypeTemplateParamDecl final : public Node {
+  Node *Name;
+
+public:
+  TypeTemplateParamDecl(Node *Name_)
+      : Node(KTypeTemplateParamDecl, Cache::Yes), Name(Name_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Name); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "typename ";
+  }
+
+  void printRight(OutputStream &S) const override {
+    Name->print(S);
+  }
+};
+
+/// A non-type template parameter declaration, 'int N'.
+class NonTypeTemplateParamDecl final : public Node {
+  Node *Name;
+  Node *Type;
+
+public:
+  NonTypeTemplateParamDecl(Node *Name_, Node *Type_)
+      : Node(KNonTypeTemplateParamDecl, Cache::Yes), Name(Name_), Type(Type_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Name, Type); }
+
+  void printLeft(OutputStream &S) const override {
+    Type->printLeft(S);
+    if (!Type->hasRHSComponent(S))
+      S += " ";
+  }
+
+  void printRight(OutputStream &S) const override {
+    Name->print(S);
+    Type->printRight(S);
+  }
+};
+
+/// A template template parameter declaration,
+/// 'template<typename T> typename N'.
+class TemplateTemplateParamDecl final : public Node {
+  Node *Name;
+  NodeArray Params;
+
+public:
+  TemplateTemplateParamDecl(Node *Name_, NodeArray Params_)
+      : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_),
+        Params(Params_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Name, Params); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "template<";
+    Params.printWithComma(S);
+    S += "> typename ";
+  }
+
+  void printRight(OutputStream &S) const override {
+    Name->print(S);
+  }
+};
+
+/// A template parameter pack declaration, 'typename ...T'.
+class TemplateParamPackDecl final : public Node {
+  Node *Param;
+
+public:
+  TemplateParamPackDecl(Node *Param_)
+      : Node(KTemplateParamPackDecl, Cache::Yes), Param(Param_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Param); }
+
+  void printLeft(OutputStream &S) const override {
+    Param->printLeft(S);
+    S += "...";
+  }
+
+  void printRight(OutputStream &S) const override {
+    Param->printRight(S);
+  }
+};
+
 /// 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.
@@ -1410,21 +1538,36 @@ public:
 };
 
 class ClosureTypeName : public Node {
+  NodeArray TemplateParams;
   NodeArray Params;
   StringView Count;
 
 public:
-  ClosureTypeName(NodeArray Params_, StringView Count_)
-      : Node(KClosureTypeName), Params(Params_), Count(Count_) {}
+  ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,
+                  StringView Count_)
+      : Node(KClosureTypeName), TemplateParams(TemplateParams_),
+        Params(Params_), Count(Count_) {}
+
+  template<typename Fn> void match(Fn F) const {
+    F(TemplateParams, Params, Count);
+  }
 
-  template<typename Fn> void match(Fn F) const { F(Params, Count); }
+  void printDeclarator(OutputStream &S) const {
+    if (!TemplateParams.empty()) {
+      S += "<";
+      TemplateParams.printWithComma(S);
+      S += ">";
+    }
+    S += "(";
+    Params.printWithComma(S);
+    S += ")";
+  }
 
   void printLeft(OutputStream &S) const override {
     S += "\'lambda";
     S += Count;
-    S += "\'(";
-    Params.printWithComma(S);
-    S += ")";
+    S += "\'";
+    printDeclarator(S);
   }
 };
 
@@ -1902,6 +2045,38 @@ public:
   }
 };
 
+class StringLiteral : public Node {
+  const Node *Type;
+
+public:
+  StringLiteral(const Node *Type_) : Node(KStringLiteral), Type(Type_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Type); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "\"<";
+    Type->print(S);
+    S += ">\"";
+  }
+};
+
+class LambdaExpr : public Node {
+  const Node *Type;
+
+  void printLambdaDeclarator(OutputStream &S) const;
+
+public:
+  LambdaExpr(const Node *Type_) : Node(KLambdaExpr), Type(Type_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Type); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "[]";
+    printLambdaDeclarator(S);
+    S += "{...}";
+  }
+};
+
 class IntegerCastExpr : public Node {
   // ty(integer)
   const Node *Ty;
@@ -2034,6 +2209,39 @@ FOR_EACH_NODE_KIND(SPECIALIZATION)
 
 #undef FOR_EACH_NODE_KIND
 
+inline void LambdaExpr::printLambdaDeclarator(OutputStream &S) const {
+  struct LambdaDeclaratorPrinter {
+    OutputStream &S;
+    void operator()(const ClosureTypeName *LambdaType) {
+      LambdaType->printDeclarator(S);
+    }
+
+    // Walk through any qualifiers to find the lambda-expression.
+    void operator()(const SpecialName *Name) {
+      Name->match([&](StringView, const Node *Name) { Name->visit(*this); });
+    }
+    void operator()(const NestedName *Name) {
+      Name->match([&](const Node *, const Node *Name) { Name->visit(*this); });
+    }
+    void operator()(const LocalName *Name) {
+      Name->match([&](const Node *, const Node *Name) { Name->visit(*this); });
+    }
+    void operator()(const QualifiedName *Name) {
+      Name->match([&](const Node *, const Node *Name) { Name->visit(*this); });
+    }
+    void operator()(const GlobalQualifiedName *Name) {
+      Name->match([&](const Node *Child) { Child->visit(*this); });
+    }
+    void operator()(const StdQualifiedName *Name) {
+      Name->match([&](const Node *Child) { Child->visit(*this); });
+    }
+    void operator()(const Node *) {
+      // If we can't find the lambda type, just print '[]{...}'.
+    }
+  };
+  return Type->visit(LambdaDeclaratorPrinter{S});
+}
+
 template <class T, size_t N>
 class PODSmallVector {
   static_assert(std::is_pod<T>::value,
@@ -2167,10 +2375,39 @@ template <typename Derived, typename All
   // table.
   PODSmallVector<Node *, 32> Subs;
 
+  using TemplateParamList = PODSmallVector<Node *, 8>;
+
+  class ScopedTemplateParamList {
+    AbstractManglingParser *Parser;
+    size_t OldNumTemplateParamLists;
+    TemplateParamList Params;
+
+  public:
+    ScopedTemplateParamList(AbstractManglingParser *Parser)
+        : Parser(Parser),
+          OldNumTemplateParamLists(Parser->TemplateParams.size()) {
+      Parser->TemplateParams.push_back(&Params);
+    }
+    ~ScopedTemplateParamList() {
+      assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists);
+      Parser->TemplateParams.dropBack(OldNumTemplateParamLists);
+    }
+    void push_back(Node *Param) {
+      Params.push_back(Param);
+    }
+  };
+
   // 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;
+  TemplateParamList OuterTemplateParams;
+
+  // Lists of template parameters indexed by template parameter depth,
+  // referenced like "TL2_4_". If nonempty, element 0 is always
+  // OuterTemplateParams; inner elements are always template parameter lists of
+  // lambda expressions. For a generic lambda with no explicit template
+  // parameter list, the corresponding parameter list pointer will be null.
+  PODSmallVector<TemplateParamList *, 4> TemplateParams;
 
   // Set of unresolved forward <template-param> references. These can occur in a
   // conversion operator's type, and are resolved in the enclosing <encoding>.
@@ -2178,7 +2415,9 @@ template <typename Derived, typename All
 
   bool TryToParseTemplateArgs = true;
   bool PermitForwardTemplateReferences = false;
-  bool ParsingLambdaParams = false;
+  size_t ParsingLambdaParamsAtLevel = (size_t)-1;
+
+  unsigned NumSyntheticTemplateParameters[3] = {};
 
   Alloc ASTAllocator;
 
@@ -2193,9 +2432,11 @@ template <typename Derived, typename All
     Names.clear();
     Subs.clear();
     TemplateParams.clear();
-    ParsingLambdaParams = false;
+    ParsingLambdaParamsAtLevel = (size_t)-1;
     TryToParseTemplateArgs = true;
     PermitForwardTemplateReferences = false;
+    for (int I = 0; I != 3; ++I)
+      NumSyntheticTemplateParameters[I] = 0;
     ASTAllocator.reset();
   }
 
@@ -2253,6 +2494,7 @@ template <typename Derived, typename All
   bool parseSeqId(size_t *Out);
   Node *parseSubstitution();
   Node *parseTemplateParam();
+  Node *parseTemplateParamDecl();
   Node *parseTemplateArgs(bool TagTemplates = false);
   Node *parseTemplateArg();
 
@@ -2301,9 +2543,10 @@ template <typename Derived, typename All
     size_t E = ForwardTemplateRefs.size();
     for (; I < E; ++I) {
       size_t Idx = ForwardTemplateRefs[I]->Index;
-      if (Idx >= TemplateParams.size())
+      if (TemplateParams.empty() || !TemplateParams[0] ||
+          Idx >= TemplateParams[0]->size())
         return true;
-      ForwardTemplateRefs[I]->Ref = TemplateParams[Idx];
+      ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx];
     }
     ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
     return false;
@@ -2470,7 +2713,12 @@ AbstractManglingParser<Derived, Alloc>::
 // <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters
 template <typename Derived, typename Alloc>
 Node *
-AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *) {
+AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
+  // <template-params> refer to the innermost <template-args>. Clear out any
+  // outer args that we may have inserted into TemplateParams.
+  if (State != nullptr)
+    TemplateParams.clear();
+
   if (consumeIf("Ut")) {
     StringView Count = parseNumber();
     if (!consumeIf('_'))
@@ -2478,22 +2726,60 @@ AbstractManglingParser<Derived, Alloc>::
     return make<UnnamedTypeName>(Count);
   }
   if (consumeIf("Ul")) {
-    NodeArray Params;
-    SwapAndRestore<bool> SwapParams(ParsingLambdaParams, true);
+    SwapAndRestore<size_t> SwapParams(ParsingLambdaParamsAtLevel,
+                                      TemplateParams.size());
+    ScopedTemplateParamList LambdaTemplateParams(this);
+
+    size_t ParamsBegin = Names.size();
+    while (look() == 'T' &&
+           StringView("yptn").find(look(1)) != StringView::npos) {
+      Node *T = parseTemplateParamDecl();
+      if (!T)
+        return nullptr;
+      LambdaTemplateParams.push_back(T);
+      Names.push_back(T);
+    }
+    NodeArray TempParams = popTrailingNodeArray(ParamsBegin);
+
+    // FIXME: If TempParams is empty and none of the function parameters
+    // includes 'auto', we should remove LambdaTemplateParams from the
+    // TemplateParams list. Unfortunately, we don't find out whether there are
+    // any 'auto' parameters until too late in an example such as:
+    //
+    //   template<typename T> void f(
+    //       decltype([](decltype([]<typename T>(T v) {}),
+    //                   auto) {})) {}
+    //   template<typename T> void f(
+    //       decltype([](decltype([]<typename T>(T w) {}),
+    //                   int) {})) {}
+    //
+    // Here, the type of v is at level 2 but the type of w is at level 1. We
+    // don't find this out until we encounter the type of the next parameter.
+    //
+    // However, compilers can't actually cope with the former example in
+    // practice, and it's likely to be made ill-formed in future, so we don't
+    // need to support it here.
+    //
+    // If we encounter an 'auto' in the function parameter types, we will
+    // recreate a template parameter scope for it, but any intervening lambdas
+    // will be parsed in the 'wrong' template parameter depth.
+    if (TempParams.empty())
+      TemplateParams.pop_back();
+
     if (!consumeIf("vE")) {
-      size_t ParamsBegin = Names.size();
       do {
         Node *P = getDerived().parseType();
         if (P == nullptr)
           return nullptr;
         Names.push_back(P);
       } while (!consumeIf('E'));
-      Params = popTrailingNodeArray(ParamsBegin);
     }
+    NodeArray Params = popTrailingNodeArray(ParamsBegin);
+
     StringView Count = parseNumber();
     if (!consumeIf('_'))
       return nullptr;
-    return make<ClosureTypeName>(Params, Count);
+    return make<ClosureTypeName>(TempParams, Params, Count);
   }
   if (consumeIf("Ub")) {
     (void)parseNumber();
@@ -3949,6 +4235,7 @@ Node *AbstractManglingParser<Derived, Al
 //                ::= L <type> <value float> E                           # floating literal
 //                ::= L <string type> E                                  # string literal
 //                ::= L <nullptr type> E                                 # nullptr literal (i.e., "LDnE")
+//                ::= L <lambda type> E                                  # lambda expression
 // FIXME:         ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)
 //                ::= L <mangled-name> E                                 # external name
 template <typename Derived, typename Alloc>
@@ -4020,6 +4307,19 @@ Node *AbstractManglingParser<Derived, Al
         return R;
     }
     return nullptr;
+  case 'A': {
+    Node *T = getDerived().parseType();
+    if (T == nullptr)
+      return nullptr;
+    // FIXME: We need to include the string contents in the mangling.
+    if (consumeIf('E'))
+      return make<StringLiteral>(T);
+    return nullptr;
+  }
+  case 'D':
+    if (consumeIf("DnE"))
+      return make<NameType>("nullptr");
+    return nullptr;
   case 'T':
     // Invalid mangled name per
     //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
@@ -4036,7 +4336,7 @@ Node *AbstractManglingParser<Derived, Al
       return make<IntegerCastExpr>(T, N);
     }
     if (consumeIf('E'))
-      return T;
+      return make<LambdaExpr>(T);
     return nullptr;
   }
   }
@@ -5062,11 +5362,22 @@ Node *AbstractManglingParser<Derived, Al
 
 // <template-param> ::= T_    # first template parameter
 //                  ::= T <parameter-2 non-negative number> _
+//                  ::= TL <level-1> __
+//                  ::= TL <level-1> _ <parameter-2 non-negative number> _
 template <typename Derived, typename Alloc>
 Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
   if (!consumeIf('T'))
     return nullptr;
 
+  size_t Level = 0;
+  if (consumeIf('L')) {
+    if (parsePositiveInteger(&Level))
+      return nullptr;
+    ++Level;
+    if (!consumeIf('_'))
+      return nullptr;
+  }
+
   size_t Index = 0;
   if (!consumeIf('_')) {
     if (parsePositiveInteger(&Index))
@@ -5076,15 +5387,11 @@ Node *AbstractManglingParser<Derived, Al
       return nullptr;
   }
 
-  // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter list
-  // are mangled as the corresponding artificial template type parameter.
-  if (ParsingLambdaParams)
-    return make<NameType>("auto");
-
   // If we're in a context where this <template-param> refers to a
   // <template-arg> further ahead in the mangled name (currently just conversion
   // operator types), then we should only look it up in the right context.
-  if (PermitForwardTemplateReferences) {
+  // This can only happen at the outermost level.
+  if (PermitForwardTemplateReferences && Level == 0) {
     Node *ForwardRef = make<ForwardTemplateReference>(Index);
     if (!ForwardRef)
       return nullptr;
@@ -5094,9 +5401,78 @@ Node *AbstractManglingParser<Derived, Al
     return ForwardRef;
   }
 
-  if (Index >= TemplateParams.size())
+  if (Level >= TemplateParams.size() || !TemplateParams[Level] ||
+      Index >= TemplateParams[Level]->size()) {
+    // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter
+    // list are mangled as the corresponding artificial template type parameter.
+    if (ParsingLambdaParamsAtLevel == Level && Level <= TemplateParams.size()) {
+      // This will be popped by the ScopedTemplateParamList in
+      // parseUnnamedTypeName.
+      if (Level == TemplateParams.size())
+        TemplateParams.push_back(nullptr);
+      return make<NameType>("auto");
+    }
+
     return nullptr;
-  return TemplateParams[Index];
+  }
+
+  return (*TemplateParams[Level])[Index];
+}
+
+// <template-param-decl> ::= Ty                          # type parameter
+//                       ::= Tn <type>                   # non-type parameter
+//                       ::= Tt <template-param-decl>* E # template parameter
+//                       ::= Tp <template-param-decl>    # parameter pack
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
+  auto InventTemplateParamName = [&](TemplateParamKind Kind) {
+    unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++;
+    Node *N = make<SyntheticTemplateParamName>(Kind, Index);
+    if (N) TemplateParams.back()->push_back(N);
+    return N;
+  };
+
+  if (consumeIf("Ty")) {
+    Node *Name = InventTemplateParamName(TemplateParamKind::Type);
+    if (!Name)
+      return nullptr;
+    return make<TypeTemplateParamDecl>(Name);
+  }
+
+  if (consumeIf("Tn")) {
+    Node *Name = InventTemplateParamName(TemplateParamKind::NonType);
+    if (!Name)
+      return nullptr;
+    Node *Type = parseType();
+    if (!Type)
+      return nullptr;
+    return make<NonTypeTemplateParamDecl>(Name, Type);
+  }
+
+  if (consumeIf("Tt")) {
+    Node *Name = InventTemplateParamName(TemplateParamKind::Template);
+    if (!Name)
+      return nullptr;
+    size_t ParamsBegin = Names.size();
+    ScopedTemplateParamList TemplateTemplateParamParams(this);
+    while (!consumeIf("E")) {
+      Node *P = parseTemplateParamDecl();
+      if (!P)
+        return nullptr;
+      Names.push_back(P);
+    }
+    NodeArray Params = popTrailingNodeArray(ParamsBegin);
+    return make<TemplateTemplateParamDecl>(Name, Params);
+  }
+
+  if (consumeIf("Tp")) {
+    Node *P = parseTemplateParamDecl();
+    if (!P)
+      return nullptr;
+    return make<TemplateParamPackDecl>(P);
+  }
+
+  return nullptr;
 }
 
 // <template-arg> ::= <type>                    # type or template
@@ -5153,8 +5529,11 @@ AbstractManglingParser<Derived, Alloc>::
 
   // <template-params> refer to the innermost <template-args>. Clear out any
   // outer args that we may have inserted into TemplateParams.
-  if (TagTemplates)
+  if (TagTemplates) {
     TemplateParams.clear();
+    TemplateParams.push_back(&OuterTemplateParams);
+    OuterTemplateParams.clear();
+  }
 
   size_t ArgsBegin = Names.size();
   while (!consumeIf('E')) {
@@ -5172,7 +5551,7 @@ AbstractManglingParser<Derived, Alloc>::
         if (!TableEntry)
           return nullptr;
       }
-      TemplateParams.push_back(TableEntry);
+      TemplateParams.back()->push_back(TableEntry);
     } else {
       Node *Arg = getDerived().parseTemplateArg();
       if (Arg == nullptr)

Modified: llvm/trunk/lib/Demangle/ItaniumDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/ItaniumDemangle.cpp?rev=371274&r1=371273&r2=371274&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/ItaniumDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/ItaniumDemangle.cpp Fri Sep  6 17:11:53 2019
@@ -174,6 +174,16 @@ struct DumpVisitor {
       return printStr("SpecialSubKind::iostream");
     }
   }
+  void print(TemplateParamKind TPK) {
+    switch (TPK) {
+    case TemplateParamKind::Type:
+      return printStr("TemplateParamKind::Type");
+    case TemplateParamKind::NonType:
+      return printStr("TemplateParamKind::NonType");
+    case TemplateParamKind::Template:
+      return printStr("TemplateParamKind::Template");
+    }
+  }
 
   void newLine() {
     printStr("\n");




More information about the llvm-commits mailing list