PR c++/56782 - Regression with empty pack expansions

In the example of the patch below, during the instantiation of
is_convertible at #1, we see at some point Tuple<>.  (Let's note '{}'
an empty argument pack.)  In that context, during the partial
specialization the member template

template<class... U>
Tuple<>::Tuple<U,
	       typename enable_if<and_<is_convertible<U, {}>...
                                      >::value,
                                  int
			         >::type
              >

Let's look at what happens to the expansion "is_convertible<U, {}>...."

To express the result of that expansion tsubst_pack_expansion receives
the expansion is_convertible<U, T>, with the argument list [{}].  This
function should detect that we have an empty argument pack for the
parameter pack T and no argument pack for the parameter pack U.  It
should thus return a pack expansion "is_convertible<U,T>..." that has this
information: "I have gotten an argument list, that is not complete
because U doesn't have any argument pack; the argument pack for T is
'{}', so I'll wait for the next time I am passed to
tsubst_pack_expansion with enough additional argument packs, to really
perform the substitution".  That information is conveyed by attaching
the the '{}' to the PACK_EXPANSION_EXTRA property of the pack expansion
returned by tsubst_pack_expansion.

The problem in this report is that we are not setting
PACK_EXPANSION_EXTRA when the non-complete argument pack list is made
of an empty argument pack, because use_pack_expansion_extra_args_p
doesn't detect this case.

Fixed thus.

gcc/cp/

	* pt.c (use_pack_expansion_extra_args_p): When at least a
	parameter pack has an empty argument pack, and another parameter
	pack has no argument pack at all, use the PACK_EXPANSION_EXTRA
	mechanism.

From-SVN: r198956
This commit is contained in:
Dodji Seketeli 2013-05-16 06:14:49 +00:00 committed by Dodji Seketeli
parent ad56ed7ebc
commit f5b6d0d1d2
3 changed files with 79 additions and 7 deletions

View file

@ -1,3 +1,11 @@
2013-05-16 Dodji Seketeli <dodji@redhat.com>
PR c++/56782 - Regression with empty pack expansions
* pt.c (use_pack_expansion_extra_args_p): When at least a
parameter pack has an empty argument pack, and another parameter
pack has no argument pack at all, use the PACK_EXPANSION_EXTRA
mechanism.
2013-05-15 Paolo Carlini <paolo.carlini@oracle.com>
* name-lookup.c (pushdecl_maybe_friend_1): Replace pairs of

View file

@ -9202,8 +9202,15 @@ use_pack_expansion_extra_args_p (tree parm_packs,
int arg_pack_len,
bool has_empty_arg)
{
/* If one pack has an expansion and another pack has a normal
argument or if one pack has an empty argument and an another
one hasn't then tsubst_pack_expansion cannot perform the
substitution and need to fall back on the
PACK_EXPANSION_EXTRA mechanism. */
if (parm_packs == NULL_TREE)
return false;
else if (has_empty_arg)
return true;
bool has_expansion_arg = false;
for (int i = 0 ; i < arg_pack_len; ++i)
@ -9221,13 +9228,7 @@ use_pack_expansion_extra_args_p (tree parm_packs,
has_non_expansion_arg = true;
}
/* If one pack has an expansion and another pack has a normal
argument or if one pack has an empty argument another one
hasn't then tsubst_pack_expansion cannot perform the
substitution and need to fall back on the
PACK_EXPANSION_EXTRA mechanism. */
if ((has_expansion_arg && has_non_expansion_arg)
|| (has_empty_arg && (has_expansion_arg || has_non_expansion_arg)))
if (has_expansion_arg && has_non_expansion_arg)
return true;
}
return false;

View file

@ -0,0 +1,63 @@
// PR c++/56782
// { dg-options -std=c++0x }
template<class T>
T&& declval();
struct is_convertible_impl {
template<class T>
static void sink(T);
template<class T, class U, class = decltype(sink<U>(declval<T>()))>
static auto test(int) -> char;
template<class, class>
static auto test(...) -> char(&)[2];
};
template<class T, class U>
struct is_convertible : is_convertible_impl
{
static const bool value = sizeof(test<T, U>(0)) == 1;
};
template<bool, class>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
template<bool, class If, class Else>
struct conditional { typedef If type; };
template<class If, class Else>
struct conditional<false, If, Else> { typedef Else type; };
template<class...>
struct and_;
template<>
struct and_<>
{
static const bool value = true;
};
template<class P>
struct and_<P> : P
{
};
template<class P1, class P2>
struct and_<P1, P2> : conditional<P1::value, P2, P1>::type
{
};
template<class... T>
struct Tuple {
template<class... U,
class = typename enable_if<and_<is_convertible<U, T>... >::value, int>::type
>
Tuple(U&&...){}
};
static_assert(is_convertible<Tuple<>, Tuple<>>::value, "Ouch"); //#1