Author: Richard Smith Date: 2020-06-22T19:34:52-07:00 New Revision: 9f9373f86d2d13b8c9f106863ce70ace69abf388
URL: https://github.com/llvm/llvm-project/commit/9f9373f86d2d13b8c9f106863ce70ace69abf388 DIFF: https://github.com/llvm/llvm-project/commit/9f9373f86d2d13b8c9f106863ce70ace69abf388.diff LOG: 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. Added: Modified: clang/include/clang/Sema/Template.h clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/test/SemaTemplate/deduction-guide.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 8166b6cf9b6f..741de48a5d24 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -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 diff erent 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 { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 073b4e818a24..00003e8a7531 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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(); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index bfda59d40c2a..8197e7d901e9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -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"); diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index 3ac37ac44a1f..2a7d438ddadd 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits