diff options
| -rw-r--r-- | libcxxabi/src/demangle/ItaniumDemangle.h | 3 | ||||
| -rw-r--r-- | llvm/include/llvm/Demangle/ItaniumDemangle.h | 437 | ||||
| -rw-r--r-- | llvm/lib/Demangle/ItaniumDemangle.cpp | 10 |
3 files changed, 420 insertions, 30 deletions
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index f5bb0d678c2..c1efd7ef4e3 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -2435,7 +2435,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { ParsingLambdaParamsAtLevel = (size_t)-1; TryToParseTemplateArgs = true; PermitForwardTemplateReferences = false; - NumSyntheticTemplateParameters = {}; + for (int I = 0; I != 3; ++I) + NumSyntheticTemplateParameters[I] = 0; ASTAllocator.reset(); } diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index aaccb27e17a..c1efd7ef4e3 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -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 &Q1, Qualifiers Q2) { 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(Params, Count); } + template<typename Fn> void match(Fn F) const { + F(TemplateParams, 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 Alloc> struct AbstractManglingParser { // 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 Alloc> struct AbstractManglingParser { bool TryToParseTemplateArgs = true; bool PermitForwardTemplateReferences = false; - bool ParsingLambdaParams = false; + size_t ParsingLambdaParamsAtLevel = (size_t)-1; + + unsigned NumSyntheticTemplateParameters[3] = {}; Alloc ASTAllocator; @@ -2193,9 +2432,11 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { Names.clear(); Subs.clear(); TemplateParams.clear(); - ParsingLambdaParams = false; + ParsingLambdaParamsAtLevel = (size_t)-1; TryToParseTemplateArgs = true; PermitForwardTemplateReferences = false; + for (int I = 0; I != 3; ++I) + NumSyntheticTemplateParameters[I] = 0; ASTAllocator.reset(); } @@ -2253,6 +2494,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { bool parseSeqId(size_t *Out); Node *parseSubstitution(); Node *parseTemplateParam(); + Node *parseTemplateParamDecl(); Node *parseTemplateArgs(bool TagTemplates = false); Node *parseTemplateArg(); @@ -2301,9 +2543,10 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { 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 +2713,12 @@ AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) { // <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 +2726,60 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *) { 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 +4235,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() { // ::= 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 +4307,19 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() { 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 +4336,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() { return make<IntegerCastExpr>(T, N); } if (consumeIf('E')) - return T; + return make<LambdaExpr>(T); return nullptr; } } @@ -5062,11 +5362,22 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() { // <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 +5387,11 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { 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 +5401,78 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { 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 +5529,11 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) { // <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 +5551,7 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) { if (!TableEntry) return nullptr; } - TemplateParams.push_back(TableEntry); + TemplateParams.back()->push_back(TableEntry); } else { Node *Arg = getDerived().parseTemplateArg(); if (Arg == nullptr) diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp index 5c99c70e3cc..760d28b3ab9 100644 --- a/llvm/lib/Demangle/ItaniumDemangle.cpp +++ b/llvm/lib/Demangle/ItaniumDemangle.cpp @@ -174,6 +174,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"); |

