forked from OSchip/llvm-project
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)'). llvm-svn: 371273
This commit is contained in:
parent
28328c3771
commit
4bbe85c5d4
|
@ -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");
|
||||
|
|
|
@ -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,10 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
|||
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 Alloc> struct AbstractManglingParser {
|
|||
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 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 +2712,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 +2725,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 +4234,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 +4306,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 +4335,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() {
|
|||
return make<IntegerCastExpr>(T, N);
|
||||
}
|
||||
if (consumeIf('E'))
|
||||
return T;
|
||||
return make<LambdaExpr>(T);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -5062,11 +5361,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 +5386,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 +5400,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 +5528,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 +5550,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)
|
||||
|
|
|
@ -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]);
|
||||
|
|
Loading…
Reference in New Issue