From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 15298388CC11 for ; Tue, 11 May 2021 16:33:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 15298388CC11 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-359-ntJ-whjKMA-B7ZpVmerg2w-1; Tue, 11 May 2021 12:33:37 -0400 X-MC-Unique: ntJ-whjKMA-B7ZpVmerg2w-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4554A1009607; Tue, 11 May 2021 16:33:36 +0000 (UTC) Received: from localhost (unknown [10.33.36.164]) by smtp.corp.redhat.com (Postfix) with ESMTP id C961E5C232; Tue, 11 May 2021 16:33:35 +0000 (UTC) Date: Tue, 11 May 2021 17:33:35 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Fix missing members in std::allocator Message-ID: MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: multipart/mixed; boundary="Uig1TrVSrBGoIPmv" Content-Disposition: inline X-Spam-Status: No, score=-15.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 11 May 2021 16:33:42 -0000 --Uig1TrVSrBGoIPmv Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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. The non-standard construct and destroy members added for PR 78052 can be private if allocator_traits> is made a friend. libstdc++-v3/ChangeLog: * include/bits/allocator.h (allocator) [C++20]: Add missing noexcept to constructor. Restore missing POCMA and is_always_equal_traits. [C++17]: Make construct and destroy members private and declare allocator_traits as a friend. * 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. Tested powerpc64le-linux. Committed to trunk. This needs to be backported to 10 and 11, but I won't make the construct/destroy members private on the branches. --Uig1TrVSrBGoIPmv Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="patch.txt" commit 5e3a1ea3d89d62972e1f036b2ede37a80b880bdf Author: Jonathan Wakely Date: Tue May 11 15:01:01 2021 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. The non-standard construct and destroy members added for PR 78052 can be private if allocator_traits> is made a friend. libstdc++-v3/ChangeLog: * include/bits/allocator.h (allocator) [C++20]: Add missing noexcept to constructor. Restore missing POCMA and is_always_equal_traits. [C++17]: Make construct and destroy members private and declare allocator_traits as a friend. * 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. diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index c5c1f28b3d0..73d5d7a25be 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,40 @@ _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; +#endif - template - constexpr - allocator(const allocator<_Up>&) { } -#endif // ! C++20 - -#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 >= 202002L + 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 + private: + // This uses construct and destroy in C++11/14/17 modes. + friend allocator_traits>; + template void construct(_Up* __p, _Args&&... __args) @@ -101,11 +120,14 @@ _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 +141,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 10a386c69d2..b0f0307eb7b 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 3112f7f52bd..1e90b179f53 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 (__builtin_expect(__n > this->_M_max_size(), false)) { // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h index 9e624ba8b50..3fb893be152 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 (__builtin_expect(__n > this->_M_max_size(), false)) { // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/testsuite/20_util/allocator/void.cc b/libstdc++-v3/testsuite/20_util/allocator/void.cc index a172606e174..e3d024d525b 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( @@ -48,12 +60,32 @@ static_assert( std::is_trivially_destructible>::value, "explicit specialization has trivial destructor"); -#if __cplusplus > 201703L +#if __cplusplus >= 202002L // 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() --Uig1TrVSrBGoIPmv--