From e5e10227dec2fcdb862f74ec8d2ddd35f29ddf6d Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 9 Nov 2025 17:31:11 +0800 Subject: [PATCH 1/3] [libc++] LWG2899: Constrain move special functions of `tuple` and `unique_ptr` libc++'s `tuple`'s move constructor is well-constrained when initially implemented. So this patch only adds test cases. For `unique_ptr`, its move constructor and move assignment operator were previously unconstrained and thus this patch changes them. - In C++20 and later, I think it's better to use obviously correct `requires`-clauses. - In C++17 and earlier, there doesn't seem "obviously correct" approach for constraining. I'm attempting to use `_nat` trick to avoid turning the functions into templates (which are not move special functions). Some tests case are adjusted because false positive of move-assignability of `unique_ptr` is reduced. Comments are updated to reflect that move-constructibility is not actually required for `unique_ptr`'s deleter. This patch also explicitly deletes copy functions of `unique_ptr` in all modes. Previously, they are implicitly deleted since C++11 mode, although the standard wording always explicitly deletes them. Clang seems to be somehow buggy on propagating deleted-ness of special member functions from unnamed structs, while the explicit deletion can act as a workaround. The title of this patch is adjusted to reflect the final resolution of LWG2899. --- libcxx/docs/Status/Cxx20Issues.csv | 2 +- libcxx/include/__memory/unique_ptr.h | 46 ++++++++++++++----- .../unique.ptr.asgn/move.pass.cpp | 11 ++++- .../unique.ptr.asgn/move_convert.pass.cpp | 6 +-- .../move_convert.runtime.pass.cpp | 2 +- .../move_convert.single.pass.cpp | 2 +- .../unique.ptr.ctor/move.pass.cpp | 24 +++++++--- .../tuple.tuple/tuple.cnstr/move.pass.cpp | 25 ++++++++++ .../tuple.elem/tuple.by.type.verify.cpp | 2 +- .../pair.astuple/pairs.by.type3.verify.cpp | 2 +- 10 files changed, 95 insertions(+), 27 deletions(-) diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index 3d01ff5bbbdfb..f2c6676f5123b 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -143,7 +143,7 @@ "`LWG3180 `__","Inconsistently named return type for ``ranges::minmax_element``\ ","2019-02 (Kona)","|Complete|","15","`#103844 `__","" "`LWG3182 `__","Specification of ``Same``\ could be clearer","2019-02 (Kona)","|Complete|","15","`#103845 `__","" "","","","","","","" -"`LWG2899 `__","``is_(nothrow_)move_constructible``\ and ``tuple``\ , ``optional``\ and ``unique_ptr``\ ","2019-07 (Cologne)","","","`#100255 `__","" +"`LWG2899 `__","``is_(nothrow_)move_constructible``\ and ``tuple``\ , ``optional``\ and ``unique_ptr``\ ","2019-07 (Cologne)","|Complete|","22","`#100255 `__","" "`LWG3055 `__","``path::operator+=(*single-character*)``\ misspecified","2019-07 (Cologne)","|Complete|","7","`#103846 `__","" "`LWG3158 `__","``tuple(allocator_arg_t, const Alloc&)``\ should be conditionally explicit","2019-07 (Cologne)","|Complete|","10","`#103847 `__","" "`LWG3169 `__","``ranges``\ permutation generators discard useful information","2019-07 (Cologne)","|Complete|","15","`#103848 `__","" diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h index eff24546cdc01..f2014440fbc05 100644 --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -45,6 +45,7 @@ #include <__type_traits/is_trivially_relocatable.h> #include <__type_traits/is_unbounded_array.h> #include <__type_traits/is_void.h> +#include <__type_traits/nat.h> #include <__type_traits/remove_extent.h> #include <__type_traits/type_identity.h> #include <__utility/declval.h> @@ -208,9 +209,15 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr { template > > _LIBCPP_HIDE_FROM_ABI unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT - : __ptr_(__u.release()), - __deleter_(std::forward(__u.get_deleter())) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 +#if _LIBCPP_STD_VER >= 20 + unique_ptr(unique_ptr&& __u) noexcept + requires is_move_constructible_v<_Dp> +#else + unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT +#endif + : __ptr_(__u.release()), __deleter_(std::forward(__u.get_deleter())) { + } template && __p) _NOEXCEPT : __ptr_(__p.release()), __deleter_() {} #endif - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& +#if _LIBCPP_STD_VER >= 20 + operator=(unique_ptr&& __u) noexcept + requires is_move_assignable_v<_Dp> +#else + operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT +#endif + { reset(__u.release()); __deleter_ = std::forward(__u.get_deleter()); return *this; @@ -251,10 +265,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr { } #endif -#ifdef _LIBCPP_CXX03_LANG unique_ptr(unique_ptr const&) = delete; unique_ptr& operator=(unique_ptr const&) = delete; -#endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 ~unique_ptr() { reset(); } @@ -532,12 +544,26 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr<_Tp[], _Dp> { class = _EnableIfPointerConvertible<_Pp> > _LIBCPP_HIDE_FROM_ABI unique_ptr(_Pp __ptr, _BadRValRefType<_Dummy> __deleter) = delete; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 +#if _LIBCPP_STD_VER >= 20 + unique_ptr(unique_ptr&& __u) noexcept + requires is_move_constructible_v<_Dp> +#else + unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT +#endif : __ptr_(__u.release()), __deleter_(std::forward(__u.get_deleter())), - __checker_(std::move(__u.__checker_)) {} + __checker_(std::move(__u.__checker_)) { + } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& +#if _LIBCPP_STD_VER >= 20 + operator=(unique_ptr&& __u) noexcept + requires is_move_assignable_v<_Dp> +#else + operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT +#endif + { reset(__u.release()); __deleter_ = std::forward(__u.get_deleter()); __checker_ = std::move(__u.__checker_); @@ -564,10 +590,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr<_Tp[], _Dp> { return *this; } -#ifdef _LIBCPP_CXX03_LANG unique_ptr(unique_ptr const&) = delete; unique_ptr& operator=(unique_ptr const&) = delete; -#endif public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 ~unique_ptr() { reset(); } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp index 1b1f848e4d587..a6e9872a5b4d2 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp @@ -112,19 +112,26 @@ TEST_CONSTEXPR_CXX23 void test_sfinae() { static_assert(!std::is_assignable::value, ""); static_assert(std::is_nothrow_assignable::value, ""); } + { + typedef std::unique_ptr > U; + static_assert(!std::is_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); + } { typedef std::unique_ptr&> U; static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); - static_assert(std::is_nothrow_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); } { typedef std::unique_ptr&> U; static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); - static_assert(std::is_nothrow_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); } } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp index 61a2bfbbc2e05..39599fa2ad045 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp @@ -220,7 +220,7 @@ TEST_CONSTEXPR_CXX23 void test_sfinae() { static_assert(!std::is_assignable::value, ""); using U1C = std::unique_ptr const&>; - static_assert(std::is_nothrow_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); } { // Test that if the deleter assignment is not valid the assignment operator // SFINAEs. @@ -296,12 +296,12 @@ TEST_CONSTEXPR_CXX23 void test_noexcept() { { typedef std::unique_ptr&> APtr; typedef std::unique_ptr&> BPtr; - static_assert(std::is_nothrow_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); } { typedef std::unique_ptr&> APtr; typedef std::unique_ptr&> BPtr; - static_assert(std::is_nothrow_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); } } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.runtime.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.runtime.pass.cpp index 7a86dd365cf95..5e8353a475cd7 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.runtime.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.runtime.pass.cpp @@ -89,7 +89,7 @@ void test_sfinae() { static_assert(!std::is_assignable::value, ""); } { // cannot move if the deleter-types cannot convert - static_assert(std::is_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.single.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.single.pass.cpp index 0201e9c4385a4..21674a79f16cf 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.single.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.single.pass.cpp @@ -87,7 +87,7 @@ TEST_CONSTEXPR_CXX23 void test_sfinae() { static_assert(!std::is_assignable::value, ""); } { // cannot move if the deleter-types cannot convert - static_assert(std::is_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp index 318f4b18a0d1e..097ca4e604711 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp @@ -12,6 +12,8 @@ // Test unique_ptr move ctor +// XFAIL: FROZEN-CXX03-HEADERS-FIXME + #include #include #include @@ -24,10 +26,8 @@ // // Concerns // 1 The moved from pointer is empty and the new pointer stores the old value. -// 2 The only requirement on the deleter is that it is MoveConstructible -// or a reference. -// 3 The constructor works for explicitly moved values (i.e. std::move(x)) -// 4 The constructor works for true temporaries (e.g. a return value) +// 2 The constructor works for explicitly moved values (i.e. std::move(x)) +// 3 The constructor works for true temporaries (e.g. a return value) // // Plan // 1 Explicitly construct unique_ptr for various deleter types 'D'. @@ -73,10 +73,22 @@ void sink3(std::unique_ptr&> p) { template TEST_CONSTEXPR_CXX23 void test_sfinae() { - typedef std::unique_ptr U; - { // Ensure unique_ptr is non-copyable + // Ensure that + // - unique_ptr is non-copyable, and + // - unique_ptr's move-constructibility is correctly propagated from its deleter's. + { + typedef std::unique_ptr U; static_assert((!std::is_constructible::value), ""); static_assert((!std::is_constructible::value), ""); + static_assert(std::is_move_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); + } + { + typedef std::unique_ptr > U; + static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_move_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); } } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp index d6c192d2e0543..c564d42e51c8e 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp @@ -49,6 +49,19 @@ struct move_only_large final { int value; }; +// a non-movable type +struct nonmovable { + nonmovable(const nonmovable&) = default; + nonmovable(nonmovable&&) = delete; +}; + +// a non-movable type with a usable copy constructor +// verifying that tuple's move constructor is not confused to select that copy constructor +struct nonmovable_with_copy_ctor { + nonmovable_with_copy_ctor(const nonmovable_with_copy_ctor&) = default; + nonmovable_with_copy_ctor(nonmovable_with_copy_ctor&&) = delete; +}; + template void test_sfinae() { using Tup = std::tuple; @@ -123,6 +136,18 @@ int main(int, char**) test_sfinae(); test_sfinae(); } + // non-movable types + { + using Alloc = std::allocator; + using Tag = std::allocator_arg_t; + + static_assert(!std::is_move_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); + + static_assert(!std::is_move_constructible::value, ""); + static_assert( + !std::is_constructible::value, ""); + } return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.verify.cpp index 00f27c3220d2e..cd64e8975a526 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.verify.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.verify.cpp @@ -30,7 +30,7 @@ void test_bad_index() { void test_bad_return_type() { typedef std::unique_ptr upint; std::tuple t; - upint p = std::get(t); // expected-error{{deleted copy constructor}} + upint p = std::get(t); // expected-error{{deleted constructor}} } void f() { diff --git a/libcxx/test/std/utilities/utility/pairs/pair.astuple/pairs.by.type3.verify.cpp b/libcxx/test/std/utilities/utility/pairs/pair.astuple/pairs.by.type3.verify.cpp index d2d9b67c5bc66..8b0a607b69b4b 100644 --- a/libcxx/test/std/utilities/utility/pairs/pair.astuple/pairs.by.type3.verify.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pair.astuple/pairs.by.type3.verify.cpp @@ -14,5 +14,5 @@ void f() { typedef std::unique_ptr Ptr; std::pair t(Ptr(new int(4)), 23); - Ptr p = std::get(t); // expected-error {{call to implicitly-deleted copy constructor of 'Ptr'}} + Ptr p = std::get(t); // expected-error {{call to deleted constructor of 'Ptr'}} } From 5102d5d64d61d0d25a1c03c2f995381b02a239ee Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 10 Nov 2025 10:45:16 +0800 Subject: [PATCH 2/3] Tweak function signatures --- libcxx/include/__memory/unique_ptr.h | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h index f2014440fbc05..3e76a94f54679 100644 --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -209,12 +209,11 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr { template > > _LIBCPP_HIDE_FROM_ABI unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 #if _LIBCPP_STD_VER >= 20 - unique_ptr(unique_ptr&& __u) noexcept + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) noexcept requires is_move_constructible_v<_Dp> #else - unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT + _LIBCPP_HIDE_FROM_ABI unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT #endif : __ptr_(__u.release()), __deleter_(std::forward(__u.get_deleter())) { } @@ -233,12 +232,11 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr { _LIBCPP_HIDE_FROM_ABI unique_ptr(auto_ptr<_Up>&& __p) _NOEXCEPT : __ptr_(__p.release()), __deleter_() {} #endif - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& #if _LIBCPP_STD_VER >= 20 - operator=(unique_ptr&& __u) noexcept + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) noexcept requires is_move_assignable_v<_Dp> #else - operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT + _LIBCPP_HIDE_FROM_ABI unique_ptr& operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT #endif { reset(__u.release()); @@ -544,24 +542,22 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr<_Tp[], _Dp> { class = _EnableIfPointerConvertible<_Pp> > _LIBCPP_HIDE_FROM_ABI unique_ptr(_Pp __ptr, _BadRValRefType<_Dummy> __deleter) = delete; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 #if _LIBCPP_STD_VER >= 20 - unique_ptr(unique_ptr&& __u) noexcept + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) noexcept requires is_move_constructible_v<_Dp> #else - unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT + _LIBCPP_HIDE_FROM_ABI unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT #endif : __ptr_(__u.release()), __deleter_(std::forward(__u.get_deleter())), __checker_(std::move(__u.__checker_)) { } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& #if _LIBCPP_STD_VER >= 20 - operator=(unique_ptr&& __u) noexcept + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) noexcept requires is_move_assignable_v<_Dp> #else - operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT + _LIBCPP_HIDE_FROM_ABI unique_ptr& operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT #endif { reset(__u.release()); From 64ab1c540cbd6f8bf12dcc3d9695e4ce3c15146b Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 10 Nov 2025 20:42:30 +0800 Subject: [PATCH 3/3] Use `__nat` trick in all modes --- libcxx/include/__memory/unique_ptr.h | 41 ++++++++-------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h index 3e76a94f54679..5ebfb248d8730 100644 --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -209,14 +209,10 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr { template > > _LIBCPP_HIDE_FROM_ABI unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete; -#if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) noexcept - requires is_move_constructible_v<_Dp> -#else - _LIBCPP_HIDE_FROM_ABI unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT -#endif - : __ptr_(__u.release()), __deleter_(std::forward(__u.get_deleter())) { - } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 + unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT + : __ptr_(__u.release()), + __deleter_(std::forward(__u.get_deleter())) {} template && __p) _NOEXCEPT : __ptr_(__p.release()), __deleter_() {} #endif -#if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) noexcept - requires is_move_assignable_v<_Dp> -#else - _LIBCPP_HIDE_FROM_ABI unique_ptr& operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT -#endif - { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& + operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT { reset(__u.release()); __deleter_ = std::forward(__u.get_deleter()); return *this; @@ -542,24 +533,14 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr<_Tp[], _Dp> { class = _EnableIfPointerConvertible<_Pp> > _LIBCPP_HIDE_FROM_ABI unique_ptr(_Pp __ptr, _BadRValRefType<_Dummy> __deleter) = delete; -#if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) noexcept - requires is_move_constructible_v<_Dp> -#else - _LIBCPP_HIDE_FROM_ABI unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT -#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 + unique_ptr(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT : __ptr_(__u.release()), __deleter_(std::forward(__u.get_deleter())), - __checker_(std::move(__u.__checker_)) { - } + __checker_(std::move(__u.__checker_)) {} -#if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) noexcept - requires is_move_assignable_v<_Dp> -#else - _LIBCPP_HIDE_FROM_ABI unique_ptr& operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT -#endif - { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& + operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT { reset(__u.release()); __deleter_ = std::forward(__u.get_deleter()); __checker_ = std::move(__u.__checker_);