Revert ABI changes to std::allocator in C++20
authorJonathan Wakely <jwakely@redhat.com>
Thu, 24 Oct 2019 15:29:41 +0000 (16:29 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Thu, 24 Oct 2019 15:29:41 +0000 (16:29 +0100)
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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/allocator.h
libstdc++-v3/testsuite/20_util/allocator/rebind_c++20.cc
libstdc++-v3/testsuite/20_util/allocator/requirements/typedefs_c++20.cc
libstdc++-v3/testsuite/20_util/allocator/void.cc
libstdc++-v3/testsuite/ext/malloc_allocator/variadic_construct.cc
libstdc++-v3/testsuite/ext/new_allocator/variadic_construct.cc

index 13e834bfb3e9e82cd2d15c0f35a029fa912963e2..0ae347ee4ff14172e3dc0b399767fc4d9e8523c7 100644 (file)
@@ -1,5 +1,18 @@
 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):
        Define partial specializations for std::allocator.
        (__use_future_ch): Overload constructor for completion tokens using
index 1a3eb88eded69a461ca2b4bb3f1b8cf2a0fe14d3..2559c57b12eb0d91e2ca23e969a014c0a2fb9bf5 100644 (file)
@@ -63,23 +63,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  @{
    */
 
-#if __cplusplus <= 201703L
   /// allocator<void> specialization.
   template<>
     class allocator<void>
     {
     public:
+      typedef void        value_type;
       typedef size_t      size_type;
       typedef ptrdiff_t   difference_type;
+#if __cplusplus <= 201703L
       typedef void*       pointer;
       typedef const void* const_pointer;
-      typedef void        value_type;
 
       template<typename _Tp1>
        struct rebind
        { 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
       // 2103. std::allocator propagate_on_container_move_assignment
       typedef true_type propagate_on_container_move_assignment;
@@ -98,9 +105,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        destroy(_Up* __p)
        noexcept(noexcept(__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].
@@ -154,9 +160,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _GLIBCXX20_CONSTEXPR
        allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { }
 
-#if __cplusplus <= 201703L
+      _GLIBCXX20_CONSTEXPR
       ~allocator() _GLIBCXX_NOTHROW { }
-#endif
 
 #if __cplusplus > 201703L
       [[nodiscard,__gnu__::__always_inline__]]
index 968e1de931befd52b7a710af017b4bc81af409e0..dd7cd67f943b5e2215cba8bf41f7abf505db9b93 100644 (file)
@@ -23,6 +23,9 @@
 template<typename T> struct Alloc : std::allocator<T> { };
 
 using T = std::allocator_traits<Alloc<int>>;
-
 // 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>> );
+
+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>> );
index e986cc9a809daa804621430abc8e00a6283d09f3..ef193fb1bf1125962d029019b559737a21ea643f 100644 (file)
@@ -54,3 +54,14 @@ static_assert( !has_rebind<A> );
 static_assert( !has_construct<A> );
 static_assert( !has_destroy<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> );
index d7aa6bd80ed02e89318b79a9cba97f6148a2e533..9d94fac3cc0218b628d7b933fa2f865fa448ec27 100644 (file)
@@ -33,6 +33,28 @@ test01()
   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
 main()
 {
index b786fae9f0acd27e4f1b4202a82de1fa1a3cb2cd..f122768d8ace01b008ba9d1590dfde328456640d 100644 (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>
 
index 5b23e5b4a2c07abf4279021963ffd606515cdec6..cfe93a7b6d91f8d8c71a18511dcdd377aeef8ab7 100644 (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>