Author: rsmith Date: Tue Dec 27 01:56:27 2016 New Revision: 290593 URL: http://llvm.org/viewvc/llvm-project?rev=290593&view=rev Log: DR1495: A partial specialization is ill-formed if it is not (strictly) more specialized than the primary template. (Put another way, if we imagine there were a partial specialization matching the primary template, we should never select it if some other partial specialization also matches.)
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/include/clang/Sema/TemplateDeduction.h cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/test/CXX/drs/dr14xx.cpp cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp cfe/trunk/test/SemaTemplate/class-template-spec.cpp cfe/trunk/test/SemaTemplate/temp_arg_nontype.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=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Dec 27 01:56:27 2016 @@ -4043,6 +4043,10 @@ def err_partial_spec_args_match_primary_ "%select{class|variable}0 template partial specialization does not " "specialize any template argument; to %select{declare|define}1 the " "primary template, remove the template argument list">; +def err_partial_spec_not_more_specialized_than_primary : Error< + "%select{class|variable}0 template partial specialization is not " + "more specialized than the primary template">; +def note_partial_spec_not_more_specialized_than_primary : Note<"%0">; def warn_partial_specs_not_deducible : Warning< "%select{class|variable}0 template partial specialization contains " "%select{a template parameter|template parameters}1 that cannot be " @@ -4147,7 +4151,7 @@ def note_function_template_deduction_ins "%1">; def note_deduced_template_arg_substitution_here : Note< "during template argument deduction for %select{class|variable}0 template " - "partial specialization %1 %2">; + "%select{partial specialization |}1%2 %3">; def note_prior_template_arg_substitution : Note< "while substituting prior template arguments into %select{non-type|template}0" " template parameter%1 %2">; Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Dec 27 01:56:27 2016 @@ -6697,10 +6697,16 @@ public: ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); + bool isMoreSpecializedThanPrimary(ClassTemplatePartialSpecializationDecl *T, + sema::TemplateDeductionInfo &Info); + VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); + bool isMoreSpecializedThanPrimary(VarTemplatePartialSpecializationDecl *T, + sema::TemplateDeductionInfo &Info); + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, @@ -6752,7 +6758,7 @@ public: /// template argument deduction for either a class template /// partial specialization or a function template. The /// Entity is either a {Class|Var}TemplatePartialSpecializationDecl or - /// a FunctionTemplateDecl. + /// a TemplateDecl. DeducedTemplateArgumentSubstitution, /// We are substituting prior template arguments into a new @@ -6973,6 +6979,14 @@ public: sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we are instantiating as part of template + /// argument deduction for a class template declaration. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we are instantiating as part of template /// argument deduction for a class template partial /// specialization. Modified: cfe/trunk/include/clang/Sema/TemplateDeduction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/TemplateDeduction.h?rev=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/TemplateDeduction.h (original) +++ cfe/trunk/include/clang/Sema/TemplateDeduction.h Tue Dec 27 01:56:27 2016 @@ -79,6 +79,11 @@ public: assert(HasSFINAEDiagnostic); PD.first = SuppressedDiagnostics.front().first; PD.second.swap(SuppressedDiagnostics.front().second); + clearSFINAEDiagnostic(); + } + + /// \brief Discard any SFINAE diagnostics. + void clearSFINAEDiagnostic() { SuppressedDiagnostics.clear(); HasSFINAEDiagnostic = false; } Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Dec 27 01:56:27 2016 @@ -2624,6 +2624,36 @@ makeTemplateArgumentListInfo(Sema &S, Te return TemplateArgs; } +template<typename PartialSpecDecl> +static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { + if (Partial->getDeclContext()->isDependentContext()) + return; + + // FIXME: Get the TDK from deduction in order to provide better diagnostics + // for non-substitution-failure issues? + TemplateDeductionInfo Info(Partial->getLocation()); + if (S.isMoreSpecializedThanPrimary(Partial, Info)) + return; + + auto *Template = Partial->getSpecializedTemplate(); + S.Diag(Partial->getLocation(), + diag::err_partial_spec_not_more_specialized_than_primary) + << /*variable template*/isa<VarTemplateDecl>(Template); + + if (Info.hasSFINAEDiagnostic()) { + PartialDiagnosticAt Diag = {SourceLocation(), + PartialDiagnostic::NullDiagnostic()}; + Info.takeSFINAEDiagnostic(Diag); + SmallString<128> SFINAEArgString; + Diag.second.EmitToString(S.getDiagnostics(), SFINAEArgString); + S.Diag(Diag.first, + diag::note_partial_spec_not_more_specialized_than_primary) + << SFINAEArgString; + } + + S.Diag(Template->getLocation(), diag::note_template_decl_here); +} + DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, @@ -2749,6 +2779,11 @@ 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 @@ -5041,7 +5076,7 @@ ExprResult Sema::CheckTemplateArgument(N if (CTAK == CTAK_Deduced && !Context.hasSameType(ParamType.getNonLValueExprType(Context), - Arg->getType().getNonLValueExprType(Context))) { + Arg->getType())) { // C++ [temp.deduct.type]p17: (DR1770) // If P has a form that contains <i>, and if the type of i differs from // the type of the corresponding template parameter of the template named @@ -5055,7 +5090,7 @@ ExprResult Sema::CheckTemplateArgument(N // itself, and so strip off references before comparing types. It's // not clear how this is supposed to work for references. Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch) - << Arg->getType().getUnqualifiedType() + << Arg->getType() << ParamType.getUnqualifiedType(); Diag(Param->getLocation(), diag::note_template_param_here); return ExprError(); @@ -6501,6 +6536,9 @@ Sema::ActOnClassTemplateSpecialization(S // // -- The argument list of the specialization shall not be identical // to the implicit argument list of the primary template. + // + // This rule has since been removed, because it's redundant given DR1495, + // but we keep it because it produces better diagnostics and recovery. Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) << /*class template*/0 << (TUK == TUK_Definition) << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); @@ -6543,6 +6581,11 @@ 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 Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Tue Dec 27 01:56:27 2016 @@ -1972,8 +1972,14 @@ DeduceTemplateArguments(Sema &S, /// \brief Determine whether two template arguments are the same. static bool isSameTemplateArg(ASTContext &Context, - const TemplateArgument &X, - const TemplateArgument &Y) { + TemplateArgument X, + const TemplateArgument &Y, + bool PackExpansionMatchesPack = false) { + // If we're checking deduced arguments (X) against original arguments (Y), + // we will have flattened packs to non-expansions in X. + if (PackExpansionMatchesPack && X.isPackExpansion() && !Y.isPackExpansion()) + X = X.getPackExpansionPattern(); + if (X.getKind() != Y.getKind()) return false; @@ -2016,7 +2022,7 @@ static bool isSameTemplateArg(ASTContext XPEnd = X.pack_end(), YP = Y.pack_begin(); XP != XPEnd; ++XP, ++YP) - if (!isSameTemplateArg(Context, *XP, *YP)) + if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack)) return false; return true; @@ -2400,6 +2406,48 @@ FinishTemplateArgumentDeduction( return Sema::TDK_Success; } +/// Complete template argument deduction for a class or variable template, +/// when partial ordering against a partial specialization. +// FIXME: Factor out duplication with partial specialization version above. +Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( + Sema &S, TemplateDecl *Template, bool PartialOrdering, + const TemplateArgumentList &TemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + TemplateDeductionInfo &Info) { + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); + Sema::SFINAETrap Trap(S); + + Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template)); + + // C++ [temp.deduct.type]p2: + // [...] or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + SmallVector<TemplateArgument, 4> Builder; + if (auto Result = ConvertDeducedTemplateArguments( + S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder)) + return Result; + + // Check that we produced the correct argument list. + TemplateParameterList *TemplateParams = Template->getTemplateParameters(); + for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { + TemplateArgument InstArg = Builder[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, + /*PackExpansionMatchesPack*/true)) { + Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); + Info.FirstArg = TemplateArgs[I]; + Info.SecondArg = InstArg; + return Sema::TDK_NonDeducedMismatch; + } + } + + if (Trap.hasErrorOccurred()) + return Sema::TDK_SubstitutionFailure; + + return Sema::TDK_Success; +} + + /// \brief Perform template argument deduction to determine whether /// the given template arguments match the given class template /// partial specialization per C++ [temp.class.spec.match]. @@ -4535,14 +4583,13 @@ UnresolvedSetIterator Sema::getMostSpeci /// specialized than another, P2. /// /// \tparam PartialSpecializationDecl The kind of P2, which must be a -/// {Class,Var}TemplatePartialSpecializationDecl. +/// {Class,Var}Template{PartialSpecialization,}Decl. /// \param T1 The injected-class-name of P1 (faked for a variable template). /// \param T2 The injected-class-name of P2 (faked for a variable template). -/// \param Loc The location at which the comparison is required. template<typename PartialSpecializationDecl> static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, PartialSpecializationDecl *P2, - SourceLocation Loc) { + TemplateDeductionInfo &Info) { // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as // specialized as the second if, given the following rewrite to two @@ -4568,7 +4615,6 @@ static bool isAtLeastAsSpecializedAs(Sem // template partial specialization's template arguments, for // example. SmallVector<DeducedTemplateArgument, 4> Deduced; - TemplateDeductionInfo Info(Loc); // Determine whether P1 is at least as specialized as P2. Deduced.resize(P2->getTemplateParameters()->size()); @@ -4579,7 +4625,8 @@ static bool isAtLeastAsSpecializedAs(Sem SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); - Sema::InstantiatingTemplate Inst(S, Loc, P2, DeducedArgs, Info); + Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs, + Info); auto *TST1 = T1->castAs<TemplateSpecializationType>(); if (FinishTemplateArgumentDeduction( S, P2, /*PartialOrdering=*/true, @@ -4609,8 +4656,9 @@ Sema::getMoreSpecializedPartialSpecializ QualType PT1 = PS1->getInjectedSpecializationType(); QualType PT2 = PS2->getInjectedSpecializationType(); - bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Loc); - bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Loc); + TemplateDeductionInfo Info(Loc); + bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); + bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); if (Better1 == Better2) return nullptr; @@ -4618,6 +4666,20 @@ Sema::getMoreSpecializedPartialSpecializ return Better1 ? PS1 : PS2; } +bool Sema::isMoreSpecializedThanPrimary( + ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { + ClassTemplateDecl *Primary = Spec->getSpecializedTemplate(); + QualType PrimaryT = Primary->getInjectedClassNameSpecialization(); + QualType PartialT = Spec->getInjectedSpecializationType(); + if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) + return false; + if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) { + Info.clearSFINAEDiagnostic(); + return false; + } + return true; +} + VarTemplatePartialSpecializationDecl * Sema::getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, @@ -4634,8 +4696,9 @@ Sema::getMoreSpecializedPartialSpecializ QualType PT2 = Context.getTemplateSpecializationType( CanonTemplate, PS2->getTemplateArgs().asArray()); - bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Loc); - bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Loc); + TemplateDeductionInfo Info(Loc); + bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); + bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); if (Better1 == Better2) return nullptr; @@ -4643,6 +4706,30 @@ Sema::getMoreSpecializedPartialSpecializ return Better1 ? PS1 : PS2; } +bool Sema::isMoreSpecializedThanPrimary( + VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { + TemplateDecl *Primary = Spec->getSpecializedTemplate(); + // FIXME: Cache the injected template arguments rather than recomputing + // them for each partial specialization. + SmallVector<TemplateArgument, 8> PrimaryArgs; + Context.getInjectedTemplateArgs(Primary->getTemplateParameters(), + PrimaryArgs); + + TemplateName CanonTemplate = + Context.getCanonicalTemplateName(TemplateName(Primary)); + QualType PrimaryT = Context.getTemplateSpecializationType( + CanonTemplate, PrimaryArgs); + QualType PartialT = Context.getTemplateSpecializationType( + CanonTemplate, Spec->getTemplateArgs().asArray()); + if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) + return false; + if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) { + Info.clearSFINAEDiagnostic(); + return false; + } + return true; +} + static void MarkUsedTemplateParameters(ASTContext &Ctx, const TemplateArgument &TemplateArg, Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Dec 27 01:56:27 2016 @@ -279,6 +279,17 @@ Sema::InstantiatingTemplate::Instantiati Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution, + PointOfInstantiation, InstantiationRange, Template, nullptr, + TemplateArgs, &DeductionInfo) {} + +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, ArrayRef<TemplateArgument> TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) @@ -497,8 +508,12 @@ void Sema::PrintInstantiationStack() { } else { bool IsVar = isa<VarTemplateDecl>(Active->Entity) || isa<VarTemplateSpecializationDecl>(Active->Entity); + bool IsTemplate = false; TemplateParameterList *Params; - if (auto *D = dyn_cast<ClassTemplatePartialSpecializationDecl>( + if (auto *D = dyn_cast<TemplateDecl>(Active->Entity)) { + IsTemplate = true; + Params = D->getTemplateParameters(); + } else if (auto *D = dyn_cast<ClassTemplatePartialSpecializationDecl>( Active->Entity)) { Params = D->getTemplateParameters(); } else if (auto *D = dyn_cast<VarTemplatePartialSpecializationDecl>( @@ -510,7 +525,7 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, diag::note_deduced_template_arg_substitution_here) - << IsVar << cast<NamedDecl>(Active->Entity) + << IsVar << IsTemplate << cast<NamedDecl>(Active->Entity) << getTemplateArgumentBindingsText(Params, Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; Modified: cfe/trunk/test/CXX/drs/dr14xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr14xx.cpp?rev=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr14xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr14xx.cpp Tue Dec 27 01:56:27 2016 @@ -342,4 +342,32 @@ namespace dr1490 { // dr1490: 3.7 c++11 char s[4]{"abc"}; // Ok std::initializer_list<char>{"abc"}; // expected-error {{expected unqualified-id}}} } // dr190 + +namespace dr1495 { // dr1495: 4.0 + // Deduction succeeds in both directions. + template<typename T, typename U> struct A {}; // expected-note {{template is declared here}} + template<typename T, typename U> struct A<U, T> {}; // expected-error {{class template partial specialization is not more specialized}} + + // Primary template is more specialized. + template<typename, typename...> struct B {}; // expected-note {{template is declared here}} + template<typename ...Ts> struct B<Ts...> {}; // expected-error {{not more specialized}} + + // Deduction fails in both directions. + template<int, typename, typename ...> struct C {}; // expected-note {{template is declared here}} + template<typename ...Ts> struct C<0, Ts...> {}; // expected-error {{not more specialized}} + +#if __cplusplus >= 201402L + // Deduction succeeds in both directions. + template<typename T, typename U> int a; // expected-note {{template is declared here}} + template<typename T, typename U> int a<U, T>; // expected-error {{variable template partial specialization is not more specialized}} + + // Primary template is more specialized. + template<typename, typename...> int b; // expected-note {{template is declared here}} + template<typename ...Ts> int b<Ts...>; // expected-error {{not more specialized}} + + // Deduction fails in both directions. + template<int, typename, typename ...> int c; // expected-note {{template is declared here}} + template<typename ...Ts> int c<0, Ts...>; // expected-error {{not more specialized}} +#endif +} #endif Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp?rev=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp Tue Dec 27 01:56:27 2016 @@ -108,10 +108,10 @@ namespace PR9021b { namespace PartialSpecialization { template<typename T, typename U, typename V = U> - struct X0; // expected-note{{template is declared here}} + struct X0; // expected-note 2{{template is declared here}} template<typename ...Ts> - struct X0<Ts...> { + struct X0<Ts...> { // expected-error {{class template partial specialization is not more specialized than the primary template}} }; X0<int> x0i; // expected-error{{too few template arguments for class template 'X0'}} 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=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original) +++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Tue Dec 27 01:56:27 2016 @@ -167,10 +167,16 @@ namespace PR16519 { // expected-warning@-2 {{variadic templates are a C++11 extension}} #endif - template<typename T, T ...N, T ...Extra> struct __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> { + // Note that the following seemingly-equivalent template parameter list is + // not OK; it would result in a partial specialization that is not more + // specialized than the primary template. (See NTTPTypeVsPartialOrder below.) + // + // template<typename T, T ...N, T ...Extra> + template<typename T, T ...N, typename integer_sequence<T, N...>::value_type ...Extra> #if __cplusplus <= 199711L - // expected-warning@-2 2 {{variadic templates are a C++11 extension}} + // expected-warning@-2 2{{variadic templates are a C++11 extension}} #endif + struct __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> { typedef integer_sequence<T, N..., sizeof...(N) + N..., Extra...> type; }; @@ -193,6 +199,25 @@ namespace PR16519 { #endif } +namespace NTTPTypeVsPartialOrder { + struct X { typedef int value_type; }; + template<typename T> struct Y { typedef T value_type; }; + + template<typename T, typename T::value_type N> struct A; // expected-note {{template}} + template<int N> struct A<X, N> {}; + template<typename T, T N> struct A<Y<T>, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y<type-parameter-0-0>::value_type'}} + A<X, 0> ax; + A<Y<int>, 0> ay; + + + template<int, typename T, typename T::value_type> struct B; // expected-note {{template}} + template<typename T, typename T::value_type N> struct B<0, T, N>; // expected-note {{matches}} + template<int N> struct B<0, X, N> {}; + template<typename T, T N> struct B<0, Y<T>, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y<type-parameter-0-0>::value_type'}} expected-note {{matches}} + B<0, X, 0> bx; + B<0, Y<int>, 0> by; // expected-error {{ambiguous}} +} + namespace DefaultArgVsPartialSpec { // Check that the diagnostic points at the partial specialization, not just at // the default argument. 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=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Tue Dec 27 01:56:27 2016 @@ -367,11 +367,11 @@ namespace PR17696 { namespace partial_order_different_types { // These are unordered because the type of the final argument doesn't match. - // FIXME: The second partial specialization should actually be rejected - // because it's not more specialized than the primary template. - template<int, int, typename T, typename, T> struct A; + template<int, int, typename T, typename, T> struct A; // expected-note {{here}} template<int N, typename T, typename U, T V> struct A<0, N, T, U, V> {}; // expected-note {{matches}} template<typename T, typename U, U V> struct A<0, 0, T, U, V> {}; // expected-note {{matches}} + // expected-error@-1 {{not more specialized than the primary}} + // expected-note@-2 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('U' vs 'type-parameter-0-0')}} A<0, 0, int, int, 0> a; // expected-error {{ambiguous partial specializations}} } @@ -389,18 +389,22 @@ namespace partial_order_references { int N; A<0, 0, N> a; - // FIXME: These should all be rejected as they are not more specialized than - // the primary template (they can never be used due to the type mismatch). - template<int, int &R> struct B; // expected-note {{template}} + template<int, int &R> struct B; // expected-note 2{{template}} template<const int &R> struct B<0, R> {}; + // expected-error@-1 {{not more specialized than the primary}} + // expected-note@-2 {{'const int' vs 'int &'}} B<0, N> b; // expected-error {{undefined}} - template<int, const int &R> struct C; // expected-note {{template}} + template<int, const int &R> struct C; // expected-note 2{{template}} template<int &R> struct C<0, R> {}; + // expected-error@-1 {{not more specialized than the primary}} + // expected-note@-2 {{'int' vs 'const int &'}} C<0, N> c; // expected-error {{undefined}} - template<int, const int &R> struct D; // expected-note {{template}} + template<int, const int &R> struct D; // expected-note 2{{template}} template<int N> struct D<0, N> {}; + // expected-error@-1 {{not more specialized than the primary}} + // expected-note@-2 {{'int' vs 'const int &'}} extern const int K = 5; D<0, K> d; // expected-error {{undefined}} } Modified: cfe/trunk/www/cxx_dr_status.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=290593&r1=290592&r2=290593&view=diff ============================================================================== --- cfe/trunk/www/cxx_dr_status.html (original) +++ cfe/trunk/www/cxx_dr_status.html Tue Dec 27 01:56:27 2016 @@ -4195,7 +4195,7 @@ and <I>POD class</I></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#692">692</a></td> <td>C++11</td> <td>Partial ordering of variadic class template partial specializations</td> - <td class="none" align="center">Unknown</td> + <td class="none" align="center">No</td> </tr> <tr id="693"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#693">693</a></td> @@ -8785,7 +8785,7 @@ and <I>POD class</I></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1495">1495</a></td> <td>CD3</td> <td>Partial specialization of variadic class template</td> - <td class="none" align="center">Unknown</td> + <td class="svn" align="center">SVN</td> </tr> <tr id="1496"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1496">1496</a></td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits