public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction
@ 2019-10-23 19:27 Jonathan Wakely
  2019-10-24 14:49 ` Jonathan Wakely
  2019-10-29  9:23 ` Stephan Bergmann
  0 siblings, 2 replies; 6+ messages in thread
From: Jonathan Wakely @ 2019-10-23 19:27 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3763 bytes --]

This patch is the first part of library support for constexpr
std::vector and std::string. This only includes the changes to
std::allocator, std::allocator_traits, std::construct_at,
std::destroy_at, std::destroy and std::destroy_n.

std::allocator::allocate and std::allocator::deallocate need to be
added so that they can be intercepted by the compiler during constant
evaluation. Outside of constant evaluation those new member functions
just forward to the existing implementation in the base class.

	PR c++/91369 Implement P0784R7 changes to allocation and construction
	* include/bits/alloc_traits.h: Include <bits/stl_construct.h>.
	(allocator_traits::_S_allocate, allocator_traits::_S_construct)
	(allocator_traits::_S_destroy, allocator_traits::_S_max_size)
	(allocator_traits::_S_select, allocator_traits::allocate)
	(allocator_traits::deallocate, allocator_traits::construct)
	(allocator_traits::destroy, allocator_traits::max_size)
	(allocator_traits::select_on_container_copy_construction)
	(allocator_traits<allocator<T>>): Add constexpr specifier for C++20.
	(allocator_traits<allocator<T>>::construct): Use construct_at.
	(allocator_traits<allocator<T>>::destroy): Use destroy_at.
	(__alloc_on_copy, __alloc_on_move, __alloc_on_swap): Add constexpr
	specifier.
	(_Destroy(ForwardIterator, ForwardIterator, Alloc&))
	(_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move here
	from <bits/stl_construct.h>.
	* include/bits/allocator.h (allocator::~allocator): Remove for C++20.
	(allocator::allocate, allocate::deallocate): Define for C++20 and up.
	(operator==, operator!=): Add constexpr specifier for C++20.
	* include/bits/stl_construct.h: Don't include <ext/alloc_traits.h>.
	(destroy_at): For C++20 add constexpr specifier and support for
	destroying arrays.
	(construct_at): Define new function for C++20.
	(_Construct): Return result of placement new-expression. For C++11 and
	up add constexpr. For C++20 dispatch to std::construct_at during
	constant evaluation.
	(_Destroy(pointer)): Add constexpr specifier. For C++20 dispatch to
	std::destroy_at during constant evaluation.
	(_Destroy_aux::__destroy, _Destroy_n_aux::__destroy_n): Add constexpr
	specifier for C++20.
	(_Destroy(ForwardIterator, ForwardIterator))
	(_Destroy(ForwardIterator, Size)): Likewise. Do not elide trivial
	destructors during constant evaluation.
	(destroy, destroy_n): Add constexpr specifier for C++20.
	(_Destroy(ForwardIterator, ForwardIterator, Alloc&))
	(_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move to
	<bits/alloc_traits.h>, to remove dependency on allocators.
	* include/bits/stl_uninitialized.h: Include <ext/alloc_traits.h>.
	Include <bits/stl_pair.h> instead of <utility>.
	* include/ext/alloc_traits.h: Always include <bits/alloc_traits.h>.
	(__alloc_traits::construct, __alloc_traits::destroy)
	(__alloc_traits::_S_select_on_copy, __alloc_traits::_S_on_swap): Add
	constexpr specifier.
	* include/ext/malloc_allocator.h  (operator==, operator!=): Add
	constexpr specifier for C++20.
	* include/ext/new_allocator.h (operator==, operator!=): Likewise.
	* testsuite/20_util/headers/memory/synopsis.cc: Add constexpr.
	* testsuite/20_util/scoped_allocator/69293_neg.cc: Ignore additional
	errors due to constexpr function called after failed static_assert.
	* testsuite/20_util/specialized_algorithms/construct_at/1.cc: New test.
	* testsuite/23_containers/vector/cons/destructible_debug_neg.cc:
	Ignore additional errors due to constexpr function called after failed
	static_assert.
	* testsuite/23_containers/vector/cons/destructible_neg.cc: Likewise.

Tested x86_64-linux and powerpc64le-linux, for every -std=gnu++NN
mode.

Committed to trunk.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 35790 bytes --]

commit da6af26699bec59f9e151a6057c74c3e060c0a79
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Oct 22 23:05:11 2019 +0100

    PR c++/91369 Implement P0784R7 changes to allocation and construction
    
    This patch is the first part of library support for constexpr
    std::vector and std::string. This only includes the changes to
    std::allocator, std::allocator_traits, std::construct_at,
    std::destroy_at, std::destroy and std::destroy_n.
    
    std::allocator::allocate and std::allocator::deallocate need to be
    added so that they can be intercepted by the compiler during constant
    evaluation. Outside of constant evaluation those new member functions
    just forward to the existing implementation in the base class.
    
            PR c++/91369 Implement P0784R7 changes to allocation and construction
            * include/bits/alloc_traits.h: Include <bits/stl_construct.h>.
            (allocator_traits::_S_allocate, allocator_traits::_S_construct)
            (allocator_traits::_S_destroy, allocator_traits::_S_max_size)
            (allocator_traits::_S_select, allocator_traits::allocate)
            (allocator_traits::deallocate, allocator_traits::construct)
            (allocator_traits::destroy, allocator_traits::max_size)
            (allocator_traits::select_on_container_copy_construction)
            (allocator_traits<allocator<T>>): Add constexpr specifier for C++20.
            (allocator_traits<allocator<T>>::construct): Use construct_at.
            (allocator_traits<allocator<T>>::destroy): Use destroy_at.
            (__alloc_on_copy, __alloc_on_move, __alloc_on_swap): Add constexpr
            specifier.
            (_Destroy(ForwardIterator, ForwardIterator, Alloc&))
            (_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move here
            from <bits/stl_construct.h>.
            * include/bits/allocator.h (allocator::~allocator): Remove for C++20.
            (allocator::allocate, allocate::deallocate): Define for C++20 and up.
            (operator==, operator!=): Add constexpr specifier for C++20.
            * include/bits/stl_construct.h: Don't include <ext/alloc_traits.h>.
            (destroy_at): For C++20 add constexpr specifier and support for
            destroying arrays.
            (construct_at): Define new function for C++20.
            (_Construct): Return result of placement new-expression. For C++11 and
            up add constexpr. For C++20 dispatch to std::construct_at during
            constant evaluation.
            (_Destroy(pointer)): Add constexpr specifier. For C++20 dispatch to
            std::destroy_at during constant evaluation.
            (_Destroy_aux::__destroy, _Destroy_n_aux::__destroy_n): Add constexpr
            specifier for C++20.
            (_Destroy(ForwardIterator, ForwardIterator))
            (_Destroy(ForwardIterator, Size)): Likewise. Do not elide trivial
            destructors during constant evaluation.
            (destroy, destroy_n): Add constexpr specifier for C++20.
            (_Destroy(ForwardIterator, ForwardIterator, Alloc&))
            (_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move to
            <bits/alloc_traits.h>, to remove dependency on allocators.
            * include/bits/stl_uninitialized.h: Include <ext/alloc_traits.h>.
            Include <bits/stl_pair.h> instead of <utility>.
            * include/ext/alloc_traits.h: Always include <bits/alloc_traits.h>.
            (__alloc_traits::construct, __alloc_traits::destroy)
            (__alloc_traits::_S_select_on_copy, __alloc_traits::_S_on_swap): Add
            constexpr specifier.
            * include/ext/malloc_allocator.h  (operator==, operator!=): Add
            constexpr specifier for C++20.
            * include/ext/new_allocator.h (operator==, operator!=): Likewise.
            * testsuite/20_util/headers/memory/synopsis.cc: Add constexpr.
            * testsuite/20_util/scoped_allocator/69293_neg.cc: Ignore additional
            errors due to constexpr function called after failed static_assert.
            * testsuite/20_util/specialized_algorithms/construct_at/1.cc: New test.
            * testsuite/23_containers/vector/cons/destructible_debug_neg.cc:
            Ignore additional errors due to constexpr function called after failed
            static_assert.
            * testsuite/23_containers/vector/cons/destructible_neg.cc: Likewise.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
index 62bbf0b2e31..26d6d26ae48 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -30,18 +30,21 @@
 #ifndef _ALLOC_TRAITS_H
 #define _ALLOC_TRAITS_H 1
 
-#if __cplusplus >= 201103L
-
+#include <bits/stl_construct.h>
 #include <bits/memoryfwd.h>
-#include <bits/ptr_traits.h>
-#include <ext/numeric_traits.h>
-
-#define __cpp_lib_allocator_traits_is_always_equal 201411
+#if __cplusplus >= 201103L
+# include <bits/allocator.h>
+# include <bits/ptr_traits.h>
+# include <ext/numeric_traits.h>
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+#if __cplusplus >= 201103L
+#define __cpp_lib_allocator_traits_is_always_equal 201411
+
   struct __allocator_traits_base
   {
     template<typename _Tp, typename _Up, typename = void>
@@ -209,13 +212,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     private:
       template<typename _Alloc2>
-	static auto
+	static constexpr auto
 	_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer __hint, int)
 	-> decltype(__a.allocate(__n, __hint))
 	{ return __a.allocate(__n, __hint); }
 
       template<typename _Alloc2>
-	static pointer
+	static constexpr pointer
 	_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer, ...)
 	{ return __a.allocate(__n); }
 
@@ -238,41 +241,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  = typename __construct_helper<_Tp, _Args...>::type;
 
       template<typename _Tp, typename... _Args>
-	static _Require<__has_construct<_Tp, _Args...>>
+	static constexpr _Require<__has_construct<_Tp, _Args...>>
 	_S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
 	noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
 	{ __a.construct(__p, std::forward<_Args>(__args)...); }
 
       template<typename _Tp, typename... _Args>
-	static
+	static constexpr
 	_Require<__and_<__not_<__has_construct<_Tp, _Args...>>,
 			       is_constructible<_Tp, _Args...>>>
 	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
 	noexcept(noexcept(::new((void*)__p)
 			  _Tp(std::forward<_Args>(__args)...)))
-	{ ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
+	{ std::_Construct(__p, std::forward<_Args>(__args)...); }
 
       template<typename _Alloc2, typename _Tp>
-	static auto
+	static constexpr auto
 	_S_destroy(_Alloc2& __a, _Tp* __p, int)
 	noexcept(noexcept(__a.destroy(__p)))
 	-> decltype(__a.destroy(__p))
 	{ __a.destroy(__p); }
 
       template<typename _Alloc2, typename _Tp>
-	static void
+	static constexpr void
 	_S_destroy(_Alloc2&, _Tp* __p, ...)
 	noexcept(noexcept(__p->~_Tp()))
-	{ __p->~_Tp(); }
+	{ std::_Destroy(__p); }
 
       template<typename _Alloc2>
-	static auto
+	static constexpr auto
 	_S_max_size(_Alloc2& __a, int)
 	-> decltype(__a.max_size())
 	{ return __a.max_size(); }
 
       template<typename _Alloc2>
-	static size_type
+	static constexpr size_type
 	_S_max_size(_Alloc2&, ...)
 	{
 	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -282,13 +285,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       template<typename _Alloc2>
-	static auto
+	static constexpr auto
 	_S_select(_Alloc2& __a, int)
 	-> decltype(__a.select_on_container_copy_construction())
 	{ return __a.select_on_container_copy_construction(); }
 
       template<typename _Alloc2>
-	static _Alloc2
+	static constexpr _Alloc2
 	_S_select(_Alloc2& __a, ...)
 	{ return __a; }
 
@@ -301,7 +304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Calls @c a.allocate(n)
       */
-      _GLIBCXX_NODISCARD static pointer
+      _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
       allocate(_Alloc& __a, size_type __n)
       { return __a.allocate(__n); }
 
@@ -316,7 +319,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  Returns <tt> a.allocate(n, hint) </tt> if that expression is
        *  well-formed, otherwise returns @c a.allocate(n)
       */
-      _GLIBCXX_NODISCARD static pointer
+      _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
       allocate(_Alloc& __a, size_type __n, const_void_pointer __hint)
       { return _S_allocate(__a, __n, __hint, 0); }
 
@@ -328,7 +331,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Calls <tt> a.deallocate(p, n) </tt>
       */
-      static void
+      static _GLIBCXX20_CONSTEXPR void
       deallocate(_Alloc& __a, pointer __p, size_type __n)
       { __a.deallocate(__p, __n); }
 
@@ -344,7 +347,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  arguments @a __args...
       */
       template<typename _Tp, typename... _Args>
-	static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+	static _GLIBCXX20_CONSTEXPR auto
+	construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
 	noexcept(noexcept(_S_construct(__a, __p,
 				       std::forward<_Args>(__args)...)))
 	-> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...))
@@ -359,7 +363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  otherwise calls @c __p->~_Tp()
       */
       template<typename _Tp>
-	static void destroy(_Alloc& __a, _Tp* __p)
+	static _GLIBCXX20_CONSTEXPR void
+	destroy(_Alloc& __a, _Tp* __p)
 	noexcept(noexcept(_S_destroy(__a, __p, 0)))
 	{ _S_destroy(__a, __p, 0); }
 
@@ -371,7 +376,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  Returns @c __a.max_size() if that expression is well-formed,
        *  otherwise returns @c numeric_limits<size_type>::max()
       */
-      static size_type max_size(const _Alloc& __a) noexcept
+      static _GLIBCXX20_CONSTEXPR size_type
+      max_size(const _Alloc& __a) noexcept
       { return _S_max_size(__a, 0); }
 
       /**
@@ -382,7 +388,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  Returns @c __rhs.select_on_container_copy_construction() if that
        *  expression is well-formed, otherwise returns @a __rhs
       */
-      static _Alloc
+      static _GLIBCXX20_CONSTEXPR _Alloc
       select_on_container_copy_construction(const _Alloc& __rhs)
       { return _S_select(__rhs, 0); }
     };
@@ -440,7 +446,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Calls @c a.allocate(n)
       */
-      _GLIBCXX_NODISCARD static pointer
+      _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
       allocate(allocator_type& __a, size_type __n)
       { return __a.allocate(__n); }
 
@@ -454,7 +460,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Returns <tt> a.allocate(n, hint) </tt>
       */
-      _GLIBCXX_NODISCARD static pointer
+      _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
       allocate(allocator_type& __a, size_type __n, const_void_pointer __hint)
       {
 #if __cplusplus <= 201703L
@@ -472,27 +478,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  Calls <tt> a.deallocate(p, n) </tt>
       */
-      static void
+      static _GLIBCXX20_CONSTEXPR void
       deallocate(allocator_type& __a, pointer __p, size_type __n)
       { __a.deallocate(__p, __n); }
 
       /**
-       *  @brief  Construct an object of type @a _Up
+       *  @brief  Construct an object of type `_Up`
        *  @param  __a  An allocator.
-       *  @param  __p  Pointer to memory of suitable size and alignment for Tp
+       *  @param  __p  Pointer to memory of suitable size and alignment for
+       *	       an object of type `_Up`.
        *  @param  __args Constructor arguments.
        *
-       *  Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
+       *  Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
+       *  in C++11, C++14 and C++17. Changed in C++20 to call
+       *  `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
       */
       template<typename _Up, typename... _Args>
-	static void
+	static _GLIBCXX20_CONSTEXPR void
 	construct(allocator_type& __a, _Up* __p, _Args&&... __args)
 	noexcept(noexcept(::new((void*)__p) _Up(std::forward<_Args>(__args)...)))
 	{
 #if __cplusplus <= 201703L
 	  __a.construct(__p, std::forward<_Args>(__args)...);
 #else
-	  ::new((void*)__p) _Up(std::forward<_Args>(__args)...);
+	  std::construct_at(__p, std::forward<_Args>(__args)...);
 #endif
 	}
 
@@ -504,14 +513,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  Calls @c __a.destroy(__p).
       */
       template<typename _Up>
-	static void
+	static _GLIBCXX20_CONSTEXPR void
 	destroy(allocator_type& __a, _Up* __p)
 	noexcept(is_nothrow_destructible<_Up>::value)
 	{
 #if __cplusplus <= 201703L
 	  __a.destroy(__p);
 #else
-	  __p->~_Up();
+	  std::destroy_at(__p);
 #endif
 	}
 
@@ -520,7 +529,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  @param  __a  An allocator.
        *  @return @c __a.max_size()
       */
-      static size_type
+      static _GLIBCXX20_CONSTEXPR size_type
       max_size(const allocator_type& __a) noexcept
       {
 #if __cplusplus <= 201703L
@@ -535,7 +544,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  @param  __rhs  An allocator.
        *  @return @c __rhs
       */
-      static allocator_type
+      static _GLIBCXX20_CONSTEXPR allocator_type
       select_on_container_copy_construction(const allocator_type& __rhs)
       { return __rhs; }
     };
@@ -553,7 +562,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   template<typename _Alloc>
-    inline void __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
+    constexpr void
+    __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
     {
       typedef allocator_traits<_Alloc> __traits;
       typedef typename __traits::propagate_on_container_copy_assignment __pocca;
@@ -566,7 +576,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Alloc>
-    inline _Alloc __alloc_on_copy(const _Alloc& __a)
+    constexpr _Alloc
+    __alloc_on_copy(const _Alloc& __a)
     {
       typedef allocator_traits<_Alloc> __traits;
       return __traits::select_on_container_copy_construction(__a);
@@ -583,7 +594,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   template<typename _Alloc>
-    inline void __alloc_on_move(_Alloc& __one, _Alloc& __two)
+    constexpr void
+    __alloc_on_move(_Alloc& __one, _Alloc& __two)
     {
       typedef allocator_traits<_Alloc> __traits;
       typedef typename __traits::propagate_on_container_move_assignment __pocma;
@@ -609,7 +621,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   template<typename _Alloc>
-    inline void __alloc_on_swap(_Alloc& __one, _Alloc& __two)
+    constexpr void
+    __alloc_on_swap(_Alloc& __one, _Alloc& __two)
     {
       typedef allocator_traits<_Alloc> __traits;
       typedef typename __traits::propagate_on_container_swap __pocs;
@@ -685,8 +698,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Alloc>
     using _RequireNotAllocator
       = typename enable_if<!__is_allocator<_Alloc>::value, _Alloc>::type;
+#endif // C++11
+
+  /**
+   * Destroy a range of objects using the supplied allocator.  For
+   * non-default allocators we do not optimize away invocation of
+   * destroy() even if _Tp has a trivial destructor.
+   */
+
+  template<typename _ForwardIterator, typename _Allocator>
+    void
+    _Destroy(_ForwardIterator __first, _ForwardIterator __last,
+	     _Allocator& __alloc)
+    {
+      for (; __first != __last; ++__first)
+#if __cplusplus < 201103L
+	__alloc.destroy(std::__addressof(*__first));
+#else
+	allocator_traits<_Allocator>::destroy(__alloc,
+					      std::__addressof(*__first));
+#endif
+    }
+
+  template<typename _ForwardIterator, typename _Tp>
+    inline void
+    _Destroy(_ForwardIterator __first, _ForwardIterator __last,
+	     allocator<_Tp>&)
+    {
+      _Destroy(__first, __last);
+    }
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
-#endif // C++11
 #endif // _ALLOC_TRAITS_H
diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h
index 62a40a17e3c..1a3eb88eded 100644
--- a/libstdc++-v3/include/bits/allocator.h
+++ b/libstdc++-v3/include/bits/allocator.h
@@ -154,13 +154,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_GLIBCXX20_CONSTEXPR
 	allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { }
 
+#if __cplusplus <= 201703L
       ~allocator() _GLIBCXX_NOTHROW { }
+#endif
 
-      friend bool
+#if __cplusplus > 201703L
+      [[nodiscard,__gnu__::__always_inline__]]
+      constexpr _Tp*
+      allocate(size_t __n)
+      {
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
+#endif
+	return __allocator_base<_Tp>::allocate(__n, 0);
+      }
+
+      [[__gnu__::__always_inline__]]
+      constexpr void
+      deallocate(_Tp* __p, size_t __n)
+      {
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  {
+	    ::operator delete(__p);
+	    return;
+	  }
+#endif
+	  __allocator_base<_Tp>::deallocate(__p, __n);
+      }
+#endif // C++20
+
+      friend _GLIBCXX20_CONSTEXPR bool
       operator==(const allocator&, const allocator&) _GLIBCXX_NOTHROW
       { return true; }
 
-      friend bool
+      friend _GLIBCXX20_CONSTEXPR bool
       operator!=(const allocator&, const allocator&) _GLIBCXX_NOTHROW
       { return false; }
 
@@ -168,13 +197,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   template<typename _T1, typename _T2>
-    inline bool
+    inline _GLIBCXX20_CONSTEXPR bool
     operator==(const allocator<_T1>&, const allocator<_T2>&)
     _GLIBCXX_NOTHROW
     { return true; }
 
   template<typename _T1, typename _T2>
-    inline bool
+    inline _GLIBCXX20_CONSTEXPR bool
     operator!=(const allocator<_T1>&, const allocator<_T2>&)
     _GLIBCXX_NOTHROW
     { return false; }
diff --git a/libstdc++-v3/include/bits/stl_construct.h b/libstdc++-v3/include/bits/stl_construct.h
index bf063398ebe..a16196ffe74 100644
--- a/libstdc++-v3/include/bits/stl_construct.h
+++ b/libstdc++-v3/include/bits/stl_construct.h
@@ -58,29 +58,69 @@
 
 #include <new>
 #include <bits/move.h>
-#include <ext/alloc_traits.h>
+#include <bits/stl_iterator_base_types.h> // for iterator_traits
+#include <bits/stl_iterator_base_funcs.h> // for advance
+
+/* This file provides the C++17 functions std::destroy_at, std::destroy, and
+ * std::destroy_n, and the C++20 function std::construct_at.
+ * It also provides std::_Construct, std::_Destroy,and std::_Destroy_n functions
+ * which are defined in all standard modes and so can be used in C++98-14 code.
+ * The _Construct and _Destroy functions will dispatch to construct_at and
+ * destroy_at during constant evaluation, because calls to those functions are
+ * intercepted by the compiler to allow use in constant expressions.
+ */
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+#if __cplusplus >= 201703L
+  template <typename _Tp>
+    _GLIBCXX20_CONSTEXPR inline void
+    destroy_at(_Tp* __location)
+    {
+      if constexpr (__cplusplus > 201703L && is_array_v<_Tp>)
+	{
+	  for (auto& __x : *__location)
+	    std::destroy_at(std::__addressof(__x));
+	}
+      else
+	__location->~_Tp();
+    }
+
+#if __cplusplus > 201703L
+  template<typename _Tp, typename... _Args>
+    constexpr auto
+    construct_at(_Tp* __location, _Args&&... __args)
+    noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
+    -> decltype(::new((void*)0) _Tp(std::declval<_Args>()...))
+    { return ::new((void*)__location) _Tp(std::forward<_Args>(__args)...); }
+#endif // C++20
+#endif// C++17
+
   /**
    * Constructs an object in existing memory by invoking an allocated
    * object's constructor with an initializer.
    */
 #if __cplusplus >= 201103L
-  template<typename _T1, typename... _Args>
-    inline void
-    _Construct(_T1* __p, _Args&&... __args)
-    { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
+  template<typename _Tp, typename... _Args>
+    constexpr _Tp*
+    _Construct(_Tp* __p, _Args&&... __args)
+    {
+#if __cplusplus > 201703L
+      return std::construct_at(__p, std::forward<_Args>(__args)...);
+#else
+      return ::new(static_cast<void*>(__p)) _Tp(std::forward<_Args>(__args)...);
+#endif
+    }
 #else
   template<typename _T1, typename _T2>
-    inline void
+    inline _T1*
     _Construct(_T1* __p, const _T2& __value)
     {
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 402. wrong new expression in [some_]allocator::construct
-      ::new(static_cast<void*>(__p)) _T1(__value);
+      return ::new(static_cast<void*>(__p)) _T1(__value);
     }
 #endif
 
@@ -89,20 +129,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     _Construct_novalue(_T1* __p)
     { ::new(static_cast<void*>(__p)) _T1; }
 
+  template<typename _ForwardIterator>
+    _GLIBCXX20_CONSTEXPR void
+    _Destroy(_ForwardIterator __first, _ForwardIterator __last);
+
   /**
    * Destroy the object pointed to by a pointer type.
    */
   template<typename _Tp>
-    inline void
+    _GLIBCXX_CONSTEXPR inline void
     _Destroy(_Tp* __pointer)
-    { __pointer->~_Tp(); }
+    {
+#if __cplusplus > 201703L
+      std::destroy_at(__pointer);
+#else
+      __pointer->~_Tp();
+#endif
+    }
 
   template<bool>
     struct _Destroy_aux
     {
       template<typename _ForwardIterator>
-        static void
-        __destroy(_ForwardIterator __first, _ForwardIterator __last)
+	static _GLIBCXX20_CONSTEXPR void
+	__destroy(_ForwardIterator __first, _ForwardIterator __last)
 	{
 	  for (; __first != __last; ++__first)
 	    std::_Destroy(std::__addressof(*__first));
@@ -123,7 +173,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * away, otherwise the objects' destructors must be invoked.
    */
   template<typename _ForwardIterator>
-    inline void
+    _GLIBCXX20_CONSTEXPR inline void
     _Destroy(_ForwardIterator __first, _ForwardIterator __last)
     {
       typedef typename iterator_traits<_ForwardIterator>::value_type
@@ -132,6 +182,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // A deleted destructor is trivial, this ensures we reject such types:
       static_assert(is_destructible<_Value_type>::value,
 		    "value type is destructible");
+#endif
+#if __cplusplus > 201703L && defined __cpp_lib_is_constant_evaluated
+      if (std::is_constant_evaluated())
+	return _Destroy_aux<false>::__destroy(__first, __last);
 #endif
       std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
 	__destroy(__first, __last);
@@ -141,8 +195,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct _Destroy_n_aux
     {
       template<typename _ForwardIterator, typename _Size>
-        static _ForwardIterator
-        __destroy_n(_ForwardIterator __first, _Size __count)
+	static _GLIBCXX20_CONSTEXPR _ForwardIterator
+	__destroy_n(_ForwardIterator __first, _Size __count)
 	{
 	  for (; __count > 0; (void)++__first, --__count)
 	    std::_Destroy(std::__addressof(*__first));
@@ -168,7 +222,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * away, otherwise the objects' destructors must be invoked.
    */
   template<typename _ForwardIterator, typename _Size>
-    inline _ForwardIterator
+    _GLIBCXX20_CONSTEXPR inline _ForwardIterator
     _Destroy_n(_ForwardIterator __first, _Size __count)
     {
       typedef typename iterator_traits<_ForwardIterator>::value_type
@@ -177,60 +231,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // A deleted destructor is trivial, this ensures we reject such types:
       static_assert(is_destructible<_Value_type>::value,
 		    "value type is destructible");
+#endif
+#if __cplusplus > 201703L && defined __cpp_lib_is_constant_evaluated
+      if (std::is_constant_evaluated())
+	return _Destroy_n_aux<false>::__destroy_n(__first, __count);
 #endif
       return std::_Destroy_n_aux<__has_trivial_destructor(_Value_type)>::
 	__destroy_n(__first, __count);
     }
 
-  /**
-   * Destroy a range of objects using the supplied allocator.  For
-   * nondefault allocators we do not optimize away invocation of 
-   * destroy() even if _Tp has a trivial destructor.
-   */
-
-  template<typename _ForwardIterator, typename _Allocator>
-    void
-    _Destroy(_ForwardIterator __first, _ForwardIterator __last,
-	     _Allocator& __alloc)
-    {
-      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
-      for (; __first != __last; ++__first)
-	__traits::destroy(__alloc, std::__addressof(*__first));
-    }
-
-  template<typename _ForwardIterator, typename _Tp>
-    inline void
-    _Destroy(_ForwardIterator __first, _ForwardIterator __last,
-	     allocator<_Tp>&)
-    {
-      _Destroy(__first, __last);
-    }
-
-#if __cplusplus > 201402L
-  template <typename _Tp>
-    inline void
-    destroy_at(_Tp* __location)
-    {
-      std::_Destroy(__location);
-    }
-
+#if __cplusplus >= 201703L
   template <typename _ForwardIterator>
-    inline void
+    _GLIBCXX20_CONSTEXPR inline void
     destroy(_ForwardIterator __first, _ForwardIterator __last)
     {
       std::_Destroy(__first, __last);
     }
 
   template <typename _ForwardIterator, typename _Size>
-    inline _ForwardIterator
+    _GLIBCXX20_CONSTEXPR inline _ForwardIterator
     destroy_n(_ForwardIterator __first, _Size __count)
     {
       return std::_Destroy_n(__first, __count);
     }
-#endif
+#endif // C++17
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #endif /* _STL_CONSTRUCT_H */
-
diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h
index cf42cbd9c76..79d27c83d85 100644
--- a/libstdc++-v3/include/bits/stl_uninitialized.h
+++ b/libstdc++-v3/include/bits/stl_uninitialized.h
@@ -57,13 +57,15 @@
 #define _STL_UNINITIALIZED_H 1
 
 #if __cplusplus > 201402L
-#include <utility>
+#include <bits/stl_pair.h>
 #endif
 
 #if __cplusplus >= 201103L
 #include <type_traits>
 #endif
 
+#include <ext/alloc_traits.h>
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
diff --git a/libstdc++-v3/include/ext/alloc_traits.h b/libstdc++-v3/include/ext/alloc_traits.h
index 65340eb7acc..052d811ec01 100644
--- a/libstdc++-v3/include/ext/alloc_traits.h
+++ b/libstdc++-v3/include/ext/alloc_traits.h
@@ -31,10 +31,8 @@
 
 #pragma GCC system_header
 
-#if __cplusplus >= 201103L
-# include <bits/move.h>
 # include <bits/alloc_traits.h>
-#else
+#if __cplusplus < 201103L
 # include <bits/allocator.h>  // for __alloc_swap
 #endif
 
@@ -78,7 +76,7 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
   public:
     // overload construct for non-standard pointer types
     template<typename _Ptr, typename... _Args>
-      static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
+      static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
       construct(_Alloc& __a, _Ptr __p, _Args&&... __args)
       noexcept(noexcept(_Base_type::construct(__a, std::__to_address(__p),
 					      std::forward<_Args>(__args)...)))
@@ -89,15 +87,15 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
 
     // overload destroy for non-standard pointer types
     template<typename _Ptr>
-      static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
+      static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
       destroy(_Alloc& __a, _Ptr __p)
       noexcept(noexcept(_Base_type::destroy(__a, std::__to_address(__p))))
       { _Base_type::destroy(__a, std::__to_address(__p)); }
 
-    static _Alloc _S_select_on_copy(const _Alloc& __a)
+    static constexpr _Alloc _S_select_on_copy(const _Alloc& __a)
     { return _Base_type::select_on_container_copy_construction(__a); }
 
-    static void _S_on_swap(_Alloc& __a, _Alloc& __b)
+    static constexpr void _S_on_swap(_Alloc& __a, _Alloc& __b)
     { std::__alloc_on_swap(__a, __b); }
 
     static constexpr bool _S_propagate_on_copy_assign()
@@ -118,7 +116,7 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
     template<typename _Tp>
       struct rebind
       { typedef typename _Base_type::template rebind_alloc<_Tp> other; };
-#else
+#else // ! C++11
 
     typedef typename _Alloc::pointer                pointer;
     typedef typename _Alloc::const_pointer          const_pointer;
@@ -162,7 +160,7 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
     template<typename _Tp>
       struct rebind
       { typedef typename _Alloc::template rebind<_Tp>::other other; };
-#endif
+#endif // C++11
   };
 
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/include/ext/malloc_allocator.h b/libstdc++-v3/include/ext/malloc_allocator.h
index cf6284080e8..a2bbdb38ebc 100644
--- a/libstdc++-v3/include/ext/malloc_allocator.h
+++ b/libstdc++-v3/include/ext/malloc_allocator.h
@@ -169,13 +169,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif // ! C++20
 
       template<typename _Up>
-	friend bool
+	friend _GLIBCXX20_CONSTEXPR bool
 	operator==(const malloc_allocator&, const malloc_allocator<_Up>&)
 	_GLIBCXX_NOTHROW
 	{ return true; }
 
       template<typename _Up>
-	friend bool
+	friend _GLIBCXX20_CONSTEXPR bool
 	operator!=(const malloc_allocator&, const malloc_allocator<_Up>&)
 	_GLIBCXX_NOTHROW
 	{ return false; }
diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h
index cff9f1dca9c..c6358da4cae 100644
--- a/libstdc++-v3/include/ext/new_allocator.h
+++ b/libstdc++-v3/include/ext/new_allocator.h
@@ -168,13 +168,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif // ! C++20
 
       template<typename _Up>
-	friend bool
+	friend _GLIBCXX20_CONSTEXPR bool
 	operator==(const new_allocator&, const new_allocator<_Up>&)
 	_GLIBCXX_NOTHROW
 	{ return true; }
 
       template<typename _Up>
-	friend bool
+	friend _GLIBCXX20_CONSTEXPR bool
 	operator!=(const new_allocator&, const new_allocator<_Up>&)
 	_GLIBCXX_NOTHROW
 	{ return false; }
diff --git a/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc b/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc
index 99b5cef1c05..579dccd9274 100644
--- a/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc
+++ b/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc
@@ -25,8 +25,14 @@ namespace std {
   template <class T> class allocator;
   template <> class allocator<void>;
   template <class T, class U>
+#if __cplusplus > 201703L
+  constexpr
+#endif
   bool operator==(const allocator<T>&, const allocator<U>&) throw();
   template <class T, class U>
+#if __cplusplus > 201703L
+  constexpr
+#endif
   bool operator!=(const allocator<T>&, const allocator<U>&) throw();
 
   //  lib.storage.iterator, raw storage iterator:
diff --git a/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc b/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
index 69f7280a3de..c14ef612c60 100644
--- a/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
@@ -48,3 +48,6 @@ test01()
   sa.construct(p);  // this is required to be ill-formed
   // { dg-error "failed: .* uses_allocator is true" "" { target *-*-* } 0 }
 }
+
+// Needed because of PR c++/92193
+// { dg-prune-output "no matching function for call to" }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/construct_at/1.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/construct_at/1.cc
new file mode 100644
index 00000000000..6485122c610
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/construct_at/1.cc
@@ -0,0 +1,64 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+template<typename T, typename... Args>
+  concept can_construct_at = requires(T* p, Args&&... args)
+  {
+    p = std::construct_at(p, std::forward<Args>(args)...);
+  };
+
+static_assert( can_construct_at<int> );
+static_assert( can_construct_at<int, int> );
+static_assert( !can_construct_at<int, int, int> );
+
+// Not required by C++20:
+static_assert( noexcept(std::construct_at(std::declval<int*>(), 1)) );
+
+void
+test01()
+{
+  int i = -1;
+  auto p = std::construct_at(&i);
+  VERIFY( p == &i );
+  VERIFY( i == 0 );
+  p = std::construct_at(&i, 42);
+  VERIFY( p == &i );
+  VERIFY( i == 42 );
+}
+
+struct X {
+  X(char&, void*) { }
+};
+
+static_assert( can_construct_at<X, char&, void*> );
+static_assert( !can_construct_at<X> );
+static_assert( !can_construct_at<X, char> );
+static_assert( !can_construct_at<X, char&, const void*> );
+
+static_assert( !noexcept(std::construct_at(std::declval<X*>(), std::declval<char&>(), std::declval<void*>())) );
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
index daeab2fe26b..905175e5a6f 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
@@ -47,3 +47,7 @@ test02()
 
 // In Debug Mode the "required from here" errors come from <debug/vector>
 // { dg-error "required from here" "" { target *-*-* } 163 }
+
+// Needed because of PR c++/92193
+// { dg-prune-output "deleted function" }
+// { dg-prune-output "private within this context" }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc
index 1ac31029baf..7f3549a7285 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc
@@ -43,3 +43,7 @@ test02()
 }
 
 // { dg-error "value type is destructible" "" { target *-*-* } 0 }
+
+// Needed because of PR c++/92193
+// { dg-prune-output "deleted function" }
+// { dg-prune-output "private within this context" }

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction
  2019-10-23 19:27 [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction Jonathan Wakely
@ 2019-10-24 14:49 ` Jonathan Wakely
  2019-10-24 15:42   ` Jonathan Wakely
  2019-10-29  9:23 ` Stephan Bergmann
  1 sibling, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2019-10-24 14:49 UTC (permalink / raw)
  To: libstdc++, gcc-patches

On 23/10/19 20:27 +0100, Jonathan Wakely wrote:
>--- a/libstdc++-v3/include/bits/allocator.h
>+++ b/libstdc++-v3/include/bits/allocator.h
>@@ -154,13 +154,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 	_GLIBCXX20_CONSTEXPR
> 	allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { }
>
>+#if __cplusplus <= 201703L
>       ~allocator() _GLIBCXX_NOTHROW { }
>+#endif

This changes the value of is_trivially_destructible_v<allocator<T>> so
maybe it would be better to keep the user-provided destructor but make
it constexpr:

--- a/libstdc++-v3/include/bits/allocator.h
+++ b/libstdc++-v3/include/bits/allocator.h
@@ -154,9 +154,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__]]

With the earlier commit r277300 I've still changed the result of
is_trivially_destructible_v<allocator<void>> and
is_trivially_*_constructible_v<allocator<void>> because the
allocator<void> explicit specialization no longer exists for C++20.
That might be a bigger problem.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction
  2019-10-24 14:49 ` Jonathan Wakely
@ 2019-10-24 15:42   ` Jonathan Wakely
  0 siblings, 0 replies; 6+ messages in thread
From: Jonathan Wakely @ 2019-10-24 15:42 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1428 bytes --]

On 24/10/19 15:31 +0100, Jonathan Wakely wrote:
>On 23/10/19 20:27 +0100, Jonathan Wakely wrote:
>>--- a/libstdc++-v3/include/bits/allocator.h
>>+++ b/libstdc++-v3/include/bits/allocator.h
>>@@ -154,13 +154,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>	_GLIBCXX20_CONSTEXPR
>>	allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { }
>>
>>+#if __cplusplus <= 201703L
>>      ~allocator() _GLIBCXX_NOTHROW { }
>>+#endif
>
>This changes the value of is_trivially_destructible_v<allocator<T>> so
>maybe it would be better to keep the user-provided destructor but make
>it constexpr:
>
>--- a/libstdc++-v3/include/bits/allocator.h
>+++ b/libstdc++-v3/include/bits/allocator.h
>@@ -154,9 +154,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__]]
>
>With the earlier commit r277300 I've still changed the result of
>is_trivially_destructible_v<allocator<void>> and
>is_trivially_*_constructible_v<allocator<void>> because the
>allocator<void> explicit specialization no longer exists for C++20.
>That might be a bigger problem.

This restores the previous properties of std::allocator.

Tested powerpc64le-linux, committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 7553 bytes --]

commit 29d60b4d998ba2678da4ef8417ef58f5373cad8b
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 24 15:52:57 2019 +0100

    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.

diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h
index 1a3eb88eded..2559c57b12e 100644
--- a/libstdc++-v3/include/bits/allocator.h
+++ b/libstdc++-v3/include/bits/allocator.h
@@ -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__]]
diff --git a/libstdc++-v3/testsuite/20_util/allocator/rebind_c++20.cc b/libstdc++-v3/testsuite/20_util/allocator/rebind_c++20.cc
index 968e1de931b..dd7cd67f943 100644
--- a/libstdc++-v3/testsuite/20_util/allocator/rebind_c++20.cc
+++ b/libstdc++-v3/testsuite/20_util/allocator/rebind_c++20.cc
@@ -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>> );
diff --git a/libstdc++-v3/testsuite/20_util/allocator/requirements/typedefs_c++20.cc b/libstdc++-v3/testsuite/20_util/allocator/requirements/typedefs_c++20.cc
index e986cc9a809..ef193fb1bf1 100644
--- a/libstdc++-v3/testsuite/20_util/allocator/requirements/typedefs_c++20.cc
+++ b/libstdc++-v3/testsuite/20_util/allocator/requirements/typedefs_c++20.cc
@@ -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> );
diff --git a/libstdc++-v3/testsuite/20_util/allocator/void.cc b/libstdc++-v3/testsuite/20_util/allocator/void.cc
index d7aa6bd80ed..9d94fac3cc0 100644
--- a/libstdc++-v3/testsuite/20_util/allocator/void.cc
+++ b/libstdc++-v3/testsuite/20_util/allocator/void.cc
@@ -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()
 {
diff --git a/libstdc++-v3/testsuite/ext/malloc_allocator/variadic_construct.cc b/libstdc++-v3/testsuite/ext/malloc_allocator/variadic_construct.cc
index b786fae9f0a..f122768d8ac 100644
--- a/libstdc++-v3/testsuite/ext/malloc_allocator/variadic_construct.cc
+++ b/libstdc++-v3/testsuite/ext/malloc_allocator/variadic_construct.cc
@@ -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>
 
diff --git a/libstdc++-v3/testsuite/ext/new_allocator/variadic_construct.cc b/libstdc++-v3/testsuite/ext/new_allocator/variadic_construct.cc
index 5b23e5b4a2c..cfe93a7b6d9 100644
--- a/libstdc++-v3/testsuite/ext/new_allocator/variadic_construct.cc
+++ b/libstdc++-v3/testsuite/ext/new_allocator/variadic_construct.cc
@@ -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>
 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction
  2019-10-23 19:27 [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction Jonathan Wakely
  2019-10-24 14:49 ` Jonathan Wakely
@ 2019-10-29  9:23 ` Stephan Bergmann
  2019-10-29  9:37   ` Jonathan Wakely
  1 sibling, 1 reply; 6+ messages in thread
From: Stephan Bergmann @ 2019-10-29  9:23 UTC (permalink / raw)
  To: libstdc++; +Cc: Jonathan Wakely, gcc-patches

On 23/10/2019 21:27, Jonathan Wakely wrote:
> This patch is the first part of library support for constexpr
> std::vector and std::string. This only includes the changes to
> std::allocator, std::allocator_traits, std::construct_at,
> std::destroy_at, std::destroy and std::destroy_n.
[...]
> Tested x86_64-linux and powerpc64le-linux, for every -std=gnu++NN
> mode.

Clang (trunk, at least) with -std=c++11 now complains about some of the 
constexpr (because they return void, or don't have a return statement) 
when including <memory>.

What fixed it for me locally:

> diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
> index 26d6d26ae48..61d3c1b794b 100644
> --- a/libstdc++-v3/include/bits/alloc_traits.h
> +++ b/libstdc++-v3/include/bits/alloc_traits.h
> @@ -241,13 +241,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  	  = typename __construct_helper<_Tp, _Args...>::type;
>  
>        template<typename _Tp, typename... _Args>
> -	static constexpr _Require<__has_construct<_Tp, _Args...>>
> +	static
> +#if __cplusplus >= 201402L
> +	       constexpr
> +#endif
> +	                 _Require<__has_construct<_Tp, _Args...>>
>  	_S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
>  	noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
>  	{ __a.construct(__p, std::forward<_Args>(__args)...); }
>  
>        template<typename _Tp, typename... _Args>
> -	static constexpr
> +	static
> +#if __cplusplus >= 201402L
> +	       constexpr
> +#endif
>  	_Require<__and_<__not_<__has_construct<_Tp, _Args...>>,
>  			       is_constructible<_Tp, _Args...>>>
>  	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
> @@ -256,14 +263,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  	{ std::_Construct(__p, std::forward<_Args>(__args)...); }
>  
>        template<typename _Alloc2, typename _Tp>
> -	static constexpr auto
> +	static
> +#if __cplusplus >= 201402L
> +	       constexpr
> +#endif
> +	                 auto
>  	_S_destroy(_Alloc2& __a, _Tp* __p, int)
>  	noexcept(noexcept(__a.destroy(__p)))
>  	-> decltype(__a.destroy(__p))
>  	{ __a.destroy(__p); }
>  
>        template<typename _Alloc2, typename _Tp>
> -	static constexpr void
> +	static
> +#if __cplusplus >= 201402L
> +	       constexpr
> +#endif
> +	                 void
>  	_S_destroy(_Alloc2&, _Tp* __p, ...)
>  	noexcept(noexcept(__p->~_Tp()))
>  	{ std::_Destroy(__p); }
> @@ -562,7 +577,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  #endif
>  
>    template<typename _Alloc>
> -    constexpr void
> +#if __cplusplus >= 201402L
> +    constexpr
> +#endif
> +              void
>      __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
>      {
>        typedef allocator_traits<_Alloc> __traits;
> @@ -594,7 +612,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  #endif
>  
>    template<typename _Alloc>
> -    constexpr void
> +#if __cplusplus >= 201402L
> +    constexpr
> +#endif
> +              void
>      __alloc_on_move(_Alloc& __one, _Alloc& __two)
>      {
>        typedef allocator_traits<_Alloc> __traits;
> @@ -621,7 +642,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  #endif
>  
>    template<typename _Alloc>
> -    constexpr void
> +#if __cplusplus >= 201402L
> +    constexpr
> +#endif
> +              void
>      __alloc_on_swap(_Alloc& __one, _Alloc& __two)
>      {
>        typedef allocator_traits<_Alloc> __traits;
> diff --git a/libstdc++-v3/include/bits/stl_construct.h b/libstdc++-v3/include/bits/stl_construct.h
> index a16196ffe74..ed9b72b7327 100644
> --- a/libstdc++-v3/include/bits/stl_construct.h
> +++ b/libstdc++-v3/include/bits/stl_construct.h
> @@ -137,7 +137,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>     * Destroy the object pointed to by a pointer type.
>     */
>    template<typename _Tp>
> -    _GLIBCXX_CONSTEXPR inline void
> +#if __cplusplus >= 201402L
> +    _GLIBCXX_CONSTEXPR
> +#endif
> +                       inline void
>      _Destroy(_Tp* __pointer)
>      {
>  #if __cplusplus > 201703L
> diff --git a/libstdc++-v3/include/ext/alloc_traits.h b/libstdc++-v3/include/ext/alloc_traits.h
> index 052d811ec01..ddeda66b57a 100644
> --- a/libstdc++-v3/include/ext/alloc_traits.h
> +++ b/libstdc++-v3/include/ext/alloc_traits.h
> @@ -76,7 +76,11 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
>    public:
>      // overload construct for non-standard pointer types
>      template<typename _Ptr, typename... _Args>
> -      static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
> +      static
> +#if __cplusplus >= 201402L
> +             constexpr
> +#endif
> +                       std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
>        construct(_Alloc& __a, _Ptr __p, _Args&&... __args)
>        noexcept(noexcept(_Base_type::construct(__a, std::__to_address(__p),
>  					      std::forward<_Args>(__args)...)))
> @@ -87,7 +91,11 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
>  
>      // overload destroy for non-standard pointer types
>      template<typename _Ptr>
> -      static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
> +      static
> +#if __cplusplus >= 201402L
> +             constexpr
> +#endif
> +                       std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
>        destroy(_Alloc& __a, _Ptr __p)
>        noexcept(noexcept(_Base_type::destroy(__a, std::__to_address(__p))))
>        { _Base_type::destroy(__a, std::__to_address(__p)); }
> @@ -95,7 +103,11 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
>      static constexpr _Alloc _S_select_on_copy(const _Alloc& __a)
>      { return _Base_type::select_on_container_copy_construction(__a); }
>  
> -    static constexpr void _S_on_swap(_Alloc& __a, _Alloc& __b)
> +    static
> +#if __cplusplus >= 201402L
> +           constexpr
> +#endif
> +                     void _S_on_swap(_Alloc& __a, _Alloc& __b)
>      { std::__alloc_on_swap(__a, __b); }
>  
>      static constexpr bool _S_propagate_on_copy_assign()

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction
  2019-10-29  9:23 ` Stephan Bergmann
@ 2019-10-29  9:37   ` Jonathan Wakely
  2019-10-29 20:16     ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2019-10-29  9:37 UTC (permalink / raw)
  To: Stephan Bergmann; +Cc: libstdc++, gcc-patches

On 29/10/19 10:23 +0100, Stephan Bergmann wrote:
>On 23/10/2019 21:27, Jonathan Wakely wrote:
>>This patch is the first part of library support for constexpr
>>std::vector and std::string. This only includes the changes to
>>std::allocator, std::allocator_traits, std::construct_at,
>>std::destroy_at, std::destroy and std::destroy_n.
>[...]
>>Tested x86_64-linux and powerpc64le-linux, for every -std=gnu++NN
>>mode.
>
>Clang (trunk, at least) with -std=c++11 now complains about some of 
>the constexpr (because they return void, or don't have a return 
>statement) when including <memory>.

Ah, thanks for letting me know. I did test with Clang, but not with
-std=c++11. I'll add that to my set of checks.

>What fixed it for me locally:
>
>>diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
>>index 26d6d26ae48..61d3c1b794b 100644
>>--- a/libstdc++-v3/include/bits/alloc_traits.h
>>+++ b/libstdc++-v3/include/bits/alloc_traits.h
>>@@ -241,13 +241,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 	  = typename __construct_helper<_Tp, _Args...>::type;
>>       template<typename _Tp, typename... _Args>
>>-	static constexpr _Require<__has_construct<_Tp, _Args...>>
>>+	static
>>+#if __cplusplus >= 201402L
>>+	       constexpr
>>+#endif

That's what the _GLIBCXX14_CONSTEXPR macro is for.

I'll fix this today, thanks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction
  2019-10-29  9:37   ` Jonathan Wakely
@ 2019-10-29 20:16     ` Jonathan Wakely
  0 siblings, 0 replies; 6+ messages in thread
From: Jonathan Wakely @ 2019-10-29 20:16 UTC (permalink / raw)
  To: Stephan Bergmann; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1608 bytes --]

On 29/10/19 09:37 +0000, Jonathan Wakely wrote:
>On 29/10/19 10:23 +0100, Stephan Bergmann wrote:
>>On 23/10/2019 21:27, Jonathan Wakely wrote:
>>>This patch is the first part of library support for constexpr
>>>std::vector and std::string. This only includes the changes to
>>>std::allocator, std::allocator_traits, std::construct_at,
>>>std::destroy_at, std::destroy and std::destroy_n.
>>[...]
>>>Tested x86_64-linux and powerpc64le-linux, for every -std=gnu++NN
>>>mode.
>>
>>Clang (trunk, at least) with -std=c++11 now complains about some of 
>>the constexpr (because they return void, or don't have a return 
>>statement) when including <memory>.
>
>Ah, thanks for letting me know. I did test with Clang, but not with
>-std=c++11. I'll add that to my set of checks.
>
>>What fixed it for me locally:
>>
>>>diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
>>>index 26d6d26ae48..61d3c1b794b 100644
>>>--- a/libstdc++-v3/include/bits/alloc_traits.h
>>>+++ b/libstdc++-v3/include/bits/alloc_traits.h
>>>@@ -241,13 +241,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>	  = typename __construct_helper<_Tp, _Args...>::type;
>>>      template<typename _Tp, typename... _Args>
>>>-	static constexpr _Require<__has_construct<_Tp, _Args...>>
>>>+	static
>>>+#if __cplusplus >= 201402L
>>>+	       constexpr
>>>+#endif
>
>That's what the _GLIBCXX14_CONSTEXPR macro is for.
>
>I'll fix this today, thanks.

Fixed with this, tested on powerpc64le-linux, and smoke tested on
x86_64-linux using Clang 7.0.1.

Committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 5552 bytes --]

commit 94674310b112c55010cfe4f49f0236fecb2dccb8
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Oct 29 19:33:51 2019 +0000

    Fix compilation errors with Clang
    
            * include/bits/alloc_traits.h (__cpp_lib_constexpr_dynamic_alloc):
            Define.
            (allocator_traits::_S_construct, allocator_traits::_S_destroy)
            (__alloc_on_copy, __alloc_on_move, __alloc_on_swap): Use
            _GLIBCXX14_CONSTEXPR instead of constexpr.
            * include/bits/stl_construct.h (_Destroy): Likewise.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
index 26d6d26ae48..55211ac1d72 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -241,13 +241,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  = typename __construct_helper<_Tp, _Args...>::type;
 
       template<typename _Tp, typename... _Args>
-	static constexpr _Require<__has_construct<_Tp, _Args...>>
+	static _GLIBCXX14_CONSTEXPR _Require<__has_construct<_Tp, _Args...>>
 	_S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
 	noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
 	{ __a.construct(__p, std::forward<_Args>(__args)...); }
 
       template<typename _Tp, typename... _Args>
-	static constexpr
+	static _GLIBCXX14_CONSTEXPR
 	_Require<__and_<__not_<__has_construct<_Tp, _Args...>>,
 			       is_constructible<_Tp, _Args...>>>
 	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
@@ -256,14 +256,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{ std::_Construct(__p, std::forward<_Args>(__args)...); }
 
       template<typename _Alloc2, typename _Tp>
-	static constexpr auto
+	static _GLIBCXX14_CONSTEXPR auto
 	_S_destroy(_Alloc2& __a, _Tp* __p, int)
 	noexcept(noexcept(__a.destroy(__p)))
 	-> decltype(__a.destroy(__p))
 	{ __a.destroy(__p); }
 
       template<typename _Alloc2, typename _Tp>
-	static constexpr void
+	static _GLIBCXX14_CONSTEXPR void
 	_S_destroy(_Alloc2&, _Tp* __p, ...)
 	noexcept(noexcept(__p->~_Tp()))
 	{ std::_Destroy(__p); }
@@ -393,6 +393,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return _S_select(__rhs, 0); }
     };
 
+#if __cplusplus > 201703L
+# define __cpp_lib_constexpr_dynamic_alloc 201907L
+#endif
+
   /// Partial specialization for std::allocator.
   template<typename _Tp>
     struct allocator_traits<allocator<_Tp>>
@@ -562,7 +566,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   template<typename _Alloc>
-    constexpr void
+    _GLIBCXX14_CONSTEXPR void
     __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
     {
       typedef allocator_traits<_Alloc> __traits;
@@ -594,7 +598,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   template<typename _Alloc>
-    constexpr void
+    _GLIBCXX14_CONSTEXPR void
     __alloc_on_move(_Alloc& __one, _Alloc& __two)
     {
       typedef allocator_traits<_Alloc> __traits;
@@ -621,7 +625,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   template<typename _Alloc>
-    constexpr void
+    _GLIBCXX14_CONSTEXPR void
     __alloc_on_swap(_Alloc& __one, _Alloc& __two)
     {
       typedef allocator_traits<_Alloc> __traits;
diff --git a/libstdc++-v3/include/bits/stl_construct.h b/libstdc++-v3/include/bits/stl_construct.h
index a16196ffe74..c714148e037 100644
--- a/libstdc++-v3/include/bits/stl_construct.h
+++ b/libstdc++-v3/include/bits/stl_construct.h
@@ -137,7 +137,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * Destroy the object pointed to by a pointer type.
    */
   template<typename _Tp>
-    _GLIBCXX_CONSTEXPR inline void
+    _GLIBCXX14_CONSTEXPR inline void
     _Destroy(_Tp* __pointer)
     {
 #if __cplusplus > 201703L
diff --git a/libstdc++-v3/include/ext/alloc_traits.h b/libstdc++-v3/include/ext/alloc_traits.h
index 052d811ec01..c7b8e5d4ba3 100644
--- a/libstdc++-v3/include/ext/alloc_traits.h
+++ b/libstdc++-v3/include/ext/alloc_traits.h
@@ -76,7 +76,8 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
   public:
     // overload construct for non-standard pointer types
     template<typename _Ptr, typename... _Args>
-      static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
+      static _GLIBCXX14_CONSTEXPR
+      std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
       construct(_Alloc& __a, _Ptr __p, _Args&&... __args)
       noexcept(noexcept(_Base_type::construct(__a, std::__to_address(__p),
 					      std::forward<_Args>(__args)...)))
@@ -87,7 +88,8 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
 
     // overload destroy for non-standard pointer types
     template<typename _Ptr>
-      static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
+      static _GLIBCXX14_CONSTEXPR
+      std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
       destroy(_Alloc& __a, _Ptr __p)
       noexcept(noexcept(_Base_type::destroy(__a, std::__to_address(__p))))
       { _Base_type::destroy(__a, std::__to_address(__p)); }
@@ -95,7 +97,7 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
     static constexpr _Alloc _S_select_on_copy(const _Alloc& __a)
     { return _Base_type::select_on_container_copy_construction(__a); }
 
-    static constexpr void _S_on_swap(_Alloc& __a, _Alloc& __b)
+    static _GLIBCXX14_CONSTEXPR void _S_on_swap(_Alloc& __a, _Alloc& __b)
     { std::__alloc_on_swap(__a, __b); }
 
     static constexpr bool _S_propagate_on_copy_assign()

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-10-29 20:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-23 19:27 [PATCH] PR c++/91369 Implement P0784R7 changes to allocation and construction Jonathan Wakely
2019-10-24 14:49 ` Jonathan Wakely
2019-10-24 15:42   ` Jonathan Wakely
2019-10-29  9:23 ` Stephan Bergmann
2019-10-29  9:37   ` Jonathan Wakely
2019-10-29 20:16     ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).