aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2022-04-25 14:24:48 +0100
committerJonathan Wakely <jwakely@redhat.com>2022-04-25 16:16:33 +0100
commit2fbdcf5e58c83a671b4d00f72b7ef91c462b6fc8 (patch)
tree430396d99d87c717c2caf14e2385278e90c78f31
parenta5cee0480c10bafa8ed65d49e5cedca23d98d7b7 (diff)
libstdc++: Implement constexpr std::unique_ptr for C++23 (P2273R3)
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.
-rw-r--r--libstdc++-v3/include/bits/ptr_traits.h5
-rw-r--r--libstdc++-v3/include/bits/unique_ptr.h124
-rw-r--r--libstdc++-v3/include/std/version4
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc48
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc73
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc85
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc34
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc68
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc46
9 files changed, 466 insertions, 21 deletions
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() );