Author: rsmith Date: Tue Dec 27 20:37:25 2016 New Revision: 290647 URL: http://llvm.org/viewvc/llvm-project?rev=290647&view=rev Log: DR1315: a non-type template argument in a partial specialization is permitted to make reference to template parameters. This is only a partial implementation; we retain the restriction that the argument must not be type-dependent, since it's unclear how that would work given the existence of other language rules requiring an exact type match in this context, even for type-dependent cases (a question has been raised on the core reflector).
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/test/CXX/drs/dr13xx.cpp cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp cfe/trunk/test/SemaTemplate/class-template-spec.cpp cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp cfe/trunk/www/cxx_dr_status.html Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Dec 27 20:37:25 2016 @@ -4032,8 +4032,8 @@ def err_specialize_member_of_template : def err_default_arg_in_partial_spec : Error< "default template argument in a class template partial specialization">; def err_dependent_non_type_arg_in_partial_spec : Error< - "non-type template argument depends on a template parameter of the " - "partial specialization">; + "type of specialized non-type template argument depends on a template " + "parameter of the partial specialization">; def note_dependent_non_type_default_arg_in_partial_spec : Note< "template parameter is used in default argument declared here">; def err_dependent_typed_non_type_arg_in_partial_spec : Error< @@ -4048,11 +4048,11 @@ def ext_partial_spec_not_more_specialize "more specialized than the primary template">, DefaultError, InGroup<DiagGroup<"invalid-partial-specialization">>; def note_partial_spec_not_more_specialized_than_primary : Note<"%0">; -def warn_partial_specs_not_deducible : Warning< +def ext_partial_specs_not_deducible : ExtWarn< "%select{class|variable}0 template partial specialization contains " "%select{a template parameter|template parameters}1 that cannot be " "deduced; this partial specialization will never be used">, - InGroup<DiagGroup<"unusable-partial-specialization">>; + DefaultError, InGroup<DiagGroup<"unusable-partial-specialization">>; def note_partial_spec_unused_parameter : Note< "non-deducible template parameter %0">; def err_partial_spec_ordering_ambiguous : Error< Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Dec 27 20:37:25 2016 @@ -5927,6 +5927,15 @@ public: MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody = nullptr); + bool CheckTemplatePartialSpecializationArgs(SourceLocation Loc, + TemplateDecl *PrimaryTemplate, + unsigned NumExplicitArgs, + ArrayRef<TemplateArgument> Args); + void CheckTemplatePartialSpecialization( + ClassTemplatePartialSpecializationDecl *Partial); + void CheckTemplatePartialSpecialization( + VarTemplatePartialSpecializationDecl *Partial); + Decl *ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D); Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Dec 27 20:37:25 2016 @@ -1638,12 +1638,22 @@ struct DependencyChecker : RecursiveASTV typedef RecursiveASTVisitor<DependencyChecker> super; unsigned Depth; + + // Whether we're looking for a use of a template parameter that makes the + // overall construct type-dependent / a dependent type. This is strictly + // best-effort for now; we may fail to match at all for a dependent type + // in some cases if this is set. + bool IgnoreNonTypeDependent; + bool Match; SourceLocation MatchLoc; - DependencyChecker(unsigned Depth) : Depth(Depth), Match(false) {} + DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent) + : Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent), + Match(false) {} - DependencyChecker(TemplateParameterList *Params) : Match(false) { + DependencyChecker(TemplateParameterList *Params, bool IgnoreNonTypeDependent) + : IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) { NamedDecl *ND = Params->getParam(0); if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) { Depth = PD->getDepth(); @@ -1664,12 +1674,31 @@ struct DependencyChecker : RecursiveASTV return false; } + bool TraverseStmt(Stmt *S, DataRecursionQueue *Q = nullptr) { + // Prune out non-type-dependent expressions if requested. This can + // sometimes result in us failing to find a template parameter reference + // (if a value-dependent expression creates a dependent type), but this + // mode is best-effort only. + if (auto *E = dyn_cast_or_null<Expr>(S)) + if (IgnoreNonTypeDependent && !E->isTypeDependent()) + return true; + return super::TraverseStmt(S, Q); + } + + bool TraverseTypeLoc(TypeLoc TL) { + if (IgnoreNonTypeDependent && !TL.isNull() && + !TL.getType()->isDependentType()) + return true; + return super::TraverseTypeLoc(TL); + } + bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { return !Matches(TL.getTypePtr()->getDepth(), TL.getNameLoc()); } bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) { - return !Matches(T->getDepth()); + // For a best-effort search, keep looking until we find a location. + return IgnoreNonTypeDependent || !Matches(T->getDepth()); } bool TraverseTemplateName(TemplateName N) { @@ -1707,7 +1736,7 @@ struct DependencyChecker : RecursiveASTV /// list. static bool DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) { - DependencyChecker Checker(Params); + DependencyChecker Checker(Params, /*IgnoreNonTypeDependent*/false); Checker.TraverseType(T); return Checker.Match; } @@ -2539,10 +2568,6 @@ TypeResult Sema::ActOnTagTemplateIdType( return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } -static bool CheckTemplatePartialSpecializationArgs( - Sema &S, SourceLocation NameLoc, TemplateParameterList *TemplateParams, - unsigned ExplicitArgs, SmallVectorImpl<TemplateArgument> &TemplateArgs); - static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, NamedDecl *PrevDecl, SourceLocation Loc, @@ -2654,6 +2679,59 @@ static void checkMoreSpecializedThanPrim S.Diag(Template->getLocation(), diag::note_template_decl_here); } +template<typename PartialSpecDecl> +static void checkTemplatePartialSpecialization(Sema &S, + PartialSpecDecl *Partial) { + // C++1z [temp.class.spec]p8: (DR1495) + // - The specialization shall be more specialized than the primary + // template (14.5.5.2). + checkMoreSpecializedThanPrimary(S, Partial); + + // C++ [temp.class.spec]p8: (DR1315) + // - Each template-parameter shall appear at least once in the + // template-id outside a non-deduced context. + // C++1z [temp.class.spec.match]p3 (P0127R2) + // If the template arguments of a partial specialization cannot be + // deduced because of the structure of its template-parameter-list + // and the template-id, the program is ill-formed. + auto *TemplateParams = Partial->getTemplateParameters(); + llvm::SmallBitVector DeducibleParams(TemplateParams->size()); + S.MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + TemplateParams->getDepth(), DeducibleParams); + + if (!DeducibleParams.all()) { + unsigned NumNonDeducible = DeducibleParams.size() - DeducibleParams.count(); + S.Diag(Partial->getLocation(), diag::ext_partial_specs_not_deducible) + << isa<VarTemplatePartialSpecializationDecl>(Partial) + << (NumNonDeducible > 1) + << SourceRange(Partial->getLocation(), + Partial->getTemplateArgsAsWritten()->RAngleLoc); + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); + if (Param->getDeclName()) + S.Diag(Param->getLocation(), + diag::note_partial_spec_unused_parameter) + << Param->getDeclName(); + else + S.Diag(Param->getLocation(), + diag::note_partial_spec_unused_parameter) + << "(anonymous)"; + } + } + } +} + +void Sema::CheckTemplatePartialSpecialization( + ClassTemplatePartialSpecializationDecl *Partial) { + checkTemplatePartialSpecialization(*this, Partial); +} + +void Sema::CheckTemplatePartialSpecialization( + VarTemplatePartialSpecializationDecl *Partial) { + checkTemplatePartialSpecialization(*this, Partial); +} + DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, @@ -2703,11 +2781,12 @@ DeclResult Sema::ActOnVarTemplateSpecial // Find the variable template (partial) specialization declaration that // corresponds to these arguments. if (IsPartialSpecialization) { - if (CheckTemplatePartialSpecializationArgs( - *this, TemplateNameLoc, VarTemplate->getTemplateParameters(), - TemplateArgs.size(), Converted)) + if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate, + TemplateArgs.size(), Converted)) return true; + // FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we + // also do them during instantiation. bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( @@ -2779,37 +2858,7 @@ DeclResult Sema::ActOnVarTemplateSpecial if (PrevPartial && PrevPartial->getInstantiatedFromMember()) PrevPartial->setMemberSpecialization(); - // C++1z [temp.class.spec]p8: (DR1495) - // - The specialization shall be more specialized than the primary - // template (14.5.5.2). - checkMoreSpecializedThanPrimary(*this, Partial); - - // Check that all of the template parameters of the variable template - // partial specialization are deducible from the template - // arguments. If not, this variable template partial specialization - // will never be used. - llvm::SmallBitVector DeducibleParams(TemplateParams->size()); - MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, - TemplateParams->getDepth(), DeducibleParams); - - if (!DeducibleParams.all()) { - unsigned NumNonDeducible = - DeducibleParams.size() - DeducibleParams.count(); - Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) - << /*variable template*/ 1 << (NumNonDeducible > 1) - << SourceRange(TemplateNameLoc, RAngleLoc); - for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { - if (!DeducibleParams[I]) { - NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); - if (Param->getDeclName()) - Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) - << Param->getDeclName(); - else - Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) - << "(anonymous)"; - } - } - } + CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. @@ -6208,12 +6257,12 @@ static bool CheckTemplateSpecializationS return false; } -static SourceRange findTemplateParameter(unsigned Depth, Expr *E) { - if (!E->isInstantiationDependent()) +static SourceRange findTemplateParameterInType(unsigned Depth, Expr *E) { + if (!E->isTypeDependent()) return SourceLocation(); - DependencyChecker Checker(Depth); + DependencyChecker Checker(Depth, /*IgnoreNonTypeDependent*/true); Checker.TraverseStmt(E); - if (Checker.Match && Checker.MatchLoc.isInvalid()) + if (Checker.MatchLoc.isInvalid()) return E->getSourceRange(); return Checker.MatchLoc; } @@ -6221,9 +6270,9 @@ static SourceRange findTemplateParameter static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) { if (!TL.getType()->isDependentType()) return SourceLocation(); - DependencyChecker Checker(Depth); + DependencyChecker Checker(Depth, /*IgnoreNonTypeDependent*/true); Checker.TraverseTypeLoc(TL); - if (Checker.Match && Checker.MatchLoc.isInvalid()) + if (Checker.MatchLoc.isInvalid()) return TL.getSourceRange(); return Checker.MatchLoc; } @@ -6275,8 +6324,16 @@ static bool CheckNonTypeTemplatePartialS // shall not involve a template parameter of the partial // specialization except when the argument expression is a // simple identifier. + // -- The type of a template parameter corresponding to a + // specialized non-type argument shall not be dependent on a + // parameter of the specialization. + // DR1315 removes the first bullet, leaving an incoherent set of rules. + // We implement a compromise between the original rules and DR1315: + // -- A specialized non-type template argument shall not be + // type-dependent and the corresponding template parameter + // shall have a non-dependent type. SourceRange ParamUseRange = - findTemplateParameter(Param->getDepth(), ArgExpr); + findTemplateParameterInType(Param->getDepth(), ArgExpr); if (ParamUseRange.isValid()) { if (IsDefaultArgument) { S.Diag(TemplateNameLoc, @@ -6292,26 +6349,15 @@ static bool CheckNonTypeTemplatePartialS return true; } - // -- The type of a template parameter corresponding to a - // specialized non-type argument shall not be dependent on a - // parameter of the specialization. - // - // FIXME: We need to delay this check until instantiation in some cases: - // - // template<template<typename> class X> struct A { - // template<typename T, X<T> N> struct B; - // template<typename T> struct B<T, 0>; - // }; - // template<typename> using X = int; - // A<X>::B<int, 0> b; ParamUseRange = findTemplateParameter( - Param->getDepth(), Param->getTypeSourceInfo()->getTypeLoc()); + Param->getDepth(), Param->getTypeSourceInfo()->getTypeLoc()); if (ParamUseRange.isValid()) { S.Diag(IsDefaultArgument ? TemplateNameLoc : ArgExpr->getLocStart(), diag::err_dependent_typed_non_type_arg_in_partial_spec) - << Param->getType() << ParamUseRange; + << Param->getType(); S.Diag(Param->getLocation(), diag::note_template_param_here) - << (IsDefaultArgument ? ParamUseRange : SourceRange()); + << (IsDefaultArgument ? ParamUseRange : SourceRange()) + << ParamUseRange; return true; } } @@ -6330,20 +6376,25 @@ static bool CheckNonTypeTemplatePartialS /// partial specialization. /// /// \returns \c true if there was an error, \c false otherwise. -static bool CheckTemplatePartialSpecializationArgs( - Sema &S, SourceLocation TemplateNameLoc, - TemplateParameterList *TemplateParams, unsigned NumExplicit, - SmallVectorImpl<TemplateArgument> &TemplateArgs) { - const TemplateArgument *ArgList = TemplateArgs.data(); +bool Sema::CheckTemplatePartialSpecializationArgs( + SourceLocation TemplateNameLoc, TemplateDecl *PrimaryTemplate, + unsigned NumExplicit, ArrayRef<TemplateArgument> TemplateArgs) { + // We have to be conservative when checking a template in a dependent + // context. + if (PrimaryTemplate->getDeclContext()->isDependentContext()) + return false; + TemplateParameterList *TemplateParams = + PrimaryTemplate->getTemplateParameters(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { NonTypeTemplateParmDecl *Param = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I)); if (!Param) continue; - if (CheckNonTypeTemplatePartialSpecializationArgs( - S, TemplateNameLoc, Param, &ArgList[I], 1, I >= NumExplicit)) + if (CheckNonTypeTemplatePartialSpecializationArgs(*this, TemplateNameLoc, + Param, &TemplateArgs[I], + 1, I >= NumExplicit)) return true; } @@ -6487,11 +6538,12 @@ Sema::ActOnClassTemplateSpecialization(S // Find the class template (partial) specialization declaration that // corresponds to these arguments. if (isPartialSpecialization) { - if (CheckTemplatePartialSpecializationArgs( - *this, TemplateNameLoc, ClassTemplate->getTemplateParameters(), - TemplateArgs.size(), Converted)) + if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate, + TemplateArgs.size(), Converted)) return true; + // FIXME: Move this to CheckTemplatePartialSpecializationArgs so we + // also do it during instantiation. bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( @@ -6581,39 +6633,7 @@ Sema::ActOnClassTemplateSpecialization(S if (PrevPartial && PrevPartial->getInstantiatedFromMember()) PrevPartial->setMemberSpecialization(); - // C++1z [temp.class.spec]p8: (DR1495) - // - The specialization shall be more specialized than the primary - // template (14.5.5.2). - checkMoreSpecializedThanPrimary(*this, Partial); - - // Check that all of the template parameters of the class template - // partial specialization are deducible from the template - // arguments. If not, this class template partial specialization - // will never be used. - llvm::SmallBitVector DeducibleParams(TemplateParams->size()); - MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, - TemplateParams->getDepth(), - DeducibleParams); - - if (!DeducibleParams.all()) { - unsigned NumNonDeducible = DeducibleParams.size()-DeducibleParams.count(); - Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) - << /*class template*/0 << (NumNonDeducible > 1) - << SourceRange(TemplateNameLoc, RAngleLoc); - for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { - if (!DeducibleParams[I]) { - NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); - if (Param->getDeclName()) - Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << Param->getDeclName(); - else - Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << "(anonymous)"; - } - } - } + CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Dec 27 20:37:25 2016 @@ -3086,6 +3086,12 @@ TemplateDeclInstantiator::InstantiateCla Converted)) return nullptr; + // Check these arguments are valid for a template partial specialization. + if (SemaRef.CheckTemplatePartialSpecializationArgs( + PartialSpec->getLocation(), ClassTemplate, InstTemplateArgs.size(), + Converted)) + return nullptr; + // Figure out where to insert this class template partial specialization // in the member template's set of class template partial specializations. void *InsertPos = nullptr; @@ -3156,6 +3162,9 @@ TemplateDeclInstantiator::InstantiateCla InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); + // Check the completed partial specialization. + SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec); + // Add this partial specialization to the set of class template partial // specializations. ClassTemplate->AddPartialSpecialization(InstPartialSpec, @@ -3208,6 +3217,12 @@ TemplateDeclInstantiator::InstantiateVar InstTemplateArgs, false, Converted)) return nullptr; + // Check these arguments are valid for a template partial specialization. + if (SemaRef.CheckTemplatePartialSpecializationArgs( + PartialSpec->getLocation(), VarTemplate, InstTemplateArgs.size(), + Converted)) + return nullptr; + // Figure out where to insert this variable template partial specialization // in the member template's set of variable template partial specializations. void *InsertPos = nullptr; @@ -3282,6 +3297,9 @@ TemplateDeclInstantiator::InstantiateVar InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); + // Check the completed partial specialization. + SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec); + // Add this partial specialization to the set of variable template partial // specializations. The instantiation of the initializer is not necessary. VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/nullptr); Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr13xx.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr13xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr13xx.cpp Tue Dec 27 20:37:25 2016 @@ -3,6 +3,34 @@ // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +namespace dr1315 { // dr1315: partial + template <int I, int J> struct A {}; + template <int I> // expected-note {{non-deducible template parameter 'I'}} + struct A<I + 5, I * 2> {}; // expected-error {{contains a template parameter that cannot be deduced}} + template <int I> struct A<I, I> {}; + + template <int I, int J, int K> struct B; + template <int I, int K> struct B<I, I * 2, K> {}; // expected-note {{matches}} + B<1, 2, 3> b1; + + // Multiple declarations with the same dependent expression are equivalent + // for partial ordering purposes. + template <int I> struct B<I, I * 2, 2> { typedef int type; }; + B<1, 2, 2>::type b2; + + // Multiple declarations with differing dependent expressions are unordered. + template <int I, int K> struct B<I, I + 1, K> {}; // expected-note {{matches}} + B<1, 2, 4> b3; // expected-error {{ambiguous}} + + // FIXME: Under dr1315, this is perhaps valid, but that is not clear: this + // fails the "more specialized than the primary template" test because the + // dependent type of T::value is not the same as 'int'. + // A core issue will be opened to decide what is supposed to happen here. + template <typename T, int I> struct C; + template <typename T> struct C<T, T::value>; + // expected-error@-1 {{type of specialized non-type template argument depends on a template parameter of the partial specialization}} +} + namespace dr1330 { // dr1330: 4.0 c++11 // exception-specifications are parsed in a context where the class is complete. struct A { Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp Tue Dec 27 20:37:25 2016 @@ -2,7 +2,10 @@ template<int ...Values> struct X1; -template<int ...Values> -struct X1<0, Values+1 ...>; // expected-error{{non-type template argument depends on a template parameter of the partial specialization}} - +template<int ...Values> // expected-note {{non-deducible}} +struct X1<0, Values+1 ...>; // expected-error{{contains a template parameter that cannot be deduced}} +template<typename T, int ...Values> struct X2; // expected-note {{here}} +template<int ...Values> struct X2<X1<Values...>, Values+1 ...> {}; // ok (DR1315) +X2<X1<1, 2, 3>, 2, 3, 4> x2; // ok +X2<X1<1, 2, 3>, 2, 3, 4, 5> x3; // expected-error {{undefined template}} Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp Tue Dec 27 20:37:25 2016 @@ -21,15 +21,16 @@ template<template<typename> class...X> i template<typename Outer> struct X { template<typename Inner> static int y; - template<typename Inner> static int y<Outer>; // expected-warning {{cannot be deduced}} expected-note {{'Inner'}} + // FIXME: It would be preferable to only diagnose this once. + template<typename Inner> static int y<Outer>; // expected-error 3{{cannot be deduced}} expected-note 3{{'Inner'}} template<typename Inner> static int y<Inner>; // expected-error {{does not specialize}} + + template<typename, int> static int z; + template<Outer N> static int z<int, N>; // expected-error {{not implicitly convertible}} }; -template<typename Outer> template<typename Inner> int X<Outer>::y<Outer>; // expected-warning {{cannot be deduced}} expected-note {{'Inner'}} +template<typename Outer> template<typename Inner> int X<Outer>::y<Outer>; // expected-error {{cannot be deduced}} expected-note {{'Inner'}} template<typename Outer> template<typename Inner> int X<Outer>::y<Inner>; // expected-error {{does not specialize}} +template<> template<typename Inner> int X<int>::y<Inner>; // expected-error {{does not specialize}} expected-note {{instantiation of}} -// FIXME: Merging this with the above class causes an assertion failure when -// instantiating one of the bogus partial specializations. -template<typename Outer> struct Y { - template<typename Inner> static int y; -}; -template<> template<typename Inner> int Y<int>::y<Inner>; // expected-error {{does not specialize}} +X<int> xi; +X<int*> xf; // expected-note {{instantiation of}} Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp Tue Dec 27 20:37:25 2016 @@ -32,7 +32,7 @@ namespace PackExpansionNotAtEnd { template<typename ... Types, // expected-note{{non-deducible template parameter 'Types'}} typename Tail> // expected-note{{non-deducible template parameter 'Tail'}} - struct UselessPartialSpec<Types..., Tail>; // expected-warning{{class template partial specialization contains template parameters that cannot be deduced; this partial specialization will never be used}} + struct UselessPartialSpec<Types..., Tail>; // expected-error{{class template partial specialization contains template parameters that cannot be deduced; this partial specialization will never be used}} } namespace DeduceNonTypeTemplateArgsInArray { Modified: cfe/trunk/test/SemaTemplate/class-template-spec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-spec.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original) +++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Tue Dec 27 20:37:25 2016 @@ -137,12 +137,16 @@ namespace PR18009 { A<int>::S<8, sizeof(int)> a; // ok template <typename T> struct B { - template <int N, int M> struct S; // expected-note {{declared here}} - template <int N> struct S<N, sizeof(T) + - N // expected-error {{non-type template argument depends on a template parameter of the partial specialization}} - > {}; + template <int N, int M> struct S; + template <int N> struct S<N, sizeof(T) + N> {}; // ok (dr1315) }; - B<int>::S<8, sizeof(int) + 8> s; // expected-error {{undefined}} + B<int>::S<8, sizeof(int) + 8> b; + + template <typename T> struct C { + template <int N, int M> struct S; + template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // expected-error {{depends on a template parameter of the partial specialization}} + }; + C<int> c; // expected-note {{in instantiation of}} template<int A> struct outer { template<int B, int C> struct inner {}; @@ -222,9 +226,9 @@ namespace DefaultArgVsPartialSpec { // Check that the diagnostic points at the partial specialization, not just at // the default argument. template<typename T, int N = - sizeof(T) // expected-note {{template parameter is used in default argument declared here}} + sizeof(T) // ok (dr1315) > struct X {}; - template<typename T> struct X<T> {}; // expected-error {{non-type template argument depends on a template parameter of the partial specialization}} + template<typename T> struct X<T> {}; template<typename T, T N = 0 // expected-note {{template parameter is declared here}} Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Tue Dec 27 20:37:25 2016 @@ -408,3 +408,29 @@ namespace partial_order_references { extern const int K = 5; D<0, K> d; // expected-error {{undefined}} } + +namespace dependent_nested_partial_specialization { + template<typename> using X = int; // expected-warning {{C++11}} + template<typename T> using Y = T*; // expected-warning {{C++11}} + int n; + + template<template<typename> class X> struct A { + template<typename T, X<T> N> struct B; // expected-note 2{{here}} + template<typename T> struct B<T, 0> {}; // expected-error {{specializes a template parameter with dependent type 'Y<T>'}} + }; + A<X>::B<int, 0> ax; + A<Y>::B<int, &n> ay; // expected-error {{undefined}} expected-note {{instantiation of}} + + template<template<typename> class X> struct C { + template<typename T, int N, int M> struct D; // expected-note {{here}} + template<typename T, X<T> N> struct D<T*, N, N + 1> {}; // expected-error {{type of specialized non-type template argument depends on}} + }; + C<X>::D<int*, 0, 1> cx; + C<Y>::D<int*, 0, 1> cy; // expected-error {{undefined}} expected-note {{instantiation of}} + + template<typename T> struct E { + template<typename U, U V> struct F; // expected-note {{template}} + template<typename W, T V> struct F<W, V> {}; // expected-error {{not more specialized than the primary}} expected-note {{does not have the same type}} + }; + E<int>::F<int, 0> e1; // expected-note {{instantiation of}} +} Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp Tue Dec 27 20:37:25 2016 @@ -34,5 +34,5 @@ namespace check_conversion_early { template<X &x> struct A<x> {}; // expected-error {{not implicitly convertible}} struct Y { constexpr operator int() const { return 0; } }; - template<Y &y> struct A<y> {}; // expected-error {{depends on a template parameter of the partial specialization}} + template<Y &y> struct A<y> {}; // expected-error {{cannot be deduced}} expected-note {{'y'}} } Modified: cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp Tue Dec 27 20:37:25 2016 @@ -20,9 +20,9 @@ struct N::M::A<T*> { }; #endif // C++ [temp.class.spec]p9 -// bullet 1 +// bullet 1, as amended by DR1315 template <int I, int J> struct A {}; -template <int I> struct A<I+5, I*2> {}; // expected-error{{depends on}} +template <int I> struct A<I+5, I*2> {}; // expected-error{{cannot be deduced}} expected-note {{'I'}} template <int I, int J> struct B {}; template <int I> struct B<I, I> {}; //OK @@ -50,4 +50,4 @@ template<typename T = int, // expected-e template<typename T> struct Test1; template<typename T, typename U> // expected-note{{non-deducible}} - struct Test1<T*> { }; // expected-warning{{never be used}} + struct Test1<T*> { }; // expected-error{{never be used}} Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp (original) +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Tue Dec 27 20:37:25 2016 @@ -688,7 +688,7 @@ TEST(TemplateTypeParmDecl, VarTemplatePa "};\n" "template<typename U>\n" "template<typename U2>\n" - "int Struct<U>::field<char> = 123;\n"; + "int Struct<U>::field<U2*> = 123;\n"; EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T")))); EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2")))); EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U")))); @@ -703,7 +703,7 @@ TEST(TemplateTypeParmDecl, ClassTemplate "};\n" "template<typename U>\n" "template<typename U2>\n" - "struct Class<U>::Struct<int> {};\n"; + "struct Class<U>::Struct<U2*> {};\n"; EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T")))); EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2")))); EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U")))); Modified: cfe/trunk/www/cxx_dr_status.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=290647&r1=290646&r2=290647&view=diff ============================================================================== --- cfe/trunk/www/cxx_dr_status.html (original) +++ cfe/trunk/www/cxx_dr_status.html Tue Dec 27 20:37:25 2016 @@ -7705,7 +7705,7 @@ and <I>POD class</I></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1315">1315</a></td> <td>DR</td> <td>Restrictions on non-type template arguments in partial specializations</td> - <td class="none" align="center">Unknown</td> + <td class="partial" align="center">Partial</td> </tr> <tr id="1316"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1316">1316</a></td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits