]> granicus.if.org Git - clang/commitdiff
When checking a template argument list against a template containing
authorDouglas Gregor <dgregor@apple.com>
Mon, 20 Dec 2010 16:57:52 +0000 (16:57 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 20 Dec 2010 16:57:52 +0000 (16:57 +0000)
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;

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

lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.decls/temp.variadic/p1.cpp [new file with mode: 0644]

index 9704495c79f3a2bdcf9a9485c30709980dd2f6f4..4651759398303090b090c280963fbfe0077e1799 100644 (file)
@@ -2377,30 +2377,40 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
   //   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 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
     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;
 }
 
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p1.cpp b/test/CXX/temp/temp.decls/temp.variadic/p1.cpp
new file mode 100644 (file)
index 0000000..02f4c59
--- /dev/null
@@ -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;