From 0e617ecdd115984ce6729554e17ea20a2783194f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 27 Dec 2016 07:56:27 +0000 Subject: [PATCH] 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.) llvm-svn: 290593 --- .../clang/Basic/DiagnosticSemaKinds.td | 6 +- clang/include/clang/Sema/Sema.h | 16 ++- clang/include/clang/Sema/TemplateDeduction.h | 5 + clang/lib/Sema/SemaTemplate.cpp | 47 +++++++- clang/lib/Sema/SemaTemplateDeduction.cpp | 111 ++++++++++++++++-- clang/lib/Sema/SemaTemplateInstantiate.cpp | 19 ++- clang/test/CXX/drs/dr14xx.cpp | 28 +++++ .../temp.variadic/fixed-expansion.cpp | 4 +- .../test/SemaTemplate/class-template-spec.cpp | 29 ++++- clang/test/SemaTemplate/temp_arg_nontype.cpp | 20 ++-- clang/www/cxx_dr_status.html | 4 +- 11 files changed, 257 insertions(+), 32 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 1ac5dfce0d0e..756f5a14d795 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4043,6 +4043,10 @@ def err_partial_spec_args_match_primary_template : Error< "%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_instantiation_here : Note< "%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">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d1f043e2d95c..5b2218db7c27 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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 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. diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h index 7344c92a5f87..f4a706ecb9ab 100644 --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -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; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 8b8ab4a6e165..b335e7e2602e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2624,6 +2624,36 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { return TemplateArgs; } +template +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(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::ActOnVarTemplateSpecialization( 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(NonTypeTemplateParmDecl *Param, 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 , 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(NonTypeTemplateParmDecl *Param, // 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(Scope *S, unsigned TagSpec, // // -- 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(Scope *S, unsigned TagSpec, 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 diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 0e20ef2441d0..d10b0c9a1ce5 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -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 &Context, 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 &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 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::getMostSpecialized( /// 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 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(Sema &S, QualType T1, QualType T2, // template partial specialization's template arguments, for // example. SmallVector 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(Sema &S, QualType T1, QualType T2, SmallVector 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(); if (FinishTemplateArgumentDeduction( S, P2, /*PartialOrdering=*/true, @@ -4609,8 +4656,9 @@ Sema::getMoreSpecializedPartialSpecialization( 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::getMoreSpecializedPartialSpecialization( 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::getMoreSpecializedPartialSpecialization( 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::getMoreSpecializedPartialSpecialization( 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 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, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 14d239b54848..160c9f090788 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -277,6 +277,17 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Kind == ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); } +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + ArrayRef 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, @@ -497,8 +508,12 @@ void Sema::PrintInstantiationStack() { } else { bool IsVar = isa(Active->Entity) || isa(Active->Entity); + bool IsTemplate = false; TemplateParameterList *Params; - if (auto *D = dyn_cast( + if (auto *D = dyn_cast(Active->Entity)) { + IsTemplate = true; + Params = D->getTemplateParameters(); + } else if (auto *D = dyn_cast( Active->Entity)) { Params = D->getTemplateParameters(); } else if (auto *D = dyn_cast( @@ -510,7 +525,7 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, diag::note_deduced_template_arg_substitution_here) - << IsVar << cast(Active->Entity) + << IsVar << IsTemplate << cast(Active->Entity) << getTemplateArgumentBindingsText(Params, Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; diff --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp index 9491f7da1476..9e724d918346 100644 --- a/clang/test/CXX/drs/dr14xx.cpp +++ b/clang/test/CXX/drs/dr14xx.cpp @@ -342,4 +342,32 @@ namespace dr1490 { // dr1490: 3.7 c++11 char s[4]{"abc"}; // Ok std::initializer_list{"abc"}; // expected-error {{expected unqualified-id}}} } // dr190 + +namespace dr1495 { // dr1495: 4.0 + // Deduction succeeds in both directions. + template struct A {}; // expected-note {{template is declared here}} + template struct A {}; // expected-error {{class template partial specialization is not more specialized}} + + // Primary template is more specialized. + template struct B {}; // expected-note {{template is declared here}} + template struct B {}; // expected-error {{not more specialized}} + + // Deduction fails in both directions. + template struct C {}; // expected-note {{template is declared here}} + template struct C<0, Ts...> {}; // expected-error {{not more specialized}} + +#if __cplusplus >= 201402L + // Deduction succeeds in both directions. + template int a; // expected-note {{template is declared here}} + template int a; // expected-error {{variable template partial specialization is not more specialized}} + + // Primary template is more specialized. + template int b; // expected-note {{template is declared here}} + template int b; // expected-error {{not more specialized}} + + // Deduction fails in both directions. + template int c; // expected-note {{template is declared here}} + template int c<0, Ts...>; // expected-error {{not more specialized}} +#endif +} #endif diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp index a466be0a61de..a990c82564aa 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp @@ -108,10 +108,10 @@ namespace PR9021b { namespace PartialSpecialization { template - struct X0; // expected-note{{template is declared here}} + struct X0; // expected-note 2{{template is declared here}} template - struct X0 { + struct X0 { // expected-error {{class template partial specialization is not more specialized than the primary template}} }; X0 x0i; // expected-error{{too few template arguments for class template 'X0'}} diff --git a/clang/test/SemaTemplate/class-template-spec.cpp b/clang/test/SemaTemplate/class-template-spec.cpp index 86cace19dbfb..cee84a750b67 100644 --- a/clang/test/SemaTemplate/class-template-spec.cpp +++ b/clang/test/SemaTemplate/class-template-spec.cpp @@ -167,10 +167,16 @@ namespace PR16519 { // expected-warning@-2 {{variadic templates are a C++11 extension}} #endif - template struct __make_integer_sequence_impl, 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 + template::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, Extra...> { typedef integer_sequence type; }; @@ -193,6 +199,25 @@ namespace PR16519 { #endif } +namespace NTTPTypeVsPartialOrder { + struct X { typedef int value_type; }; + template struct Y { typedef T value_type; }; + + template struct A; // expected-note {{template}} + template struct A {}; + template struct A, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y::value_type'}} + A ax; + A, 0> ay; + + + template struct B; // expected-note {{template}} + template struct B<0, T, N>; // expected-note {{matches}} + template struct B<0, X, N> {}; + template struct B<0, Y, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y::value_type'}} expected-note {{matches}} + B<0, X, 0> bx; + B<0, Y, 0> by; // expected-error {{ambiguous}} +} + namespace DefaultArgVsPartialSpec { // Check that the diagnostic points at the partial specialization, not just at // the default argument. diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp index e99c56ba1f5e..dc67ecac1d45 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp @@ -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 struct A; + template struct A; // expected-note {{here}} template struct A<0, N, T, U, V> {}; // expected-note {{matches}} template 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 struct B; // expected-note {{template}} + template struct B; // expected-note 2{{template}} template 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 struct C; // expected-note {{template}} + template struct C; // expected-note 2{{template}} template 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 struct D; // expected-note {{template}} + template struct D; // expected-note 2{{template}} template 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}} } diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 90c28d54c7c9..d3d3cce7bfd7 100644 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -4195,7 +4195,7 @@ and POD class 692 C++11 Partial ordering of variadic class template partial specializations - Unknown + No 693 @@ -8785,7 +8785,7 @@ and POD class 1495 CD3 Partial specialization of variadic class template - Unknown + SVN 1496