diff options
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/pt.c | 31 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/variadic-alias2.C | 103 |
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() {} |