<div dir="ltr">I played with this a bit and was surprised by this behavior:<div><br></div><div>Nicos-MacBook-Pro:llvm-project thakis$ cat test.cc<br>inline void inline_func() {<br>  []<class T1, class T2>(T1, T2){}(1, 2);<br>}<br><br>void call_inline_func() {<br>  inline_func();<br>}<br>Nicos-MacBook-Pro:llvm-project thakis$ out/gn/bin/clang -c test.cc -std=c++2a<br>Nicos-MacBook-Pro:llvm-project thakis$ nm test.o | out/gn/bin/llvm-cxxfilt -_<br>0000000000000010 T inline_func()<br>0000000000000000 T call_inline_func()<br>0000000000000040 T auto inline_func()::'lambda'<typename $T, typename $T0>($T, typename $T)::operator()<int, int>($T, typename $T) const<br></div><div><br></div><div>Note how the parameter list lists $T twice instead of $T and $T0, and also one of the two $T is prefixed by typename but the other isn't. Is this intentional?</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Sep 6, 2019 at 10:12 PM Richard Smith via libcxx-commits <<a href="mailto:libcxx-commits@lists.llvm.org">libcxx-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: rsmith<br>
Date: Fri Sep  6 16:53:21 2019<br>
New Revision: 371273<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=371273&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=371273&view=rev</a><br>
Log:<br>
Implement demangling support for C++20 lambda expression extensions.<br>
<br>
This implements demangling support for the mangling extensions specified<br>
in <a href="https://github.com/itanium-cxx-abi/cxx-abi/pull/85" rel="noreferrer" target="_blank">https://github.com/itanium-cxx-abi/cxx-abi/pull/85</a>, much of which is<br>
implemented in Clang r359967 and r371004.<br>
<br>
Specifically, this provides demangling for:<br>
<br>
 * <template-param-decl> in <lambda-sig><br>
 * <template-param> with non-zero level<br>
 * lambda-expression literals (not emitted by Clang yet)<br>
 * nullptr literals<br>
 * string literals<br>
<br>
(The final two seem unrelated, but handling them was necessary in order<br>
to disambiguate between lambda expressions and the other forms of<br>
literal for which we have a type but no value.)<br>
<br>
When demangling a <lambda-sig>, we form template parameters with no<br>
corresponding argument, so we cannot substitute in the argument in the<br>
demangling. Instead we invent synthetic names for the template<br>
parameters (eg, '[]<typename $T>($T *x)').<br>
<br>
Modified:<br>
    libcxxabi/trunk/src/cxa_demangle.cpp<br>
    libcxxabi/trunk/src/demangle/ItaniumDemangle.h<br>
    libcxxabi/trunk/test/test_demangle.pass.cpp<br>
<br>
Modified: libcxxabi/trunk/src/cxa_demangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=371273&r1=371272&r2=371273&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=371273&r1=371272&r2=371273&view=diff</a><br>
==============================================================================<br>
--- libcxxabi/trunk/src/cxa_demangle.cpp (original)<br>
+++ libcxxabi/trunk/src/cxa_demangle.cpp Fri Sep  6 16:53:21 2019<br>
@@ -171,6 +171,16 @@ struct DumpVisitor {<br>
       return printStr("SpecialSubKind::iostream");<br>
     }<br>
   }<br>
+  void print(TemplateParamKind TPK) {<br>
+    switch (TPK) {<br>
+    case TemplateParamKind::Type:<br>
+      return printStr("TemplateParamKind::Type");<br>
+    case TemplateParamKind::NonType:<br>
+      return printStr("TemplateParamKind::NonType");<br>
+    case TemplateParamKind::Template:<br>
+      return printStr("TemplateParamKind::Template");<br>
+    }<br>
+  }<br>
<br>
   void newLine() {<br>
     printStr("\n");<br>
<br>
Modified: libcxxabi/trunk/src/demangle/ItaniumDemangle.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/demangle/ItaniumDemangle.h?rev=371273&r1=371272&r2=371273&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/demangle/ItaniumDemangle.h?rev=371273&r1=371272&r2=371273&view=diff</a><br>
==============================================================================<br>
--- libcxxabi/trunk/src/demangle/ItaniumDemangle.h (original)<br>
+++ libcxxabi/trunk/src/demangle/ItaniumDemangle.h Fri Sep  6 16:53:21 2019<br>
@@ -57,6 +57,11 @@<br>
     X(LocalName) \<br>
     X(VectorType) \<br>
     X(PixelVectorType) \<br>
+    X(SyntheticTemplateParamName) \<br>
+    X(TypeTemplateParamDecl) \<br>
+    X(NonTypeTemplateParamDecl) \<br>
+    X(TemplateTemplateParamDecl) \<br>
+    X(TemplateParamPackDecl) \<br>
     X(ParameterPack) \<br>
     X(TemplateArgumentPack) \<br>
     X(ParameterPackExpansion) \<br>
@@ -91,6 +96,8 @@<br>
     X(ThrowExpr) \<br>
     X(UUIDOfExpr) \<br>
     X(BoolExpr) \<br>
+    X(StringLiteral) \<br>
+    X(LambdaExpr) \<br>
     X(IntegerCastExpr) \<br>
     X(IntegerLiteral) \<br>
     X(FloatLiteral) \<br>
@@ -303,7 +310,7 @@ inline Qualifiers operator|=(Qualifiers<br>
   return Q1 = static_cast<Qualifiers>(Q1 | Q2);<br>
 }<br>
<br>
-class QualType : public Node {<br>
+class QualType final : public Node {<br>
 protected:<br>
   const Qualifiers Quals;<br>
   const Node *Child;<br>
@@ -964,6 +971,127 @@ public:<br>
   }<br>
 };<br>
<br>
+enum class TemplateParamKind { Type, NonType, Template };<br>
+<br>
+/// An invented name for a template parameter for which we don't have a<br>
+/// corresponding template argument.<br>
+///<br>
+/// This node is created when parsing the <lambda-sig> for a lambda with<br>
+/// explicit template arguments, which might be referenced in the parameter<br>
+/// types appearing later in the <lambda-sig>.<br>
+class SyntheticTemplateParamName final : public Node {<br>
+  TemplateParamKind Kind;<br>
+  unsigned Index;<br>
+<br>
+public:<br>
+  SyntheticTemplateParamName(TemplateParamKind Kind_, unsigned Index_)<br>
+      : Node(KSyntheticTemplateParamName), Kind(Kind_), Index(Index_) {}<br>
+<br>
+  template<typename Fn> void match(Fn F) const { F(Kind, Index); }<br>
+<br>
+  void printLeft(OutputStream &S) const override {<br>
+    switch (Kind) {<br>
+    case TemplateParamKind::Type:<br>
+      S += "$T";<br>
+      break;<br>
+    case TemplateParamKind::NonType:<br>
+      S += "$N";<br>
+      break;<br>
+    case TemplateParamKind::Template:<br>
+      S += "$TT";<br>
+      break;<br>
+    }<br>
+    if (Index > 0)<br>
+      S << Index - 1;<br>
+  }<br>
+};<br>
+<br>
+/// A template type parameter declaration, 'typename T'.<br>
+class TypeTemplateParamDecl final : public Node {<br>
+  Node *Name;<br>
+<br>
+public:<br>
+  TypeTemplateParamDecl(Node *Name_)<br>
+      : Node(KTypeTemplateParamDecl, Cache::Yes), Name(Name_) {}<br>
+<br>
+  template<typename Fn> void match(Fn F) const { F(Name); }<br>
+<br>
+  void printLeft(OutputStream &S) const override {<br>
+    S += "typename ";<br>
+  }<br>
+<br>
+  void printRight(OutputStream &S) const override {<br>
+    Name->print(S);<br>
+  }<br>
+};<br>
+<br>
+/// A non-type template parameter declaration, 'int N'.<br>
+class NonTypeTemplateParamDecl final : public Node {<br>
+  Node *Name;<br>
+  Node *Type;<br>
+<br>
+public:<br>
+  NonTypeTemplateParamDecl(Node *Name_, Node *Type_)<br>
+      : Node(KNonTypeTemplateParamDecl, Cache::Yes), Name(Name_), Type(Type_) {}<br>
+<br>
+  template<typename Fn> void match(Fn F) const { F(Name, Type); }<br>
+<br>
+  void printLeft(OutputStream &S) const override {<br>
+    Type->printLeft(S);<br>
+    if (!Type->hasRHSComponent(S))<br>
+      S += " ";<br>
+  }<br>
+<br>
+  void printRight(OutputStream &S) const override {<br>
+    Name->print(S);<br>
+    Type->printRight(S);<br>
+  }<br>
+};<br>
+<br>
+/// A template template parameter declaration,<br>
+/// 'template<typename T> typename N'.<br>
+class TemplateTemplateParamDecl final : public Node {<br>
+  Node *Name;<br>
+  NodeArray Params;<br>
+<br>
+public:<br>
+  TemplateTemplateParamDecl(Node *Name_, NodeArray Params_)<br>
+      : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_),<br>
+        Params(Params_) {}<br>
+<br>
+  template<typename Fn> void match(Fn F) const { F(Name, Params); }<br>
+<br>
+  void printLeft(OutputStream &S) const override {<br>
+    S += "template<";<br>
+    Params.printWithComma(S);<br>
+    S += "> typename ";<br>
+  }<br>
+<br>
+  void printRight(OutputStream &S) const override {<br>
+    Name->print(S);<br>
+  }<br>
+};<br>
+<br>
+/// A template parameter pack declaration, 'typename ...T'.<br>
+class TemplateParamPackDecl final : public Node {<br>
+  Node *Param;<br>
+<br>
+public:<br>
+  TemplateParamPackDecl(Node *Param_)<br>
+      : Node(KTemplateParamPackDecl, Cache::Yes), Param(Param_) {}<br>
+<br>
+  template<typename Fn> void match(Fn F) const { F(Param); }<br>
+<br>
+  void printLeft(OutputStream &S) const override {<br>
+    Param->printLeft(S);<br>
+    S += "...";<br>
+  }<br>
+<br>
+  void printRight(OutputStream &S) const override {<br>
+    Param->printRight(S);<br>
+  }<br>
+};<br>
+<br>
 /// An unexpanded parameter pack (either in the expression or type context). If<br>
 /// this AST is correct, this node will have a ParameterPackExpansion node above<br>
 /// it.<br>
@@ -1410,21 +1538,36 @@ public:<br>
 };<br>
<br>
 class ClosureTypeName : public Node {<br>
+  NodeArray TemplateParams;<br>
   NodeArray Params;<br>
   StringView Count;<br>
<br>
 public:<br>
-  ClosureTypeName(NodeArray Params_, StringView Count_)<br>
-      : Node(KClosureTypeName), Params(Params_), Count(Count_) {}<br>
+  ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,<br>
+                  StringView Count_)<br>
+      : Node(KClosureTypeName), TemplateParams(TemplateParams_),<br>
+        Params(Params_), Count(Count_) {}<br>
+<br>
+  template<typename Fn> void match(Fn F) const {<br>
+    F(TemplateParams, Params, Count);<br>
+  }<br>
<br>
-  template<typename Fn> void match(Fn F) const { F(Params, Count); }<br>
+  void printDeclarator(OutputStream &S) const {<br>
+    if (!TemplateParams.empty()) {<br>
+      S += "<";<br>
+      TemplateParams.printWithComma(S);<br>
+      S += ">";<br>
+    }<br>
+    S += "(";<br>
+    Params.printWithComma(S);<br>
+    S += ")";<br>
+  }<br>
<br>
   void printLeft(OutputStream &S) const override {<br>
     S += "\'lambda";<br>
     S += Count;<br>
-    S += "\'(";<br>
-    Params.printWithComma(S);<br>
-    S += ")";<br>
+    S += "\'";<br>
+    printDeclarator(S);<br>
   }<br>
 };<br>
<br>
@@ -1902,6 +2045,38 @@ public:<br>
   }<br>
 };<br>
<br>
+class StringLiteral : public Node {<br>
+  const Node *Type;<br>
+<br>
+public:<br>
+  StringLiteral(const Node *Type_) : Node(KStringLiteral), Type(Type_) {}<br>
+<br>
+  template<typename Fn> void match(Fn F) const { F(Type); }<br>
+<br>
+  void printLeft(OutputStream &S) const override {<br>
+    S += "\"<";<br>
+    Type->print(S);<br>
+    S += ">\"";<br>
+  }<br>
+};<br>
+<br>
+class LambdaExpr : public Node {<br>
+  const Node *Type;<br>
+<br>
+  void printLambdaDeclarator(OutputStream &S) const;<br>
+<br>
+public:<br>
+  LambdaExpr(const Node *Type_) : Node(KLambdaExpr), Type(Type_) {}<br>
+<br>
+  template<typename Fn> void match(Fn F) const { F(Type); }<br>
+<br>
+  void printLeft(OutputStream &S) const override {<br>
+    S += "[]";<br>
+    printLambdaDeclarator(S);<br>
+    S += "{...}";<br>
+  }<br>
+};<br>
+<br>
 class IntegerCastExpr : public Node {<br>
   // ty(integer)<br>
   const Node *Ty;<br>
@@ -2034,6 +2209,39 @@ FOR_EACH_NODE_KIND(SPECIALIZATION)<br>
<br>
 #undef FOR_EACH_NODE_KIND<br>
<br>
+inline void LambdaExpr::printLambdaDeclarator(OutputStream &S) const {<br>
+  struct LambdaDeclaratorPrinter {<br>
+    OutputStream &S;<br>
+    void operator()(const ClosureTypeName *LambdaType) {<br>
+      LambdaType->printDeclarator(S);<br>
+    }<br>
+<br>
+    // Walk through any qualifiers to find the lambda-expression.<br>
+    void operator()(const SpecialName *Name) {<br>
+      Name->match([&](StringView, const Node *Name) { Name->visit(*this); });<br>
+    }<br>
+    void operator()(const NestedName *Name) {<br>
+      Name->match([&](const Node *, const Node *Name) { Name->visit(*this); });<br>
+    }<br>
+    void operator()(const LocalName *Name) {<br>
+      Name->match([&](const Node *, const Node *Name) { Name->visit(*this); });<br>
+    }<br>
+    void operator()(const QualifiedName *Name) {<br>
+      Name->match([&](const Node *, const Node *Name) { Name->visit(*this); });<br>
+    }<br>
+    void operator()(const GlobalQualifiedName *Name) {<br>
+      Name->match([&](const Node *Child) { Child->visit(*this); });<br>
+    }<br>
+    void operator()(const StdQualifiedName *Name) {<br>
+      Name->match([&](const Node *Child) { Child->visit(*this); });<br>
+    }<br>
+    void operator()(const Node *) {<br>
+      // If we can't find the lambda type, just print '[]{...}'.<br>
+    }<br>
+  };<br>
+  return Type->visit(LambdaDeclaratorPrinter{S});<br>
+}<br>
+<br>
 template <class T, size_t N><br>
 class PODSmallVector {<br>
   static_assert(std::is_pod<T>::value,<br>
@@ -2167,10 +2375,39 @@ template <typename Derived, typename All<br>
   // table.<br>
   PODSmallVector<Node *, 32> Subs;<br>
<br>
+  using TemplateParamList = PODSmallVector<Node *, 8>;<br>
+<br>
+  class ScopedTemplateParamList {<br>
+    AbstractManglingParser *Parser;<br>
+    size_t OldNumTemplateParamLists;<br>
+    TemplateParamList Params;<br>
+<br>
+  public:<br>
+    ScopedTemplateParamList(AbstractManglingParser *Parser)<br>
+        : Parser(Parser),<br>
+          OldNumTemplateParamLists(Parser->TemplateParams.size()) {<br>
+      Parser->TemplateParams.push_back(&Params);<br>
+    }<br>
+    ~ScopedTemplateParamList() {<br>
+      assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists);<br>
+      Parser->TemplateParams.dropBack(OldNumTemplateParamLists);<br>
+    }<br>
+    void push_back(Node *Param) {<br>
+      Params.push_back(Param);<br>
+    }<br>
+  };<br>
+<br>
   // Template parameter table. Like the above, but referenced like "T42_".<br>
   // This has a smaller size compared to Subs and Names because it can be<br>
   // stored on the stack.<br>
-  PODSmallVector<Node *, 8> TemplateParams;<br>
+  TemplateParamList OuterTemplateParams;<br>
+<br>
+  // Lists of template parameters indexed by template parameter depth,<br>
+  // referenced like "TL2_4_". If nonempty, element 0 is always<br>
+  // OuterTemplateParams; inner elements are always template parameter lists of<br>
+  // lambda expressions. For a generic lambda with no explicit template<br>
+  // parameter list, the corresponding parameter list pointer will be null.<br>
+  PODSmallVector<TemplateParamList *, 4> TemplateParams;<br>
<br>
   // Set of unresolved forward <template-param> references. These can occur in a<br>
   // conversion operator's type, and are resolved in the enclosing <encoding>.<br>
@@ -2178,7 +2415,9 @@ template <typename Derived, typename All<br>
<br>
   bool TryToParseTemplateArgs = true;<br>
   bool PermitForwardTemplateReferences = false;<br>
-  bool ParsingLambdaParams = false;<br>
+  size_t ParsingLambdaParamsAtLevel = (size_t)-1;<br>
+<br>
+  unsigned NumSyntheticTemplateParameters[3] = {};<br>
<br>
   Alloc ASTAllocator;<br>
<br>
@@ -2193,9 +2432,10 @@ template <typename Derived, typename All<br>
     Names.clear();<br>
     Subs.clear();<br>
     TemplateParams.clear();<br>
-    ParsingLambdaParams = false;<br>
+    ParsingLambdaParamsAtLevel = (size_t)-1;<br>
     TryToParseTemplateArgs = true;<br>
     PermitForwardTemplateReferences = false;<br>
+    NumSyntheticTemplateParameters = {};<br>
     ASTAllocator.reset();<br>
   }<br>
<br>
@@ -2253,6 +2493,7 @@ template <typename Derived, typename All<br>
   bool parseSeqId(size_t *Out);<br>
   Node *parseSubstitution();<br>
   Node *parseTemplateParam();<br>
+  Node *parseTemplateParamDecl();<br>
   Node *parseTemplateArgs(bool TagTemplates = false);<br>
   Node *parseTemplateArg();<br>
<br>
@@ -2301,9 +2542,10 @@ template <typename Derived, typename All<br>
     size_t E = ForwardTemplateRefs.size();<br>
     for (; I < E; ++I) {<br>
       size_t Idx = ForwardTemplateRefs[I]->Index;<br>
-      if (Idx >= TemplateParams.size())<br>
+      if (TemplateParams.empty() || !TemplateParams[0] ||<br>
+          Idx >= TemplateParams[0]->size())<br>
         return true;<br>
-      ForwardTemplateRefs[I]->Ref = TemplateParams[Idx];<br>
+      ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx];<br>
     }<br>
     ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);<br>
     return false;<br>
@@ -2470,7 +2712,12 @@ AbstractManglingParser<Derived, Alloc>::<br>
 // <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters<br>
 template <typename Derived, typename Alloc><br>
 Node *<br>
-AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *) {<br>
+AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {<br>
+  // <template-params> refer to the innermost <template-args>. Clear out any<br>
+  // outer args that we may have inserted into TemplateParams.<br>
+  if (State != nullptr)<br>
+    TemplateParams.clear();<br>
+<br>
   if (consumeIf("Ut")) {<br>
     StringView Count = parseNumber();<br>
     if (!consumeIf('_'))<br>
@@ -2478,22 +2725,60 @@ AbstractManglingParser<Derived, Alloc>::<br>
     return make<UnnamedTypeName>(Count);<br>
   }<br>
   if (consumeIf("Ul")) {<br>
-    NodeArray Params;<br>
-    SwapAndRestore<bool> SwapParams(ParsingLambdaParams, true);<br>
+    SwapAndRestore<size_t> SwapParams(ParsingLambdaParamsAtLevel,<br>
+                                      TemplateParams.size());<br>
+    ScopedTemplateParamList LambdaTemplateParams(this);<br>
+<br>
+    size_t ParamsBegin = Names.size();<br>
+    while (look() == 'T' &&<br>
+           StringView("yptn").find(look(1)) != StringView::npos) {<br>
+      Node *T = parseTemplateParamDecl();<br>
+      if (!T)<br>
+        return nullptr;<br>
+      LambdaTemplateParams.push_back(T);<br>
+      Names.push_back(T);<br>
+    }<br>
+    NodeArray TempParams = popTrailingNodeArray(ParamsBegin);<br>
+<br>
+    // FIXME: If TempParams is empty and none of the function parameters<br>
+    // includes 'auto', we should remove LambdaTemplateParams from the<br>
+    // TemplateParams list. Unfortunately, we don't find out whether there are<br>
+    // any 'auto' parameters until too late in an example such as:<br>
+    //<br>
+    //   template<typename T> void f(<br>
+    //       decltype([](decltype([]<typename T>(T v) {}),<br>
+    //                   auto) {})) {}<br>
+    //   template<typename T> void f(<br>
+    //       decltype([](decltype([]<typename T>(T w) {}),<br>
+    //                   int) {})) {}<br>
+    //<br>
+    // Here, the type of v is at level 2 but the type of w is at level 1. We<br>
+    // don't find this out until we encounter the type of the next parameter.<br>
+    //<br>
+    // However, compilers can't actually cope with the former example in<br>
+    // practice, and it's likely to be made ill-formed in future, so we don't<br>
+    // need to support it here.<br>
+    //<br>
+    // If we encounter an 'auto' in the function parameter types, we will<br>
+    // recreate a template parameter scope for it, but any intervening lambdas<br>
+    // will be parsed in the 'wrong' template parameter depth.<br>
+    if (TempParams.empty())<br>
+      TemplateParams.pop_back();<br>
+<br>
     if (!consumeIf("vE")) {<br>
-      size_t ParamsBegin = Names.size();<br>
       do {<br>
         Node *P = getDerived().parseType();<br>
         if (P == nullptr)<br>
           return nullptr;<br>
         Names.push_back(P);<br>
       } while (!consumeIf('E'));<br>
-      Params = popTrailingNodeArray(ParamsBegin);<br>
     }<br>
+    NodeArray Params = popTrailingNodeArray(ParamsBegin);<br>
+<br>
     StringView Count = parseNumber();<br>
     if (!consumeIf('_'))<br>
       return nullptr;<br>
-    return make<ClosureTypeName>(Params, Count);<br>
+    return make<ClosureTypeName>(TempParams, Params, Count);<br>
   }<br>
   if (consumeIf("Ub")) {<br>
     (void)parseNumber();<br>
@@ -3949,6 +4234,7 @@ Node *AbstractManglingParser<Derived, Al<br>
 //                ::= L <type> <value float> E                           # floating literal<br>
 //                ::= L <string type> E                                  # string literal<br>
 //                ::= L <nullptr type> E                                 # nullptr literal (i.e., "LDnE")<br>
+//                ::= L <lambda type> E                                  # lambda expression<br>
 // FIXME:         ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)<br>
 //                ::= L <mangled-name> E                                 # external name<br>
 template <typename Derived, typename Alloc><br>
@@ -4020,6 +4306,19 @@ Node *AbstractManglingParser<Derived, Al<br>
         return R;<br>
     }<br>
     return nullptr;<br>
+  case 'A': {<br>
+    Node *T = getDerived().parseType();<br>
+    if (T == nullptr)<br>
+      return nullptr;<br>
+    // FIXME: We need to include the string contents in the mangling.<br>
+    if (consumeIf('E'))<br>
+      return make<StringLiteral>(T);<br>
+    return nullptr;<br>
+  }<br>
+  case 'D':<br>
+    if (consumeIf("DnE"))<br>
+      return make<NameType>("nullptr");<br>
+    return nullptr;<br>
   case 'T':<br>
     // Invalid mangled name per<br>
     //   <a href="http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html" rel="noreferrer" target="_blank">http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html</a><br>
@@ -4036,7 +4335,7 @@ Node *AbstractManglingParser<Derived, Al<br>
       return make<IntegerCastExpr>(T, N);<br>
     }<br>
     if (consumeIf('E'))<br>
-      return T;<br>
+      return make<LambdaExpr>(T);<br>
     return nullptr;<br>
   }<br>
   }<br>
@@ -5062,11 +5361,22 @@ Node *AbstractManglingParser<Derived, Al<br>
<br>
 // <template-param> ::= T_    # first template parameter<br>
 //                  ::= T <parameter-2 non-negative number> _<br>
+//                  ::= TL <level-1> __<br>
+//                  ::= TL <level-1> _ <parameter-2 non-negative number> _<br>
 template <typename Derived, typename Alloc><br>
 Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {<br>
   if (!consumeIf('T'))<br>
     return nullptr;<br>
<br>
+  size_t Level = 0;<br>
+  if (consumeIf('L')) {<br>
+    if (parsePositiveInteger(&Level))<br>
+      return nullptr;<br>
+    ++Level;<br>
+    if (!consumeIf('_'))<br>
+      return nullptr;<br>
+  }<br>
+<br>
   size_t Index = 0;<br>
   if (!consumeIf('_')) {<br>
     if (parsePositiveInteger(&Index))<br>
@@ -5076,15 +5386,11 @@ Node *AbstractManglingParser<Derived, Al<br>
       return nullptr;<br>
   }<br>
<br>
-  // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter list<br>
-  // are mangled as the corresponding artificial template type parameter.<br>
-  if (ParsingLambdaParams)<br>
-    return make<NameType>("auto");<br>
-<br>
   // If we're in a context where this <template-param> refers to a<br>
   // <template-arg> further ahead in the mangled name (currently just conversion<br>
   // operator types), then we should only look it up in the right context.<br>
-  if (PermitForwardTemplateReferences) {<br>
+  // This can only happen at the outermost level.<br>
+  if (PermitForwardTemplateReferences && Level == 0) {<br>
     Node *ForwardRef = make<ForwardTemplateReference>(Index);<br>
     if (!ForwardRef)<br>
       return nullptr;<br>
@@ -5094,9 +5400,78 @@ Node *AbstractManglingParser<Derived, Al<br>
     return ForwardRef;<br>
   }<br>
<br>
-  if (Index >= TemplateParams.size())<br>
+  if (Level >= TemplateParams.size() || !TemplateParams[Level] ||<br>
+      Index >= TemplateParams[Level]->size()) {<br>
+    // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter<br>
+    // list are mangled as the corresponding artificial template type parameter.<br>
+    if (ParsingLambdaParamsAtLevel == Level && Level <= TemplateParams.size()) {<br>
+      // This will be popped by the ScopedTemplateParamList in<br>
+      // parseUnnamedTypeName.<br>
+      if (Level == TemplateParams.size())<br>
+        TemplateParams.push_back(nullptr);<br>
+      return make<NameType>("auto");<br>
+    }<br>
+<br>
     return nullptr;<br>
-  return TemplateParams[Index];<br>
+  }<br>
+<br>
+  return (*TemplateParams[Level])[Index];<br>
+}<br>
+<br>
+// <template-param-decl> ::= Ty                          # type parameter<br>
+//                       ::= Tn <type>                   # non-type parameter<br>
+//                       ::= Tt <template-param-decl>* E # template parameter<br>
+//                       ::= Tp <template-param-decl>    # parameter pack<br>
+template <typename Derived, typename Alloc><br>
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {<br>
+  auto InventTemplateParamName = [&](TemplateParamKind Kind) {<br>
+    unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++;<br>
+    Node *N = make<SyntheticTemplateParamName>(Kind, Index);<br>
+    if (N) TemplateParams.back()->push_back(N);<br>
+    return N;<br>
+  };<br>
+<br>
+  if (consumeIf("Ty")) {<br>
+    Node *Name = InventTemplateParamName(TemplateParamKind::Type);<br>
+    if (!Name)<br>
+      return nullptr;<br>
+    return make<TypeTemplateParamDecl>(Name);<br>
+  }<br>
+<br>
+  if (consumeIf("Tn")) {<br>
+    Node *Name = InventTemplateParamName(TemplateParamKind::NonType);<br>
+    if (!Name)<br>
+      return nullptr;<br>
+    Node *Type = parseType();<br>
+    if (!Type)<br>
+      return nullptr;<br>
+    return make<NonTypeTemplateParamDecl>(Name, Type);<br>
+  }<br>
+<br>
+  if (consumeIf("Tt")) {<br>
+    Node *Name = InventTemplateParamName(TemplateParamKind::Template);<br>
+    if (!Name)<br>
+      return nullptr;<br>
+    size_t ParamsBegin = Names.size();<br>
+    ScopedTemplateParamList TemplateTemplateParamParams(this);<br>
+    while (!consumeIf("E")) {<br>
+      Node *P = parseTemplateParamDecl();<br>
+      if (!P)<br>
+        return nullptr;<br>
+      Names.push_back(P);<br>
+    }<br>
+    NodeArray Params = popTrailingNodeArray(ParamsBegin);<br>
+    return make<TemplateTemplateParamDecl>(Name, Params);<br>
+  }<br>
+<br>
+  if (consumeIf("Tp")) {<br>
+    Node *P = parseTemplateParamDecl();<br>
+    if (!P)<br>
+      return nullptr;<br>
+    return make<TemplateParamPackDecl>(P);<br>
+  }<br>
+<br>
+  return nullptr;<br>
 }<br>
<br>
 // <template-arg> ::= <type>                    # type or template<br>
@@ -5153,8 +5528,11 @@ AbstractManglingParser<Derived, Alloc>::<br>
<br>
   // <template-params> refer to the innermost <template-args>. Clear out any<br>
   // outer args that we may have inserted into TemplateParams.<br>
-  if (TagTemplates)<br>
+  if (TagTemplates) {<br>
     TemplateParams.clear();<br>
+    TemplateParams.push_back(&OuterTemplateParams);<br>
+    OuterTemplateParams.clear();<br>
+  }<br>
<br>
   size_t ArgsBegin = Names.size();<br>
   while (!consumeIf('E')) {<br>
@@ -5172,7 +5550,7 @@ AbstractManglingParser<Derived, Alloc>::<br>
         if (!TableEntry)<br>
           return nullptr;<br>
       }<br>
-      TemplateParams.push_back(TableEntry);<br>
+      TemplateParams.back()->push_back(TableEntry);<br>
     } else {<br>
       Node *Arg = getDerived().parseTemplateArg();<br>
       if (Arg == nullptr)<br>
<br>
Modified: libcxxabi/trunk/test/test_demangle.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=371273&r1=371272&r2=371273&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=371273&r1=371272&r2=371273&view=diff</a><br>
==============================================================================<br>
--- libcxxabi/trunk/test/test_demangle.pass.cpp (original)<br>
+++ libcxxabi/trunk/test/test_demangle.pass.cpp Fri Sep  6 16:53:21 2019<br>
@@ -29582,8 +29582,8 @@ const char* cases[][2] =<br>
     {"_ZSteqIcEN9__gnu_cxx11__enable_ifIXsr9__is_charIT_EE7__valueEbE6__typeERKSbIS2_St11char_traitsIS2_ESaIS2_EESA_", "__gnu_cxx::__enable_if<__is_char<char>::__value, bool>::__type std::operator==<char>(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)"},<br>
     {"_ZZ10+[Foo bar]E3Baz", "+[Foo bar]::Baz"},<br>
     {"_ZN9__gnu_cxx17__normal_iteratorIPKSt4pairISsbESt6vectorIS2_SaIS2_EEEC5ERKS4_", "__gnu_cxx::__normal_iterator<std::pair<std::string, bool> const*, std::vector<std::pair<std::string, bool>, std::allocator<std::pair<std::string, bool> > > >::__normal_iterator(std::pair<std::string, bool> const* const&)"},<br>
-    {"_Z1fIiEDTeqfp_LDnEEPT_", "decltype((fp) == (std::nullptr_t)) f<int>(int*)"},<br>
-    {"_Z1fIiEDTeqfp1_LDnEEicPT_", "decltype((fp1) == (std::nullptr_t)) f<int>(int, char, int*)"},<br>
+    {"_Z1fIiEDTeqfp_LDnEEPT_", "decltype((fp) == (nullptr)) f<int>(int*)"},<br>
+    {"_Z1fIiEDTeqfp1_LDnEEicPT_", "decltype((fp1) == (nullptr)) f<int>(int, char, int*)"},<br>
     {"_ZZN1S1fEiiEd0_NKUlvE_clEv", "S::f(int, int)::'lambda'()::operator()() const"},<br>
     {"_Z3fooPM2ABi", "foo(int AB::**)"},<br>
     {"_Z1rM1GFivEMS_KFivES_M1HFivES1_4whatIKS_E5what2IS8_ES3_", "r(int (G::*)(), int (G::*)() const, G, int (H::*)(), int (G::*)(), what<G const>, what2<G const>, int (G::*)() const)"},<br>
@@ -29669,6 +29669,10 @@ const char* cases[][2] =<br>
     {"_ZN6test481fINS_1SEEEvPTuNT_1uE", "void test48::f<test48::S>(union test48::S::u*)"},<br>
     {"_ZN6test451fINS_1SEEEvPTeNT_1eE", "void test45::f<test45::S>(enum test45::S::e*)"},<br>
<br>
+    // String literals<br>
+    // FIXME: We need to encode the string contents in order to avoid symbol collisions.<br>
+    {"_Z1fIcEvDTcv3StrIT_ELA6_KcEE", "void f<char>(decltype((Str<char>)(\"<char const [6]>\")))"},<br>
+<br>
     // Initializer list expressions<br>
     {"_ZN5test43tf2INS_1XEEEvDTnw_T_piilLi1EEEE", "void test4::tf2<test4::X>(decltype(new test4::X({1})))"},<br>
     {"_ZN5test73fA1IiEEDTcmtlNS_1AELi1ELi2EEcvT__EES2_", "decltype((test7::A{1, 2}) , ((int)())) test7::fA1<int>(int)"},<br>
@@ -29775,6 +29779,12 @@ const char* cases[][2] =<br>
<br>
     // C++2a char8_t:<br>
     {"_ZTSPDu", "typeinfo name for char8_t*"},<br>
+<br>
+    // C++2a lambda-expressions:<br>
+    {"_ZNK1xMUlTyT_E_clIiEEDaS_", "auto x::'lambda'<typename $T>($T)::operator()<int>(x) const"},<br>
+    {"_ZNK1xMUlTnPA3_ivE_clILS0_0EEEDav", "auto x::'lambda'<int (*$N) [3]>()::operator()<(int [3])0>() const"},<br>
+    {"_ZNK1xMUlTyTtTyTnT_TpTnPA3_TL0__ETpTyvE_clIi1XJfEEEDav", "auto x::'lambda'<typename $T, template<typename $T0, $T $N, $T0 (*...$N0) [3]> typename $TT, typename ...$T1>()::operator()<int, X, float>() const"},<br>
+    {"_ZN1AIiE1fIfEEvDTLZ1AIiEEUlTyTtTyTnTL1__ETL0_1_T_TL0__E_EE", "void A<int>::f<float>(decltype([]<typename $T, template<typename $T0, $T0 $N> typename $TT>($TT, int, $T){...}))"},<br>
 };<br>
<br>
 const unsigned N = sizeof(cases) / sizeof(cases[0]);<br>
<br>
<br>
_______________________________________________<br>
libcxx-commits mailing list<br>
<a href="mailto:libcxx-commits@lists.llvm.org" target="_blank">libcxx-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/libcxx-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/libcxx-commits</a><br>
</blockquote></div>