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..5ebfb248d8730 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,7 +209,8 @@ 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 + _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())) {} @@ -226,7 +228,8 @@ 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& operator=(unique_ptr&& __u) _NOEXCEPT { + _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; @@ -251,10 +254,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 +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; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT + _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_)) {} - _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& + operator=(_If::value, unique_ptr&&, __nat> __u) _NOEXCEPT { reset(__u.release()); __deleter_ = std::forward(__u.get_deleter()); __checker_ = std::move(__u.__checker_); @@ -564,10 +567,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'}} }