mirror of git://gcc.gnu.org/git/gcc.git
libstdc++: Ensure that ranges::destroy destroys in constexpr [PR121024]
The new test is currently marked as XFAIL because PR c++/102284 means that GCC doesn't notice that the lifetimes have ended. libstdc++-v3/ChangeLog: PR libstdc++/121024 * include/bits/ranges_uninitialized.h (ranges::destroy): Do not optimize away trivial destructors during constant evaluation. (ranges::destroy_n): Likewise. * testsuite/20_util/specialized_algorithms/destroy/121024.cc: New test. Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
parent
aeeeeef396
commit
a63b663c7b
|
@ -556,13 +556,12 @@ namespace ranges
|
|||
__destroy_fn::operator()(_Iter __first, _Sent __last) const noexcept
|
||||
{
|
||||
if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>)
|
||||
return ranges::next(std::move(__first), __last);
|
||||
else
|
||||
{
|
||||
for (; __first != __last; ++__first)
|
||||
ranges::destroy_at(std::__addressof(*__first));
|
||||
return __first;
|
||||
}
|
||||
if (!is_constant_evaluated())
|
||||
return ranges::next(std::move(__first), __last);
|
||||
|
||||
for (; __first != __last; ++__first)
|
||||
ranges::destroy_at(std::__addressof(*__first));
|
||||
return __first;
|
||||
}
|
||||
|
||||
template<__detail::__nothrow_input_range _Range>
|
||||
|
@ -581,13 +580,12 @@ namespace ranges
|
|||
operator()(_Iter __first, iter_difference_t<_Iter> __n) const noexcept
|
||||
{
|
||||
if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>)
|
||||
return ranges::next(std::move(__first), __n);
|
||||
else
|
||||
{
|
||||
for (; __n > 0; ++__first, (void)--__n)
|
||||
ranges::destroy_at(std::__addressof(*__first));
|
||||
return __first;
|
||||
}
|
||||
if (!is_constant_evaluated())
|
||||
return ranges::next(std::move(__first), __n);
|
||||
|
||||
for (; __n > 0; ++__first, (void)--__n)
|
||||
ranges::destroy_at(std::__addressof(*__first));
|
||||
return __first;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
// { dg-do compile { target c++26 } }
|
||||
|
||||
// Bug 121024
|
||||
// ranges::destroy and ranges::destroy_n do not end lifetime of trivial types
|
||||
|
||||
#include <memory>
|
||||
|
||||
consteval bool is_within_lifetime(const auto* p) noexcept
|
||||
{
|
||||
return __builtin_constant_p(*p);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Buf
|
||||
{
|
||||
constexpr Buf() : p(std::allocator<T>().allocate(2)) { }
|
||||
constexpr ~Buf() { std::allocator<T>().deallocate(p, 2); }
|
||||
T* p;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
consteval bool
|
||||
test_destroy()
|
||||
{
|
||||
Buf<T> buf;
|
||||
std::uninitialized_value_construct(buf.p, buf.p + 2);
|
||||
std::destroy(buf.p, buf.p + 2);
|
||||
return not is_within_lifetime(buf.p) && not is_within_lifetime(buf.p + 1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
consteval bool
|
||||
test_destroy_n()
|
||||
{
|
||||
Buf<T> buf;
|
||||
std::uninitialized_value_construct_n(buf.p, 2);
|
||||
std::destroy_n(buf.p, 2);
|
||||
return not is_within_lifetime(buf.p) && not is_within_lifetime(buf.p + 1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
consteval bool
|
||||
test_ranges_destroy()
|
||||
{
|
||||
Buf<T> buf;
|
||||
std::uninitialized_value_construct(buf.p, buf.p + 2);
|
||||
std::ranges::destroy(buf.p, buf.p + 2);
|
||||
return not is_within_lifetime(buf.p) && not is_within_lifetime(buf.p + 1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
consteval bool
|
||||
test_ranges_destroy_n()
|
||||
{
|
||||
Buf<T> buf;
|
||||
std::uninitialized_value_construct_n(buf.p, 2);
|
||||
std::ranges::destroy_n(buf.p, 2);
|
||||
return not is_within_lifetime(buf.p) && not is_within_lifetime(buf.p + 1);
|
||||
}
|
||||
|
||||
struct O
|
||||
{
|
||||
constexpr O() { }
|
||||
constexpr ~O() { }
|
||||
};
|
||||
|
||||
// These all fail for GCC because is_within_lifetime still returns true
|
||||
// after the lifetime has been ended.
|
||||
// { dg-xfail-if "PR c++/102284" { *-*-* } }
|
||||
static_assert( test_destroy<int>() );
|
||||
static_assert( test_destroy<O>() );
|
||||
static_assert( test_destroy_n<int>() );
|
||||
static_assert( test_destroy_n<O>() );
|
||||
static_assert( test_ranges_destroy<int>() );
|
||||
static_assert( test_ranges_destroy<O>() );
|
||||
static_assert( test_ranges_destroy_n<int>() );
|
||||
static_assert( test_ranges_destroy_n<O>() );
|
Loading…
Reference in New Issue