public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack
@ 2012-09-20  9:05 Dodji Seketeli
  2012-11-16 13:16 ` [PING] " Dodji Seketeli
  2012-11-16 22:39 ` Jason Merrill
  0 siblings, 2 replies; 17+ messages in thread
From: Dodji Seketeli @ 2012-09-20  9:05 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jason Merrill

Hello,

Consider this example:

     1	template<class...I> struct List {};
     2	template<int T> struct Z {static const int value = T;};
     3	template<int...T> using LZ = List<Z<T>...>;
     4
     5	template<class...U>
     6	struct F
     7	{
     8	  using N = LZ<U::value...>; //#1 This should amount to List<Z<U::value>...>
     9	}
    10
    11	F<Z<1>, Z<2> >::N A; //#2

which G++ fails to compile, with this error message:

test-PR53609-3.cc: In instantiation of 'struct F<Z<1>, Z<2> >':
test-PR53609-3.cc:11:15:   required from here
test-PR53609-3.cc:3:43: error: wrong number of template arguments (2, should be 1)
 template<int...T> using LZ = List<Z<T>...>;
                                           ^
test-PR53609-3.cc:2:24: error: provided for 'template<int T> struct Z'
 template<int T> struct Z {static const int value = T;};

I think this is because in #1, when we substitute the argument pack
{U::value...} into the pack expansion Z<T>..., tsubst_pack_expansion
yields Z<U::value...>, instead of Z<U::value>..., so the instantiation
of LZ amounts to List<Z<U::value...> >, instead of
List<Z<U::value>...>.

The idea of this patch is to make tsubst_pack_expansion support
substituting an argument pack (into a pack expansion) where one of the
arguments (let's call it the Ith argument) is itself a pack expansion
P.  In that case, the Ith element resulting from the substituting
should be a pack expansion P'.

The pattern of P' is then the pattern of P into which the pattern of
the Ith argument of the argument pack has been substituted.

Tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	* pt.c (real_argument_pack_element_p)
	(any_non_real_argument_pack_element_p)
	(arg_pack_select_for_pack_expansion)
	(set_arg_pack_select_index_for_pack_expansion): New static
	functions.
	(has_bare_parameter_packs): Factorized out of ...
	(check_for_bare_parameter_packs): ... here.
	(tsubst_pack_expansion): Support substituting an argument pack
	that contains a pack expansion.

gcc/testsuite/

	* g++.dg/cpp0x/variadic139.C: New test.
	* g++.dg/cpp0x/variadic140.C: Likewise.
	* g++.dg/cpp0x/variadic141.C: Likewise.
---
 gcc/cp/pt.c                              |  151 ++++++++++++++++++++++++------
 gcc/testsuite/g++.dg/cpp0x/variadic139.C |   14 +++
 gcc/testsuite/g++.dg/cpp0x/variadic140.C |   22 +++++
 gcc/testsuite/g++.dg/cpp0x/variadic141.C |   22 +++++
 4 files changed, 182 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic139.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic140.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic141.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 16952bf..bcfe83f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3310,6 +3310,29 @@ make_pack_expansion (tree arg)
   return result;
 }
 
+/* Return NULL_TREE iff T contains *NO* unexpanded parameter packs.
+   Return the TREE_LIST of unexpanded parameter packs otherwise.  */
+
+static tree
+has_bare_parameter_packs (tree t)
+{
+  tree parameter_packs = NULL_TREE;
+  struct find_parameter_pack_data ppd;
+
+  if (!processing_template_decl || !t || t == error_mark_node)
+    return NULL_TREE;
+
+  if (TREE_CODE (t) == TYPE_DECL)
+    t = TREE_TYPE (t);
+
+  ppd.parameter_packs = &parameter_packs;
+  ppd.visited = pointer_set_create ();
+  cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
+  pointer_set_destroy (ppd.visited);
+
+  return parameter_packs;
+}
+
 /* Checks T for any "bare" parameter packs, which have not yet been
    expanded, and issues an error if any are found. This operation can
    only be done on full expressions or types (e.g., an expression
@@ -3327,19 +3350,7 @@ make_pack_expansion (tree arg)
 bool 
 check_for_bare_parameter_packs (tree t)
 {
-  tree parameter_packs = NULL_TREE;
-  struct find_parameter_pack_data ppd;
-
-  if (!processing_template_decl || !t || t == error_mark_node)
-    return false;
-
-  if (TREE_CODE (t) == TYPE_DECL)
-    t = TREE_TYPE (t);
-
-  ppd.parameter_packs = &parameter_packs;
-  ppd.visited = pointer_set_create ();
-  cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
-  pointer_set_destroy (ppd.visited);
+  tree parameter_packs = has_bare_parameter_packs (t);
 
   if (parameter_packs) 
     {
@@ -9065,6 +9076,86 @@ 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
+   *NOT* a pack expansion.  */
+
+static bool
+real_argument_pack_element_p (tree arg_pack, int i)
+{
+  return !PACK_EXPANSION_P (TREE_VEC_ELT
+			    (ARGUMENT_PACK_ARGS (arg_pack), i));
+}
+
+/* Return true iff ARG_PACK is an argument pack that contains a pack
+   expansion.  */
+
+static bool
+any_non_real_argument_pack_element_p (tree arg_pack)
+{
+  if (arg_pack == NULL_TREE
+      || arg_pack == error_mark_node
+      || !ARGUMENT_PACK_P (arg_pack))
+    return false;
+
+  for (int i = 0; i < TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)); ++i)
+    if (!real_argument_pack_element_p (arg_pack, i))
+      return true;
+  return false;
+}
+
+/* Creates an ARGUMENT_PACK_SELECT tree node, for the purpose of
+   substituting an argument pack into a pack expansion.  This is a
+   subroutine of tsubst_pack_expansion.   */
+
+static tree
+arg_pack_select_for_pack_expansion (tree arg_pack)
+{
+  tree aps = make_node (ARGUMENT_PACK_SELECT);
+
+  if (!any_non_real_argument_pack_element_p (arg_pack))
+    ARGUMENT_PACK_SELECT_FROM_PACK (aps) = arg_pack;
+  else
+    {
+      tree tmp_arg_pack = TYPE_P (arg_pack)
+	? cxx_make_type (TREE_CODE (arg_pack))
+	: make_node (TREE_CODE (arg_pack));
+      tree tmp_vec =
+	make_tree_vec (TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)));
+      SET_ARGUMENT_PACK_ARGS (tmp_arg_pack, tmp_vec);
+      ARGUMENT_PACK_SELECT_FROM_PACK (aps) = tmp_arg_pack;
+    }
+
+   return aps;
+}
+
+/* Setup APS, which is an instance of an ARGUMENT_PACK_SELECT tree, so
+   that it selects the Ith argument out of the argument pack
+   ARG_PACK.  If the Ith argument is a pack expansion, then just
+   select its pattern.  Otherwise, select the whole argument.  This
+   is a subroutine of tsubst_pack_expansion.  */
+
+static void
+set_arg_pack_select_index_for_pack_expansion (tree aps,
+					      int i,
+					      tree arg_pack)
+{
+  if (any_non_real_argument_pack_element_p (arg_pack))
+    {
+      tree args_vec =
+	ARGUMENT_PACK_ARGS (ARGUMENT_PACK_SELECT_FROM_PACK (aps));
+      if (real_argument_pack_element_p (arg_pack, i))
+	TREE_VEC_ELT (args_vec, i) =
+	  TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), i);
+      else
+	TREE_VEC_ELT (args_vec, i) =
+	  PACK_EXPANSION_PATTERN (TREE_VEC_ELT
+				  (ARGUMENT_PACK_ARGS (arg_pack),
+				   i));
+    }
+
+  ARGUMENT_PACK_SELECT_INDEX (aps) = i;
+}
+
 /* Substitute ARGS into T, which is an pack expansion
    (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a
    TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node
@@ -9284,20 +9375,21 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
       for (pack = packs; pack; pack = TREE_CHAIN (pack))
         {
           tree parm = TREE_PURPOSE (pack);
-	  tree arg;
+	  tree arg_pack = TREE_VALUE (pack);
+	  tree aps; 		/* instance of ARGUMENT_PACK_SELECT
+				   tree.  */
 
 	  /* Select the Ith argument from the pack.  */
           if (TREE_CODE (parm) == PARM_DECL)
             {
 	      if (i == 0)
 		{
-		  arg = make_node (ARGUMENT_PACK_SELECT);
-		  ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack);
+		  aps = arg_pack_select_for_pack_expansion (arg_pack);
 		  mark_used (parm);
-		  register_local_specialization (arg, parm);
+		  register_local_specialization (aps, parm);
 		}
 	      else
-		arg = retrieve_local_specialization (parm);
+		aps = retrieve_local_specialization (parm);
             }
           else
             {
@@ -9306,25 +9398,30 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 
 	      if (i == 0)
 		{
-		  arg = make_node (ARGUMENT_PACK_SELECT);
-		  ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack);
+		  aps = arg_pack_select_for_pack_expansion (arg_pack);
 		  /* Update the corresponding argument.  */
-		  TMPL_ARG (args, level, idx) = arg;
+		  TMPL_ARG (args, level, idx) = aps;
 		}
 	      else
 		/* Re-use the ARGUMENT_PACK_SELECT.  */
-		arg = TMPL_ARG (args, level, idx);
+		aps = TMPL_ARG (args, level, idx);
             }
-	  ARGUMENT_PACK_SELECT_INDEX (arg) = i;
+	  set_arg_pack_select_index_for_pack_expansion (aps, i,
+							arg_pack);
         }
 
       /* Substitute into the PATTERN with the altered arguments.  */
       if (!TYPE_P (pattern))
-        TREE_VEC_ELT (result, i) = 
-          tsubst_expr (pattern, args, complain, in_decl,
-                       /*integral_constant_expression_p=*/false);
+	t = tsubst_expr (pattern, args, complain, in_decl,
+			 /*integral_constant_expression_p=*/false);
       else
-        TREE_VEC_ELT (result, i) = tsubst (pattern, args, complain, in_decl);
+	t = tsubst (pattern, args, complain, in_decl);
+
+      /*  If the Ith argument pack element is a pack expansion, then
+	  the Ith element resulting from the substituting is going to
+	  be a pack expansion as well.  */
+      TREE_VEC_ELT (result, i) =
+	(has_bare_parameter_packs (t)) ? make_pack_expansion (t) : t;
 
       if (TREE_VEC_ELT (result, i) == error_mark_node)
 	{
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic139.C b/gcc/testsuite/g++.dg/cpp0x/variadic139.C
new file mode 100644
index 0000000..89f7b32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic139.C
@@ -0,0 +1,14 @@
+// Origin: PR c++/53609
+// { dg-do compile { target c++11 } }
+
+template<class...I> struct List {};
+template<int T> struct Z {static const int value = T;};
+template<int...T> using LZ = List<Z<T>...>;
+
+template<class...U>
+struct F
+{
+  using N = LZ<U::value...>;
+};                           
+
+F<Z<1>, Z<2> >::N A;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic140.C b/gcc/testsuite/g++.dg/cpp0x/variadic140.C
new file mode 100644
index 0000000..17ca9e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic140.C
@@ -0,0 +1,22 @@
+// Origin: PR c++/53609
+// { dg-do compile { target c++11 } }
+
+template<class...I> struct List{ static const bool is_ok = false;};
+template<int T> struct Z
+{
+  static const int value = T;
+  static const int value_square = T * T;
+};
+
+template<template<int> class U>
+struct List<U<2>, U<3>, U<4>, U<9>> { static const bool is_ok = true;};
+
+template<int...T> using LZ = List<Z<T>...>;
+
+template<class...T>
+struct F
+{
+  using N = LZ<T::value..., T::value_square...>;
+};
+
+static_assert (F<Z<2>, Z<3>>::N::is_ok, "");
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic141.C b/gcc/testsuite/g++.dg/cpp0x/variadic141.C
new file mode 100644
index 0000000..6b893a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic141.C
@@ -0,0 +1,22 @@
+// Origin: PR c++/53609
+// { dg-do compile { target c++11 } }
+
+template<class...I> struct List{ static const bool is_ok = false;};
+template<int T> struct Z
+{
+  static const int value = T;
+  static const int value_square = T * T;
+};
+
+template<template<int> class U>
+struct List<U<2>, U<3>, U<4>, U<9>> { static const bool is_ok = true;};
+
+template<int...T> using LZ = List<Z<T>...>;
+
+template<class...T>
+struct F
+{
+  using N = LZ<T::value..., Z<4>::value, Z<9>::value>;
+};
+
+static_assert (F<Z<2>, Z<3>>::N::is_ok, "");
-- 
		Dodji

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2013-01-21 20:44 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-20  9:05 [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack Dodji Seketeli
2012-11-16 13:16 ` [PING] " Dodji Seketeli
2012-11-16 22:39 ` Jason Merrill
2012-12-03 13:28   ` Dodji Seketeli
2012-12-05 16:01     ` Jason Merrill
2012-12-08 22:12       ` Dodji Seketeli
2012-12-10 22:38         ` Jason Merrill
2012-12-11 15:55           ` Dodji Seketeli
2012-12-11 16:40             ` Jason Merrill
2012-12-11 21:10               ` Dodji Seketeli
2012-12-11 21:26                 ` Jason Merrill
2012-12-12 13:28                   ` Dodji Seketeli
2012-12-17 19:03                     ` Jason Merrill
2012-12-19 18:21                       ` Dodji Seketeli
2013-01-19  1:49                         ` Jason Merrill
2013-01-21 20:09                           ` Dodji Seketeli
2013-01-21 20:44                             ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).