public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] libstdc++: Implement constexpr std::unique_ptr for C++23 (P2273R3)
@ 2022-04-25 16:58 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2022-04-25 16:58 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Tested powerpc64le-linux, pushed to trunk.

-- >8 --

libstdc++-v3/ChangeLog:

	* include/bits/ptr_traits.h (__cpp_lib_constexpr_memory): Define
	conditionally.
	* include/bits/unique_ptr.h (__cpp_lib_constexpr_memory):
	Define for C++23.
	(default_delete, default_delete<T[]>, __uniq_ptr_impl)
	(unique_ptr, unique_ptr<T[], D>): Add constexpr to all member
	functions.
	* include/std/version (__cpp_lib_constexpr_memory): Define new
	value for C++23.
	* testsuite/20_util/unique_ptr/assign/constexpr.cc: New test.
	* testsuite/20_util/unique_ptr/comparison/constexpr.cc: New test.
	* testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc: New test.
	* testsuite/20_util/unique_ptr/creation/constexpr.cc: New test.
	* testsuite/20_util/unique_ptr/modifiers/constexpr.cc: New test.
	* testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc:
	New test.
---
 libstdc++-v3/include/bits/ptr_traits.h        |   5 +-
 libstdc++-v3/include/bits/unique_ptr.h        | 124 +++++++++++++++---
 libstdc++-v3/include/std/version              |   4 +
 .../20_util/unique_ptr/assign/constexpr.cc    |  48 +++++++
 .../unique_ptr/comparison/constexpr.cc        |  73 +++++++++++
 .../unique_ptr/cons/constexpr_c++20.cc        |  85 ++++++++++++
 .../20_util/unique_ptr/creation/constexpr.cc  |  34 +++++
 .../20_util/unique_ptr/modifiers/constexpr.cc |  68 ++++++++++
 .../specialized_algorithms/constexpr.cc       |  46 +++++++
 9 files changed, 466 insertions(+), 21 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc

diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h
index c85e6d44ded..047efa5cf28 100644
--- a/libstdc++-v3/include/bits/ptr_traits.h
+++ b/libstdc++-v3/include/bits/ptr_traits.h
@@ -36,7 +36,10 @@
 
 #if __cplusplus > 201703L
 #include <concepts>
-#define __cpp_lib_constexpr_memory 201811L
+# ifndef __cpp_lib_constexpr_memory
+// Defined to a newer value in bits/unique_ptr.h for C++23
+#  define __cpp_lib_constexpr_memory 201811L
+# endif
 namespace __gnu_debug { struct _Safe_iterator_base; }
 #endif
 
diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h
index 8f4430f61f5..ad60fada59b 100644
--- a/libstdc++-v3/include/bits/unique_ptr.h
+++ b/libstdc++-v3/include/bits/unique_ptr.h
@@ -41,6 +41,14 @@
 # include <ostream>
 #endif
 
+#if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc
+# if __cpp_lib_constexpr_memory < 202202L
+// Defined with older value in bits/ptr_traits.h for C++20
+#  undef __cpp_lib_constexpr_memory
+#  define __cpp_lib_constexpr_memory 202202L
+# endif
+#endif
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -72,9 +80,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        */
       template<typename _Up,
 	       typename = _Require<is_convertible<_Up*, _Tp*>>>
+	_GLIBCXX23_CONSTEXPR
         default_delete(const default_delete<_Up>&) noexcept { }
 
       /// Calls `delete __ptr`
+      _GLIBCXX23_CONSTEXPR
       void
       operator()(_Tp* __ptr) const
       {
@@ -108,10 +118,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        */
       template<typename _Up,
 	       typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>>
+	_GLIBCXX23_CONSTEXPR
         default_delete(const default_delete<_Up[]>&) noexcept { }
 
       /// Calls `delete[] __ptr`
       template<typename _Up>
+	_GLIBCXX23_CONSTEXPR
 	typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type
 	operator()(_Up* __ptr) const
 	{
@@ -152,16 +164,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		     " or an lvalue reference type" );
 
       __uniq_ptr_impl() = default;
+      _GLIBCXX23_CONSTEXPR
       __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
 
       template<typename _Del>
-      __uniq_ptr_impl(pointer __p, _Del&& __d)
+	_GLIBCXX23_CONSTEXPR
+	__uniq_ptr_impl(pointer __p, _Del&& __d)
 	: _M_t(__p, std::forward<_Del>(__d)) { }
 
+      _GLIBCXX23_CONSTEXPR
       __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept
       : _M_t(std::move(__u._M_t))
       { __u._M_ptr() = nullptr; }
 
+      _GLIBCXX23_CONSTEXPR
       __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept
       {
 	reset(__u.release());
@@ -169,11 +185,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 
+      _GLIBCXX23_CONSTEXPR
       pointer&   _M_ptr() noexcept { return std::get<0>(_M_t); }
+      _GLIBCXX23_CONSTEXPR
       pointer    _M_ptr() const noexcept { return std::get<0>(_M_t); }
+      _GLIBCXX23_CONSTEXPR
       _Dp&       _M_deleter() noexcept { return std::get<1>(_M_t); }
+      _GLIBCXX23_CONSTEXPR
       const _Dp& _M_deleter() const noexcept { return std::get<1>(_M_t); }
 
+      _GLIBCXX23_CONSTEXPR
       void reset(pointer __p) noexcept
       {
 	const pointer __old_p = _M_ptr();
@@ -182,6 +203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _M_deleter()(__old_p);
       }
 
+      _GLIBCXX23_CONSTEXPR
       pointer release() noexcept
       {
 	pointer __p = _M_ptr();
@@ -189,6 +211,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return __p;
       }
 
+      _GLIBCXX23_CONSTEXPR
       void
       swap(__uniq_ptr_impl& __rhs) noexcept
       {
@@ -281,6 +304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * The deleter will be value-initialized.
        */
       template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
+	_GLIBCXX23_CONSTEXPR
 	explicit
 	unique_ptr(pointer __p) noexcept
 	: _M_t(__p)
@@ -295,6 +319,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        */
       template<typename _Del = deleter_type,
 	       typename = _Require<is_copy_constructible<_Del>>>
+	_GLIBCXX23_CONSTEXPR
 	unique_ptr(pointer __p, const deleter_type& __d) noexcept
 	: _M_t(__p, __d) { }
 
@@ -307,6 +332,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        */
       template<typename _Del = deleter_type,
 	       typename = _Require<is_move_constructible<_Del>>>
+	_GLIBCXX23_CONSTEXPR
 	unique_ptr(pointer __p,
 		   __enable_if_t<!is_lvalue_reference<_Del>::value,
 				 _Del&&> __d) noexcept
@@ -315,6 +341,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       template<typename _Del = deleter_type,
 	       typename _DelUnref = typename remove_reference<_Del>::type>
+	_GLIBCXX23_CONSTEXPR
 	unique_ptr(pointer,
 		   __enable_if_t<is_lvalue_reference<_Del>::value,
 				 _DelUnref&&>) = delete;
@@ -341,6 +368,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	       __conditional_t<is_reference<_Dp>::value,
 			       is_same<_Ep, _Dp>,
 			       is_convertible<_Ep, _Dp>>>>
+	_GLIBCXX23_CONSTEXPR
 	unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
 	: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
 	{ }
@@ -356,6 +384,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
       /// Destructor, invokes the deleter if the stored pointer is not null.
+#if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc
+      constexpr
+#endif
       ~unique_ptr() noexcept
       {
 	static_assert(__is_invocable<deleter_type&, pointer>::value,
@@ -382,6 +413,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * Invokes the deleter if this object owns a pointer.
        */
       template<typename _Up, typename _Ep>
+	_GLIBCXX23_CONSTEXPR
         typename enable_if< __and_<
           __safe_conversion_up<_Up, _Ep>,
           is_assignable<deleter_type&, _Ep&&>
@@ -395,6 +427,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
+      _GLIBCXX23_CONSTEXPR
       unique_ptr&
       operator=(nullptr_t) noexcept
       {
@@ -405,6 +438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Observers.
 
       /// Dereference the stored pointer.
+      _GLIBCXX23_CONSTEXPR
       typename add_lvalue_reference<element_type>::type
       operator*() const noexcept(noexcept(*std::declval<pointer>()))
       {
@@ -413,6 +447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       /// Return the stored pointer.
+      _GLIBCXX23_CONSTEXPR
       pointer
       operator->() const noexcept
       {
@@ -421,27 +456,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       /// Return the stored pointer.
+      _GLIBCXX23_CONSTEXPR
       pointer
       get() const noexcept
       { return _M_t._M_ptr(); }
 
       /// Return a reference to the stored deleter.
+      _GLIBCXX23_CONSTEXPR
       deleter_type&
       get_deleter() noexcept
       { return _M_t._M_deleter(); }
 
       /// Return a reference to the stored deleter.
+      _GLIBCXX23_CONSTEXPR
       const deleter_type&
       get_deleter() const noexcept
       { return _M_t._M_deleter(); }
 
       /// Return @c true if the stored pointer is not null.
+      _GLIBCXX23_CONSTEXPR
       explicit operator bool() const noexcept
       { return get() == pointer() ? false : true; }
 
       // Modifiers.
 
       /// Release ownership of any stored pointer.
+      _GLIBCXX23_CONSTEXPR
       pointer
       release() noexcept
       { return _M_t.release(); }
@@ -452,6 +492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        * The deleter will be invoked if a pointer is already owned.
        */
+      _GLIBCXX23_CONSTEXPR
       void
       reset(pointer __p = pointer()) noexcept
       {
@@ -461,6 +502,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       /// Exchange the pointer and deleter with another object.
+      _GLIBCXX23_CONSTEXPR
       void
       swap(unique_ptr& __u) noexcept
       {
@@ -551,6 +593,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	       typename = _DeleterConstraint<_Vp>,
 	       typename = typename enable_if<
                  __safe_conversion_raw<_Up>::value, bool>::type>
+	_GLIBCXX23_CONSTEXPR
 	explicit
 	unique_ptr(_Up __p) noexcept
 	: _M_t(__p)
@@ -567,8 +610,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up, typename _Del = deleter_type,
 	       typename = _Require<__safe_conversion_raw<_Up>,
 				   is_copy_constructible<_Del>>>
-      unique_ptr(_Up __p, const deleter_type& __d) noexcept
-      : _M_t(__p, __d) { }
+	_GLIBCXX23_CONSTEXPR
+	unique_ptr(_Up __p, const deleter_type& __d) noexcept
+	: _M_t(__p, __d) { }
 
       /** Takes ownership of a pointer.
        *
@@ -581,6 +625,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up, typename _Del = deleter_type,
 	       typename = _Require<__safe_conversion_raw<_Up>,
 				   is_move_constructible<_Del>>>
+	_GLIBCXX23_CONSTEXPR
 	unique_ptr(_Up __p,
 		   __enable_if_t<!is_lvalue_reference<_Del>::value,
 				 _Del&&> __d) noexcept
@@ -608,11 +653,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	       __conditional_t<is_reference<_Dp>::value,
 			       is_same<_Ep, _Dp>,
 			       is_convertible<_Ep, _Dp>>>>
+	_GLIBCXX23_CONSTEXPR
 	unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
 	: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
 	{ }
 
       /// Destructor, invokes the deleter if the stored pointer is not null.
+#if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc
+      constexpr
+#endif
       ~unique_ptr()
       {
 	auto& __ptr = _M_t._M_ptr();
@@ -638,6 +687,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * Invokes the deleter if this object owns a pointer.
        */
       template<typename _Up, typename _Ep>
+	_GLIBCXX23_CONSTEXPR
 	typename
 	enable_if<__and_<__safe_conversion_up<_Up, _Ep>,
                          is_assignable<deleter_type&, _Ep&&>
@@ -651,6 +701,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
+      _GLIBCXX23_CONSTEXPR
       unique_ptr&
       operator=(nullptr_t) noexcept
       {
@@ -661,6 +712,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Observers.
 
       /// Access an element of owned array.
+      _GLIBCXX23_CONSTEXPR
       typename std::add_lvalue_reference<element_type>::type
       operator[](size_t __i) const
       {
@@ -669,27 +721,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       /// Return the stored pointer.
+      _GLIBCXX23_CONSTEXPR
       pointer
       get() const noexcept
       { return _M_t._M_ptr(); }
 
       /// Return a reference to the stored deleter.
+      _GLIBCXX23_CONSTEXPR
       deleter_type&
       get_deleter() noexcept
       { return _M_t._M_deleter(); }
 
       /// Return a reference to the stored deleter.
+      _GLIBCXX23_CONSTEXPR
       const deleter_type&
       get_deleter() const noexcept
       { return _M_t._M_deleter(); }
 
       /// Return @c true if the stored pointer is not null.
+      _GLIBCXX23_CONSTEXPR
       explicit operator bool() const noexcept
       { return get() == pointer() ? false : true; }
 
       // Modifiers.
 
       /// Release ownership of any stored pointer.
+      _GLIBCXX23_CONSTEXPR
       pointer
       release() noexcept
       { return _M_t.release(); }
@@ -712,14 +769,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                         >
                   >
                >>
+      _GLIBCXX23_CONSTEXPR
       void
       reset(_Up __p) noexcept
       { _M_t.reset(std::move(__p)); }
 
+      _GLIBCXX23_CONSTEXPR
       void reset(nullptr_t = nullptr) noexcept
       { reset(pointer()); }
 
       /// Exchange the pointer and deleter with another object.
+      _GLIBCXX23_CONSTEXPR
       void
       swap(unique_ptr& __u) noexcept
       {
@@ -740,6 +800,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline
 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
     // Constrained free swap overload, see p0185r1
+    _GLIBCXX23_CONSTEXPR
     typename enable_if<__is_swappable<_Dp>::value>::type
 #else
     void
@@ -758,41 +819,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// Equality operator for unique_ptr objects, compares the owned pointers
   template<typename _Tp, typename _Dp,
 	   typename _Up, typename _Ep>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator==(const unique_ptr<_Tp, _Dp>& __x,
 	       const unique_ptr<_Up, _Ep>& __y)
     { return __x.get() == __y.get(); }
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
     { return !__x; }
 
 #ifndef __cpp_lib_three_way_comparison
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD
+    inline bool
     operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
     { return !__x; }
 
   /// Inequality operator for unique_ptr objects, compares the owned pointers
   template<typename _Tp, typename _Dp,
 	   typename _Up, typename _Ep>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD
+    inline bool
     operator!=(const unique_ptr<_Tp, _Dp>& __x,
 	       const unique_ptr<_Up, _Ep>& __y)
     { return __x.get() != __y.get(); }
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD
+    inline bool
     operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
     { return (bool)__x; }
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD
+    inline bool
     operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
     { return (bool)__x; }
 #endif // three way comparison
@@ -800,7 +867,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// Relational operator for unique_ptr objects, compares the owned pointers
   template<typename _Tp, typename _Dp,
 	   typename _Up, typename _Ep>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator<(const unique_ptr<_Tp, _Dp>& __x,
 	      const unique_ptr<_Up, _Ep>& __y)
     {
@@ -812,7 +880,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
     {
       return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
@@ -821,7 +890,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
     {
       return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
@@ -831,34 +901,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// Relational operator for unique_ptr objects, compares the owned pointers
   template<typename _Tp, typename _Dp,
 	   typename _Up, typename _Ep>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator<=(const unique_ptr<_Tp, _Dp>& __x,
 	       const unique_ptr<_Up, _Ep>& __y)
     { return !(__y < __x); }
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
     { return !(nullptr < __x); }
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
     { return !(__x < nullptr); }
 
   /// Relational operator for unique_ptr objects, compares the owned pointers
   template<typename _Tp, typename _Dp,
 	   typename _Up, typename _Ep>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator>(const unique_ptr<_Tp, _Dp>& __x,
 	      const unique_ptr<_Up, _Ep>& __y)
     { return (__y < __x); }
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
     {
       return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
@@ -867,7 +942,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
     {
       return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
@@ -877,14 +953,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// Relational operator for unique_ptr objects, compares the owned pointers
   template<typename _Tp, typename _Dp,
 	   typename _Up, typename _Ep>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator>=(const unique_ptr<_Tp, _Dp>& __x,
 	       const unique_ptr<_Up, _Ep>& __y)
     { return !(__x < __y); }
 
   /// unique_ptr comparison with nullptr
   template<typename _Tp, typename _Dp>
-    _GLIBCXX_NODISCARD inline bool
+    _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
+    inline bool
     operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
     { return !(__x < nullptr); }
 
@@ -898,6 +976,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Dp, typename _Up, typename _Ep>
     requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer,
 				       typename unique_ptr<_Up, _Ep>::pointer>
+    _GLIBCXX23_CONSTEXPR
     inline
     compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer,
 			       typename unique_ptr<_Up, _Ep>::pointer>
@@ -907,6 +986,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _Tp, typename _Dp>
     requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer>
+    _GLIBCXX23_CONSTEXPR
     inline
     compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer>
     operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
@@ -979,6 +1059,7 @@ namespace __detail
    *  @relates unique_ptr
    */
   template<typename _Tp, typename... _Args>
+    _GLIBCXX23_CONSTEXPR
     inline __detail::__unique_ptr_t<_Tp>
     make_unique(_Args&&... __args)
     { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
@@ -993,6 +1074,7 @@ namespace __detail
    *  The array elements are value-initialized.
    */
   template<typename _Tp>
+    _GLIBCXX23_CONSTEXPR
     inline __detail::__unique_ptr_array_t<_Tp>
     make_unique(size_t __num)
     { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
@@ -1014,6 +1096,7 @@ namespace __detail
    *  @relates unique_ptr
    */
   template<typename _Tp>
+    _GLIBCXX23_CONSTEXPR
     inline __detail::__unique_ptr_t<_Tp>
     make_unique_for_overwrite()
     { return unique_ptr<_Tp>(new _Tp); }
@@ -1026,6 +1109,7 @@ namespace __detail
    *  @relates unique_ptr
    */
   template<typename _Tp>
+    _GLIBCXX23_CONSTEXPR
     inline __detail::__unique_ptr_array_t<_Tp>
     make_unique_for_overwrite(size_t __num)
     { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]); }
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d8ec658484f..22280e1a349 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -307,6 +307,10 @@
 
 #if _GLIBCXX_HOSTED
 #define __cpp_lib_adaptor_iterator_pair_constructor 202106L
+#if __cpp_constexpr_dynamic_alloc
+# undef __cpp_lib_constexpr_memory
+# define __cpp_lib_constexpr_memory 202202L
+#endif
 #if __cpp_concepts >= 202002L
 # define __cpp_lib_expected 202202L
 #endif
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc
new file mode 100644
index 00000000000..fb4acbda2d5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc
@@ -0,0 +1,48 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_move()
+{
+  std::unique_ptr<int> p1(new int(2));
+  std::unique_ptr<int> p2;
+  p2 = std::move(p1);
+  VERIFY( *p2 == 2 );
+  std::unique_ptr<int[]> a1(new int[]{0, 1, 2});
+  std::unique_ptr<int[]> a2;
+  a2 = std::move(a1);
+  VERIFY( a2[2] == 2 );
+
+  return true;
+}
+static_assert( test_move() );
+
+constexpr bool
+test_convert()
+{
+  std::unique_ptr<int> p1(new int(2));
+  std::unique_ptr<const int> p2;
+  p2 = std::move(p1);
+  VERIFY( *p2 == 2 );
+  std::unique_ptr<int[]> a1(new int[]{0, 1, 2});
+  std::unique_ptr<const int[]> a2;
+  a2 = std::move(a1);
+  VERIFY( a2[2] == 2 );
+
+  return true;
+}
+static_assert( test_convert() );
+
+constexpr bool
+test_null()
+{
+  std::unique_ptr<int> p(new int(2));
+  p = nullptr;
+  VERIFY( !p );
+  p = nullptr;
+  return true;
+}
+static_assert( test_null() );
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc
new file mode 100644
index 00000000000..83e4f0826a8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc
@@ -0,0 +1,73 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_eq()
+{
+  std::unique_ptr<int> p1, p2;
+  VERIFY( p1 == p2 );
+  p1.reset(new int(1));
+  VERIFY( p1 == p1 );
+  VERIFY( p1 != p2 );
+  struct null_deleter { constexpr void operator()(const void*) const { } };
+  std::unique_ptr<const int[], null_deleter> p3(p1.get());
+  VERIFY( p3 == p3 );
+  VERIFY( p1 == p3 );
+  VERIFY( p3 != p2 );
+
+  return true;
+}
+static_assert( test_eq() );
+
+constexpr bool
+test_rel()
+{
+  std::unique_ptr<int> p1, p2;
+  VERIFY( !(p1 < p2) );
+  VERIFY( !(p1 > p2) );
+  VERIFY( p1 <= p2 );
+  VERIFY( p1 >= p2 );
+  p1.reset(new int(1));
+  VERIFY( p1 <= p1 );
+  VERIFY( p1 >= p1 );
+  VERIFY( p1 > p2 );
+  VERIFY( p2 < p1 );
+  VERIFY( p2 <= p1 );
+  VERIFY( p1 >= p2 );
+  struct null_deleter { constexpr void operator()(const void*) const { } };
+  std::unique_ptr<const int[], null_deleter> p3(p1.get());
+  VERIFY( p3 <= p3 );
+  VERIFY( p3 >= p3 );
+  VERIFY( p1 <= p3 );
+  VERIFY( p3 > p2 );
+  VERIFY( p3 >= p2 );
+  VERIFY( p2 < p3 );
+  VERIFY( p2 <= p3 );
+
+  return true;
+}
+static_assert( test_rel() );
+
+constexpr bool
+test_3way()
+{
+  std::unique_ptr<int> p1, p2;
+  VERIFY( (p1 <=> p1) == 0 );
+  VERIFY( (p1 <=> p2) == 0 );
+  p1.reset(new int(1));
+  VERIFY( (p1 <=> p1) == 0 );
+  VERIFY( (p1 <=> p2) > 0 );
+  VERIFY( (p2 <=> p1) < 0 );
+  struct null_deleter { constexpr void operator()(const void*) const { } };
+  std::unique_ptr<const int[], null_deleter> p3(p1.get());
+  VERIFY( (p3 <=> p3) == 0 );
+  VERIFY( (p1 <=> p3) == 0 );
+  VERIFY( (p3 <=> p2) > 0 );
+  VERIFY( (p2 <=> p3) < 0 );
+
+  return true;
+}
+static_assert( test_3way() );
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc
new file mode 100644
index 00000000000..243d80aaba5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc
@@ -0,0 +1,85 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <memory>
+
+#ifndef __cpp_lib_constexpr_memory
+# error "Feature test macro for constexpr unique_ptr is missing in <memory>"
+#elif __cpp_lib_constexpr_memory < 202202L
+# error "Feature test macro for constexpr unique_ptr has wrong value in <memory>"
+#endif
+
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_default()
+{
+  std::unique_ptr<int> p;
+  std::unique_ptr<int> np(nullptr);
+  VERIFY( p == np );
+
+  std::unique_ptr<int[]> a;
+  std::unique_ptr<int[]> na(nullptr);
+  VERIFY( a == na );
+
+  return true;
+}
+static_assert( test_default() );
+
+constexpr bool
+test_ptr()
+{
+  std::unique_ptr<int> p(new int(2));
+  VERIFY( *p == 2 );
+  std::unique_ptr<int[]> a(new int[]{0, 1, 2});
+  VERIFY( a[2] == 2 );
+
+  return true;
+}
+static_assert( test_ptr() );
+
+constexpr bool
+test_del()
+{
+  const std::default_delete<int> pd;
+  std::unique_ptr<int> p1(new int(1), pd);
+  VERIFY( *p1 == 1 );
+  std::unique_ptr<int> p2(new int(2), std::default_delete<int>{});
+  VERIFY( *p2 == 2 );
+  const std::default_delete<int[]> ad;
+  std::unique_ptr<int[]> a1(new int[]{3, 4}, ad);
+  VERIFY( a1[0] == 3 );
+  std::unique_ptr<int[]> a2(new int[]{5, 6}, std::default_delete<int[]>{});
+  VERIFY( a2[1] == 6 );
+
+  return true;
+}
+static_assert( test_del() );
+
+constexpr bool
+test_move()
+{
+  std::unique_ptr<int> p1(new int(2));
+  std::unique_ptr<int> p2 = std::move(p1);
+  VERIFY( *p2 == 2 );
+  std::unique_ptr<int[]> a1(new int[]{0, 1, 2});
+  std::unique_ptr<int[]> a2 = std::move(a1);
+  VERIFY( a2[2] == 2 );
+
+  return true;
+}
+static_assert( test_move() );
+
+constexpr bool
+test_convert()
+{
+  std::unique_ptr<int> p1(new int(2));
+  std::unique_ptr<const int> p2 = std::move(p1);
+  VERIFY( *p2 == 2 );
+  std::unique_ptr<int[]> a1(new int[]{0, 1, 2});
+  std::unique_ptr<const int[]> a2 = std::move(a1);
+  VERIFY( a2[2] == 2 );
+
+  return true;
+}
+static_assert( test_convert() );
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc
new file mode 100644
index 00000000000..90d11198578
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc
@@ -0,0 +1,34 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_creation_single()
+{
+  std::unique_ptr<int> p = std::make_unique<int>(1);
+  VERIFY( *p == 1 );
+  p = std::make_unique_for_overwrite<int>();
+  *p = 2;
+  VERIFY( *p == 2 );
+
+  return true;
+}
+static_assert( test_creation_single() );
+
+constexpr bool
+test_creation_array()
+{
+  std::unique_ptr<int[]> a = std::make_unique<int[]>(2);
+  VERIFY( a[0] == 0 );
+  VERIFY( a[1] == 0 );
+  a = std::make_unique_for_overwrite<int[]>(2);
+  a[0] = 1;
+  a[1] = 2;
+  VERIFY( a[0] == 1 );
+  VERIFY( a[1] == 2 );
+
+  return true;
+}
+static_assert( test_creation_array() );
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc
new file mode 100644
index 00000000000..81908fdc081
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc
@@ -0,0 +1,68 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_release()
+{
+  std::unique_ptr<int> p1;
+  int* r = p1.release();
+  VERIFY( !r );
+  VERIFY( !p1 );
+
+  std::unique_ptr<int> p2(new int(2));
+  r = p2.release();
+  VERIFY( r );
+  VERIFY( !p2 );
+  delete r;
+
+  std::unique_ptr<int[]> a1;
+  r = a1.release();
+  VERIFY( !r );
+  VERIFY( !a1 );
+
+  std::unique_ptr<int[]> a2(new int[2]{});
+  r = a2.release();
+  VERIFY( r );
+  VERIFY( !a2 );
+  delete[] r;
+
+  return true;
+}
+static_assert( test_release() );
+
+constexpr bool
+test_reset()
+{
+  std::unique_ptr<int> p1;
+  p1.reset();
+  VERIFY( !p1 );
+  p1.reset(nullptr);
+  VERIFY( !p1 );
+  p1.reset(new int(2));
+  VERIFY( *p1 == 2 );
+  p1.reset(new int(3));
+  VERIFY( *p1 == 3 );
+  p1.reset(nullptr);
+  VERIFY( !p1 );
+
+  std::unique_ptr<int[]> a1;
+  a1.reset();
+  VERIFY( !a1 );
+  a1.reset(nullptr);
+  VERIFY( !a1 );
+  a1.reset(new int[]{2,3});
+  VERIFY( a1[0] == 2 );
+  a1.reset(new int[]{4,5,6});
+  VERIFY( a1[1] == 5 );
+  a1.reset(nullptr);
+  VERIFY( !a1 );
+
+  std::unique_ptr<const int[]> a2;
+  a2.reset(new int[2]{});
+
+  return true;
+}
+static_assert( test_reset() );
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc
new file mode 100644
index 00000000000..91a0165d212
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc
@@ -0,0 +1,46 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_swap_single()
+{
+  std::unique_ptr<int> p1;
+  swap(p1, p1);
+  VERIFY( !p1 );
+  std::unique_ptr<int> p2;
+  swap(p1, p2);
+  VERIFY( !p1 && !p2 );
+  std::unique_ptr<int> p3(new int(3));
+  swap(p3, p3);
+  VERIFY( *p3 == 3 );
+  swap(p1, p3);
+  VERIFY( *p1 == 3 );
+  std::unique_ptr<int> p4(new int(4));
+  swap(p4, p1);
+  VERIFY( *p4 == 3 );
+  VERIFY( *p1 == 4 );
+
+  return true;
+}
+static_assert( test_swap_single() );
+
+constexpr bool
+test_swap_array()
+{
+  std::unique_ptr<int[]> a1;
+  std::unique_ptr<int[]> a2;
+  swap(a1, a2);
+  VERIFY( !a1 && !a2 );
+  std::unique_ptr<int[]> a3(new int[]{3});
+  swap(a1, a3);
+  VERIFY( a1[0] == 3 );
+  std::unique_ptr<int[]> a4(new int[]{4, 5});
+  swap(a1, a4);
+  VERIFY( a1[1] == 5 );
+
+  return true;
+}
+static_assert( test_swap_array() );
-- 
2.34.1


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-04-25 16:58 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-25 16:58 [committed] libstdc++: Implement constexpr std::unique_ptr for C++23 (P2273R3) 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).