From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20872 invoked by alias); 16 Nov 2012 13:16:06 -0000 Received: (qmail 20850 invoked by uid 22791); 16 Nov 2012 13:16:04 -0000 X-SWARE-Spam-Status: No, hits=-6.1 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_CX X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 16 Nov 2012 13:15:53 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id qAGDFqR2032463 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 16 Nov 2012 08:15:53 -0500 Received: from localhost (ovpn-116-79.ams2.redhat.com [10.36.116.79]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id qAGDFpgr015552 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 16 Nov 2012 08:15:52 -0500 Received: by localhost (Postfix, from userid 1000) id 9F26B2C0104; Fri, 16 Nov 2012 14:15:50 +0100 (CET) From: Dodji Seketeli To: GCC Patches Cc: Jason Merrill Subject: [PING] [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack References: X-URL: http://www.seketeli.net/~dodji Date: Fri, 16 Nov 2012 13:16:00 -0000 In-Reply-To: (Dodji Seketeli's message of "Thu, 20 Sep 2012 10:44:08 +0200") Message-ID: <87a9uhvgca.fsf@seketeli.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2012-11/txt/msg01376.txt.bz2 I am friendly pinging the patch below ... Dodji Seketeli a =C3=A9crit: > Hello, > > Consider this example: > > 1 template struct List {}; > 2 template struct Z {static const int value =3D T;}; > 3 template using LZ =3D List...>; > 4 > 5 template > 6 struct F > 7 { > 8 using N =3D LZ; //#1 This should amount to List...> > 9 } > 10 > 11 F, Z<2> >::N A; //#2 > > which G++ fails to compile, with this error message: > > test-PR53609-3.cc: In instantiation of 'struct F, Z<2> >': > test-PR53609-3.cc:11:15: required from here > test-PR53609-3.cc:3:43: error: wrong number of template arguments (2, sho= uld be 1) > template using LZ =3D List...>; > ^ > test-PR53609-3.cc:2:24: error: provided for 'template struct Z' > template struct Z {static const int value =3D T;}; > > I think this is because in #1, when we substitute the argument pack > {U::value...} into the pack expansion Z..., tsubst_pack_expansion > yields Z, instead of Z..., so the instantiation > of LZ amounts to List >, instead of > List...>. > > 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; > } >=20=20 > +/* 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 =3D NULL_TREE; > + struct find_parameter_pack_data ppd; > + > + if (!processing_template_decl || !t || t =3D=3D error_mark_node) > + return NULL_TREE; > + > + if (TREE_CODE (t) =3D=3D TYPE_DECL) > + t =3D TREE_TYPE (t); > + > + ppd.parameter_packs =3D ¶meter_packs; > + ppd.visited =3D 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=20 > check_for_bare_parameter_packs (tree t) > { > - tree parameter_packs =3D NULL_TREE; > - struct find_parameter_pack_data ppd; > - > - if (!processing_template_decl || !t || t =3D=3D error_mark_node) > - return false; > - > - if (TREE_CODE (t) =3D=3D TYPE_DECL) > - t =3D TREE_TYPE (t); > - > - ppd.parameter_packs =3D ¶meter_packs; > - ppd.visited =3D pointer_set_create (); > - cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited); > - pointer_set_destroy (ppd.visited); > + tree parameter_packs =3D has_bare_parameter_packs (t); >=20=20 > if (parameter_packs)=20 > { > @@ -9065,6 +9076,86 @@ make_fnparm_pack (tree spec_parm) > return extract_fnparm_pack (NULL_TREE, &spec_parm); > } >=20=20 > +/* 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 =3D=3D NULL_TREE > + || arg_pack =3D=3D error_mark_node > + || !ARGUMENT_PACK_P (arg_pack)) > + return false; > + > + for (int i =3D 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 =3D make_node (ARGUMENT_PACK_SELECT); > + > + if (!any_non_real_argument_pack_element_p (arg_pack)) > + ARGUMENT_PACK_SELECT_FROM_PACK (aps) =3D arg_pack; > + else > + { > + tree tmp_arg_pack =3D TYPE_P (arg_pack) > + ? cxx_make_type (TREE_CODE (arg_pack)) > + : make_node (TREE_CODE (arg_pack)); > + tree tmp_vec =3D > + 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) =3D 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 =3D > + ARGUMENT_PACK_ARGS (ARGUMENT_PACK_SELECT_FROM_PACK (aps)); > + if (real_argument_pack_element_p (arg_pack, i)) > + TREE_VEC_ELT (args_vec, i) =3D > + TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), i); > + else > + TREE_VEC_ELT (args_vec, i) =3D > + PACK_EXPANSION_PATTERN (TREE_VEC_ELT > + (ARGUMENT_PACK_ARGS (arg_pack), > + i)); > + } > + > + ARGUMENT_PACK_SELECT_INDEX (aps) =3D 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 =3D packs; pack; pack =3D TREE_CHAIN (pack)) > { > tree parm =3D TREE_PURPOSE (pack); > - tree arg; > + tree arg_pack =3D TREE_VALUE (pack); > + tree aps; /* instance of ARGUMENT_PACK_SELECT > + tree. */ >=20=20 > /* Select the Ith argument from the pack. */ > if (TREE_CODE (parm) =3D=3D PARM_DECL) > { > if (i =3D=3D 0) > { > - arg =3D make_node (ARGUMENT_PACK_SELECT); > - ARGUMENT_PACK_SELECT_FROM_PACK (arg) =3D TREE_VALUE (pack); > + aps =3D arg_pack_select_for_pack_expansion (arg_pack); > mark_used (parm); > - register_local_specialization (arg, parm); > + register_local_specialization (aps, parm); > } > else > - arg =3D retrieve_local_specialization (parm); > + aps =3D retrieve_local_specialization (parm); > } > else > { > @@ -9306,25 +9398,30 @@ tsubst_pack_expansion (tree t, tree args, tsubst_= flags_t complain, >=20=20 > if (i =3D=3D 0) > { > - arg =3D make_node (ARGUMENT_PACK_SELECT); > - ARGUMENT_PACK_SELECT_FROM_PACK (arg) =3D TREE_VALUE (pack); > + aps =3D arg_pack_select_for_pack_expansion (arg_pack); > /* Update the corresponding argument. */ > - TMPL_ARG (args, level, idx) =3D arg; > + TMPL_ARG (args, level, idx) =3D aps; > } > else > /* Re-use the ARGUMENT_PACK_SELECT. */ > - arg =3D TMPL_ARG (args, level, idx); > + aps =3D TMPL_ARG (args, level, idx); > } > - ARGUMENT_PACK_SELECT_INDEX (arg) =3D i; > + set_arg_pack_select_index_for_pack_expansion (aps, i, > + arg_pack); > } >=20=20 > /* Substitute into the PATTERN with the altered arguments. */ > if (!TYPE_P (pattern)) > - TREE_VEC_ELT (result, i) =3D=20 > - tsubst_expr (pattern, args, complain, in_decl, > - /*integral_constant_expression_p=3D*/false); > + t =3D tsubst_expr (pattern, args, complain, in_decl, > + /*integral_constant_expression_p=3D*/false); > else > - TREE_VEC_ELT (result, i) =3D tsubst (pattern, args, complain, in= _decl); > + t =3D 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) =3D > + (has_bare_parameter_packs (t)) ? make_pack_expansion (t) : t; >=20=20 > if (TREE_VEC_ELT (result, i) =3D=3D 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 struct List {}; > +template struct Z {static const int value =3D T;}; > +template using LZ =3D List...>; > + > +template > +struct F > +{ > + using N =3D LZ; > +};=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20 > + > +F, 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 struct List{ static const bool is_ok =3D false;}; > +template struct Z > +{ > + static const int value =3D T; > + static const int value_square =3D T * T; > +}; > + > +template class U> > +struct List, U<3>, U<4>, U<9>> { static const bool is_ok =3D true;}; > + > +template using LZ =3D List...>; > + > +template > +struct F > +{ > + using N =3D LZ; > +}; > + > +static_assert (F, 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 struct List{ static const bool is_ok =3D false;}; > +template struct Z > +{ > + static const int value =3D T; > + static const int value_square =3D T * T; > +}; > + > +template class U> > +struct List, U<3>, U<4>, U<9>> { static const bool is_ok =3D true;}; > + > +template using LZ =3D List...>; > + > +template > +struct F > +{ > + using N =3D LZ::value, Z<9>::value>; > +}; > + > +static_assert (F, Z<3>>::N::is_ok, ""); --=20 Dodji