[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