diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2024-07-10 23:14:19 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2024-08-23 13:39:36 +0100 |
commit | 8cf51d7516b92b352c358c14ab4e456ae53c3371 (patch) | |
tree | f1f88a471ea22c4d2f272bc02cae91bc59feccba /libstdc++-v3/testsuite/ext | |
parent | 43b8153c26655a7a00f1584fcb4f511dc5e45fab (diff) | |
download | gcc-8cf51d7516b92b352c358c14ab4e456ae53c3371.zip gcc-8cf51d7516b92b352c358c14ab4e456ae53c3371.tar.gz gcc-8cf51d7516b92b352c358c14ab4e456ae53c3371.tar.bz2 |
libstdc++: Fix std::allocator_traits::construct constraints [PR108619]
Using std::is_constructible in the constraints introduces a spurious
dependency on the type being destructible, which should not be required
for constructing with an allocator. The test case shows a case where the
type has a private destructor, which can be destroyed by the allocator,
but std::is_destructible and std::is_constructible are false.
Similarly, using is_nothrow_constructible in the noexcept-specifiers
for the construct members of allocator_traits and std::allocator,
__gnu_cxx::__new_allocator, and __gnu_cxx::__malloc_allocator gives the
wrong answer if the type isn't destructible.
We need a new type trait to define those correctly, so that we only
check if the placement new-expression is nothrow after using
is_constructible to check that it would be well-formed.
Instead of just fixing the overly restrictive constraint to check for
placement new, rewrite allocator_traits in terms of 'if constexpr' using
variable templates and the detection idiom.
Although we can use 'if constexpr' and variable templates in C++11 with
appropriate uses of diagnostic pragmas, we can't have constexpr
functions with multiple return statements. This means that in C++11 mode
the _S_nothrow_construct and _S_nothrow_destroy helpers used for
noexcept-specifiers still need to be overlaods using enable_if. Nearly
everything else can be simplified to reduce overload resolution and
enable_if checks.
libstdc++-v3/ChangeLog:
PR libstdc++/108619
* include/bits/alloc_traits.h (__allocator_traits_base): Add
variable templates for detecting which allocator operations are
supported.
(allocator_traits): Use 'if constexpr' instead of dispatching to
overloads constrained with enable_if.
(allocator_traits<allocator<T>>::construct): Use Construct if
construct_at is not supported. Use
__is_nothrow_new_constructible for noexcept-specifier.
(allocator_traits<allocator<void>>::construct): Use
__is_nothrow_new_constructible for noexcept-specifier.
* include/bits/new_allocator.h (construct): Likewise.
* include/ext/malloc_allocator.h (construct): Likewise.
* include/std/type_traits (__is_nothrow_new_constructible): New
variable template.
* testsuite/20_util/allocator/89510.cc: Adjust expected results.
* testsuite/ext/malloc_allocator/89510.cc: Likewise.
* testsuite/ext/new_allocator/89510.cc: Likewise.
* testsuite/20_util/allocator_traits/members/108619.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite/ext')
-rw-r--r-- | libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc | 14 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/ext/new_allocator/89510.cc | 14 |
2 files changed, 12 insertions, 16 deletions
diff --git a/libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc b/libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc index 1889c88..771facb 100644 --- a/libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc +++ b/libstdc++-v3/testsuite/ext/malloc_allocator/89510.cc @@ -137,13 +137,11 @@ struct Z }; Z* zp; -// These construct calls should be noexcept, but they are false because -// they use is_nothrow_constructible which depends on is_nothrow_destructible. #if __cplusplus <= 201703L -static_assert( ! noexcept(a.construct(zp)), "wrong" ); -static_assert( ! noexcept(a.construct(zp, 1)), "wrong" ); -static_assert( ! noexcept(a.destroy(zp)), "" ); +static_assert( noexcept(a.construct(zp)), "" ); +static_assert( noexcept(a.construct(zp, 1)), "" ); +static_assert( ! noexcept(a.destroy(zp)), "~Z is noexcept(false)" ); #endif -static_assert( ! noexcept(AT::construct(a, zp)), "" ); -static_assert( ! noexcept(AT::construct(a, zp, 1)), "" ); -static_assert( ! noexcept(AT::destroy(a, zp)), "" ); +static_assert( noexcept(AT::construct(a, zp)), "" ); +static_assert( noexcept(AT::construct(a, zp, 1)), "" ); +static_assert( ! noexcept(AT::destroy(a, zp)), "~Z is noexcept(false)" ); diff --git a/libstdc++-v3/testsuite/ext/new_allocator/89510.cc b/libstdc++-v3/testsuite/ext/new_allocator/89510.cc index 06384ae..7fc4438 100644 --- a/libstdc++-v3/testsuite/ext/new_allocator/89510.cc +++ b/libstdc++-v3/testsuite/ext/new_allocator/89510.cc @@ -137,13 +137,11 @@ struct Z }; Z* zp; -// These construct calls should be noexcept, but they are false because -// they use is_nothrow_constructible which depends on is_nothrow_destructible. #if __cplusplus <= 201703L -static_assert( ! noexcept(a.construct(zp)), "wrong" ); -static_assert( ! noexcept(a.construct(zp, 1)), "wrong" ); -static_assert( ! noexcept(a.destroy(zp)), "" ); +static_assert( noexcept(a.construct(zp)), "" ); +static_assert( noexcept(a.construct(zp, 1)), "" ); +static_assert( ! noexcept(a.destroy(zp)), "~Z is noexcept(false)" ); #endif -static_assert( ! noexcept(AT::construct(a, zp)), "" ); -static_assert( ! noexcept(AT::construct(a, zp, 1)), "" ); -static_assert( ! noexcept(AT::destroy(a, zp)), "" ); +static_assert( noexcept(AT::construct(a, zp)), "" ); +static_assert( noexcept(AT::construct(a, zp, 1)), "" ); +static_assert( ! noexcept(AT::destroy(a, zp)), "~Z is noexcept(false)" ); |