From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 7542A39DC4FB; Fri, 18 Jun 2021 11:50:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7542A39DC4FB MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r10-9934] libstdc++: Fix missing members in std::allocator X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/releases/gcc-10 X-Git-Oldrev: 15d6f574615b78c5e783ea51924f6e452a3ff45b X-Git-Newrev: ec759162b317147a99a505ae4f34875dbc4308aa Message-Id: <20210618115033.7542A39DC4FB@sourceware.org> Date: Fri, 18 Jun 2021 11:50:33 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 18 Jun 2021 11:50:33 -0000 https://gcc.gnu.org/g:ec759162b317147a99a505ae4f34875dbc4308aa commit r10-9934-gec759162b317147a99a505ae4f34875dbc4308aa Author: Jonathan Wakely Date: Tue May 11 15:01:01 2021 +0100 libstdc++: Fix missing members in std::allocator The changes in 75c6a925dab5b7af9ab47c10906cb0e140261cc2 were slightly incorrect, because the converting constructor should be noexcept, and the POCMA and is_always_equal traits should still be present in C++20. This fixes it, and slightly refactors the preprocessor conditions and order of members. Also add comments explaining things. libstdc++-v3/ChangeLog: * include/bits/allocator.h (allocator) [C++20]: Add missing noexcept to constructor. Restore missing POCMA and is_always_equal_traits. * include/bits/memoryfwd.h (allocator_traits): Declare. * include/ext/malloc_allocator.h (malloc_allocator::allocate): Add nodiscard attribute. Add static assertion for LWG 3307. * include/ext/new_allocator.h (new_allocator::allocate): Add static assertion for LWG 3307. * testsuite/20_util/allocator/void.cc: Check that converting constructor is noexcept. Check for propagation traits and size_type and difference_type. Check that pointer and const_pointer are gone in C++20. (cherry picked from commit 5e3a1ea3d89d62972e1f036b2ede37a80b880bdf) Diff: --- libstdc++-v3/include/bits/allocator.h | 40 ++++++++++++++++++------ libstdc++-v3/include/bits/memoryfwd.h | 7 +++-- libstdc++-v3/include/ext/malloc_allocator.h | 8 ++++- libstdc++-v3/include/ext/new_allocator.h | 8 ++++- libstdc++-v3/testsuite/20_util/allocator/void.cc | 38 ++++++++++++++++++++-- 5 files changed, 83 insertions(+), 18 deletions(-) diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index d224aa3ec5e..8c538954caf 100644 --- a/libstdc++-v3/include/bits/allocator.h +++ b/libstdc++-v3/include/bits/allocator.h @@ -60,6 +60,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ + // Since C++20 the primary template should be used for allocator, + // but then it would have a non-trivial default ctor and dtor, which + // would be an ABI change. So C++20 still uses the allocator explicit + // specialization, with the historical ABI properties, but with the same + // members that are present in the primary template. + +#if ! _GLIBCXX_INLINE_VERSION /// allocator specialization. template<> class allocator @@ -68,28 +75,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef void value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; + #if __cplusplus <= 201703L + // These were removed for C++20. typedef void* pointer; typedef const void* const_pointer; template struct rebind { typedef allocator<_Tp1> other; }; -#else - allocator() = default; - - template - constexpr - allocator(const allocator<_Up>&) { } -#endif // ! C++20 +#endif -#if __cplusplus >= 201103L && __cplusplus <= 201703L +#if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2103. std::allocator propagate_on_container_move_assignment typedef true_type propagate_on_container_move_assignment; typedef true_type is_always_equal; +#if __cplusplus > 201703L + allocator() = default; + + template + constexpr + allocator(const allocator<_Up>&) noexcept { } + + // No allocate member because it's ill-formed by LWG 3307. + // No deallocate member because it would be undefined to call it + // with any pointer which wasn't obtained from allocate. + +#else // ! C++20 + // allocator_traits> uses construct and destroy. template void construct(_Up* __p, _Args&&... __args) @@ -101,11 +117,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION destroy(_Up* __p) noexcept(std::is_nothrow_destructible<_Up>::value) { __p->~_Up(); } -#endif // C++11 to C++17 +#endif // C++17 +#endif // C++11 }; +#endif // ! _GLIBCXX_INLINE_VERSION /** - * @brief The @a standard allocator, as per [20.4]. + * @brief The @a standard allocator, as per C++03 [20.4.1]. * * See https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.allocator * for further details. @@ -119,7 +137,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef _Tp value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; + #if __cplusplus <= 201703L + // These were removed for C++20. typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; diff --git a/libstdc++-v3/include/bits/memoryfwd.h b/libstdc++-v3/include/bits/memoryfwd.h index af1a1c69c64..8f7a5a96250 100644 --- a/libstdc++-v3/include/bits/memoryfwd.h +++ b/libstdc++-v3/include/bits/memoryfwd.h @@ -63,15 +63,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template class allocator; -#if __cplusplus <= 201703L template<> class allocator; -#endif #if __cplusplus >= 201103L - /// Declare uses_allocator so it can be specialized in \ etc. + /// Declare uses_allocator so it can be specialized in `` etc. template struct uses_allocator; + + template + struct allocator_traits; #endif /// @} group memory diff --git a/libstdc++-v3/include/ext/malloc_allocator.h b/libstdc++-v3/include/ext/malloc_allocator.h index 366c766f25b..8de833f3641 100644 --- a/libstdc++-v3/include/ext/malloc_allocator.h +++ b/libstdc++-v3/include/ext/malloc_allocator.h @@ -99,9 +99,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // NB: __n is permitted to be 0. The C++ standard says nothing // about what the return value is when __n == 0. - _Tp* + _GLIBCXX_NODISCARD _Tp* allocate(size_type __n, const void* = 0) { +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3308. std::allocator().allocate(n) + static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types"); +#endif + if (__n > this->_M_max_size()) std::__throw_bad_alloc(); diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h index 131718b8b2f..5375be3bbb9 100644 --- a/libstdc++-v3/include/ext/new_allocator.h +++ b/libstdc++-v3/include/ext/new_allocator.h @@ -42,7 +42,7 @@ namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) _GLIBCXX_BEGIN_NAMESPACE_VERSION /** - * @brief An allocator that uses global new, as per [20.4]. + * @brief An allocator that uses global new, as per C++03 [20.4.1]. * @ingroup allocators * * This is precisely the allocator defined in the C++ Standard. @@ -102,6 +102,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NODISCARD _Tp* allocate(size_type __n, const void* = static_cast(0)) { +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3308. std::allocator().allocate(n) + static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types"); +#endif + if (__n > this->_M_max_size()) std::__throw_bad_alloc(); diff --git a/libstdc++-v3/testsuite/20_util/allocator/void.cc b/libstdc++-v3/testsuite/20_util/allocator/void.cc index 86dde5416ea..309f3b5f850 100644 --- a/libstdc++-v3/testsuite/20_util/allocator/void.cc +++ b/libstdc++-v3/testsuite/20_util/allocator/void.cc @@ -33,6 +33,18 @@ test01() std::allocator_traits::destroy(a, &i); } +static_assert( std::allocator::propagate_on_container_move_assignment(), + "POCMA trait should always be present" ); +static_assert( std::allocator::is_always_equal(), + "is_always_equal trait should always be present" ); + +static_assert( + std::is_same::size_type, std::size_t>(), + "size_type is size_t" ); +static_assert( + std::is_same::difference_type, std::ptrdiff_t>(), + "size_type is size_t" ); + // These properties are formally unspecified, but have always been true for // the libstdc++ definition of allocator. static_assert( @@ -51,9 +63,29 @@ static_assert( #if __cplusplus > 201703L // C++20 removes the allocator explicit specialization, so it can now be // constructed using the converting constructor from other specializations. -static_assert( std::is_constructible_v, - std::allocator> ); -#endif +static_assert( std::is_nothrow_constructible_v, + std::allocator> ); + +template +concept has_pointer = requires { typename T::pointer; }; +template +concept has_const_pointer = requires { typename T::const_pointer; }; +template +concept has_size_type = requires { typename T::size_type; }; +template +concept has_difference_type = requires { typename T::difference_type; }; + +// These were removed for C++20 +static_assert( ! has_pointer> ); +static_assert( ! has_const_pointer> ); + +#else +static_assert( + std::is_same::pointer, void*>(), + "pointer is void*" ); +static_assert( std::is_same::const_pointer, const void*>(), + "const_pointer is const void*" ); +#endif // C++20 int main()