Revert ABI changes to std::allocator in C++20

The recent C++20 changes to remove the std::allocator<void> explicit
specialization and the destructor in the std::allocator primary template
change the result of some is_trivially_xxx type traits. To avoid those
changes, this patch restores the explicit specialization and the
destructor.

In order to meet the C++20 requirements the std::allocator<void>
explicit specialization must provide the same interface as the primary
template (except for the unusable allocate and deallocate member
functions) and the destructor in the primary template must be constexpr.

	* include/bits/allocator.h (allocator<void>): Restore the explicit
	specialization for C++20, but make its API consistent with the primary
	template.
	(allocator::~allocator()): Restore the destructor for C++20, but make
	it constexpr.
	* testsuite/20_util/allocator/rebind_c++20.cc: Check allocator<void>.
	* testsuite/20_util/allocator/requirements/typedefs_c++20.cc: Likewise.
	* testsuite/20_util/allocator/void.cc: Check that constructors and
	destructors are trivial. Check for converting constructor in C++20.
	* testsuite/ext/malloc_allocator/variadic_construct.cc: Simplify
	dejagnu target selector.
	* testsuite/ext/new_allocator/variadic_construct.cc: Likewise.

From-SVN: r277410
This commit is contained in:
Jonathan Wakely 2019-10-24 16:29:41 +01:00 committed by Jonathan Wakely
parent bf037872d3
commit 75c6a925da
7 changed files with 64 additions and 10 deletions

View File

@ -1,5 +1,18 @@
2019-10-24 Jonathan Wakely <jwakely@redhat.com> 2019-10-24 Jonathan Wakely <jwakely@redhat.com>
* include/bits/allocator.h (allocator<void>): Restore the explicit
specialization for C++20, but make its API consistent with the primary
template.
(allocator::~allocator()): Restore the destructor for C++20, but make
it constexpr.
* testsuite/20_util/allocator/rebind_c++20.cc: Check allocator<void>.
* testsuite/20_util/allocator/requirements/typedefs_c++20.cc: Likewise.
* testsuite/20_util/allocator/void.cc: Check that constructors and
destructors are trivial. Check for converting constructor in C++20.
* testsuite/ext/malloc_allocator/variadic_construct.cc: Simplify
dejagnu target selector.
* testsuite/ext/new_allocator/variadic_construct.cc: Likewise.
* include/experimental/executor (__use_future_ct, use_future_t): * include/experimental/executor (__use_future_ct, use_future_t):
Define partial specializations for std::allocator. Define partial specializations for std::allocator.
(__use_future_ch): Overload constructor for completion tokens using (__use_future_ch): Overload constructor for completion tokens using

View File

@ -63,23 +63,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @{ * @{
*/ */
#if __cplusplus <= 201703L
/// allocator<void> specialization. /// allocator<void> specialization.
template<> template<>
class allocator<void> class allocator<void>
{ {
public: public:
typedef void value_type;
typedef size_t size_type; typedef size_t size_type;
typedef ptrdiff_t difference_type; typedef ptrdiff_t difference_type;
#if __cplusplus <= 201703L
typedef void* pointer; typedef void* pointer;
typedef const void* const_pointer; typedef const void* const_pointer;
typedef void value_type;
template<typename _Tp1> template<typename _Tp1>
struct rebind struct rebind
{ typedef allocator<_Tp1> other; }; { typedef allocator<_Tp1> other; };
#else
allocator() = default;
#if __cplusplus >= 201103L template<typename _Up>
constexpr
allocator(const allocator<_Up>&) { }
#endif // ! C++20
#if __cplusplus >= 201103L && __cplusplus <= 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS // _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2103. std::allocator propagate_on_container_move_assignment // 2103. std::allocator propagate_on_container_move_assignment
typedef true_type propagate_on_container_move_assignment; typedef true_type propagate_on_container_move_assignment;
@ -98,9 +105,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
destroy(_Up* __p) destroy(_Up* __p)
noexcept(noexcept(__p->~_Up())) noexcept(noexcept(__p->~_Up()))
{ __p->~_Up(); } { __p->~_Up(); }
#endif // C++11 #endif // C++11 to C++17
}; };
#endif // ! C++20
/** /**
* @brief The @a standard allocator, as per [20.4]. * @brief The @a standard allocator, as per [20.4].
@ -154,9 +160,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX20_CONSTEXPR _GLIBCXX20_CONSTEXPR
allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { } allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { }
#if __cplusplus <= 201703L _GLIBCXX20_CONSTEXPR
~allocator() _GLIBCXX_NOTHROW { } ~allocator() _GLIBCXX_NOTHROW { }
#endif
#if __cplusplus > 201703L #if __cplusplus > 201703L
[[nodiscard,__gnu__::__always_inline__]] [[nodiscard,__gnu__::__always_inline__]]

View File

@ -23,6 +23,9 @@
template<typename T> struct Alloc : std::allocator<T> { }; template<typename T> struct Alloc : std::allocator<T> { };
using T = std::allocator_traits<Alloc<int>>; using T = std::allocator_traits<Alloc<int>>;
// Prior to C++20 this finds std::allocator<int>::rebind and so fails: // Prior to C++20 this finds std::allocator<int>::rebind and so fails:
static_assert( std::is_same_v<T::rebind_alloc<long>, Alloc<long>> ); static_assert( std::is_same_v<T::rebind_alloc<long>, Alloc<long>> );
using V = std::allocator_traits<Alloc<void>>;
// Prior to C++20 this finds std::allocator<void>::rebind and so fails:
static_assert( std::is_same_v<V::rebind_alloc<long>, Alloc<long>> );

View File

@ -54,3 +54,14 @@ static_assert( !has_rebind<A> );
static_assert( !has_construct<A> ); static_assert( !has_construct<A> );
static_assert( !has_destroy<A> ); static_assert( !has_destroy<A> );
static_assert( !has_max_size<A> ); static_assert( !has_max_size<A> );
using V = std::allocator<void>;
static_assert( !has_pointer<V> );
static_assert( !has_const_pointer<V> );
static_assert( !has_reference<V> );
static_assert( !has_const_reference<V> );
static_assert( !has_rebind<V> );
static_assert( !has_construct<V> );
static_assert( !has_destroy<V> );
static_assert( !has_max_size<V> );

View File

@ -33,6 +33,28 @@ test01()
std::allocator_traits<alloc_type>::destroy(a, &i); std::allocator_traits<alloc_type>::destroy(a, &i);
} }
// These properties are formally unspecified, but have always been true for
// the libstdc++ definition of allocator<void>.
static_assert(
std::is_trivially_default_constructible<std::allocator<void>>::value,
"explicit specialization has trivial default constructor");
static_assert(
std::is_trivially_copy_constructible<std::allocator<void>>::value,
"explicit specialization has trivial copy constructor");
static_assert(
std::is_trivially_move_constructible<std::allocator<void>>::value,
"explicit specialization has trivial move constructor");
static_assert(
std::is_trivially_destructible<std::allocator<void>>::value,
"explicit specialization has trivial destructor");
#if __cplusplus > 201703L
// C++20 removes the allocator<void> explicit specialization, so it can now be
// constructed using the converting constructor from other specializations.
static_assert( std::is_constructible_v<std::allocator<void>,
std::allocator<int>> );
#endif
int int
main() main()
{ {

View File

@ -1,4 +1,4 @@
// { dg-do run { target { { c++11_only || c++14_only } || c++17_only } } } // { dg-do run { target { c++11 && { ! c++2a } } } }
// 2007-10-26 Paolo Carlini <pcarlini@suse.de> // 2007-10-26 Paolo Carlini <pcarlini@suse.de>

View File

@ -1,4 +1,4 @@
// { dg-do run { target { { c++11_only || c++14_only } || c++17_only } } } // { dg-do run { target { c++11 && { ! c++2a } } } }
// 2007-10-26 Paolo Carlini <pcarlini@suse.de> // 2007-10-26 Paolo Carlini <pcarlini@suse.de>