Author: rsmith Date: Tue Feb 21 00:30:38 2017 New Revision: 295696 URL: http://llvm.org/viewvc/llvm-project?rev=295696&view=rev Log: PR32010: Fix template argument depth mixup when forming implicit constructor template deduction guides for class template argument deduction.
Ensure that we have a local instantiation scope for tracking the instantiated parameters. Additionally, unusually, we're substituting at depth 1 and leaving depth 0 alone; make sure that we don't reduce template parameter depth by 2 for inner parameters in the process. (This is probably also broken for alias templates in the case where they're expanded within a dependent context, but this patch doesn't fix that.) Modified: cfe/trunk/include/clang/AST/DeclTemplate.h cfe/trunk/include/clang/Sema/Template.h cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp cfe/trunk/test/SemaTemplate/deduction.cpp Modified: cfe/trunk/include/clang/AST/DeclTemplate.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=295696&r1=295695&r2=295696&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h (original) +++ cfe/trunk/include/clang/AST/DeclTemplate.h Tue Feb 21 00:30:38 2017 @@ -1479,6 +1479,7 @@ public: unsigned NumExpansions); using TemplateParmPosition::getDepth; + using TemplateParmPosition::setDepth; using TemplateParmPosition::getPosition; using TemplateParmPosition::setPosition; using TemplateParmPosition::getIndex; Modified: cfe/trunk/include/clang/Sema/Template.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=295696&r1=295695&r2=295696&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Template.h (original) +++ cfe/trunk/include/clang/Sema/Template.h Tue Feb 21 00:30:38 2017 @@ -46,6 +46,10 @@ namespace clang { /// \brief The template argument lists, stored from the innermost template /// argument list (first) to the outermost template argument list (last). SmallVector<ArgList, 4> TemplateArgumentLists; + + /// \brief The number of outer levels of template arguments that are not + /// being substituted. + unsigned NumRetainedOuterLevels = 0; public: /// \brief Construct an empty set of template argument lists. @@ -59,11 +63,19 @@ namespace clang { /// \brief Determine the number of levels in this template argument /// list. - unsigned getNumLevels() const { return TemplateArgumentLists.size(); } - + unsigned getNumLevels() const { + return TemplateArgumentLists.size() + NumRetainedOuterLevels; + } + + /// \brief Determine the number of substituted levels in this template + /// argument list. + unsigned getNumSubstitutedLevels() const { + return TemplateArgumentLists.size(); + } + /// \brief Retrieve the template argument at a given depth and index. const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { - assert(Depth < TemplateArgumentLists.size()); + assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); return TemplateArgumentLists[getNumLevels() - Depth - 1][Index]; } @@ -73,7 +85,10 @@ namespace clang { /// /// There must exist a template argument list at the given depth. bool hasTemplateArgument(unsigned Depth, unsigned Index) const { - assert(Depth < TemplateArgumentLists.size()); + assert(Depth < getNumLevels()); + + if (Depth < NumRetainedOuterLevels) + return false; if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size()) return false; @@ -84,7 +99,7 @@ namespace clang { /// \brief Clear out a specific template argument. void setArgument(unsigned Depth, unsigned Index, TemplateArgument Arg) { - assert(Depth < TemplateArgumentLists.size()); + assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); const_cast<TemplateArgument&>( TemplateArgumentLists[getNumLevels() - Depth - 1][Index]) @@ -101,9 +116,18 @@ namespace clang { /// \brief Add a new outmost level to the multi-level template argument /// list. void addOuterTemplateArguments(ArgList Args) { + assert(!NumRetainedOuterLevels && + "substituted args outside retained args?"); TemplateArgumentLists.push_back(Args); } + /// \brief Add an outermost level that we are not substituting. We have no + /// arguments at this level, and do not remove it from the depth of inner + /// template parameters that we instantiate. + void addOuterRetainedLevel() { + ++NumRetainedOuterLevels; + } + /// \brief Retrieve the innermost template argument list. const ArgList &getInnermost() const { return TemplateArgumentLists.front(); Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=295696&r1=295695&r2=295696&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Feb 21 00:30:38 2017 @@ -1442,6 +1442,8 @@ struct ConvertConstructorToDeductionGuid CXXConstructorDecl *CD) { SmallVector<TemplateArgument, 16> SubstArgs; + LocalInstantiationScope Scope(SemaRef); + // C++ [over.match.class.deduct]p1: // -- For each constructor of the class template designated by the // template-name, a function template with the following properties: @@ -1463,7 +1465,7 @@ struct ConvertConstructorToDeductionGuid for (NamedDecl *Param : *InnerParams) { MultiLevelTemplateArgumentList Args; Args.addOuterTemplateArguments(SubstArgs); - Args.addOuterTemplateArguments(None); + Args.addOuterRetainedLevel(); NamedDecl *NewParam = transformTemplateParameter(Param, Args); if (!NewParam) return nullptr; @@ -1483,7 +1485,7 @@ struct ConvertConstructorToDeductionGuid MultiLevelTemplateArgumentList Args; if (FTD) { Args.addOuterTemplateArguments(SubstArgs); - Args.addOuterTemplateArguments(None); + Args.addOuterRetainedLevel(); } FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc() @@ -1555,6 +1557,8 @@ private: if (InstantiatedDefaultArg) NewTTP->setDefaultArgument(InstantiatedDefaultArg); } + SemaRef.CurrentInstantiationScope->InstantiatedLocal(TemplateParam, + NewTTP); return NewTTP; } Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=295696&r1=295695&r2=295696&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Feb 21 00:30:38 2017 @@ -1121,6 +1121,23 @@ TemplateInstantiator::TransformTemplateP return 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 (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"); + Arg = Arg.pack_begin()->getPackExpansionPattern(); + } + assert(Arg.getKind() == TemplateArgument::Expression && + "unexpected nontype template argument kind in partial substitution"); + return Arg.getAsExpr(); + } + if (NTTP->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1429,12 +1446,9 @@ TemplateInstantiator::TransformTemplateT NewTTPDecl = cast_or_null<TemplateTypeParmDecl>( TransformDecl(TL.getNameLoc(), OldTTPDecl)); - QualType Result - = getSema().Context.getTemplateTypeParmType(T->getDepth() - - TemplateArgs.getNumLevels(), - T->getIndex(), - T->isParameterPack(), - NewTTPDecl); + QualType Result = getSema().Context.getTemplateTypeParmType( + T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(), + T->isParameterPack(), NewTTPDecl); TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=295696&r1=295695&r2=295696&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Feb 21 00:30:38 2017 @@ -2074,13 +2074,10 @@ Decl *TemplateDeclInstantiator::VisitTem // TODO: don't always clone when decls are refcounted. assert(D->getTypeForDecl()->isTemplateTypeParmType()); - TemplateTypeParmDecl *Inst = - TemplateTypeParmDecl::Create(SemaRef.Context, Owner, - D->getLocStart(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getIndex(), D->getIdentifier(), - D->wasDeclaredWithTypename(), - D->isParameterPack()); + TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create( + SemaRef.Context, Owner, D->getLocStart(), D->getLocation(), + D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(), + D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack()); Inst->setAccess(AS_public); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { @@ -2218,17 +2215,14 @@ Decl *TemplateDeclInstantiator::VisitNon if (IsExpandedParameterPack) Param = NonTypeTemplateParmDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(), - D->getIdentifier(), T, DI, ExpandedParameterPackTypes, + D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), + D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes, ExpandedParameterPackTypesAsWritten); else - Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, - D->getInnerLocStart(), - D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), - D->getIdentifier(), T, - D->isParameterPack(), DI); + Param = NonTypeTemplateParmDecl::Create( + SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), + D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), + D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI); Param->setAccess(AS_public); if (Invalid) @@ -2349,19 +2343,15 @@ TemplateDeclInstantiator::VisitTemplateT // Build the template template parameter. TemplateTemplateParmDecl *Param; if (IsExpandedParameterPack) - Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, - D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), - D->getIdentifier(), InstParams, - ExpandedParams); + Param = TemplateTemplateParmDecl::Create( + SemaRef.Context, Owner, D->getLocation(), + D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), + D->getPosition(), D->getIdentifier(), InstParams, ExpandedParams); else - Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, - D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), - D->isParameterPack(), - D->getIdentifier(), InstParams); + Param = TemplateTemplateParmDecl::Create( + SemaRef.Context, Owner, D->getLocation(), + D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), + D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { NestedNameSpecifierLoc QualifierLoc = D->getDefaultArgument().getTemplateQualifierLoc(); Modified: cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp?rev=295696&r1=295695&r2=295696&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp Tue Feb 21 00:30:38 2017 @@ -176,3 +176,29 @@ namespace default_args_from_ctor { template <class A> struct T { template<typename B> T(A = 0, B = 0) {} }; T t(0, 0); } + +namespace transform_params { + template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]> + struct A { // expected-note 2{{candidate}} + template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W> + A(U<X>, W<Y>); // expected-note {{[with V = int, M = 12, Y = &transform_params::n]}} + + static constexpr T v = N; + }; + + int n[12]; + template<int (*)[12]> struct Q {}; + Q<&n> qn; + // FIXME: The class template argument deduction result here is correct, but + // we incorrectly fail to deduce arguments for the constructor! + A a(qn, qn); // expected-error {{no matching constructor for initialization of 'transform_params::A<int, 12, Q, &transform_params::n>'}} + static_assert(a.v == 12); + + // FIXME: This causes a crash right now (not class template deduction related). +#if 0 + template<typename ...T> struct B { + template<T ...V> B(T (&...p)[V]); + }; + B b({1, 2, 3}, {"foo", "bar"}, {'x', 'y', 'z', 'w'}); +#endif +} Modified: cfe/trunk/test/SemaTemplate/deduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/deduction.cpp?rev=295696&r1=295695&r2=295696&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/deduction.cpp (original) +++ cfe/trunk/test/SemaTemplate/deduction.cpp Tue Feb 21 00:30:38 2017 @@ -481,3 +481,16 @@ namespace check_extended_pack { int n; void h() { g<0>(Y<0, &n>()); } // expected-error {{no matching function}} } + +namespace dependent_template_template_param_non_type_param_type { + template<int N> struct A { // expected-note 2{{candidate}} + template<typename V = int, V M = 12, V (*Y)[M], template<V (*v)[M]> class W> + A(W<Y>); // expected-note {{[with V = int, M = 12, Y = &dependent_template_template_param_non_type_param_type::n]}} + }; + + int n[12]; + template<int (*)[12]> struct Q {}; + Q<&n> qn; + // FIXME: This should be accepted, but we somehow fail to deduce W. + A<0> a(qn); // expected-error {{no matching constructor for initialization}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits