Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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