forked from OSchip/llvm-project
Distinguish between template parameter substitutions that are forming
specializations and those that are done as part of rewrites. Do not create Subst* nodes in the latter. We previously had a hybrid of these two behaviors where we would only create some Subst* nodes but not others during deduction guide rewrites. No functional change intended, but the resulting ASTs are more principled.
This commit is contained in:
parent
19df9e2959
commit
9f9373f86d
|
@ -42,6 +42,17 @@ class TypedefNameDecl;
|
|||
class TypeSourceInfo;
|
||||
class VarDecl;
|
||||
|
||||
/// The kind of template substitution being performed.
|
||||
enum class TemplateSubstitutionKind : char {
|
||||
/// We are substituting template parameters for template arguments in order
|
||||
/// to form a template specialization.
|
||||
Specialization,
|
||||
/// We are substituting template parameters for (typically) other template
|
||||
/// parameters in order to rewrite a declaration as a different declaration
|
||||
/// (for example, when forming a deduction guide from a constructor).
|
||||
Rewrite,
|
||||
};
|
||||
|
||||
/// Data structure that captures multiple levels of template argument
|
||||
/// lists for use in template instantiation.
|
||||
///
|
||||
|
@ -73,6 +84,9 @@ class VarDecl;
|
|||
/// being substituted.
|
||||
unsigned NumRetainedOuterLevels = 0;
|
||||
|
||||
/// The kind of substitution described by this argument list.
|
||||
TemplateSubstitutionKind Kind = TemplateSubstitutionKind::Specialization;
|
||||
|
||||
public:
|
||||
/// Construct an empty set of template argument lists.
|
||||
MultiLevelTemplateArgumentList() = default;
|
||||
|
@ -83,6 +97,18 @@ class VarDecl;
|
|||
addOuterTemplateArguments(&TemplateArgs);
|
||||
}
|
||||
|
||||
void setKind(TemplateSubstitutionKind K) { Kind = K; }
|
||||
|
||||
/// Determine the kind of template substitution being performed.
|
||||
TemplateSubstitutionKind getKind() const { return Kind; }
|
||||
|
||||
/// Determine whether we are rewriting template parameters rather than
|
||||
/// substituting for them. If so, we should not leave references to the
|
||||
/// original template parameters behind.
|
||||
bool isRewrite() const {
|
||||
return Kind == TemplateSubstitutionKind::Rewrite;
|
||||
}
|
||||
|
||||
/// Determine the number of levels in this template argument
|
||||
/// list.
|
||||
unsigned getNumLevels() const {
|
||||
|
|
|
@ -2038,6 +2038,7 @@ struct ConvertConstructorToDeductionGuideTransform {
|
|||
// a list of substituted template arguments as we go.
|
||||
for (NamedDecl *Param : *InnerParams) {
|
||||
MultiLevelTemplateArgumentList Args;
|
||||
Args.setKind(TemplateSubstitutionKind::Rewrite);
|
||||
Args.addOuterTemplateArguments(SubstArgs);
|
||||
Args.addOuterRetainedLevel();
|
||||
NamedDecl *NewParam = transformTemplateParameter(Param, Args);
|
||||
|
@ -2057,6 +2058,7 @@ struct ConvertConstructorToDeductionGuideTransform {
|
|||
// substitute references to the old parameters into references to the
|
||||
// new ones.
|
||||
MultiLevelTemplateArgumentList Args;
|
||||
Args.setKind(TemplateSubstitutionKind::Rewrite);
|
||||
if (FTD) {
|
||||
Args.addOuterTemplateArguments(SubstArgs);
|
||||
Args.addOuterRetainedLevel();
|
||||
|
|
|
@ -1362,6 +1362,19 @@ TemplateName TemplateInstantiator::TransformTemplateName(
|
|||
|
||||
TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
|
||||
|
||||
if (TemplateArgs.isRewrite()) {
|
||||
// We're rewriting the template parameter as a reference to another
|
||||
// template parameter.
|
||||
if (Arg.getKind() == TemplateArgument::Pack) {
|
||||
assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
|
||||
"unexpected pack arguments in template rewrite");
|
||||
Arg = Arg.pack_begin()->getPackExpansionPattern();
|
||||
}
|
||||
assert(Arg.getKind() == TemplateArgument::Template &&
|
||||
"unexpected nontype template argument kind in template rewrite");
|
||||
return Arg.getAsTemplate();
|
||||
}
|
||||
|
||||
if (TTP->isParameterPack()) {
|
||||
assert(Arg.getKind() == TemplateArgument::Pack &&
|
||||
"Missing argument pack");
|
||||
|
@ -1458,19 +1471,18 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
|
|||
|
||||
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
|
||||
|
||||
if (TemplateArgs.getNumLevels() != TemplateArgs.getNumSubstitutedLevels()) {
|
||||
// We're performing a partial substitution, so the substituted argument
|
||||
// could be dependent. As a result we can't create a SubstNonType*Expr
|
||||
// node now, since that represents a fully-substituted argument.
|
||||
// FIXME: We should have some AST representation for this.
|
||||
if (TemplateArgs.isRewrite()) {
|
||||
// We're rewriting the template parameter as a reference to another
|
||||
// template parameter.
|
||||
if (Arg.getKind() == TemplateArgument::Pack) {
|
||||
// FIXME: This won't work for alias templates.
|
||||
assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
|
||||
"unexpected pack arguments in partial substitution");
|
||||
"unexpected pack arguments in template rewrite");
|
||||
Arg = Arg.pack_begin()->getPackExpansionPattern();
|
||||
}
|
||||
assert(Arg.getKind() == TemplateArgument::Expression &&
|
||||
"unexpected nontype template argument kind in partial substitution");
|
||||
"unexpected nontype template argument kind in template rewrite");
|
||||
// FIXME: This can lead to the same subexpression appearing multiple times
|
||||
// in a complete expression.
|
||||
return Arg.getAsExpr();
|
||||
}
|
||||
|
||||
|
@ -1782,6 +1794,24 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
|
|||
|
||||
TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
|
||||
|
||||
if (TemplateArgs.isRewrite()) {
|
||||
// We're rewriting the template parameter as a reference to another
|
||||
// template parameter.
|
||||
if (Arg.getKind() == TemplateArgument::Pack) {
|
||||
assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
|
||||
"unexpected pack arguments in template rewrite");
|
||||
Arg = Arg.pack_begin()->getPackExpansionPattern();
|
||||
}
|
||||
assert(Arg.getKind() == TemplateArgument::Type &&
|
||||
"unexpected nontype template argument kind in template rewrite");
|
||||
QualType NewT = Arg.getAsType();
|
||||
assert(isa<TemplateTypeParmType>(NewT) &&
|
||||
"type parm not rewritten to type parm");
|
||||
auto NewTL = TLB.push<TemplateTypeParmTypeLoc>(NewT);
|
||||
NewTL.setNameLoc(TL.getNameLoc());
|
||||
return NewT;
|
||||
}
|
||||
|
||||
if (T->isParameterPack()) {
|
||||
assert(Arg.getKind() == TemplateArgument::Pack &&
|
||||
"Missing argument pack");
|
||||
|
|
|
@ -66,7 +66,7 @@ using BT = B<char, 'x'>;
|
|||
// CHECK: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T
|
||||
// CHECK: |-NonTypeTemplateParmDecl {{.*}} 'T' depth 0 index 1 V
|
||||
// CHECK: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 2 U
|
||||
// CHECK: |-NonTypeTemplateParmDecl {{.*}} 'type-parameter-0-2':'type-parameter-0-2' depth 0 index 3 W
|
||||
// CHECK: |-NonTypeTemplateParmDecl {{.*}} 'type-parameter-0-2' depth 0 index 3 W
|
||||
// CHECK: |-CXXDeductionGuideDecl {{.*}} 'auto (X<W, V>) -> B<T, V>'
|
||||
// CHECK: | `-ParmVarDecl {{.*}} 'X<W, V>'
|
||||
// CHECK: `-CXXDeductionGuideDecl {{.*}} 'auto (X<nullptr, 'x'>) -> B<char, 'x'>'
|
||||
|
@ -79,6 +79,44 @@ using BT = B<char, 'x'>;
|
|||
// CHECK: |-InjectedClassNameType {{.*}} 'B<T, V>' dependent
|
||||
// CHECK: `-TemplateSpecializationType {{.*}} 'X<W, V>' dependent X
|
||||
// CHECK: |-TemplateArgument expr
|
||||
// CHECK: | `-DeclRefExpr {{.*}} 'type-parameter-0-2':'type-parameter-0-2' NonTypeTemplateParm {{.*}} 'W' 'type-parameter-0-2':'type-parameter-0-2'
|
||||
// CHECK: | `-DeclRefExpr {{.*}} 'type-parameter-0-2' NonTypeTemplateParm {{.*}} 'W' 'type-parameter-0-2'
|
||||
// CHECK: `-TemplateArgument expr
|
||||
// CHECK: `-DeclRefExpr {{.*}} 'T' NonTypeTemplateParm {{.*}} 'V' 'T'
|
||||
|
||||
template<template<typename X, X> typename> struct Y {};
|
||||
template<typename A> struct C {
|
||||
template<template<typename X, X> typename T, typename U, U V = 0> C(A, Y<T>, U);
|
||||
};
|
||||
C c(1, Y<B>{}, 2);
|
||||
using CT = decltype(c);
|
||||
using CT = C<int>;
|
||||
|
||||
// CHECK: Dumping <deduction guide for C>:
|
||||
// CHECK: FunctionTemplateDecl
|
||||
// CHECK: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 A
|
||||
// CHECK: |-TemplateTemplateParmDecl {{.*}} depth 0 index 1 T
|
||||
// CHECK: | |-TemplateTypeParmDecl {{.*}} typename depth 1 index 0 X
|
||||
// CHECK: | `-NonTypeTemplateParmDecl {{.*}} 'X' depth 1 index 1
|
||||
// CHECK: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 2 U
|
||||
// CHECK: |-NonTypeTemplateParmDecl {{.*}} 'type-parameter-0-2' depth 0 index 3 V
|
||||
// CHECK: | `-TemplateArgument expr
|
||||
// CHECK: | `-IntegerLiteral {{.*}} 'int' 0
|
||||
// CHECK: |-CXXDeductionGuideDecl {{.*}} 'auto (A, Y<>, type-parameter-0-2) -> C<A>'
|
||||
// CHECK: | |-ParmVarDecl {{.*}} 'A'
|
||||
// CHECK: | |-ParmVarDecl {{.*}} 'Y<>'
|
||||
// CHECK: | `-ParmVarDecl {{.*}} 'type-parameter-0-2'
|
||||
// CHECK: `-CXXDeductionGuideDecl {{.*}} 'auto (int, Y<B>, int) -> C<int>'
|
||||
// CHECK: |-TemplateArgument type 'int'
|
||||
// CHECK: |-TemplateArgument template B
|
||||
// CHECK: |-TemplateArgument type 'int'
|
||||
// CHECK: |-TemplateArgument integral 0
|
||||
// CHECK: |-ParmVarDecl {{.*}} 'int':'int'
|
||||
// CHECK: |-ParmVarDecl {{.*}} 'Y<B>':'Y<B>'
|
||||
// CHECK: `-ParmVarDecl {{.*}} 'int':'int'
|
||||
// CHECK: FunctionProtoType {{.*}} 'auto (A, Y<>, type-parameter-0-2) -> C<A>' dependent trailing_return cdecl
|
||||
// CHECK: |-InjectedClassNameType {{.*}} 'C<A>' dependent
|
||||
// CHECK: |-TemplateTypeParmType {{.*}} 'A' dependent depth 0 index 0
|
||||
// CHECK: | `-TemplateTypeParm {{.*}} 'A'
|
||||
// CHECK: |-TemplateSpecializationType {{.*}} 'Y<>' dependent Y
|
||||
// CHECK: | `-TemplateArgument template
|
||||
// CHECK: `-TemplateTypeParmType {{.*}} 'type-parameter-0-2' dependent depth 0 index 2
|
||||
|
|
Loading…
Reference in New Issue