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