aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDodji Seketeli <dodji@redhat.com>2013-05-16 06:14:49 +0000
committerDodji Seketeli <dodji@gcc.gnu.org>2013-05-16 08:14:49 +0200
commitf5b6d0d1d2cf80e685084eedd5ce68370a6f4248 (patch)
treec6b464617b7d00a515b81b19e8d79595d99f21d2 /gcc
parentad56ed7ebca514b172e13172f2486951218d3c8b (diff)
downloadgcc-f5b6d0d1d2cf80e685084eedd5ce68370a6f4248.zip
gcc-f5b6d0d1d2cf80e685084eedd5ce68370a6f4248.tar.gz
gcc-f5b6d0d1d2cf80e685084eedd5ce68370a6f4248.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/pt.c15
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic143.C63
3 files changed, 79 insertions, 7 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a602af3..3609fa5 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 04dc4fc..b0be950 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 0000000..7737b4c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic143.C
@@ -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