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

login
register
mail settings
Submitter Dodji Seketeli
Date May 15, 2013, 10:56 p.m.
Message ID <87hai3vomk.fsf@redhat.com>
Download mbox | patch
Permalink /patch/244198/
State New
Headers show

Comments

Dodji Seketeli - May 15, 2013, 10:56 p.m.
Jason Merrill <jason@redhat.com> writes:

> On 05/15/2013 10:33 AM, Dodji Seketeli wrote:
>> So let's rule out the particular case of a zero argument pack
>> length.
>
> I don't think there's anything special about zero length; if
> has_empty_arg is true and parm_packs is non-null, we want to return
> true.  Does that make sense to you?

Yes, of course.

So here is what bootstraped.

        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.
Jason Merrill - May 16, 2013, 4:29 a.m.
On 05/15/2013 06:56 PM, Dodji Seketeli wrote:
> So here is what bootstraped.

I thought I approved this on IRC; please apply it to trunk and 4.8.

Jason
Dodji Seketeli - May 16, 2013, 8:32 a.m.
Jason Merrill <jason@redhat.com> writes:

> I thought I approved this on IRC; please apply it to trunk and 4.8.

Applied to both branches, thanks.

Patch

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