[libcxx-commits] [libcxxabi] r371273 - Implement demangling support for C++20 lambda expression extensions.

Nico Weber via libcxx-commits libcxx-commits at lists.llvm.org
Sat Sep 7 17:36:17 PDT 2019


I played with this a bit and was surprised by this behavior:

Nicos-MacBook-Pro:llvm-project thakis$ cat test.cc
inline void inline_func() {
  []<class T1, class T2>(T1, T2){}(1, 2);
}

void call_inline_func() {
  inline_func();
}
Nicos-MacBook-Pro:llvm-project thakis$ out/gn/bin/clang -c test.cc
-std=c++2a
Nicos-MacBook-Pro:llvm-project thakis$ nm test.o | out/gn/bin/llvm-cxxfilt
-_
0000000000000010 T inline_func()
0000000000000000 T call_inline_func()
0000000000000040 T auto inline_func()::'lambda'<typename $T, typename
$T0>($T, typename $T)::operator()<int, int>($T, typename $T) const

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?

On Fri, Sep 6, 2019 at 10:12 PM Richard Smith via libcxx-commits <
libcxx-commits at lists.llvm.org> wrote:

> Author: rsmith
> Date: Fri Sep  6 16:53:21 2019
> New Revision: 371273
>
> URL: http://llvm.org/viewvc/llvm-project?rev=371273&view=rev
> Log:
> Implement demangling support for C++20 lambda expression extensions.
>
> This implements demangling support for the mangling extensions specified
> in https://github.com/itanium-cxx-abi/cxx-abi/pull/85, much of which is
> implemented in Clang r359967 and r371004.
>
> Specifically, this provides demangling for:
>
>  * <template-param-decl> in <lambda-sig>
>  * <template-param> with non-zero level
>  * lambda-expression literals (not emitted by Clang yet)
>  * nullptr literals
>  * string literals
>
> (The final two seem unrelated, but handling them was necessary in order
> to disambiguate between lambda expressions and the other forms of
> literal for which we have a type but no value.)
>
> When demangling a <lambda-sig>, we form template parameters with no
> corresponding argument, so we cannot substitute in the argument in the
> demangling. Instead we invent synthetic names for the template
> parameters (eg, '[]<typename $T>($T *x)').
>
> Modified:
>     libcxxabi/trunk/src/cxa_demangle.cpp
>     libcxxabi/trunk/src/demangle/ItaniumDemangle.h
>     libcxxabi/trunk/test/test_demangle.pass.cpp
>
> Modified: libcxxabi/trunk/src/cxa_demangle.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=371273&r1=371272&r2=371273&view=diff
>
> ==============================================================================
> --- libcxxabi/trunk/src/cxa_demangle.cpp (original)
> +++ libcxxabi/trunk/src/cxa_demangle.cpp Fri Sep  6 16:53:21 2019
> @@ -171,6 +171,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");
>
> Modified: libcxxabi/trunk/src/demangle/ItaniumDemangle.h
> URL:
> http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/demangle/ItaniumDemangle.h?rev=371273&r1=371272&r2=371273&view=diff
>
> ==============================================================================
> --- libcxxabi/trunk/src/demangle/ItaniumDemangle.h (original)
> +++ libcxxabi/trunk/src/demangle/ItaniumDemangle.h Fri Sep  6 16:53:21 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,10 @@ template <typename Derived, typename All
>      Names.clear();
>      Subs.clear();
>      TemplateParams.clear();
> -    ParsingLambdaParams = false;
> +    ParsingLambdaParamsAtLevel = (size_t)-1;
>      TryToParseTemplateArgs = true;
>      PermitForwardTemplateReferences = false;
> +    NumSyntheticTemplateParameters = {};
>      ASTAllocator.reset();
>    }
>
> @@ -2253,6 +2493,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 +2542,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 +2712,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 +2725,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 +4234,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 +4306,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 +4335,7 @@ Node *AbstractManglingParser<Derived, Al
>        return make<IntegerCastExpr>(T, N);
>      }
>      if (consumeIf('E'))
> -      return T;
> +      return make<LambdaExpr>(T);
>      return nullptr;
>    }
>    }
> @@ -5062,11 +5361,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 +5386,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 +5400,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 +5528,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 +5550,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: libcxxabi/trunk/test/test_demangle.pass.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=371273&r1=371272&r2=371273&view=diff
>
> ==============================================================================
> --- libcxxabi/trunk/test/test_demangle.pass.cpp (original)
> +++ libcxxabi/trunk/test/test_demangle.pass.cpp Fri Sep  6 16:53:21 2019
> @@ -29582,8 +29582,8 @@ const char* cases[][2] =
>
>  {"_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&)"},
>      {"_ZZ10+[Foo bar]E3Baz", "+[Foo bar]::Baz"},
>
>  {"_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&)"},
> -    {"_Z1fIiEDTeqfp_LDnEEPT_", "decltype((fp) == (std::nullptr_t))
> f<int>(int*)"},
> -    {"_Z1fIiEDTeqfp1_LDnEEicPT_", "decltype((fp1) == (std::nullptr_t))
> f<int>(int, char, int*)"},
> +    {"_Z1fIiEDTeqfp_LDnEEPT_", "decltype((fp) == (nullptr))
> f<int>(int*)"},
> +    {"_Z1fIiEDTeqfp1_LDnEEicPT_", "decltype((fp1) == (nullptr))
> f<int>(int, char, int*)"},
>      {"_ZZN1S1fEiiEd0_NKUlvE_clEv", "S::f(int,
> int)::'lambda'()::operator()() const"},
>      {"_Z3fooPM2ABi", "foo(int AB::**)"},
>      {"_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)"},
> @@ -29669,6 +29669,10 @@ const char* cases[][2] =
>      {"_ZN6test481fINS_1SEEEvPTuNT_1uE", "void test48::f<test48::S>(union
> test48::S::u*)"},
>      {"_ZN6test451fINS_1SEEEvPTeNT_1eE", "void test45::f<test45::S>(enum
> test45::S::e*)"},
>
> +    // String literals
> +    // FIXME: We need to encode the string contents in order to avoid
> symbol collisions.
> +    {"_Z1fIcEvDTcv3StrIT_ELA6_KcEE", "void
> f<char>(decltype((Str<char>)(\"<char const [6]>\")))"},
> +
>      // Initializer list expressions
>      {"_ZN5test43tf2INS_1XEEEvDTnw_T_piilLi1EEEE", "void
> test4::tf2<test4::X>(decltype(new test4::X({1})))"},
>      {"_ZN5test73fA1IiEEDTcmtlNS_1AELi1ELi2EEcvT__EES2_",
> "decltype((test7::A{1, 2}) , ((int)())) test7::fA1<int>(int)"},
> @@ -29775,6 +29779,12 @@ const char* cases[][2] =
>
>      // C++2a char8_t:
>      {"_ZTSPDu", "typeinfo name for char8_t*"},
> +
> +    // C++2a lambda-expressions:
> +    {"_ZNK1xMUlTyT_E_clIiEEDaS_", "auto x::'lambda'<typename
> $T>($T)::operator()<int>(x) const"},
> +    {"_ZNK1xMUlTnPA3_ivE_clILS0_0EEEDav", "auto x::'lambda'<int (*$N)
> [3]>()::operator()<(int [3])0>() const"},
> +    {"_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"},
> +    {"_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){...}))"},
>  };
>
>  const unsigned N = sizeof(cases) / sizeof(cases[0]);
>
>
> _______________________________________________
> libcxx-commits mailing list
> libcxx-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/libcxx-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20190907/185a662d/attachment-0001.html>


More information about the libcxx-commits mailing list