I am friendly pinging the patch below ...

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

> Hello,
>
> Consider this example:
>
>      1        template<class...I> struct List {};
>      2        template<int T> struct Z {static const int value = T;};
>      3        template<int...T> using LZ = List<Z<T>...>;
>      4
>      5        template<class...U>
>      6        struct F
>      7        {
>      8          using N = LZ<U::value...>; //#1 This should amount to 
> List<Z<U::value>...>
>      9        }
>     10
>     11        F<Z<1>, Z<2> >::N A; //#2
>
> which G++ fails to compile, with this error message:
>
> test-PR53609-3.cc: In instantiation of 'struct F<Z<1>, Z<2> >':
> test-PR53609-3.cc:11:15:   required from here
> test-PR53609-3.cc:3:43: error: wrong number of template arguments (2, should 
> be 1)
>  template<int...T> using LZ = List<Z<T>...>;
>                                            ^
> test-PR53609-3.cc:2:24: error: provided for 'template<int T> struct Z'
>  template<int T> struct Z {static const int value = T;};
>
> I think this is because in #1, when we substitute the argument pack
> {U::value...} into the pack expansion Z<T>..., tsubst_pack_expansion
> yields Z<U::value...>, instead of Z<U::value>..., so the instantiation
> of LZ amounts to List<Z<U::value...> >, instead of
> List<Z<U::value>...>.
>
> The idea of this patch is to make tsubst_pack_expansion support
> substituting an argument pack (into a pack expansion) where one of the
> arguments (let's call it the Ith argument) is itself a pack expansion
> P.  In that case, the Ith element resulting from the substituting
> should be a pack expansion P'.
>
> The pattern of P' is then the pattern of P into which the pattern of
> the Ith argument of the argument pack has been substituted.
>
> Tested on x86_64-unknown-linux-gnu against trunk.
>
> gcc/cp/
>
>       * pt.c (real_argument_pack_element_p)
>       (any_non_real_argument_pack_element_p)
>       (arg_pack_select_for_pack_expansion)
>       (set_arg_pack_select_index_for_pack_expansion): New static
>       functions.
>       (has_bare_parameter_packs): Factorized out of ...
>       (check_for_bare_parameter_packs): ... here.
>       (tsubst_pack_expansion): Support substituting an argument pack
>       that contains a pack expansion.
>
> gcc/testsuite/
>
>       * g++.dg/cpp0x/variadic139.C: New test.
>       * g++.dg/cpp0x/variadic140.C: Likewise.
>       * g++.dg/cpp0x/variadic141.C: Likewise.
> ---
>  gcc/cp/pt.c                              |  151 
> ++++++++++++++++++++++++------
>  gcc/testsuite/g++.dg/cpp0x/variadic139.C |   14 +++
>  gcc/testsuite/g++.dg/cpp0x/variadic140.C |   22 +++++
>  gcc/testsuite/g++.dg/cpp0x/variadic141.C |   22 +++++
>  4 files changed, 182 insertions(+), 27 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic139.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic140.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic141.C
>
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 16952bf..bcfe83f 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -3310,6 +3310,29 @@ make_pack_expansion (tree arg)
>    return result;
>  }
>  
> +/* Return NULL_TREE iff T contains *NO* unexpanded parameter packs.
> +   Return the TREE_LIST of unexpanded parameter packs otherwise.  */
> +
> +static tree
> +has_bare_parameter_packs (tree t)
> +{
> +  tree parameter_packs = NULL_TREE;
> +  struct find_parameter_pack_data ppd;
> +
> +  if (!processing_template_decl || !t || t == error_mark_node)
> +    return NULL_TREE;
> +
> +  if (TREE_CODE (t) == TYPE_DECL)
> +    t = TREE_TYPE (t);
> +
> +  ppd.parameter_packs = &parameter_packs;
> +  ppd.visited = pointer_set_create ();
> +  cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
> +  pointer_set_destroy (ppd.visited);
> +
> +  return parameter_packs;
> +}
> +
>  /* Checks T for any "bare" parameter packs, which have not yet been
>     expanded, and issues an error if any are found. This operation can
>     only be done on full expressions or types (e.g., an expression
> @@ -3327,19 +3350,7 @@ make_pack_expansion (tree arg)
>  bool 
>  check_for_bare_parameter_packs (tree t)
>  {
> -  tree parameter_packs = NULL_TREE;
> -  struct find_parameter_pack_data ppd;
> -
> -  if (!processing_template_decl || !t || t == error_mark_node)
> -    return false;
> -
> -  if (TREE_CODE (t) == TYPE_DECL)
> -    t = TREE_TYPE (t);
> -
> -  ppd.parameter_packs = &parameter_packs;
> -  ppd.visited = pointer_set_create ();
> -  cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
> -  pointer_set_destroy (ppd.visited);
> +  tree parameter_packs = has_bare_parameter_packs (t);
>  
>    if (parameter_packs) 
>      {
> @@ -9065,6 +9076,86 @@ make_fnparm_pack (tree spec_parm)
>    return extract_fnparm_pack (NULL_TREE, &spec_parm);
>  }
>  
> +/* Return true iff the Ith element of the argument pack ARG_PACK is
> +   *NOT* a pack expansion.  */
> +
> +static bool
> +real_argument_pack_element_p (tree arg_pack, int i)
> +{
> +  return !PACK_EXPANSION_P (TREE_VEC_ELT
> +                         (ARGUMENT_PACK_ARGS (arg_pack), i));
> +}
> +
> +/* Return true iff ARG_PACK is an argument pack that contains a pack
> +   expansion.  */
> +
> +static bool
> +any_non_real_argument_pack_element_p (tree arg_pack)
> +{
> +  if (arg_pack == NULL_TREE
> +      || arg_pack == error_mark_node
> +      || !ARGUMENT_PACK_P (arg_pack))
> +    return false;
> +
> +  for (int i = 0; i < TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)); ++i)
> +    if (!real_argument_pack_element_p (arg_pack, i))
> +      return true;
> +  return false;
> +}
> +
> +/* Creates an ARGUMENT_PACK_SELECT tree node, for the purpose of
> +   substituting an argument pack into a pack expansion.  This is a
> +   subroutine of tsubst_pack_expansion.   */
> +
> +static tree
> +arg_pack_select_for_pack_expansion (tree arg_pack)
> +{
> +  tree aps = make_node (ARGUMENT_PACK_SELECT);
> +
> +  if (!any_non_real_argument_pack_element_p (arg_pack))
> +    ARGUMENT_PACK_SELECT_FROM_PACK (aps) = arg_pack;
> +  else
> +    {
> +      tree tmp_arg_pack = TYPE_P (arg_pack)
> +     ? cxx_make_type (TREE_CODE (arg_pack))
> +     : make_node (TREE_CODE (arg_pack));
> +      tree tmp_vec =
> +     make_tree_vec (TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)));
> +      SET_ARGUMENT_PACK_ARGS (tmp_arg_pack, tmp_vec);
> +      ARGUMENT_PACK_SELECT_FROM_PACK (aps) = tmp_arg_pack;
> +    }
> +
> +   return aps;
> +}
> +
> +/* Setup APS, which is an instance of an ARGUMENT_PACK_SELECT tree, so
> +   that it selects the Ith argument out of the argument pack
> +   ARG_PACK.  If the Ith argument is a pack expansion, then just
> +   select its pattern.  Otherwise, select the whole argument.  This
> +   is a subroutine of tsubst_pack_expansion.  */
> +
> +static void
> +set_arg_pack_select_index_for_pack_expansion (tree aps,
> +                                           int i,
> +                                           tree arg_pack)
> +{
> +  if (any_non_real_argument_pack_element_p (arg_pack))
> +    {
> +      tree args_vec =
> +     ARGUMENT_PACK_ARGS (ARGUMENT_PACK_SELECT_FROM_PACK (aps));
> +      if (real_argument_pack_element_p (arg_pack, i))
> +     TREE_VEC_ELT (args_vec, i) =
> +       TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), i);
> +      else
> +     TREE_VEC_ELT (args_vec, i) =
> +       PACK_EXPANSION_PATTERN (TREE_VEC_ELT
> +                               (ARGUMENT_PACK_ARGS (arg_pack),
> +                                i));
> +    }
> +
> +  ARGUMENT_PACK_SELECT_INDEX (aps) = i;
> +}
> +
>  /* Substitute ARGS into T, which is an pack expansion
>     (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a
>     TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node
> @@ -9284,20 +9375,21 @@ tsubst_pack_expansion (tree t, tree args, 
> tsubst_flags_t complain,
>        for (pack = packs; pack; pack = TREE_CHAIN (pack))
>          {
>            tree parm = TREE_PURPOSE (pack);
> -       tree arg;
> +       tree arg_pack = TREE_VALUE (pack);
> +       tree aps;             /* instance of ARGUMENT_PACK_SELECT
> +                                tree.  */
>  
>         /* Select the Ith argument from the pack.  */
>            if (TREE_CODE (parm) == PARM_DECL)
>              {
>             if (i == 0)
>               {
> -               arg = make_node (ARGUMENT_PACK_SELECT);
> -               ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack);
> +               aps = arg_pack_select_for_pack_expansion (arg_pack);
>                 mark_used (parm);
> -               register_local_specialization (arg, parm);
> +               register_local_specialization (aps, parm);
>               }
>             else
> -             arg = retrieve_local_specialization (parm);
> +             aps = retrieve_local_specialization (parm);
>              }
>            else
>              {
> @@ -9306,25 +9398,30 @@ tsubst_pack_expansion (tree t, tree args, 
> tsubst_flags_t complain,
>  
>             if (i == 0)
>               {
> -               arg = make_node (ARGUMENT_PACK_SELECT);
> -               ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack);
> +               aps = arg_pack_select_for_pack_expansion (arg_pack);
>                 /* Update the corresponding argument.  */
> -               TMPL_ARG (args, level, idx) = arg;
> +               TMPL_ARG (args, level, idx) = aps;
>               }
>             else
>               /* Re-use the ARGUMENT_PACK_SELECT.  */
> -             arg = TMPL_ARG (args, level, idx);
> +             aps = TMPL_ARG (args, level, idx);
>              }
> -       ARGUMENT_PACK_SELECT_INDEX (arg) = i;
> +       set_arg_pack_select_index_for_pack_expansion (aps, i,
> +                                                     arg_pack);
>          }
>  
>        /* Substitute into the PATTERN with the altered arguments.  */
>        if (!TYPE_P (pattern))
> -        TREE_VEC_ELT (result, i) = 
> -          tsubst_expr (pattern, args, complain, in_decl,
> -                       /*integral_constant_expression_p=*/false);
> +     t = tsubst_expr (pattern, args, complain, in_decl,
> +                      /*integral_constant_expression_p=*/false);
>        else
> -        TREE_VEC_ELT (result, i) = tsubst (pattern, args, complain, in_decl);
> +     t = tsubst (pattern, args, complain, in_decl);
> +
> +      /*  If the Ith argument pack element is a pack expansion, then
> +       the Ith element resulting from the substituting is going to
> +       be a pack expansion as well.  */
> +      TREE_VEC_ELT (result, i) =
> +     (has_bare_parameter_packs (t)) ? make_pack_expansion (t) : t;
>  
>        if (TREE_VEC_ELT (result, i) == error_mark_node)
>       {
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic139.C 
> b/gcc/testsuite/g++.dg/cpp0x/variadic139.C
> new file mode 100644
> index 0000000..89f7b32
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic139.C
> @@ -0,0 +1,14 @@
> +// Origin: PR c++/53609
> +// { dg-do compile { target c++11 } }
> +
> +template<class...I> struct List {};
> +template<int T> struct Z {static const int value = T;};
> +template<int...T> using LZ = List<Z<T>...>;
> +
> +template<class...U>
> +struct F
> +{
> +  using N = LZ<U::value...>;
> +};                           
> +
> +F<Z<1>, Z<2> >::N A;
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic140.C 
> b/gcc/testsuite/g++.dg/cpp0x/variadic140.C
> new file mode 100644
> index 0000000..17ca9e5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic140.C
> @@ -0,0 +1,22 @@
> +// Origin: PR c++/53609
> +// { dg-do compile { target c++11 } }
> +
> +template<class...I> struct List{ static const bool is_ok = false;};
> +template<int T> struct Z
> +{
> +  static const int value = T;
> +  static const int value_square = T * T;
> +};
> +
> +template<template<int> class U>
> +struct List<U<2>, U<3>, U<4>, U<9>> { static const bool is_ok = true;};
> +
> +template<int...T> using LZ = List<Z<T>...>;
> +
> +template<class...T>
> +struct F
> +{
> +  using N = LZ<T::value..., T::value_square...>;
> +};
> +
> +static_assert (F<Z<2>, Z<3>>::N::is_ok, "");
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic141.C 
> b/gcc/testsuite/g++.dg/cpp0x/variadic141.C
> new file mode 100644
> index 0000000..6b893a7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic141.C
> @@ -0,0 +1,22 @@
> +// Origin: PR c++/53609
> +// { dg-do compile { target c++11 } }
> +
> +template<class...I> struct List{ static const bool is_ok = false;};
> +template<int T> struct Z
> +{
> +  static const int value = T;
> +  static const int value_square = T * T;
> +};
> +
> +template<template<int> class U>
> +struct List<U<2>, U<3>, U<4>, U<9>> { static const bool is_ok = true;};
> +
> +template<int...T> using LZ = List<Z<T>...>;
> +
> +template<class...T>
> +struct F
> +{
> +  using N = LZ<T::value..., Z<4>::value, Z<9>::value>;
> +};
> +
> +static_assert (F<Z<2>, Z<3>>::N::is_ok, "");

-- 
                Dodji

Reply via email to