]> granicus.if.org Git - clang/commitdiff
Unwrap template argument packs when checking the template arguments of
authorDouglas Gregor <dgregor@apple.com>
Mon, 3 Jan 2011 21:13:47 +0000 (21:13 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 3 Jan 2011 21:13:47 +0000 (21:13 +0000)
a class template partial specialiation, and look through pack
expansions when checking the conditions of C++0x [temp.class.spec]p8.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122774 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp [new file with mode: 0644]

index 2d349bc34c2fd9312e3d2083755f2ac35a2b27f3..b5dfe0a480c390e593f4a2b991068647a5cf8009 100644 (file)
@@ -2910,10 +2910,6 @@ public:
                                               bool EnteringContext,
                                               TemplateTy &Template);
 
-  bool CheckClassTemplatePartialSpecializationArgs(
-                                        TemplateParameterList *TemplateParams,
-                        llvm::SmallVectorImpl<TemplateArgument> &TemplateArgs);
-
   DeclResult
   ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
                                    SourceLocation KWLoc,
index 6384e53e80b1faff55add8936d71ed38f32ce4ae..c3cfbb8c258996cb7eef2bf30b639c5da89243ac 100644 (file)
@@ -3915,34 +3915,31 @@ static bool CheckTemplateSpecializationScope(Sema &S,
   
   return false;
 }
-                                             
-/// \brief Check the non-type template arguments of a class template
-/// partial specialization according to C++ [temp.class.spec]p9.
-///
-/// \param TemplateParams the template parameters of the primary class
-/// template.
-///
-/// \param TemplateArg the template arguments of the class template
-/// partial specialization.
-///
-/// \returns true if there was an error, false otherwise.
-bool Sema::CheckClassTemplatePartialSpecializationArgs(
-                                        TemplateParameterList *TemplateParams,
-                       llvm::SmallVectorImpl<TemplateArgument> &TemplateArgs) {
-  const TemplateArgument *ArgList = TemplateArgs.data();
-
-  for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
-    NonTypeTemplateParmDecl *Param
-      = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I));
-    if (!Param)
+                     
+/// \brief Subroutine of Sema::CheckClassTemplatePartialSpecializationArgs
+/// that checks non-type template partial specialization arguments.
+static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
+                                                NonTypeTemplateParmDecl *Param,
+                                                  const TemplateArgument *Args,
+                                                        unsigned NumArgs) {
+  for (unsigned I = 0; I != NumArgs; ++I) {
+    if (Args[I].getKind() == TemplateArgument::Pack) {
+      if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param,
+                                                           Args[I].pack_begin(), 
+                                                           Args[I].pack_size()))
+        return true;
+      
       continue;
-
-    Expr *ArgExpr = ArgList[I].getAsExpr();
+    }
+      
+    Expr *ArgExpr = Args[I].getAsExpr();
     if (!ArgExpr) {
       continue;
     }
 
-    // FIXME: Variadic templates. Unwrap argument packs.
+    // We can have a pack expansion of any of the above.
+    if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(ArgExpr))
+      ArgExpr = Expansion->getPattern();
     
     // C++ [temp.class.spec]p8:
     //   A non-type argument is non-specialized if it is the name of a
@@ -3964,24 +3961,53 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
     //        specialization except when the argument expression is a
     //        simple identifier.
     if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) {
-      Diag(ArgExpr->getLocStart(),
+      S.Diag(ArgExpr->getLocStart(),
            diag::err_dependent_non_type_arg_in_partial_spec)
         << ArgExpr->getSourceRange();
       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()) {
-      Diag(ArgExpr->getLocStart(),
+      S.Diag(ArgExpr->getLocStart(),
            diag::err_dependent_typed_non_type_arg_in_partial_spec)
         << Param->getType()
         << ArgExpr->getSourceRange();
-      Diag(Param->getLocation(), diag::note_template_param_here);
+      S.Diag(Param->getLocation(), diag::note_template_param_here);
       return true;
     }
   }
+  
+  return false;
+}
+                                                        
+/// \brief Check the non-type template arguments of a class template
+/// partial specialization according to C++ [temp.class.spec]p9.
+///
+/// \param TemplateParams the template parameters of the primary class
+/// template.
+///
+/// \param TemplateArg the template arguments of the class template
+/// partial specialization.
+///
+/// \returns true if there was an error, false otherwise.
+static bool CheckClassTemplatePartialSpecializationArgs(Sema &S,
+                                        TemplateParameterList *TemplateParams,
+                       llvm::SmallVectorImpl<TemplateArgument> &TemplateArgs) {
+  const TemplateArgument *ArgList = TemplateArgs.data();
+
+  for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+    NonTypeTemplateParmDecl *Param
+      = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I));
+    if (!Param)
+      continue;
+
+    if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, 
+                                                           &ArgList[I], 1))
+      return true;
+  }
 
   return false;
 }
@@ -4145,7 +4171,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
   // Find the class template (partial) specialization declaration that
   // corresponds to these arguments.
   if (isPartialSpecialization) {
-    if (CheckClassTemplatePartialSpecializationArgs(
+    if (CheckClassTemplatePartialSpecializationArgs(*this,
                                          ClassTemplate->getTemplateParameters(),
                                          Converted))
       return true;
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp
new file mode 100644 (file)
index 0000000..14152cf
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+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}}
+
+