libstdc++: Make byte-sized std::fill_n a constant expression (PR 94933)

The overload for byte types uses memset and isn't constexpr. This adds
the specifier and uses std::is_constant_evaluated() to provide a
compile-time alternative.

	PR libstdc++/94933
	* include/bits/stl_algobase.h (__fill_a1): Make overload for byte types
	usable in constant expressions.
	* testsuite/25_algorithms/fill_n/constexpr.cc: Test with bytes and
	non-scalars.
This commit is contained in:
Jonathan Wakely 2020-05-03 12:46:15 +01:00
parent 18a6e4130f
commit 22b6b5d6cf
3 changed files with 48 additions and 1 deletions

View File

@ -1,3 +1,11 @@
2020-05-03 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/94933
* include/bits/stl_algobase.h (__fill_a1): Make overload for byte types
usable in constant expressions.
* testsuite/25_algorithms/fill_n/constexpr.cc: Test with bytes and
non-scalars.
2020-05-01 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/94901

View File

@ -875,11 +875,20 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
// Specialization: for char types we can use memset.
template<typename _Tp>
_GLIBCXX20_CONSTEXPR
inline typename
__gnu_cxx::__enable_if<__is_byte<_Tp>::__value, void>::__type
__fill_a1(_Tp* __first, _Tp* __last, const _Tp& __c)
{
const _Tp __tmp = __c;
#if __cpp_lib_is_constant_evaluated
if (std::is_constant_evaluated())
{
for (; __first != __last; ++__first)
*__first = __tmp;
return;
}
#endif
if (const size_t __len = __last - __first)
__builtin_memset(__first, static_cast<unsigned char>(__tmp), __len);
}

View File

@ -28,7 +28,37 @@ test()
const auto outd = std::fill_n(ma0.begin(), 6, 77);
return outd == ma0.begin() + 6;
return outd == ma0.begin() + 6 && ma0[5] == 77 && ma0[6] == 0;
}
static_assert(test());
constexpr bool
test_byte()
{
// PR libstdc++/94933
std::array<char, 12> ma0{};
const auto outd = std::fill_n(ma0.begin(), 6, 77);
return outd == ma0.begin() + 6 && ma0[5] == 77 && ma0[6] == 0;
}
static_assert( test_byte() );
struct S
{
int i = 0;
};
constexpr bool
test_nonscalar()
{
std::array<S, 12> ma0{};
const auto outd = std::fill_n(ma0.begin(), 6, S{77});
return outd == ma0.begin() + 6 && ma0[5].i == 77 && ma0[6].i == 0;
}
static_assert( test_nonscalar() );