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.
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.
///
/// 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;
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 {
// 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);
// 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();
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");
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();
}
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");
// 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'>'
// 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