libstdc++: Do not use memset in constexpr calls to ranges::fill_n [PR101608]

libstdc++-v3/ChangeLog:

	PR libstdc++/101608
	* include/bits/ranges_algobase.h (__fill_n_fn): Check for
	constant evaluation before using memset.
	* testsuite/25_algorithms/fill_n/constrained.cc: Check
	byte-sized values as well.
This commit is contained in:
Jonathan Wakely 2021-11-24 13:17:54 +00:00
parent 6ea5fb3cc7
commit 82c3657dd7
2 changed files with 22 additions and 12 deletions

View File

@ -527,17 +527,25 @@ namespace ranges
if (__n <= 0)
return __first;
// 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;
}
else if constexpr (is_scalar_v<_Tp>)
if constexpr (is_scalar_v<_Tp>)
{
// 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>)
{
#ifdef __cpp_lib_is_constant_evaluated
if (!std::is_constant_evaluated())
#endif
{
__builtin_memset(__first,
static_cast<unsigned char>(__value),
__n);
return __first + __n;
}
}
const auto __tmp = __value;
for (; __n > 0; --__n, (void)++__first)
*__first = __tmp;

View File

@ -73,11 +73,12 @@ test01()
}
}
template<typename T>
constexpr bool
test02()
{
bool ok = true;
int x[6] = { 1, 2, 3, 4, 5, 6 };
T x[6] = { 1, 2, 3, 4, 5, 6 };
const int y[6] = { 1, 2, 3, 4, 5, 6 };
const int z[6] = { 17, 17, 17, 4, 5, 6 };
@ -94,5 +95,6 @@ int
main()
{
test01();
static_assert(test02());
static_assert(test02<int>());
static_assert(test02<unsigned char>()); // PR libstdc++/101608
}