Message ID | 20200303214609.2229459-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | libstdc++: Fix incorrect use of memset in ranges::fill_n (PR 94017) | expand |
On Tue, 3 Mar 2020, Patrick Palka wrote: > When deciding whether to perform the memset optimization in ranges::fill_n, we > were crucially neglecting to check whether the output pointer's value type is a > byte type. This patch adds such a check to the problematic condition in > ranges::fill_n. > > I think the __is_byte<_Tp>::__value check, which checks that the fill type is a > byte type, is too restrictive. It means that we won't enable the memset > optimization in the following example: > > char c[100]; > ranges::fill(c, 37); > > since the fill type is deduced to be int here. It seems we could get away > with instead just checking that _Tp is an integral type; I've added a TODO > about this in the code. Here's v2 of the patch which actually replaces the aforementioned conservative condition with integral<_Tp>, following discussion on IRC. -- >8 -- Subject: [PATCH] libstdc++: Fix incorrect use of memset in ranges::fill_n (PR 94017) When deciding whether to perform the memset optimization in ranges::fill_n, we were crucially neglecting to check whether the output pointer's value type is a byte type. This patch adds such a check to the problematic condition in ranges::fill_n. At the same time, this patch relaxes the overly conservative __is_byte<_Tp>::__value check that requires the fill type be a byte type. It's overly conservative because it means we won't enable the memset optimization in the following example char c[100]; ranges::fill(c, 37); because the fill type is deduced to be int here. Rather than requiring that the fill type be a byte type, it seems safe to instead require the fill type be an integral type, which is what this patch does. libstdc++-v3/ChangeLog: PR libstdc++/94017 * include/bits/ranges_algobase.h (__fill_n_fn::operator()): Refine condition for when to use memset, making sure to additionally check that the output pointer's value type is a non-volatile byte type. Instead of requiring that the fill type is a byte type, just require that it's an integral type. * testsuite/20_util/specialized_algorithms/uninitialized_fill/94017.cc: New test. * testsuite/20_util/specialized_algorithms/uninitialized_fill_n/94017.cc: New test. * testsuite/25_algorithms/fill/94013.cc: Uncomment part of test that was blocked by PR 94017. * testsuite/25_algorithms/fill/94017.cc: New test. * testsuite/25_algorithms/fill_n/94017.cc: New test. --- libstdc++-v3/include/bits/ranges_algobase.h | 7 +- .../uninitialized_fill/94017.cc | 77 +++++++++++++++++++ .../uninitialized_fill_n/94017.cc | 77 +++++++++++++++++++ .../testsuite/25_algorithms/fill/94013.cc | 5 +- .../testsuite/25_algorithms/fill/94017.cc | 76 ++++++++++++++++++ .../testsuite/25_algorithms/fill_n/94017.cc | 76 ++++++++++++++++++ 6 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/94017.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/94017.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/fill/94017.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/fill_n/94017.cc diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h index c0102f5ab11..80c9a774301 100644 --- a/libstdc++-v3/include/bits/ranges_algobase.h +++ b/libstdc++-v3/include/bits/ranges_algobase.h @@ -516,8 +516,11 @@ namespace ranges if (__n <= 0) return __first; - // TODO: is __is_byte the best condition? - if constexpr (is_pointer_v<_Out> && __is_byte<_Tp>::__value) + // TODO: Generalize this optimization to contiguous iterators. + if constexpr (is_pointer_v<_Out> + // Note that __is_byte already implies !is_volatile. + && __is_byte<remove_pointer_t<_Out>>::__value + && integral<_Tp>) { __builtin_memset(__first, static_cast<unsigned char>(__value), __n); return __first + __n; diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/94017.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/94017.cc new file mode 100644 index 00000000000..1686d1ba8d5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/94017.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <memory> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using __gnu_test::test_output_range; + +namespace ranges = std::ranges; + +template<typename Out, auto value> +void +test01() +{ + { + Out x[5]; + ranges::uninitialized_fill(x, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } + + { + Out x[5]; + test_output_range<Out> rx(x); + ranges::uninitialized_fill(x, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } +} + +int +main() +{ + test01<char, 'a'>(); + test01<char, 100>(); + test01<char, 150>(); + test01<char, 300>(); + test01<char, 1000>(); + test01<char, -10000L>(); + + test01<signed char, 'a'>(); + test01<signed char, 100>(); + test01<signed char, 150>(); + test01<signed char, 300>(); + + test01<unsigned char, 'a'>(); + test01<unsigned char, 100>(); + test01<unsigned char, 150>(); + test01<unsigned char, 300>(); + + test01<int, 'a'>(); + test01<int, u8'a'>(); + test01<int, (signed char)'a'>(); + test01<int, (unsigned char)'a'>(); + + test01<volatile int, 'a'>(); + test01<volatile int, 'a'>(); + test01<volatile int, 500>(); + test01<volatile char, 500>(); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/94017.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/94017.cc new file mode 100644 index 00000000000..b5325080e02 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/94017.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <memory> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using __gnu_test::test_output_range; + +namespace ranges = std::ranges; + +template<typename Out, auto value> +void +test01() +{ + { + Out x[5]; + ranges::uninitialized_fill_n(x, 5, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } + + { + Out x[5]; + test_output_range<Out> rx(x); + ranges::uninitialized_fill_n(x, 5, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } +} + +int +main() +{ + test01<char, 'a'>(); + test01<char, 100>(); + test01<char, 150>(); + test01<char, 300>(); + test01<char, 1000>(); + test01<char, -10000L>(); + + test01<signed char, 'a'>(); + test01<signed char, 100>(); + test01<signed char, 150>(); + test01<signed char, 300>(); + + test01<unsigned char, 'a'>(); + test01<unsigned char, 100>(); + test01<unsigned char, 150>(); + test01<unsigned char, 300>(); + + test01<int, 'a'>(); + test01<int, u8'a'>(); + test01<int, (signed char)'a'>(); + test01<int, (unsigned char)'a'>(); + + test01<volatile int, 'a'>(); + test01<volatile int, 'a'>(); + test01<volatile int, 500>(); + test01<volatile char, 500>(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/fill/94013.cc b/libstdc++-v3/testsuite/25_algorithms/fill/94013.cc index b28eb76157b..9785d740a35 100644 --- a/libstdc++-v3/testsuite/25_algorithms/fill/94013.cc +++ b/libstdc++-v3/testsuite/25_algorithms/fill/94013.cc @@ -33,9 +33,8 @@ test01() c = 4; std::ranges::fill(a, c); VERIFY( a[0] == 4 && a[1] == 4 ); - // currently fails, see PR 94017 - // unsigned char c2 = 5; - // std::ranges::fill(a, c2); + unsigned char c2 = 5; + std::ranges::fill(a, c2); #endif } diff --git a/libstdc++-v3/testsuite/25_algorithms/fill/94017.cc b/libstdc++-v3/testsuite/25_algorithms/fill/94017.cc new file mode 100644 index 00000000000..ace4cc9c87f --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/fill/94017.cc @@ -0,0 +1,76 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using __gnu_test::test_output_range; + +namespace ranges = std::ranges; + +template<typename Out, auto value> +void +test01() +{ + { + Out x[5]; + ranges::fill(x, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } + + { + Out x[5]; + test_output_range<Out> rx(x); + ranges::fill(x, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } +} + +int +main() +{ + test01<char, 'a'>(); + test01<char, 100>(); + test01<char, 150>(); + test01<char, 300>(); + test01<char, 1000>(); + test01<char, -10000L>(); + + test01<signed char, 'a'>(); + test01<signed char, 100>(); + test01<signed char, 150>(); + test01<signed char, 300>(); + + test01<unsigned char, 'a'>(); + test01<unsigned char, 100>(); + test01<unsigned char, 150>(); + test01<unsigned char, 300>(); + + test01<int, 'a'>(); + test01<int, u8'a'>(); + test01<int, (signed char)'a'>(); + test01<int, (unsigned char)'a'>(); + + test01<volatile int, 'a'>(); + test01<volatile int, 'a'>(); + test01<volatile int, 500>(); + test01<volatile char, 500>(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/fill_n/94017.cc b/libstdc++-v3/testsuite/25_algorithms/fill_n/94017.cc new file mode 100644 index 00000000000..fc93dd5ab26 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/fill_n/94017.cc @@ -0,0 +1,76 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using __gnu_test::test_output_range; + +namespace ranges = std::ranges; + +template<typename Out, auto value> +void +test01() +{ + { + Out x[5]; + ranges::fill_n(x, 5, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } + + { + Out x[5]; + test_output_range<Out> rx(x); + ranges::fill_n(x, 5, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } +} + +int +main() +{ + test01<char, 'a'>(); + test01<char, 100>(); + test01<char, 150>(); + test01<char, 300>(); + test01<char, 1000>(); + test01<char, -10000L>(); + + test01<signed char, 'a'>(); + test01<signed char, 100>(); + test01<signed char, 150>(); + test01<signed char, 300>(); + + test01<unsigned char, 'a'>(); + test01<unsigned char, 100>(); + test01<unsigned char, 150>(); + test01<unsigned char, 300>(); + + test01<int, 'a'>(); + test01<int, u8'a'>(); + test01<int, (signed char)'a'>(); + test01<int, (unsigned char)'a'>(); + + test01<volatile int, 'a'>(); + test01<volatile int, 'a'>(); + test01<volatile int, 500>(); + test01<volatile char, 500>(); +}
On 03/03/20 17:13 -0500, Patrick Palka wrote: >On Tue, 3 Mar 2020, Patrick Palka wrote: > >> When deciding whether to perform the memset optimization in ranges::fill_n, we >> were crucially neglecting to check whether the output pointer's value type is a >> byte type. This patch adds such a check to the problematic condition in >> ranges::fill_n. >> >> I think the __is_byte<_Tp>::__value check, which checks that the fill type is a >> byte type, is too restrictive. It means that we won't enable the memset >> optimization in the following example: >> >> char c[100]; >> ranges::fill(c, 37); >> >> since the fill type is deduced to be int here. It seems we could get away >> with instead just checking that _Tp is an integral type; I've added a TODO >> about this in the code. > >Here's v2 of the patch which actually replaces the aforementioned >conservative condition with integral<_Tp>, following discussion on IRC. OK for master, thanks.
diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h index feb6c5723dd..35309986e53 100644 --- a/libstdc++-v3/include/bits/ranges_algobase.h +++ b/libstdc++-v3/include/bits/ranges_algobase.h @@ -531,8 +531,13 @@ namespace ranges if (__n <= 0) return __first; - // TODO: is __is_byte the best condition? - if constexpr (is_pointer_v<_Out> && __is_byte<_Tp>::__value) + // TODO: Generalize this optimization to contiguous iterators. + if constexpr (is_pointer_v<_Out> + // Note that __is_byte already implies !is_volatile. + && __is_byte<remove_pointer_t<_Out>>::__value + // TODO: Can we relax this next condition to just + // integral<_Tp>? + && __is_byte<_Tp>::__value) { __builtin_memset(__first, static_cast<unsigned char>(__value), __n); return __first + __n; diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/94017.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/94017.cc new file mode 100644 index 00000000000..c039935d78e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/94017.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <memory> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using __gnu_test::test_output_range; + +namespace ranges = std::ranges; + +template<typename Out, auto value> +void +test01() +{ + { + Out x[5]; + ranges::uninitialized_fill(x, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } + + { + Out x[5]; + test_output_range<Out> rx(x); + ranges::uninitialized_fill(x, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } +} + +int +main() +{ + test01<char, 100>(); + test01<char, 150>(); + test01<char, 300>(); + test01<char, 1000>(); + test01<char, -10000L>(); + + test01<signed char, 100>(); + test01<signed char, 150>(); + test01<signed char, 300>(); + + test01<unsigned char, 100>(); + test01<unsigned char, 150>(); + test01<unsigned char, 300>(); + + test01<int, 'a'>(); + test01<int, u8'a'>(); + test01<int, (signed char)'a'>(); + test01<int, (unsigned char)'a'>(); + + test01<volatile int, 'a'>(); + test01<volatile int, 'a'>(); + test01<volatile int, 500>(); + test01<volatile char, 500>(); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/94017.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/94017.cc new file mode 100644 index 00000000000..e7928295a82 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/94017.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <memory> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using __gnu_test::test_output_range; + +namespace ranges = std::ranges; + +template<typename Out, auto value> +void +test01() +{ + { + Out x[5]; + ranges::uninitialized_fill_n(x, 5, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } + + { + Out x[5]; + test_output_range<Out> rx(x); + ranges::uninitialized_fill_n(x, 5, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } +} + +int +main() +{ + test01<char, 100>(); + test01<char, 150>(); + test01<char, 300>(); + test01<char, 1000>(); + test01<char, -10000L>(); + + test01<signed char, 100>(); + test01<signed char, 150>(); + test01<signed char, 300>(); + + test01<unsigned char, 100>(); + test01<unsigned char, 150>(); + test01<unsigned char, 300>(); + + test01<int, 'a'>(); + test01<int, u8'a'>(); + test01<int, (signed char)'a'>(); + test01<int, (unsigned char)'a'>(); + + test01<volatile int, 'a'>(); + test01<volatile int, 'a'>(); + test01<volatile int, 500>(); + test01<volatile char, 500>(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/fill/94017.cc b/libstdc++-v3/testsuite/25_algorithms/fill/94017.cc new file mode 100644 index 00000000000..d2d59f927e4 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/fill/94017.cc @@ -0,0 +1,73 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using __gnu_test::test_output_range; + +namespace ranges = std::ranges; + +template<typename Out, auto value> +void +test01() +{ + { + Out x[5]; + ranges::fill(x, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } + + { + Out x[5]; + test_output_range<Out> rx(x); + ranges::fill(x, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } +} + +int +main() +{ + test01<char, 100>(); + test01<char, 150>(); + test01<char, 300>(); + test01<char, 1000>(); + test01<char, -10000L>(); + + test01<signed char, 100>(); + test01<signed char, 150>(); + test01<signed char, 300>(); + + test01<unsigned char, 100>(); + test01<unsigned char, 150>(); + test01<unsigned char, 300>(); + + test01<int, 'a'>(); + test01<int, u8'a'>(); + test01<int, (signed char)'a'>(); + test01<int, (unsigned char)'a'>(); + + test01<volatile int, 'a'>(); + test01<volatile int, 'a'>(); + test01<volatile int, 500>(); + test01<volatile char, 500>(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/fill_n/94017.cc b/libstdc++-v3/testsuite/25_algorithms/fill_n/94017.cc new file mode 100644 index 00000000000..3cfaf39301a --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/fill_n/94017.cc @@ -0,0 +1,73 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +using __gnu_test::test_output_range; + +namespace ranges = std::ranges; + +template<typename Out, auto value> +void +test01() +{ + { + Out x[5]; + ranges::fill_n(x, 5, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } + + { + Out x[5]; + test_output_range<Out> rx(x); + ranges::fill_n(x, 5, value); + VERIFY( ranges::count(x, static_cast<Out>(value)) == ranges::size(x) ); + } +} + +int +main() +{ + test01<char, 100>(); + test01<char, 150>(); + test01<char, 300>(); + test01<char, 1000>(); + test01<char, -10000L>(); + + test01<signed char, 100>(); + test01<signed char, 150>(); + test01<signed char, 300>(); + + test01<unsigned char, 100>(); + test01<unsigned char, 150>(); + test01<unsigned char, 300>(); + + test01<int, 'a'>(); + test01<int, u8'a'>(); + test01<int, (signed char)'a'>(); + test01<int, (unsigned char)'a'>(); + + test01<volatile int, 'a'>(); + test01<volatile int, 'a'>(); + test01<volatile int, 500>(); + test01<volatile char, 500>(); +}