From f5b6d0d1d2cf80e685084eedd5ce68370a6f4248 Mon Sep 17 00:00:00 2001 From: Dodji Seketeli Date: Thu, 16 May 2013 06:14:49 +0000 Subject: [PATCH] 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 Tuple<>::Tuple... >::value, int >::type > Let's look at what happens to the expansion "is_convertible...." To express the result of that expansion tsubst_pack_expansion receives the expansion is_convertible, 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..." 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 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/pt.c | 15 +++--- gcc/testsuite/g++.dg/cpp0x/variadic143.C | 63 ++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic143.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a602af3addb..3609fa5e675 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2013-05-16 Dodji Seketeli + + 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 * name-lookup.c (pushdecl_maybe_friend_1): Replace pairs of diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 04dc4fcf1a9..b0be950b590 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic143.C b/gcc/testsuite/g++.dg/cpp0x/variadic143.C new file mode 100644 index 00000000000..7737b4cacf4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic143.C @@ -0,0 +1,63 @@ +// PR c++/56782 +// { dg-options -std=c++0x } + +template +T&& declval(); + +struct is_convertible_impl { + template + static void sink(T); + + template(declval()))> + static auto test(int) -> char; + + template + static auto test(...) -> char(&)[2]; +}; + +template +struct is_convertible : is_convertible_impl +{ + static const bool value = sizeof(test(0)) == 1; +}; + +template +struct enable_if {}; + +template +struct enable_if { typedef T type; }; + +template +struct conditional { typedef If type; }; + +template +struct conditional { typedef Else type; }; + +template +struct and_; + +template<> +struct and_<> +{ + static const bool value = true; +}; + +template +struct and_

: P +{ +}; + +template +struct and_ : conditional::type +{ +}; + +template +struct Tuple { + template... >::value, int>::type + > + Tuple(U&&...){} +}; + +static_assert(is_convertible, Tuple<>>::value, "Ouch"); //#1