aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/pt.c31
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic-alias2.C103
3 files changed, 139 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7651d0e..e7a49b2 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2020-04-03 Jason Merrill <jason@redhat.com>
+
+ PR c++/91966
+ * pt.c (complex_pack_expansion_r): New.
+ (complex_alias_template_p): Use it.
+
2020-03-27 Nathan Sidwell <nathan@acm.org>
PR c++/84733
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 527d6f9..4673c27 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6186,6 +6186,33 @@ uses_all_template_parms_r (tree t, void *data_)
return 0;
}
+/* for_each_template_parm any_fn callback for complex_alias_template_p. */
+
+static int
+complex_pack_expansion_r (tree t, void *data_)
+{
+ /* An alias template with a pack expansion that expands a pack from the
+ enclosing class needs to be considered complex, to avoid confusion with
+ the same pack being used as an argument to the alias's own template
+ parameter (91966). */
+ if (!PACK_EXPANSION_P (t))
+ return 0;
+ struct uses_all_template_parms_data &data
+ = *(struct uses_all_template_parms_data*)data_;
+ for (tree pack = PACK_EXPANSION_PARAMETER_PACKS (t); pack;
+ pack = TREE_CHAIN (pack))
+ {
+ tree parm_pack = TREE_VALUE (pack);
+ if (!TEMPLATE_PARM_P (parm_pack))
+ continue;
+ int idx, level;
+ template_parm_level_and_index (parm_pack, &level, &idx);
+ if (level < data.level)
+ return 1;
+ }
+ return 0;
+}
+
static bool
complex_alias_template_p (const_tree tmpl)
{
@@ -6198,7 +6225,9 @@ complex_alias_template_p (const_tree tmpl)
for (int i = 0; i < len; ++i)
data.seen[i] = false;
- for_each_template_parm (pat, uses_all_template_parms_r, &data, NULL, true);
+ if (for_each_template_parm (pat, uses_all_template_parms_r, &data,
+ NULL, true, complex_pack_expansion_r))
+ return true;
for (int i = 0; i < len; ++i)
if (!data.seen[i])
return true;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-alias2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-alias2.C
new file mode 100644
index 0000000..ab64866
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-alias2.C
@@ -0,0 +1,103 @@
+// PR c++/91966
+// { dg-do compile { target c++11 } }
+
+// Reduced to this include-free example. Further reduction is hard: Either
+// the bug(?) disappears, or the program becomes meaningless.
+
+template<class...>
+struct list {};
+
+struct nil;
+
+////////////////////////////////////////////////////////////////////////////////
+
+template<int n>
+struct number {
+ constexpr /*implicit*/ operator int() const { return n; }
+ using type = number<n>;
+};
+
+using false_ = number<0>;
+using true_ = number<1>;
+
+static_assert(!false_{}, "");
+static_assert(true_{}, "");
+
+template<int... ns> using numbers = list<number<ns>...>;
+
+////////////////////////////////////////////////////////////////////////////////
+
+template<class lhs, class rhs>
+struct less_impl;
+
+template<int lhs, int rhs>
+struct less_impl<number<lhs>, number<rhs>>
+ : number<(lhs < rhs)> {};
+
+template<class lhs, class rhs> using less = typename less_impl<lhs, rhs>::type;
+
+////////////////////////////////////////////////////////////////////////////////
+
+template<class v0, class... vs>
+struct sum_impl {
+ static_assert(sizeof...(vs) == 0, "see specialization");
+ using type = v0;
+};
+
+template<int v0, int v1, class... vs>
+struct sum_impl<number<v0>, number<v1>, vs...>
+ : sum_impl<number<v0 + v1>, vs...> {};
+
+template<class... nums> using sum = typename sum_impl<nums...>::type;
+
+////////////////////////////////////////////////////////////////////////////////
+
+template<class num>
+struct conditional_impl {
+ static_assert(num{}, "see specialization");
+
+ template<class T, class F>
+ using type = T;
+};
+
+template<>
+struct conditional_impl<false_> {
+ template<class T, class F>
+ using type = F;
+};
+
+template<class num, class T, class F>
+using conditional = typename conditional_impl<num>::template type<T, F>;
+
+////////////////////////////////////////////////////////////////////////////////
+
+template<class seq>
+struct min_filter_impl;
+
+template<class... nums>
+struct min_filter_impl<list<nums...>> {
+ template<class num>
+ using count_better_mins = sum<less<nums, num>...>;
+
+ using type = list<conditional<count_better_mins<nums>, nil, nums>...>;
+
+//using debug = list<conditional<count_better_mins<nums>, nil, void>...>;
+
+// error: expansion pattern 'conditional<typename sum_impl<less<nums, nums>...>::type, nil, void>' contains no parameter packs
+
+};
+
+template<class seq> using min_filter = typename min_filter_impl<seq>::type;
+
+////////////////////////////////////////////////////////////////////////////////
+
+void test_min_filter() {
+ using computed = min_filter<numbers<2, 7, 2>>;
+ using expected = list<number<2>, nil, number<2>>;
+ (void)(computed{} = expected{});// compiles for identical types
+
+// error: no match for 'operator=' (operand types are 'computed' {aka 'list<number<2>, number<7>, number<2> >'} and 'expected' {aka 'list<number<2>, nil, number<2> >'})
+
+}
+
+int main() {}