@@ -9158,31 +9158,57 @@ use_pack_expansion_extra_args_p (tree parm_packs,
if (parm_packs == NULL_TREE)
return false;
+ /* The general reasoning is the following:
+
+ If one pack has an expansion and another pack has a normal
+ argument or if one pack has an empty argument and another one
+ hasn't then tsubst_pack_expansion cannot perform the substitution
+ and need to fall back on the PACK_EXPANSION_EXTRA mechanism so we
+ must return TRUE. */
+
bool has_expansion_arg = false;
- for (int i = 0 ; i < arg_pack_len; ++i)
- {
- bool has_non_expansion_arg = false;
+ if (arg_pack_len == 0)
+ {
+ /* So let's rule out the particular case of a zero argument pack
+ length. It means either there is parameter pack that has an
+ empty argument argument pack, or there are no argument packs
+ at all. In the former case, if there is also at least a
+ parameter pack that has no argument pack, then we must return
+ true.*/
for (tree parm_pack = parm_packs;
parm_pack;
parm_pack = TREE_CHAIN (parm_pack))
{
tree arg = TREE_VALUE (parm_pack);
- if (argument_pack_element_is_expansion_p (arg, i))
- has_expansion_arg = true;
- else
- has_non_expansion_arg = true;
+ if (arg
+ && ARGUMENT_PACK_P (arg)
+ && TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) == 0
+ && has_empty_arg)
+ return 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)))
- return true;
}
+ else
+ /* So let's handle the general case. */
+ for (int i = 0 ; i < arg_pack_len; ++i)
+ {
+ bool has_non_expansion_arg = false;
+ for (tree parm_pack = parm_packs;
+ parm_pack;
+ parm_pack = TREE_CHAIN (parm_pack))
+ {
+ tree arg = TREE_VALUE (parm_pack);
+
+ if (argument_pack_element_is_expansion_p (arg, i))
+ has_expansion_arg = true;
+ else
+ has_non_expansion_arg = true;
+ }
+
+ if ((has_expansion_arg && has_non_expansion_arg)
+ || (has_empty_arg && (has_expansion_arg || has_non_expansion_arg)))
+ return true;
+ }
return false;
}
new file mode 100644
@@ -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