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.
This commit is contained in:
Jonathan Wakely 2022-04-25 14:24:48 +01:00
parent a5cee0480c
commit 2fbdcf5e58
9 changed files with 466 additions and 21 deletions

View File

@ -36,7 +36,10 @@
#if __cplusplus > 201703L #if __cplusplus > 201703L
#include <concepts> #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; } namespace __gnu_debug { struct _Safe_iterator_base; }
#endif #endif

View File

@ -41,6 +41,14 @@
# include <ostream> # include <ostream>
#endif #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) namespace std _GLIBCXX_VISIBILITY(default)
{ {
_GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_VERSION
@ -72,9 +80,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/ */
template<typename _Up, template<typename _Up,
typename = _Require<is_convertible<_Up*, _Tp*>>> typename = _Require<is_convertible<_Up*, _Tp*>>>
_GLIBCXX23_CONSTEXPR
default_delete(const default_delete<_Up>&) noexcept { } default_delete(const default_delete<_Up>&) noexcept { }
/// Calls `delete __ptr` /// Calls `delete __ptr`
_GLIBCXX23_CONSTEXPR
void void
operator()(_Tp* __ptr) const operator()(_Tp* __ptr) const
{ {
@ -108,10 +118,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/ */
template<typename _Up, template<typename _Up,
typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>> typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>>
_GLIBCXX23_CONSTEXPR
default_delete(const default_delete<_Up[]>&) noexcept { } default_delete(const default_delete<_Up[]>&) noexcept { }
/// Calls `delete[] __ptr` /// Calls `delete[] __ptr`
template<typename _Up> template<typename _Up>
_GLIBCXX23_CONSTEXPR
typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type
operator()(_Up* __ptr) const operator()(_Up* __ptr) const
{ {
@ -152,16 +164,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
" or an lvalue reference type" ); " or an lvalue reference type" );
__uniq_ptr_impl() = default; __uniq_ptr_impl() = default;
_GLIBCXX23_CONSTEXPR
__uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; } __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
template<typename _Del> template<typename _Del>
_GLIBCXX23_CONSTEXPR
__uniq_ptr_impl(pointer __p, _Del&& __d) __uniq_ptr_impl(pointer __p, _Del&& __d)
: _M_t(__p, std::forward<_Del>(__d)) { } : _M_t(__p, std::forward<_Del>(__d)) { }
_GLIBCXX23_CONSTEXPR
__uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept
: _M_t(std::move(__u._M_t)) : _M_t(std::move(__u._M_t))
{ __u._M_ptr() = nullptr; } { __u._M_ptr() = nullptr; }
_GLIBCXX23_CONSTEXPR
__uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept
{ {
reset(__u.release()); reset(__u.release());
@ -169,11 +185,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return *this; return *this;
} }
_GLIBCXX23_CONSTEXPR
pointer& _M_ptr() noexcept { return std::get<0>(_M_t); } pointer& _M_ptr() noexcept { return std::get<0>(_M_t); }
_GLIBCXX23_CONSTEXPR
pointer _M_ptr() const noexcept { return std::get<0>(_M_t); } pointer _M_ptr() const noexcept { return std::get<0>(_M_t); }
_GLIBCXX23_CONSTEXPR
_Dp& _M_deleter() noexcept { return std::get<1>(_M_t); } _Dp& _M_deleter() noexcept { return std::get<1>(_M_t); }
_GLIBCXX23_CONSTEXPR
const _Dp& _M_deleter() const noexcept { return std::get<1>(_M_t); } const _Dp& _M_deleter() const noexcept { return std::get<1>(_M_t); }
_GLIBCXX23_CONSTEXPR
void reset(pointer __p) noexcept void reset(pointer __p) noexcept
{ {
const pointer __old_p = _M_ptr(); const pointer __old_p = _M_ptr();
@ -182,6 +203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_deleter()(__old_p); _M_deleter()(__old_p);
} }
_GLIBCXX23_CONSTEXPR
pointer release() noexcept pointer release() noexcept
{ {
pointer __p = _M_ptr(); pointer __p = _M_ptr();
@ -189,6 +211,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __p; return __p;
} }
_GLIBCXX23_CONSTEXPR
void void
swap(__uniq_ptr_impl& __rhs) noexcept swap(__uniq_ptr_impl& __rhs) noexcept
{ {
@ -281,6 +304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* The deleter will be value-initialized. * The deleter will be value-initialized.
*/ */
template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
_GLIBCXX23_CONSTEXPR
explicit explicit
unique_ptr(pointer __p) noexcept unique_ptr(pointer __p) noexcept
: _M_t(__p) : _M_t(__p)
@ -295,6 +319,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/ */
template<typename _Del = deleter_type, template<typename _Del = deleter_type,
typename = _Require<is_copy_constructible<_Del>>> typename = _Require<is_copy_constructible<_Del>>>
_GLIBCXX23_CONSTEXPR
unique_ptr(pointer __p, const deleter_type& __d) noexcept unique_ptr(pointer __p, const deleter_type& __d) noexcept
: _M_t(__p, __d) { } : _M_t(__p, __d) { }
@ -307,6 +332,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/ */
template<typename _Del = deleter_type, template<typename _Del = deleter_type,
typename = _Require<is_move_constructible<_Del>>> typename = _Require<is_move_constructible<_Del>>>
_GLIBCXX23_CONSTEXPR
unique_ptr(pointer __p, unique_ptr(pointer __p,
__enable_if_t<!is_lvalue_reference<_Del>::value, __enable_if_t<!is_lvalue_reference<_Del>::value,
_Del&&> __d) noexcept _Del&&> __d) noexcept
@ -315,6 +341,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Del = deleter_type, template<typename _Del = deleter_type,
typename _DelUnref = typename remove_reference<_Del>::type> typename _DelUnref = typename remove_reference<_Del>::type>
_GLIBCXX23_CONSTEXPR
unique_ptr(pointer, unique_ptr(pointer,
__enable_if_t<is_lvalue_reference<_Del>::value, __enable_if_t<is_lvalue_reference<_Del>::value,
_DelUnref&&>) = delete; _DelUnref&&>) = delete;
@ -341,6 +368,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__conditional_t<is_reference<_Dp>::value, __conditional_t<is_reference<_Dp>::value,
is_same<_Ep, _Dp>, is_same<_Ep, _Dp>,
is_convertible<_Ep, _Dp>>>> is_convertible<_Ep, _Dp>>>>
_GLIBCXX23_CONSTEXPR
unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
{ } { }
@ -356,6 +384,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif #endif
/// Destructor, invokes the deleter if the stored pointer is not null. /// Destructor, invokes the deleter if the stored pointer is not null.
#if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc
constexpr
#endif
~unique_ptr() noexcept ~unique_ptr() noexcept
{ {
static_assert(__is_invocable<deleter_type&, pointer>::value, 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. * Invokes the deleter if this object owns a pointer.
*/ */
template<typename _Up, typename _Ep> template<typename _Up, typename _Ep>
_GLIBCXX23_CONSTEXPR
typename enable_if< __and_< typename enable_if< __and_<
__safe_conversion_up<_Up, _Ep>, __safe_conversion_up<_Up, _Ep>,
is_assignable<deleter_type&, _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. /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
_GLIBCXX23_CONSTEXPR
unique_ptr& unique_ptr&
operator=(nullptr_t) noexcept operator=(nullptr_t) noexcept
{ {
@ -405,6 +438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Observers. // Observers.
/// Dereference the stored pointer. /// Dereference the stored pointer.
_GLIBCXX23_CONSTEXPR
typename add_lvalue_reference<element_type>::type typename add_lvalue_reference<element_type>::type
operator*() const noexcept(noexcept(*std::declval<pointer>())) operator*() const noexcept(noexcept(*std::declval<pointer>()))
{ {
@ -413,6 +447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
/// Return the stored pointer. /// Return the stored pointer.
_GLIBCXX23_CONSTEXPR
pointer pointer
operator->() const noexcept operator->() const noexcept
{ {
@ -421,27 +456,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
/// Return the stored pointer. /// Return the stored pointer.
_GLIBCXX23_CONSTEXPR
pointer pointer
get() const noexcept get() const noexcept
{ return _M_t._M_ptr(); } { return _M_t._M_ptr(); }
/// Return a reference to the stored deleter. /// Return a reference to the stored deleter.
_GLIBCXX23_CONSTEXPR
deleter_type& deleter_type&
get_deleter() noexcept get_deleter() noexcept
{ return _M_t._M_deleter(); } { return _M_t._M_deleter(); }
/// Return a reference to the stored deleter. /// Return a reference to the stored deleter.
_GLIBCXX23_CONSTEXPR
const deleter_type& const deleter_type&
get_deleter() const noexcept get_deleter() const noexcept
{ return _M_t._M_deleter(); } { return _M_t._M_deleter(); }
/// Return @c true if the stored pointer is not null. /// Return @c true if the stored pointer is not null.
_GLIBCXX23_CONSTEXPR
explicit operator bool() const noexcept explicit operator bool() const noexcept
{ return get() == pointer() ? false : true; } { return get() == pointer() ? false : true; }
// Modifiers. // Modifiers.
/// Release ownership of any stored pointer. /// Release ownership of any stored pointer.
_GLIBCXX23_CONSTEXPR
pointer pointer
release() noexcept release() noexcept
{ return _M_t.release(); } { return _M_t.release(); }
@ -452,6 +492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* *
* The deleter will be invoked if a pointer is already owned. * The deleter will be invoked if a pointer is already owned.
*/ */
_GLIBCXX23_CONSTEXPR
void void
reset(pointer __p = pointer()) noexcept reset(pointer __p = pointer()) noexcept
{ {
@ -461,6 +502,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
/// Exchange the pointer and deleter with another object. /// Exchange the pointer and deleter with another object.
_GLIBCXX23_CONSTEXPR
void void
swap(unique_ptr& __u) noexcept swap(unique_ptr& __u) noexcept
{ {
@ -551,6 +593,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typename = _DeleterConstraint<_Vp>, typename = _DeleterConstraint<_Vp>,
typename = typename enable_if< typename = typename enable_if<
__safe_conversion_raw<_Up>::value, bool>::type> __safe_conversion_raw<_Up>::value, bool>::type>
_GLIBCXX23_CONSTEXPR
explicit explicit
unique_ptr(_Up __p) noexcept unique_ptr(_Up __p) noexcept
: _M_t(__p) : _M_t(__p)
@ -567,6 +610,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Up, typename _Del = deleter_type, template<typename _Up, typename _Del = deleter_type,
typename = _Require<__safe_conversion_raw<_Up>, typename = _Require<__safe_conversion_raw<_Up>,
is_copy_constructible<_Del>>> is_copy_constructible<_Del>>>
_GLIBCXX23_CONSTEXPR
unique_ptr(_Up __p, const deleter_type& __d) noexcept unique_ptr(_Up __p, const deleter_type& __d) noexcept
: _M_t(__p, __d) { } : _M_t(__p, __d) { }
@ -581,6 +625,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Up, typename _Del = deleter_type, template<typename _Up, typename _Del = deleter_type,
typename = _Require<__safe_conversion_raw<_Up>, typename = _Require<__safe_conversion_raw<_Up>,
is_move_constructible<_Del>>> is_move_constructible<_Del>>>
_GLIBCXX23_CONSTEXPR
unique_ptr(_Up __p, unique_ptr(_Up __p,
__enable_if_t<!is_lvalue_reference<_Del>::value, __enable_if_t<!is_lvalue_reference<_Del>::value,
_Del&&> __d) noexcept _Del&&> __d) noexcept
@ -608,11 +653,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__conditional_t<is_reference<_Dp>::value, __conditional_t<is_reference<_Dp>::value,
is_same<_Ep, _Dp>, is_same<_Ep, _Dp>,
is_convertible<_Ep, _Dp>>>> is_convertible<_Ep, _Dp>>>>
_GLIBCXX23_CONSTEXPR
unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
{ } { }
/// Destructor, invokes the deleter if the stored pointer is not null. /// Destructor, invokes the deleter if the stored pointer is not null.
#if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc
constexpr
#endif
~unique_ptr() ~unique_ptr()
{ {
auto& __ptr = _M_t._M_ptr(); auto& __ptr = _M_t._M_ptr();
@ -638,6 +687,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* Invokes the deleter if this object owns a pointer. * Invokes the deleter if this object owns a pointer.
*/ */
template<typename _Up, typename _Ep> template<typename _Up, typename _Ep>
_GLIBCXX23_CONSTEXPR
typename typename
enable_if<__and_<__safe_conversion_up<_Up, _Ep>, enable_if<__and_<__safe_conversion_up<_Up, _Ep>,
is_assignable<deleter_type&, _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. /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
_GLIBCXX23_CONSTEXPR
unique_ptr& unique_ptr&
operator=(nullptr_t) noexcept operator=(nullptr_t) noexcept
{ {
@ -661,6 +712,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Observers. // Observers.
/// Access an element of owned array. /// Access an element of owned array.
_GLIBCXX23_CONSTEXPR
typename std::add_lvalue_reference<element_type>::type typename std::add_lvalue_reference<element_type>::type
operator[](size_t __i) const operator[](size_t __i) const
{ {
@ -669,27 +721,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
/// Return the stored pointer. /// Return the stored pointer.
_GLIBCXX23_CONSTEXPR
pointer pointer
get() const noexcept get() const noexcept
{ return _M_t._M_ptr(); } { return _M_t._M_ptr(); }
/// Return a reference to the stored deleter. /// Return a reference to the stored deleter.
_GLIBCXX23_CONSTEXPR
deleter_type& deleter_type&
get_deleter() noexcept get_deleter() noexcept
{ return _M_t._M_deleter(); } { return _M_t._M_deleter(); }
/// Return a reference to the stored deleter. /// Return a reference to the stored deleter.
_GLIBCXX23_CONSTEXPR
const deleter_type& const deleter_type&
get_deleter() const noexcept get_deleter() const noexcept
{ return _M_t._M_deleter(); } { return _M_t._M_deleter(); }
/// Return @c true if the stored pointer is not null. /// Return @c true if the stored pointer is not null.
_GLIBCXX23_CONSTEXPR
explicit operator bool() const noexcept explicit operator bool() const noexcept
{ return get() == pointer() ? false : true; } { return get() == pointer() ? false : true; }
// Modifiers. // Modifiers.
/// Release ownership of any stored pointer. /// Release ownership of any stored pointer.
_GLIBCXX23_CONSTEXPR
pointer pointer
release() noexcept release() noexcept
{ return _M_t.release(); } { return _M_t.release(); }
@ -712,14 +769,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >
> >
>> >>
_GLIBCXX23_CONSTEXPR
void void
reset(_Up __p) noexcept reset(_Up __p) noexcept
{ _M_t.reset(std::move(__p)); } { _M_t.reset(std::move(__p)); }
_GLIBCXX23_CONSTEXPR
void reset(nullptr_t = nullptr) noexcept void reset(nullptr_t = nullptr) noexcept
{ reset(pointer()); } { reset(pointer()); }
/// Exchange the pointer and deleter with another object. /// Exchange the pointer and deleter with another object.
_GLIBCXX23_CONSTEXPR
void void
swap(unique_ptr& __u) noexcept swap(unique_ptr& __u) noexcept
{ {
@ -740,6 +800,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline inline
#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
// Constrained free swap overload, see p0185r1 // Constrained free swap overload, see p0185r1
_GLIBCXX23_CONSTEXPR
typename enable_if<__is_swappable<_Dp>::value>::type typename enable_if<__is_swappable<_Dp>::value>::type
#else #else
void void
@ -758,41 +819,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Equality operator for unique_ptr objects, compares the owned pointers /// Equality operator for unique_ptr objects, compares the owned pointers
template<typename _Tp, typename _Dp, template<typename _Tp, typename _Dp,
typename _Up, typename _Ep> typename _Up, typename _Ep>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator==(const unique_ptr<_Tp, _Dp>& __x, operator==(const unique_ptr<_Tp, _Dp>& __x,
const unique_ptr<_Up, _Ep>& __y) const unique_ptr<_Up, _Ep>& __y)
{ return __x.get() == __y.get(); } { return __x.get() == __y.get(); }
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> 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 operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
{ return !__x; } { return !__x; }
#ifndef __cpp_lib_three_way_comparison #ifndef __cpp_lib_three_way_comparison
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD
inline bool
operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
{ return !__x; } { return !__x; }
/// Inequality operator for unique_ptr objects, compares the owned pointers /// Inequality operator for unique_ptr objects, compares the owned pointers
template<typename _Tp, typename _Dp, template<typename _Tp, typename _Dp,
typename _Up, typename _Ep> typename _Up, typename _Ep>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD
inline bool
operator!=(const unique_ptr<_Tp, _Dp>& __x, operator!=(const unique_ptr<_Tp, _Dp>& __x,
const unique_ptr<_Up, _Ep>& __y) const unique_ptr<_Up, _Ep>& __y)
{ return __x.get() != __y.get(); } { return __x.get() != __y.get(); }
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD
inline bool
operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
{ return (bool)__x; } { return (bool)__x; }
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD
inline bool
operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
{ return (bool)__x; } { return (bool)__x; }
#endif // three way comparison #endif // three way comparison
@ -800,7 +867,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Relational operator for unique_ptr objects, compares the owned pointers /// Relational operator for unique_ptr objects, compares the owned pointers
template<typename _Tp, typename _Dp, template<typename _Tp, typename _Dp,
typename _Up, typename _Ep> typename _Up, typename _Ep>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator<(const unique_ptr<_Tp, _Dp>& __x, operator<(const unique_ptr<_Tp, _Dp>& __x,
const unique_ptr<_Up, _Ep>& __y) const unique_ptr<_Up, _Ep>& __y)
{ {
@ -812,7 +880,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
{ {
return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(), return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
@ -821,7 +890,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
{ {
return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr, 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 /// Relational operator for unique_ptr objects, compares the owned pointers
template<typename _Tp, typename _Dp, template<typename _Tp, typename _Dp,
typename _Up, typename _Ep> typename _Up, typename _Ep>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator<=(const unique_ptr<_Tp, _Dp>& __x, operator<=(const unique_ptr<_Tp, _Dp>& __x,
const unique_ptr<_Up, _Ep>& __y) const unique_ptr<_Up, _Ep>& __y)
{ return !(__y < __x); } { return !(__y < __x); }
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
{ return !(nullptr < __x); } { return !(nullptr < __x); }
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
{ return !(__x < nullptr); } { return !(__x < nullptr); }
/// Relational operator for unique_ptr objects, compares the owned pointers /// Relational operator for unique_ptr objects, compares the owned pointers
template<typename _Tp, typename _Dp, template<typename _Tp, typename _Dp,
typename _Up, typename _Ep> typename _Up, typename _Ep>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator>(const unique_ptr<_Tp, _Dp>& __x, operator>(const unique_ptr<_Tp, _Dp>& __x,
const unique_ptr<_Up, _Ep>& __y) const unique_ptr<_Up, _Ep>& __y)
{ return (__y < __x); } { return (__y < __x); }
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
{ {
return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr, return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
@ -867,7 +942,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
{ {
return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(), 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 /// Relational operator for unique_ptr objects, compares the owned pointers
template<typename _Tp, typename _Dp, template<typename _Tp, typename _Dp,
typename _Up, typename _Ep> typename _Up, typename _Ep>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator>=(const unique_ptr<_Tp, _Dp>& __x, operator>=(const unique_ptr<_Tp, _Dp>& __x,
const unique_ptr<_Up, _Ep>& __y) const unique_ptr<_Up, _Ep>& __y)
{ return !(__x < __y); } { return !(__x < __y); }
/// unique_ptr comparison with nullptr /// unique_ptr comparison with nullptr
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
_GLIBCXX_NODISCARD inline bool _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR
inline bool
operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
{ return !(__x < nullptr); } { return !(__x < nullptr); }
@ -898,6 +976,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Dp, typename _Up, typename _Ep> template<typename _Tp, typename _Dp, typename _Up, typename _Ep>
requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer, requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer,
typename unique_ptr<_Up, _Ep>::pointer> typename unique_ptr<_Up, _Ep>::pointer>
_GLIBCXX23_CONSTEXPR
inline inline
compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer, compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer,
typename unique_ptr<_Up, _Ep>::pointer> typename unique_ptr<_Up, _Ep>::pointer>
@ -907,6 +986,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer> requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer>
_GLIBCXX23_CONSTEXPR
inline inline
compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer> compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer>
operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
@ -979,6 +1059,7 @@ namespace __detail
* @relates unique_ptr * @relates unique_ptr
*/ */
template<typename _Tp, typename... _Args> template<typename _Tp, typename... _Args>
_GLIBCXX23_CONSTEXPR
inline __detail::__unique_ptr_t<_Tp> inline __detail::__unique_ptr_t<_Tp>
make_unique(_Args&&... __args) make_unique(_Args&&... __args)
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
@ -993,6 +1074,7 @@ namespace __detail
* The array elements are value-initialized. * The array elements are value-initialized.
*/ */
template<typename _Tp> template<typename _Tp>
_GLIBCXX23_CONSTEXPR
inline __detail::__unique_ptr_array_t<_Tp> inline __detail::__unique_ptr_array_t<_Tp>
make_unique(size_t __num) make_unique(size_t __num)
{ return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); } { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
@ -1014,6 +1096,7 @@ namespace __detail
* @relates unique_ptr * @relates unique_ptr
*/ */
template<typename _Tp> template<typename _Tp>
_GLIBCXX23_CONSTEXPR
inline __detail::__unique_ptr_t<_Tp> inline __detail::__unique_ptr_t<_Tp>
make_unique_for_overwrite() make_unique_for_overwrite()
{ return unique_ptr<_Tp>(new _Tp); } { return unique_ptr<_Tp>(new _Tp); }
@ -1026,6 +1109,7 @@ namespace __detail
* @relates unique_ptr * @relates unique_ptr
*/ */
template<typename _Tp> template<typename _Tp>
_GLIBCXX23_CONSTEXPR
inline __detail::__unique_ptr_array_t<_Tp> inline __detail::__unique_ptr_array_t<_Tp>
make_unique_for_overwrite(size_t __num) make_unique_for_overwrite(size_t __num)
{ return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]); } { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]); }

View File

@ -307,6 +307,10 @@
#if _GLIBCXX_HOSTED #if _GLIBCXX_HOSTED
#define __cpp_lib_adaptor_iterator_pair_constructor 202106L #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 #if __cpp_concepts >= 202002L
# define __cpp_lib_expected 202202L # define __cpp_lib_expected 202202L
#endif #endif

View File

@ -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() );

View File

@ -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() );

View File

@ -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() );

View File

@ -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() );

View File

@ -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() );

View File

@ -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() );