r290647 - DR1315: a non-type template argument in a partial specialization is permitted

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 27 18:37:26 PST 2016


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 at -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>




More information about the cfe-commits mailing list