r290593 - DR1495: A partial specialization is ill-formed if it is not (strictly) more

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 26 23:56:28 PST 2016


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 at -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 at -2 2 {{variadic templates are a C++11 extension}}
+  // expected-warning at -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 at -1 {{not more specialized than the primary}}
+  // expected-note at -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 at -1 {{not more specialized than the primary}}
+  // expected-note at -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 at -1 {{not more specialized than the primary}}
+  // expected-note at -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 at -1 {{not more specialized than the primary}}
+  // expected-note at -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>




More information about the cfe-commits mailing list