Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2013-01-21 Thread Jason Merrill

On 01/21/2013 03:09 PM, Dodji Seketeli wrote:

+  ith_elem_is_expansion |=
+   PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack),
+   index));


Let's use argument_pack_element_is_expansion_p here, too.


+  /*  Do we need to use the PACK_EXPANSION_EXTRA_ARGS mechanism?  */
+  bool use_pack_expansion_extra_args =
+use_pack_expansion_extra_args_p (packs, len, unsubstituted_packs);
+
   /* We cannot expand this expansion expression, because we don't have
  all of the argument packs we need.  */
-  if (unsubstituted_packs)
+  if (use_pack_expansion_extra_args)


I think we don't need the variable anymore.


-  /* We could not find any argument packs that work.  */
-  if (len  0)
-return error_mark_node;


Let's replace this with an assert that len can't be 0.

OK with these changes.

Jason



Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2013-01-18 Thread Jason Merrill
Sorry it's taken so long for me to respond to this; I forgot about it 
over the holiday break.  The patch is in good shape now, just a few 
tweaks left:


On 12/19/2012 01:21 PM, Dodji Seketeli wrote:

+  tree aps;/* instance of ARGUMENT_PACK_SELECT
+  tree.  */


Odd comment formatting.


+  /* We could not find any argument packs that work, so we'll just
+ return an unsubstituted pack expansion.  The caller must be
+ prepared to deal with this.  */


I still find this comment confusing.  I think it would be more correct 
to say we'll just return a substituted pack expansion.


Also, it seems like the unsubstituted_packs code does what we want, so 
you could use that directly rather than change len.



+  if (unsubstituted_packs || use_pack_expansion_extra)
 {
-  if (real_packs)
+  if (use_pack_expansion_extra)


It seems like the outer if is redundant here.


+  /*  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.  */
+  if (has_bare_parameter_packs (t))
+t = make_pack_expansion (t);


Instead of walking through 't' here, I think it would be cheaper to 
remember if the pack element was a pack expansion.  In which case maybe 
we don't need to split out has_bare_parameter_packs.



+  if (len  0)
 {
+  for (i = 0; i  len; ++i)
{


The if seems redundant here, too.

Jason


Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-19 Thread Dodji Seketeli
How about the below?

gcc/cp/

* pt.c (argument_pack_element_is_expansion_p)
(make_argument_pack_select, use_pack_expansion_extra_args_p)
(gen_elem_of_pack_expansion_instantiation): New static functions.
(has_bare_parameter_packs): Factorized out of ...
(check_for_bare_parameter_packs): ... here.
(tsubst): When looking through an ARGUMENT_PACK_SELECT tree node,
look through the possibly resulting pack expansion as well.
(tsubst_pack_expansion): Use use_pack_expansion_extra_p to
generalize when to use the PACK_EXPANSION_EXTRA_ARGS mechanism.
Use gen_elem_of_pack_expansion_instantiation to build the
instantiation piece-wise.  Don't use arg_from_parm_pack_p anymore,
as gen_elem_of_pack_expansion_instantiation and the change in
tsubst above generalize this particular case.
(arg_from_parm_pack_p): Remove this for it's not used by
tsubst_pack_expansion anymore.

gcc/testsuite/

* g++.dg/cpp0x/variadic139.C: New test.
* g++.dg/cpp0x/variadic140.C: Likewise.
* g++.dg/cpp0x/variadic141.C: Likewise.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ecb013e..313f7a4 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -201,7 +201,6 @@ static void append_type_to_template_for_access_check_1 
(tree, tree, tree,
 static tree listify (tree);
 static tree listify_autos (tree, tree);
 static tree template_parm_to_arg (tree t);
-static bool arg_from_parm_pack_p (tree, tree);
 static tree current_template_args (void);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
 static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
@@ -3308,6 +3307,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
@@ -3325,19 +3347,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) 
 {
@@ -3812,42 +3822,6 @@ template_parm_to_arg (tree t)
   return t;
 }
 
-/* This function returns TRUE if PARM_PACK is a template parameter
-   pack and if ARG_PACK is what template_parm_to_arg returned when
-   passed PARM_PACK.  */
-
-static bool
-arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
-{
-  /* For clarity in the comments below let's use the representation
- argument_packelements' to denote an argument pack and its
- elements.
-
- In the 'if' block below, we want to detect cases where
- ARG_PACK is argument_packPARM_PACK  I.e, we want to
- check if ARG_PACK is an argument pack which sole element is
- the expansion of PARM_PACK.  That argument pack is typically
- created by template_parm_to_arg when passed a parameter
- pack.  */
-
-  if (arg_pack
-   TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
-   PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0)))
-{
-  tree expansion = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0);
-  tree pattern = PACK_EXPANSION_PATTERN (expansion);
-  if ((TYPE_P (pattern)  same_type_p (pattern, parm_pack))
- || (!TYPE_P (pattern)  cp_tree_equal (parm_pack, pattern)))
-   /* The argument pack that the parameter maps to is just an
-  expansion of the parameter itself, such as one would
-  find in the implicit typedef of a class inside the
-  class itself.  Consider this parameter unsubstituted,
-  so that we will maintain the outer pack expansion.  */
-   return true;
-}
-  return false;
-}
-
 /* Given a set of template parameters, return them as a set of template
arguments.  The template parameters are represented as a TREE_VEC, in
the form documented in 

[PING] Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-17 Thread Dodji Seketeli
Ping?

---BeginMessage---
Jason Merrill ja...@redhat.com writes:

 On 12/08/2012 05:12 PM, Dodji Seketeli wrote:
  +  else if (arg_from_pack_level_to_prune || has_empty_arg)
  +{
  +  /* ... we just return a pack expansion which pattern is PATTERN
  +  into which ARGS has been substituted.  */
  +  *instantiation_yields_no_list_p = true;
  +}
 
  Though I think it would still be appropriate to keep this 'if' just to
  avoid going into the 'else' block for cases where we know that looping
  over the parameter packs (and do the ARGUMENT_PACK_SELECT dance) is
  unnecessary; all we want is to go straight to the point where we
  substitute args into the pattern, build a pack expansion and return
  it.  Or isn't what you meant?
 
 I suppose we should keep this for has_empty_arg, but I'd like to do
 away with special handling of the arg_from_parm_pack case if possible,
 as it's a lot of extra complexity.

OK, done.

 
  My understanding is that in practise, we never hit this point in the
  previous code.  The reason why len would still be negative at this
  point would be if we didn't find any (good) argument pack.  But in
  that case, we would have considered that we have unsubstituted packs
  and would have returned an unsubstituted pack expansion before we
  reach this point.
 
 I don't see that; in the old code, if there are unsubstituted packs we
 tsubst the args into the pattern.

Yes, and we build and return a pack expansion with that pattern.
That's what I meant clumsily by unsubstituted pack expansion.  I
should have probably said uninstantiated.

So, all this to say that we never return error_mark_node for the case
where len  0 in practise.  Do you agree?

 
  +  /* We got some full packs, but we can't substitute them in until we
  +have values for all the packs.  So remember these until then.  */
 
 How can having this in gen_elem_of_pack_expansion_instantiation could
 work?  We don't want an expansion for each element of the packs that
 we have.

Oops, it seems I was too hasty in trying to do away with the
instantiation_yields_no_list_p parameter to
gen_elem_of_pack_expansion_instantiation.  That is, whenever we are in
this case we must return just one expansion, as you noted.  So I am
putting back a way for gen_elem_of_pack_expansion_instantiation to
notify its caller that it needs to return the uninstantiated pack
expansion right away.

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

gcc/cp/

* pt.c (argument_pack_element_is_expansion_p)
(make_argument_pack_select, scan_parm_packs)
(gen_elem_of_pack_expansion_instantiation): New static functions.
(has_bare_parameter_packs): Factorized out of ...
(check_for_bare_parameter_packs): ... here.
(tsubst): When looking through an ARGUMENT_PACK_SELECT tree node,
look through the possibly resulting pack expansion as well.
(tsubst_pack_expansion): Now this function is clearly organized in
two parts: a part that maps each parameter pack with its matching
argument pack, and a part that walks that map to build the result
of substituting each element of the argument packs into the
parameter packs.  Use gen_elem_of_pack_expansion_instantiation for
the latter part.

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  | 473 +--
 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, 387 insertions(+), 144 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 ecb013e..663d46a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3308,6 +3308,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
@@ -3325,19 +3348,7 @@ make_pack_expansion 

Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-12 Thread Dodji Seketeli
Jason Merrill ja...@redhat.com writes:


 I'd also like to move the scan and PACK_EXPANSION_EXTRA_ARGS code back
 out of the loop.

Like this?

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

gcc/cp/

* pt.c (argument_pack_element_is_expansion_p)
(make_argument_pack_select, scan_parm_packs_and_args)
(gen_elem_of_pack_expansion_instantiation): New static functions.
(has_bare_parameter_packs): Factorized out of ...
(check_for_bare_parameter_packs): ... here.
(tsubst): When looking through an ARGUMENT_PACK_SELECT tree node,
look through the possibly resulting pack expansion as well.
(tsubst_pack_expansion): Now this function is clearly organized in
two parts: a part that maps each parameter pack with its matching
argument pack, and a part that walks that map to build the result
of substituting each element of the argument packs into the
parameter packs.  Use gen_elem_of_pack_expansion_instantiation for
the latter part.
(arg_from_parm_pack_p): Remove this for it's not used by
tsubst_pack_expansion anymore.

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  | 485 ---
 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, 366 insertions(+), 177 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 ecb013e..221323c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -201,7 +201,6 @@ static void append_type_to_template_for_access_check_1 
(tree, tree, tree,
 static tree listify (tree);
 static tree listify_autos (tree, tree);
 static tree template_parm_to_arg (tree t);
-static bool arg_from_parm_pack_p (tree, tree);
 static tree current_template_args (void);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
 static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
@@ -3308,6 +3307,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
@@ -3325,19 +3347,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) 
 {
@@ -3812,42 +3822,6 @@ template_parm_to_arg (tree t)
   return t;
 }
 
-/* This function returns TRUE if PARM_PACK is a template parameter
-   pack and if ARG_PACK is what template_parm_to_arg returned when
-   passed PARM_PACK.  */
-
-static bool
-arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
-{
-  /* For clarity in the comments below let's use the representation
- argument_packelements' to denote an argument pack and its
- elements.
-
- In the 'if' block below, we want to detect cases where
- ARG_PACK is argument_packPARM_PACK  I.e, we want to
- check if ARG_PACK is an argument pack which sole element is
- the expansion of PARM_PACK.  That argument pack is typically
- created by template_parm_to_arg when passed a parameter
- pack.  */
-
-  if (arg_pack
-   TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
-   PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0)))
-{
-  tree expansion = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0);
-  tree pattern = PACK_EXPANSION_PATTERN (expansion);
-  if ((TYPE_P (pattern)  same_type_p (pattern, parm_pack))
- || 

Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-11 Thread Dodji Seketeli
Jason Merrill ja...@redhat.com writes:

 On 12/08/2012 05:12 PM, Dodji Seketeli wrote:
  +  else if (arg_from_pack_level_to_prune || has_empty_arg)
  +{
  +  /* ... we just return a pack expansion which pattern is PATTERN
  +  into which ARGS has been substituted.  */
  +  *instantiation_yields_no_list_p = true;
  +}
 
  Though I think it would still be appropriate to keep this 'if' just to
  avoid going into the 'else' block for cases where we know that looping
  over the parameter packs (and do the ARGUMENT_PACK_SELECT dance) is
  unnecessary; all we want is to go straight to the point where we
  substitute args into the pattern, build a pack expansion and return
  it.  Or isn't what you meant?
 
 I suppose we should keep this for has_empty_arg, but I'd like to do
 away with special handling of the arg_from_parm_pack case if possible,
 as it's a lot of extra complexity.

OK, done.

 
  My understanding is that in practise, we never hit this point in the
  previous code.  The reason why len would still be negative at this
  point would be if we didn't find any (good) argument pack.  But in
  that case, we would have considered that we have unsubstituted packs
  and would have returned an unsubstituted pack expansion before we
  reach this point.
 
 I don't see that; in the old code, if there are unsubstituted packs we
 tsubst the args into the pattern.

Yes, and we build and return a pack expansion with that pattern.
That's what I meant clumsily by unsubstituted pack expansion.  I
should have probably said uninstantiated.

So, all this to say that we never return error_mark_node for the case
where len  0 in practise.  Do you agree?

 
  +  /* We got some full packs, but we can't substitute them in until we
  +have values for all the packs.  So remember these until then.  */
 
 How can having this in gen_elem_of_pack_expansion_instantiation could
 work?  We don't want an expansion for each element of the packs that
 we have.

Oops, it seems I was too hasty in trying to do away with the
instantiation_yields_no_list_p parameter to
gen_elem_of_pack_expansion_instantiation.  That is, whenever we are in
this case we must return just one expansion, as you noted.  So I am
putting back a way for gen_elem_of_pack_expansion_instantiation to
notify its caller that it needs to return the uninstantiated pack
expansion right away.

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

gcc/cp/

* pt.c (argument_pack_element_is_expansion_p)
(make_argument_pack_select, scan_parm_packs)
(gen_elem_of_pack_expansion_instantiation): New static functions.
(has_bare_parameter_packs): Factorized out of ...
(check_for_bare_parameter_packs): ... here.
(tsubst): When looking through an ARGUMENT_PACK_SELECT tree node,
look through the possibly resulting pack expansion as well.
(tsubst_pack_expansion): Now this function is clearly organized in
two parts: a part that maps each parameter pack with its matching
argument pack, and a part that walks that map to build the result
of substituting each element of the argument packs into the
parameter packs.  Use gen_elem_of_pack_expansion_instantiation for
the latter part.

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  | 473 +--
 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, 387 insertions(+), 144 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 ecb013e..663d46a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3308,6 +3308,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
@@ -3325,19 +3348,7 @@ make_pack_expansion (tree arg)
 bool 
 

Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-11 Thread Jason Merrill

On 12/11/2012 10:55 AM, Dodji Seketeli wrote:

Oops, it seems I was too hasty in trying to do away with the
instantiation_yields_no_list_p parameter to
gen_elem_of_pack_expansion_instantiation.


I still think that the elem function should just deal with the single 
element case; the cases where we can't do a piecewise substitution 
should be handled outside the elem function.



I suppose we should keep this for has_empty_arg, but I'd like to do
away with special handling of the arg_from_parm_pack case if possible,
as it's a lot of extra complexity.


OK, done.


Looks like you only removed the check from that one if; I'd like to do 
away with the arg_from_parm_pack function entirely if we can.


Jason



Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-11 Thread Dodji Seketeli
Jason Merrill ja...@redhat.com writes:

 On 12/11/2012 10:55 AM, Dodji Seketeli wrote:
 Oops, it seems I was too hasty in trying to do away with the
 instantiation_yields_no_list_p parameter to
 gen_elem_of_pack_expansion_instantiation.

 I still think that the elem function should just deal with the single
 element case; the cases where we can't do a piecewise substitution
 should be handled outside the elem function.

Like in the patch below?


 I suppose we should keep this for has_empty_arg, but I'd like to do
 away with special handling of the arg_from_parm_pack case if possible,
 as it's a lot of extra complexity.

 OK, done.

 Looks like you only removed the check from that one if; I'd like to do
 away with the arg_from_parm_pack function entirely if we can.

OK.  The below should hopefully approach what you have in mind.


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

gcc/cp/

* pt.c (argument_pack_element_is_expansion_p)
(make_argument_pack_select, scan_parm_packs_and_args)
(gen_elem_of_pack_expansion_instantiation): New static functions.
(has_bare_parameter_packs): Factorized out of ...
(check_for_bare_parameter_packs): ... here.
(tsubst): When looking through an ARGUMENT_PACK_SELECT tree node,
look through the possibly resulting pack expansion as well.
(tsubst_pack_expansion): Now this function is clearly organized in
two parts: a part that maps each parameter pack with its matching
argument pack, and a part that walks that map to build the result
of substituting each element of the argument packs into the
parameter packs.  Use gen_elem_of_pack_expansion_instantiation for
the latter part.
(arg_from_parm_pack_p): Remove this for it's not used by
tsubst_pack_expansion anymore.

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  | 487 ---
 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, 370 insertions(+), 175 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 ecb013e..14914d5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -201,7 +201,6 @@ static void append_type_to_template_for_access_check_1 
(tree, tree, tree,
 static tree listify (tree);
 static tree listify_autos (tree, tree);
 static tree template_parm_to_arg (tree t);
-static bool arg_from_parm_pack_p (tree, tree);
 static tree current_template_args (void);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
 static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
@@ -3308,6 +3307,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
@@ -3325,19 +3347,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) 
 {
@@ -3812,42 +3822,6 @@ template_parm_to_arg (tree t)
   return t;
 }
 
-/* This function returns TRUE if PARM_PACK is a template parameter
-   pack and if ARG_PACK is what template_parm_to_arg returned when
-   passed PARM_PACK.  */
-
-static bool
-arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
-{
-  /* For clarity in the comments below let's use the representation
- argument_packelements' to denote an argument pack and its
- elements.
-
- 

Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-11 Thread Jason Merrill

On 12/11/2012 04:09 PM, Dodji Seketeli wrote:

OK.  The below should hopefully approach what you have in mind.


Thanks, that's closer to what I was thinking.  I'd also like to move the 
scan and PACK_EXPANSION_EXTRA_ARGS code back out of the loop.


Jason



Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-10 Thread Jason Merrill

On 12/08/2012 05:12 PM, Dodji Seketeli wrote:

+  else if (arg_from_pack_level_to_prune || has_empty_arg)
+{
+  /* ... we just return a pack expansion which pattern is PATTERN
+into which ARGS has been substituted.  */
+  *instantiation_yields_no_list_p = true;
+}



Though I think it would still be appropriate to keep this 'if' just to
avoid going into the 'else' block for cases where we know that looping
over the parameter packs (and do the ARGUMENT_PACK_SELECT dance) is
unnecessary; all we want is to go straight to the point where we
substitute args into the pattern, build a pack expansion and return
it.  Or isn't what you meant?


I suppose we should keep this for has_empty_arg, but I'd like to do away 
with special handling of the arg_from_parm_pack case if possible, as 
it's a lot of extra complexity.



My understanding is that in practise, we never hit this point in the
previous code.  The reason why len would still be negative at this
point would be if we didn't find any (good) argument pack.  But in
that case, we would have considered that we have unsubstituted packs
and would have returned an unsubstituted pack expansion before we
reach this point.


I don't see that; in the old code, if there are unsubstituted packs we 
tsubst the args into the pattern.



+  /* We got some full packs, but we can't substitute them in until we
+have values for all the packs.  So remember these until then.  */


How can having this in gen_elem_of_pack_expansion_instantiation could 
work?  We don't want an expansion for each element of the packs that we 
have.


Jason



Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-08 Thread Dodji Seketeli
Jason Merrill ja...@redhat.com writes:

 On 12/03/2012 08:27 AM, Dodji Seketeli wrote:
  +   - HAS_EXPANSION_ARG_P: Set to TRUE iff at least one parameter
  + pack has got an argument that is an expansion.
 
 The got is unnecessary, just has an argument is better.

Removed, thanks.

  +   Setup APS, which is an instance of an ARGUMENT_PACK_SELECT tree, so
  +   that it selects the Ith element out of the argument pack ARG_PACK.
  +   If the Ith element is a pack expansion, then just select its
  +   pattern.  Otherwise, select the whole element.
 
 I wonder if, rather than set up a temporary pack at this point, it
 makes sense to look through pack expansions when we use an
 ARGUMENT_PACK_SELECT.

Yeah, good point.

 Is there any case where we actually want an ARGUMENT_PACK_SELECT to
 be an expansion?

I did the change to look through pack expansions in tsubst and nothing
in the testsuite seems to be wanting an ARGUMENT_PACK_SELECT to
resolve to an expansion.

 
  +  /* If we have one parameter pack whose matching argument pack is
  + just what template_parm_to_arg returned when passed the
  + parameter pack, or if we only have empty arguments ... */
  +  else if (arg_from_pack_level_to_prune || has_empty_arg)
  +{
  +  /* ... we just return a pack expansion which pattern is PATTERN
  +into which ARGS has been substituted.  */
  +  *instantiation_yields_no_list_p = true;
  +}
 
 I was thinking we wouldn't need to recognize this case specifically,
 that the code following it would work the way we want.  If callers get
 a vector with a single pack expansion element rather than just a pack
 expansion, is that a problem?  Alternately, if len == 1, maybe we
 should always just return the single element.

Right, I made the change to do away with the need of the
instantiation_yields_no_list_p variable.

Though I think it would still be appropriate to keep this 'if' just to
avoid going into the 'else' block for cases where we know that looping
over the parameter packs (and do the ARGUMENT_PACK_SELECT dance) is
unnecessary; all we want is to go straight to the point where we
substitute args into the pattern, build a pack expansion and return
it.  Or isn't what you meant?

 
  +  /* We could not find any argument packs that work, so we'll just
  + return an unsubstituted pack expansion.  The caller must be
  + prepared to deal with this.  */
 if (len  0)
  -return error_mark_node;
  +len = 1;
 
 Why this change?  Why is returning error_mark_node no longer the right
 thing to do?

My understanding is that in practise, we never hit this point in the
previous code.  The reason why len would still be negative at this
point would be if we didn't find any (good) argument pack.  But in
that case, we would have considered that we have unsubstituted packs
and would have returned an unsubstituted pack expansion before we
reach this point.  So I believe this new code follows the same logic.
Am I missing something?  Also, I just tried returning error_mark_node,
(just to make sure) and it broke quite some tests of the suite.


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

gcc/cp/

* pt.c (argument_pack_element_is_expansion_p)
(make_argument_pack_select, scan_parm_packs)
(gen_elem_of_pack_expansion_instantiation): New static functions.
(has_bare_parameter_packs): Factorized out of ...
(check_for_bare_parameter_packs): ... here.
(tsubst): When looking through an ARGUMENT_PACK_SELECT tree node,
look through the possibly resulting pack expansion as well.
(tsubst_pack_expansion): Now this function is clearly organized in
two parts: a part that maps each parameter pack with its matching
argument pack, and a part that walks that map to build the result
of substituting each element of the argument packs into the
parameter packs.  Use gen_elem_of_pack_expansion_instantiation for
the latter part.

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  | 459 +--
 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, 373 insertions(+), 144 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 ecb013e..1436721 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3308,6 +3308,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 

Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-05 Thread Jason Merrill

On 12/03/2012 08:27 AM, Dodji Seketeli wrote:

+   - HAS_EXPANSION_ARG_P: Set to TRUE iff at least one parameter
+ pack has got an argument that is an expansion.


The got is unnecessary, just has an argument is better.


+   Setup APS, which is an instance of an ARGUMENT_PACK_SELECT tree, so
+   that it selects the Ith element out of the argument pack ARG_PACK.
+   If the Ith element is a pack expansion, then just select its
+   pattern.  Otherwise, select the whole element.


I wonder if, rather than set up a temporary pack at this point, it makes 
sense to look through pack expansions when we use an 
ARGUMENT_PACK_SELECT.  Is there any case where we actually want an 
ARGUMENT_PACK_SELECT to be an expansion?



+  /* If we have one parameter pack whose matching argument pack is
+ just what template_parm_to_arg returned when passed the
+ parameter pack, or if we only have empty arguments ... */
+  else if (arg_from_pack_level_to_prune || has_empty_arg)
+{
+  /* ... we just return a pack expansion which pattern is PATTERN
+into which ARGS has been substituted.  */
+  *instantiation_yields_no_list_p = true;
+}


I was thinking we wouldn't need to recognize this case specifically, 
that the code following it would work the way we want.  If callers get a 
vector with a single pack expansion element rather than just a pack 
expansion, is that a problem?  Alternately, if len == 1, maybe we should 
always just return the single element.



+  /* We could not find any argument packs that work, so we'll just
+ return an unsubstituted pack expansion.  The caller must be
+ prepared to deal with this.  */
   if (len  0)
-return error_mark_node;
+len = 1;


Why this change?  Why is returning error_mark_node no longer the right 
thing to do?


Jason



Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-12-03 Thread Dodji Seketeli
Jason Merrill ja...@redhat.com writes:

 It seems like your new code is a generalization of the old code for
 handling substitution of a pack for itself (arg_from_parm_pack and
 such) and the code for handling other packs with a single pack
 expansion argument, and should replace those rather than adding on.

I guess that can of worms is now open.  :-)

I tried to think about how to do this properly.  What I came up with
in the patch below is to properly organize tsubst_pack_expansion in
two parts that are already screaming to emerge, IMHO.  The first part
maps each parameter pack with its matching argument pack, and does
only that.  The second part walks that map and builds the list of Ei
where each Ei is the result of substituting elements at index I in the
argument packs into the pattern of the expansion passed to
tsubst_pack_expansion.

It's only the latter part knows how to deal with special cases like:
  - some parameter packs having no matching argument pack
  - parameter packs having matching argument packs element that are
  expansions
  - etc

Is that what you had in mind?

 The solution that if at a certain index all the packs have expansion
 arguments then the substitution produces a pack expansion seems right
 to me, but if one pack has an expansion and another pack has a normal
 argument, we can't do the substitution and need to fall back on the
 PACK_EXPANSION_EXTRA_ARGS mechanism.

Right, this is hopefully what this updated patch implements.

  +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))
 
 I don't think we care if *any* element is an expansion (and please
 talk about expansions rather than non-real elements).  What we care
 about is whether the i'th element is an expansion.  And we need to
 compare all the pack elements, so I think this needs to be handled in
 the main function rather than encapsulated here.

Done.

 
  +   TREE_VEC_ELT (args_vec, i) =
  + TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), i);
 
 Aren't the LHS and RHS the same location here?

Yes, this is hopefully dropped now.

Bootstrapped and tested against trunk on x86_64-unknown-linux-gnu.

gcc/cp/

* pt.c (argument_pack_element_is_expansion_p)
(arg_pack_select_for_pack_expansion)
(set_arg_pack_select_index_for_pack_expansion, scan_parm_packs)
(gen_elem_of_pack_expansion_instantiation): New static functions.
(has_bare_parameter_packs): Factorized out of ...
(check_for_bare_parameter_packs): ... here.
(tsubst_pack_expansion): Now this function is clearly organized in
two parts: a part that maps each parameter pack with its matching
argument pack, and a part that walks that map to build the result
of the substituting each element of the argument packs into the
parameter packs.  Use gen_elem_of_pack_expansion_instantiation for
the latter part.

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  | 525 ++-
 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, 441 insertions(+), 142 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 ecb013e..b8f4294 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3308,6 +3308,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
@@ -3325,19 +3348,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 

[PING] [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-11-16 Thread Dodji Seketeli
I am friendly pinging the patch below ...


Dodji Seketeli do...@redhat.com a écrit:

 Hello,

 Consider this example:

  1templateclass...I struct List {};
  2templateint T struct Z {static const int value = T;};
  3templateint...T using LZ = ListZT...;
  4
  5templateclass...U
  6struct F
  7{
  8  using N = LZU::value...; //#1 This should amount to 
 ListZU::value...
  9}
 10
 11FZ1, Z2 ::N A; //#2

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

 test-PR53609-3.cc: In instantiation of 'struct FZ1, Z2 ':
 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)
  templateint...T using LZ = ListZT...;
^
 test-PR53609-3.cc:2:24: error: provided for 'templateint T struct Z'
  templateint 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 ZT..., tsubst_pack_expansion
 yields ZU::value..., instead of ZU::value..., so the instantiation
 of LZ amounts to ListZU::value... , instead of
 ListZU::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 

Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-11-16 Thread Jason Merrill
It seems like your new code is a generalization of the old code for 
handling substitution of a pack for itself (arg_from_parm_pack and such) 
and the code for handling other packs with a single pack expansion 
argument, and should replace those rather than adding on.


The solution that if at a certain index all the packs have expansion 
arguments then the substitution produces a pack expansion seems right to 
me, but if one pack has an expansion and another pack has a normal 
argument, we can't do the substitution and need to fall back on the 
PACK_EXPANSION_EXTRA_ARGS mechanism.



+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))


I don't think we care if *any* element is an expansion (and please talk 
about expansions rather than non-real elements).  What we care about 
is whether the i'th element is an expansion.  And we need to compare all 
the pack elements, so I think this needs to be handled in the main 
function rather than encapsulated here.



+   TREE_VEC_ELT (args_vec, i) =
+ TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), i);


Aren't the LHS and RHS the same location here?

Jason



[PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack

2012-09-20 Thread Dodji Seketeli
Hello,

Consider this example:

 1  templateclass...I struct List {};
 2  templateint T struct Z {static const int value = T;};
 3  templateint...T using LZ = ListZT...;
 4
 5  templateclass...U
 6  struct F
 7  {
 8using N = LZU::value...; //#1 This should amount to 
ListZU::value...
 9  }
10
11  FZ1, Z2 ::N A; //#2

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

test-PR53609-3.cc: In instantiation of 'struct FZ1, Z2 ':
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)
 templateint...T using LZ = ListZT...;
   ^
test-PR53609-3.cc:2:24: error: provided for 'templateint T struct Z'
 templateint 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 ZT..., tsubst_pack_expansion
yields ZU::value..., instead of ZU::value..., so the instantiation
of LZ amounts to ListZU::value... , instead of
ListZU::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