Patchwork C++ PATCH for c++/49785 (ice-on-valid with variadic templates)

login
register
mail settings
Submitter Jason Merrill
Date July 19, 2011, 5:25 p.m.
Message ID <4E25BDF6.2040805@redhat.com>
Download mbox | patch
Permalink /patch/105498/
State New
Headers show

Comments

Jason Merrill - July 19, 2011, 5:25 p.m.
The code was assuming that a template parameter pack can only be 
followed by another parameter pack; this is not the case in this testcase.

Tested x86_64-pc-linux-gnu, applying to trunk and 4.6.

Patch

commit 4d9cede24b6be5a717b54cdcbc6bdbd00e19ef7f
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jul 19 12:16:29 2011 -0400

    	PR c++/49785
    	* pt.c (coerce_template_parms): Handle non-pack after pack.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f34e1df..178685c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6537,6 +6537,7 @@  coerce_template_parms (tree parms,
      subtract it from nparms to get the number of non-variadic
      parameters.  */
   int variadic_p = 0;
+  int post_variadic_parms = 0;
 
   if (args == error_mark_node)
     return error_mark_node;
@@ -6547,19 +6548,22 @@  coerce_template_parms (tree parms,
   for (parm_idx = 0; parm_idx < nparms; ++parm_idx)
     {
       tree tparm = TREE_VALUE (TREE_VEC_ELT (parms, parm_idx));
+      if (variadic_p)
+	++post_variadic_parms;
       if (template_parameter_pack_p (tparm))
 	++variadic_p;
     }
 
   inner_args = INNERMOST_TEMPLATE_ARGS (args);
-  /* If there are 0 or 1 parameter packs, we need to expand any argument
-     packs so that we can deduce a parameter pack from some non-packed args
-     followed by an argument pack, as in variadic85.C.  If there are more
-     than that, we need to leave argument packs intact so the arguments are
-     assigned to the right parameter packs.  This should only happen when
-     dealing with a nested class inside a partial specialization of a class
-     template, as in variadic92.C.  */
-  if (variadic_p <= 1)
+  /* If there are no parameters that follow a parameter pack, we need to
+     expand any argument packs so that we can deduce a parameter pack from
+     some non-packed args followed by an argument pack, as in variadic85.C.
+     If there are such parameters, we need to leave argument packs intact
+     so the arguments are assigned properly.  This can happen when dealing
+     with a nested class inside a partial specialization of a class
+     template, as in variadic92.C, or when deducing a template parameter pack
+     from a sub-declarator, as in variadic114.C.  */
+  if (!post_variadic_parms)
     inner_args = expand_template_argument_pack (inner_args);
 
   nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
@@ -6574,7 +6578,7 @@  coerce_template_parms (tree parms,
 	{
           if (variadic_p)
             {
-              --nparms;
+              nparms -= variadic_p;
 	      error ("wrong number of template arguments "
 		     "(%d, should be %d or more)", nargs, nparms);
             }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic114.C b/gcc/testsuite/g++.dg/cpp0x/variadic114.C
new file mode 100644
index 0000000..3ffede5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic114.C
@@ -0,0 +1,27 @@ 
+// PR c++/49785
+// { dg-options -std=c++0x }
+
+template <typename, typename ...> struct B { };
+template <typename> class A;
+
+template <typename R, typename ... S>
+struct A <R (S ...)> : public B <R, S ...>
+{
+  struct C {};
+  template <typename D> A (D, C = C ()) { }
+  R operator () (...);
+};
+
+template <typename R, typename ... S, typename T>
+auto operator >> (A <R (S ...)>, T)->A <R (S ...)>
+{
+  []() {};
+}
+
+int
+main ()
+{
+  A <int (int, int)> a = [](int, int) {};
+  auto b = []{};
+  (a >> b) (3, 5);
+}