[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