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

Richard Smith via libcxx-commits libcxx-commits at lists.llvm.org
Mon Sep 9 16:52:01 PDT 2019


On Sat, 7 Sep 2019 at 17:36, Nico Weber <thakis at chromium.org> wrote:

> 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?
>

No, that's a bug, thanks. Fixed in r371469. We now produce

auto inline_func()::'lambda'<typename $T, typename $T0>($T,
$T0)::operator()<int, int>($T, $T0) const

... which is at least correct, but it doesn't substitute the values $T=int
$T0=int into the signature like we usually would. The problem is that we
have a substitution from the later $T to the earlier $T, but we'd probably
want to render them differently:

auto inline_func()::'lambda'<typename $T, typename $T0>($T,
$T0)::operator()<int, int>(int, int) const

That said, special-casing the operator() of a lambda might be reasonable;
we could feasibly render the above as:

auto inline_func()::'lambda'<int, int>(int, int) const

This risks introducing demangling collisions, since this loses information
about *which* lambda, but we make no guarantees that demanglings are unique
anyway, so that may well be OK.


> 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/20190909/191cd613/attachment-0001.html>


More information about the libcxx-commits mailing list