When substituting one pack expansion into another, we try to simplify the expansion by substituting one pattern into the other, but this doesn't work in this case, because the argument expansion is partially instantiated (the enclosing class template's parms are bound, but not the member template's) and therefore the expansion has extra args attached that we can't throw away. It would probably be possible to propagate the extra args to the resulting substituted expansion, but it's simpler not to try to do the expansion.

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


commit 39ee96b66659979cfdfa54117343b69903d210b0
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Jun 5 14:28:34 2015 -0400

    	PR c++/66405
    	* pt.c (argument_pack_element_is_expansion_p): Return 2 if
    	the expansion has extra args.
    	(use_pack_expansion_extra_args_p): Return true in that case.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 87b35fa..4a9fff0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9740,16 +9740,22 @@ make_fnparm_pack (tree spec_parm)
   return extract_fnparm_pack (NULL_TREE, &spec_parm);
 }
 
-/* Return true iff the Ith element of the argument pack ARG_PACK is a
-   pack expansion.  */
+/* Return 1 if the Ith element of the argument pack ARG_PACK is a
+   pack expansion with no extra args, 2 if it has extra args, or 0
+   if it is not a pack expansion.  */
 
-static bool
+static int
 argument_pack_element_is_expansion_p (tree arg_pack, int i)
 {
   tree vec = ARGUMENT_PACK_ARGS (arg_pack);
   if (i >= TREE_VEC_LENGTH (vec))
-    return false;
-  return PACK_EXPANSION_P (TREE_VEC_ELT (vec, i));
+    return 0;
+  tree elt = TREE_VEC_ELT (vec, i);
+  if (!PACK_EXPANSION_P (elt))
+    return 0;
+  if (PACK_EXPANSION_EXTRA_ARGS (elt))
+    return 2;
+  return 1;
 }
 
 
@@ -9799,7 +9805,12 @@ use_pack_expansion_extra_args_p (tree parm_packs,
 	{
 	  tree arg = TREE_VALUE (parm_pack);
 
-	  if (argument_pack_element_is_expansion_p (arg, i))
+	  int exp = argument_pack_element_is_expansion_p (arg, i);
+	  if (exp == 2)
+	    /* We can't substitute a pack expansion with extra args into
+	       our pattern.  */
+	    return true;
+	  else if (exp)
 	    has_expansion_arg = true;
 	  else
 	    has_non_expansion_arg = true;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-alias1.C b/gcc/testsuite/g++.dg/cpp0x/variadic-alias1.C
new file mode 100644
index 0000000..e931bc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-alias1.C
@@ -0,0 +1,13 @@
+// PR c++/66405
+// { dg-do compile { target c++11 } }
+
+template <typename T, T...> struct B;
+template <bool... Bools> using and_c = B<bool, +Bools...>;
+template <typename T, typename U> using Constructible = int;
+template <typename... Ts> struct common_tuple {
+  template <typename... Us,
+	    typename = and_c<Constructible<Ts, Us>{}...> >
+    common_tuple();
+  void foo();
+};
+template <> void common_tuple<>::foo(){}

Reply via email to