r201031 - PR16519, PR18009: When checking a partial specialization for uses of its own

Richard Smith richard-llvm at metafoo.co.uk
Sat Feb 8 16:54:43 PST 2014


Author: rsmith
Date: Sat Feb  8 18:54:43 2014
New Revision: 201031

URL: http://llvm.org/viewvc/llvm-project?rev=201031&view=rev
Log:
PR16519, PR18009: When checking a partial specialization for uses of its own
template parameters, don't look for parameters of outer templates. If a problem
is found in a default template argument, point the diagnostic at the partial
specialization (with a note pointing at the default argument) instead of
pointing it at the default argument and leaving it unclear which partial
specialization os problematic.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/class-template-spec.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=201031&r1=201030&r2=201031&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Feb  8 18:54:43 2014
@@ -3202,9 +3202,13 @@ def err_default_arg_in_partial_spec : Er
 def err_dependent_non_type_arg_in_partial_spec : Error<
     "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<
     "non-type template argument specializes a template parameter with "
     "dependent type %0">;
+def note_dependent_typed_non_type_default_arg_in_partial_spec : Note<
+    "template parameter is declared here">;
 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 "

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=201031&r1=201030&r2=201031&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat Feb  8 18:54:43 2014
@@ -1488,6 +1488,9 @@ struct DependencyChecker : RecursiveASTV
 
   unsigned Depth;
   bool Match;
+  SourceLocation MatchLoc;
+
+  DependencyChecker(unsigned Depth) : Depth(Depth), Match(false) {}
 
   DependencyChecker(TemplateParameterList *Params) : Match(false) {
     NamedDecl *ND = Params->getParam(0);
@@ -1501,14 +1504,20 @@ struct DependencyChecker : RecursiveASTV
     }
   }
 
-  bool Matches(unsigned ParmDepth) {
+  bool Matches(unsigned ParmDepth, SourceLocation Loc = SourceLocation()) {
+    llvm::errs() << "Found " << ParmDepth << " vs " << Depth << "\n";
     if (ParmDepth >= Depth) {
       Match = true;
+      MatchLoc = Loc;
       return true;
     }
     return false;
   }
 
+  bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+    return !Matches(TL.getTypePtr()->getDepth(), TL.getNameLoc());
+  }
+
   bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
     return !Matches(T->getDepth());
   }
@@ -1516,21 +1525,28 @@ struct DependencyChecker : RecursiveASTV
   bool TraverseTemplateName(TemplateName N) {
     if (TemplateTemplateParmDecl *PD =
           dyn_cast_or_null<TemplateTemplateParmDecl>(N.getAsTemplateDecl()))
-      if (Matches(PD->getDepth())) return false;
+      if (Matches(PD->getDepth()))
+        return false;
     return super::TraverseTemplateName(N);
   }
 
   bool VisitDeclRefExpr(DeclRefExpr *E) {
     if (NonTypeTemplateParmDecl *PD =
-          dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
-      if (PD->getDepth() == Depth) {
-        Match = true;
+          dyn_cast<NonTypeTemplateParmDecl>(E->getDecl()))
+      if (Matches(PD->getDepth(), E->getExprLoc()))
         return false;
-      }
-    }
     return super::VisitDeclRefExpr(E);
   }
-  
+
+  bool VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
+    return TraverseType(T->getReplacementType());
+  }
+
+  bool
+  VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
+    return TraverseTemplateArgument(T->getArgumentPack());
+  }
+
   bool TraverseInjectedClassNameType(const InjectedClassNameType *T) {
     return TraverseType(T->getInjectedSpecializationType());
   }
@@ -2267,8 +2283,8 @@ TypeResult Sema::ActOnTagTemplateIdType(
 }
 
 static bool CheckTemplatePartialSpecializationArgs(
-    Sema &S, TemplateParameterList *TemplateParams,
-    SmallVectorImpl<TemplateArgument> &TemplateArgs);
+    Sema &S, SourceLocation NameLoc, TemplateParameterList *TemplateParams,
+    unsigned ExplicitArgs, SmallVectorImpl<TemplateArgument> &TemplateArgs);
 
 static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
                                              NamedDecl *PrevDecl,
@@ -2401,7 +2417,8 @@ DeclResult Sema::ActOnVarTemplateSpecial
   // corresponds to these arguments.
   if (IsPartialSpecialization) {
     if (CheckTemplatePartialSpecializationArgs(
-            *this, VarTemplate->getTemplateParameters(), Converted))
+            *this, TemplateNameLoc, VarTemplate->getTemplateParameters(),
+            TemplateArgs.size(), Converted))
       return true;
 
     bool InstantiationDependent;
@@ -5679,15 +5696,36 @@ static bool CheckTemplateSpecializationS
   return false;
 }
 
+static SourceRange findTemplateParameter(unsigned Depth, Expr *E) {
+  if (!E->isInstantiationDependent())
+    return SourceLocation();
+  DependencyChecker Checker(Depth);
+  Checker.TraverseStmt(E);
+  if (Checker.Match && Checker.MatchLoc.isInvalid())
+    return E->getSourceRange();
+  return Checker.MatchLoc;
+}
+
+static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) {
+  if (!TL.getType()->isDependentType())
+    return SourceLocation();
+  DependencyChecker Checker(Depth);
+  Checker.TraverseTypeLoc(TL);
+  if (Checker.Match && Checker.MatchLoc.isInvalid())
+    return TL.getSourceRange();
+  return Checker.MatchLoc;
+}
+
 /// \brief Subroutine of Sema::CheckTemplatePartialSpecializationArgs
 /// that checks non-type template partial specialization arguments.
 static bool CheckNonTypeTemplatePartialSpecializationArgs(
-    Sema &S, NonTypeTemplateParmDecl *Param, const TemplateArgument *Args,
-    unsigned NumArgs) {
+    Sema &S, SourceLocation TemplateNameLoc, NonTypeTemplateParmDecl *Param,
+    const TemplateArgument *Args, unsigned NumArgs, bool IsDefaultArgument) {
   for (unsigned I = 0; I != NumArgs; ++I) {
     if (Args[I].getKind() == TemplateArgument::Pack) {
       if (CheckNonTypeTemplatePartialSpecializationArgs(
-              S, Param, Args[I].pack_begin(), Args[I].pack_size()))
+              S, TemplateNameLoc, Param, Args[I].pack_begin(),
+              Args[I].pack_size(), IsDefaultArgument))
         return true;
 
       continue;
@@ -5725,22 +5763,43 @@ static bool CheckNonTypeTemplatePartialS
     //        shall not involve a template parameter of the partial
     //        specialization except when the argument expression is a
     //        simple identifier.
-    if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) {
-      S.Diag(ArgExpr->getLocStart(),
-           diag::err_dependent_non_type_arg_in_partial_spec)
-        << ArgExpr->getSourceRange();
+    SourceRange ParamUseRange =
+        findTemplateParameter(Param->getDepth(), ArgExpr);
+    if (ParamUseRange.isValid()) {
+      if (IsDefaultArgument) {
+        S.Diag(TemplateNameLoc,
+               diag::err_dependent_non_type_arg_in_partial_spec);
+        S.Diag(ParamUseRange.getBegin(),
+               diag::note_dependent_non_type_default_arg_in_partial_spec)
+          << ParamUseRange;
+      } else {
+        S.Diag(ParamUseRange.getBegin(),
+               diag::err_dependent_non_type_arg_in_partial_spec)
+          << ParamUseRange;
+      }
       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.
-    if (Param->getType()->isDependentType()) {
-      S.Diag(ArgExpr->getLocStart(),
-           diag::err_dependent_typed_non_type_arg_in_partial_spec)
-        << Param->getType()
-        << ArgExpr->getSourceRange();
-      S.Diag(Param->getLocation(), diag::note_template_param_here);
+    //
+    // 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());
+    if (ParamUseRange.isValid()) {
+      S.Diag(IsDefaultArgument ? TemplateNameLoc : ArgExpr->getLocStart(),
+             diag::err_dependent_typed_non_type_arg_in_partial_spec)
+        << Param->getType() << ParamUseRange;
+      S.Diag(Param->getLocation(), diag::note_template_param_here)
+        << (IsDefaultArgument ? ParamUseRange : SourceRange());
       return true;
     }
   }
@@ -5751,15 +5810,17 @@ static bool CheckNonTypeTemplatePartialS
 /// \brief Check the non-type template arguments of a class template
 /// partial specialization according to C++ [temp.class.spec]p9.
 ///
+/// \param TemplateNameLoc the location of the template name.
 /// \param TemplateParams the template parameters of the primary class
-/// template.
-///
+///        template.
+/// \param NumExplicit the number of explicitly-specified template arguments.
 /// \param TemplateArgs the template arguments of the class template
-/// partial specialization.
+///        partial specialization.
 ///
-/// \returns true if there was an error, false otherwise.
+/// \returns \c true if there was an error, \c false otherwise.
 static bool CheckTemplatePartialSpecializationArgs(
-    Sema &S, TemplateParameterList *TemplateParams,
+    Sema &S, SourceLocation TemplateNameLoc,
+    TemplateParameterList *TemplateParams, unsigned NumExplicit,
     SmallVectorImpl<TemplateArgument> &TemplateArgs) {
   const TemplateArgument *ArgList = TemplateArgs.data();
 
@@ -5769,7 +5830,8 @@ static bool CheckTemplatePartialSpeciali
     if (!Param)
       continue;
 
-    if (CheckNonTypeTemplatePartialSpecializationArgs(S, Param, &ArgList[I], 1))
+    if (CheckNonTypeTemplatePartialSpecializationArgs(
+            S, TemplateNameLoc, Param, &ArgList[I], 1, I >= NumExplicit))
       return true;
   }
 
@@ -5916,7 +5978,8 @@ Sema::ActOnClassTemplateSpecialization(S
   // corresponds to these arguments.
   if (isPartialSpecialization) {
     if (CheckTemplatePartialSpecializationArgs(
-            *this, ClassTemplate->getTemplateParameters(), Converted))
+            *this, TemplateNameLoc, ClassTemplate->getTemplateParameters(),
+            TemplateArgs.size(), Converted))
       return true;
 
     bool InstantiationDependent;

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=201031&r1=201030&r2=201031&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Sat Feb  8 18:54:43 2014
@@ -119,3 +119,61 @@ namespace rdar9676205 {
   };
 
 }
+
+namespace PR18009 {
+  template <typename T> struct A {
+    template <int N, int M> struct S;
+    template <int N> struct S<N, sizeof(T)> {};
+  };
+  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}}
+        > {};
+  };
+  B<int>::S<8, sizeof(int) + 8> s; // expected-error {{undefined}}
+
+  template<int A> struct outer {
+    template<int B, int C> struct inner {};
+    template<int C> struct inner<A * 2, C> {};
+  };
+}
+
+namespace PR16519 {
+  template<typename T, T...N> struct integer_sequence { typedef T value_type; }; // expected-warning {{extension}}
+
+  template<typename T> struct __make_integer_sequence;
+  template<typename T, T N> using make_integer_sequence = typename __make_integer_sequence<T>::template make<N, N % 2>::type; // expected-warning {{extension}}
+
+  template<typename T, typename T::value_type ...Extra> struct __make_integer_sequence_impl; // expected-warning {{extension}}
+  template<typename T, T ...N, T ...Extra> struct __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> { // expected-warning 2{{extension}}
+    typedef integer_sequence<T, N..., sizeof...(N) + N..., Extra...> type;
+  };
+
+  template<typename T> struct __make_integer_sequence {
+    template<T N, T Parity, typename = void> struct make;
+    template<typename Dummy> struct make<0, 0, Dummy> { typedef integer_sequence<T> type; };
+    template<typename Dummy> struct make<1, 1, Dummy> { typedef integer_sequence<T, 0> type; };
+    template<T N, typename Dummy> struct make<N, 0, Dummy> : __make_integer_sequence_impl<make_integer_sequence<T, N/2> > {};
+    template<T N, typename Dummy> struct make<N, 1, Dummy> : __make_integer_sequence_impl<make_integer_sequence<T, N/2>, N - 1> {};
+  };
+
+  using X = make_integer_sequence<int, 5>; // expected-warning {{extension}}
+  using X = integer_sequence<int, 0, 1, 2, 3, 4>; // expected-warning {{extension}}
+}
+
+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}}
+  > 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,
+      T N = 0 // expected-note {{template parameter is declared here}}
+  > struct S;
+  template<typename T> struct S<T> {}; // expected-error {{non-type template argument specializes a template parameter with dependent type 'T'}}
+}





More information about the cfe-commits mailing list