Commit b0ffaa36 by Dodji Seketeli Committed by Dodji Seketeli

PR c++/53609 - Wrong variadic template pack expansion in alias template

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 (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.
	(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.

From-SVN: r195367
parent 257e81a6
2013-01-22 Dodji Seketeli <dodji@redhat.com>
PR c++/53609
* 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.
(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.
2013-01-21 Jason Merrill <jason@redhat.com>
PR c++/56059
......
2013-01-22 Dodji Seketeli <dodji@redhat.com>
PR c++/53609
* g++.dg/cpp0x/variadic139.C: New test.
* g++.dg/cpp0x/variadic140.C: Likewise.
* g++.dg/cpp0x/variadic141.C: Likewise.
2013-01-22 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/warn8.adb: New test.
......
// 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;
// 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, "");
// 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, "");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment