[cfe-commits] r122251 - in /cfe/trunk: lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.decls/temp.variadic/p1.cpp

Douglas Gregor dgregor at apple.com
Mon Dec 20 08:57:52 PST 2010


Author: dgregor
Date: Mon Dec 20 10:57:52 2010
New Revision: 122251

URL: http://llvm.org/viewvc/llvm-project?rev=122251&view=rev
Log:
When checking a template argument list against a template containing
a parameter pack, check the parameter pack against each of the
template arguments it corresponds to, then pack the converted
arguments into a template argument pack. Allows us to use variadic
class templates so long as instantiation isn't required, e.g.,

  template<typename... Types> struct Tuple;
  Tuple<int, float> *t2;


Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p1.cpp
Modified:
    cfe/trunk/lib/Sema/SemaTemplate.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=122251&r1=122250&r2=122251&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Dec 20 10:57:52 2010
@@ -2377,30 +2377,40 @@
   //   a template-id shall match the type and form specified for the
   //   corresponding parameter declared by the template in its
   //   template-parameter-list.
+  llvm::SmallVector<TemplateArgument, 2> ArgumentPack;
+  TemplateParameterList::iterator Param = Params->begin(),
+                               ParamEnd = Params->end();
   unsigned ArgIdx = 0;
-  for (TemplateParameterList::iterator Param = Params->begin(),
-                                       ParamEnd = Params->end();
-       Param != ParamEnd; ++Param, ++ArgIdx) {
+  while (Param != ParamEnd) {
     if (ArgIdx > NumArgs && PartialTemplateArgs)
       break;
 
-    // If we have a template parameter pack, check every remaining template
-    // argument against that template parameter pack.
-    // FIXME: Variadic templates are unimplemented
-    if ((*Param)->isTemplateParameterPack()) {
-      Diag(TemplateLoc, diag::err_variadic_templates_unsupported);
-      return true;
-    }
-    
     if (ArgIdx < NumArgs) {
       // Check the template argument we were given.
       if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, 
                                 TemplateLoc, RAngleLoc, Converted))
         return true;
       
+      if ((*Param)->isTemplateParameterPack()) {
+        // The template parameter was a template parameter pack, so take the
+        // deduced argument and place it on the argument pack. Note that we
+        // stay on the same template parameter so that we can deduce more
+        // arguments.
+        ArgumentPack.push_back(Converted.back());
+        Converted.pop_back();
+      } else {
+        // Move to the next template parameter.
+        ++Param;
+      }
+      ++ArgIdx;
       continue;
     }
     
+    // If we have a template parameter pack with no more corresponding 
+    // arguments, just break out now and we'll fill in the argument pack below.
+    if ((*Param)->isTemplateParameterPack())
+      break;
+    
     // We have a default template argument that we will use.
     TemplateArgumentLoc Arg;
     
@@ -2475,8 +2485,31 @@
     if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
                               RAngleLoc, Converted))
       return true;
+    
+    // Move to the next template parameter and argument.
+    ++Param;
+    ++ArgIdx;
   }
-
+  
+  // Form argument packs for each of the parameter packs remaining.
+  while (Param != ParamEnd) {
+    if ((*Param)->isTemplateParameterPack()) {     
+      // The parameter pack takes the contents of the current argument pack,
+      // which we built up earlier.
+      if (ArgumentPack.empty()) {
+        Converted.push_back(TemplateArgument(0, 0));
+      } else {
+        TemplateArgument *PackedArgs
+          = new (Context) TemplateArgument [ArgumentPack.size()];
+        std::copy(ArgumentPack.begin(), ArgumentPack.end(), PackedArgs);
+        Converted.push_back(TemplateArgument(PackedArgs, ArgumentPack.size()));
+        ArgumentPack.clear();
+      }
+    }
+    
+    ++Param;
+  }
+  
   return Invalid;
 }
 

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p1.cpp?rev=122251&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p1.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p1.cpp Mon Dec 20 10:57:52 2010
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<class ...Types> struct Tuple;
+
+Tuple<> *t0;
+Tuple<int> *t1;
+Tuple<int, char> *t2a;
+Tuple<int, float> *t2b = t2a; // expected-error{{cannot initialize a variable of type 'Tuple<int, float> *' with an lvalue of type 'Tuple<int, char> *'}}
+Tuple<int, float, double> *t3;





More information about the cfe-commits mailing list