diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -27,7 +27,7 @@ "`3420 `__","cpp17-iterator should check that the type looks like an iterator first","November 2020","|Complete|","14.0","|ranges|" "`3421 `__","Imperfect ADL emulation for boolean-testable","November 2020","|Nothing To Do|","","|ranges|" "`3425 `__","``condition_variable_any`` fails to constrain its Lock parameters","November 2020","|Nothing To Do|","" -"`3426 `__","``operator<=>(const unique_ptr&, nullptr_t)`` can't get no satisfaction","November 2020","","","|spaceship|" +"`3426 `__","``operator<=>(const unique_ptr&, nullptr_t)`` can't get no satisfaction","November 2020","|Complete|","16.0","|spaceship|" "`3427 `__","``operator<=>(const shared_ptr&, nullptr_t)`` definition ill-formed","November 2020","","","|spaceship|" "`3428 `__","``single_view``'s in place constructor should be explicit","November 2020","|Complete|","14.0","|ranges|" "`3434 `__","``ios_base`` never reclaims memory for iarray and parray","November 2020","|Nothing To Do|","" diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv --- a/libcxx/docs/Status/SpaceshipProjects.csv +++ b/libcxx/docs/Status/SpaceshipProjects.csv @@ -25,7 +25,7 @@ "| `[variant.relops] `_ | `[variant.monostate.relops] `_","| monostate | variant",None,Kent Ross,|In Progress| -| `[unique.ptr.special] `_,| `unique_ptr `_,[comparisons.three.way],Adrian Vogelsgesang,|In Progress| +| `[unique.ptr.special] `_,| `unique_ptr `_,[comparisons.three.way],Adrian Vogelsgesang,|Complete| | `[util.smartptr.shared.cmp] `_,| `shared_ptr `_,[comparisons.three.way],Adrian Vogelsgesang,|In Progress| | `[type.index.members] `_,| type_index,None,Unassigned,|Not Started| | `[charconv.syn] `_,| to_chars_result,None,Mark de Wever,|Complete| diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -10,6 +10,9 @@ #ifndef _LIBCPP___MEMORY_UNIQUE_PTR_H #define _LIBCPP___MEMORY_UNIQUE_PTR_H +#include <__compare/compare_three_way.h> +#include <__compare/compare_three_way_result.h> +#include <__compare/three_way_comparable.h> #include <__config> #include <__functional/hash.h> #include <__functional/operations.h> @@ -557,10 +560,12 @@ bool operator==(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return __x.get() == __y.get();} +#if _LIBCPP_STD_VER <= 17 template inline _LIBCPP_INLINE_VISIBILITY bool operator!=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__x == __y);} +#endif template inline _LIBCPP_INLINE_VISIBILITY @@ -588,6 +593,18 @@ bool operator>=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__x < __y);} + +#if _LIBCPP_STD_VER > 17 +template +requires three_way_comparable_with::pointer, + typename unique_ptr<_T2, _D2>::pointer> +compare_three_way_result_t::pointer, + typename unique_ptr<_T2, _D2>::pointer> +operator<=>(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) { + return compare_three_way()(__x.get(), __y.get()); +} +#endif + template inline _LIBCPP_INLINE_VISIBILITY bool @@ -596,6 +613,7 @@ return !__x; } +#if _LIBCPP_STD_VER <= 17 template inline _LIBCPP_INLINE_VISIBILITY bool @@ -619,6 +637,7 @@ { return static_cast(__x); } +#endif // _LIBCPP_STD_VER <= 17 template inline _LIBCPP_INLINE_VISIBILITY @@ -686,6 +705,15 @@ return !(nullptr < __x); } +#if _LIBCPP_STD_VER > 17 +template +requires three_way_comparable::pointer> +compare_three_way_result_t::pointer> +operator<=>(const unique_ptr<_T1, _D1>& __x, nullptr_t) { + return compare_three_way()(__x.get(), static_cast::pointer>(nullptr)); +} +#endif + #if _LIBCPP_STD_VER > 11 template diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -505,7 +505,7 @@ template bool operator==(const unique_ptr& x, const unique_ptr& y); template - bool operator!=(const unique_ptr& x, const unique_ptr& y); + bool operator!=(const unique_ptr& x, const unique_ptr& y); // removed in C++20 template bool operator<(const unique_ptr& x, const unique_ptr& y); template @@ -514,15 +514,21 @@ bool operator>(const unique_ptr& x, const unique_ptr& y); template bool operator>=(const unique_ptr& x, const unique_ptr& y); +template + requires three_way_comparable_with::pointer, + typename unique_ptr::pointer> + compare_three_way_result_t::pointer, + typename unique_ptr::pointer> + operator<=>(const unique_ptr& x, const unique_ptr& y); // C++20 template bool operator==(const unique_ptr& x, nullptr_t) noexcept; template - bool operator==(nullptr_t, const unique_ptr& y) noexcept; + bool operator==(nullptr_t, const unique_ptr& y) noexcept; // removed in C++20 template - bool operator!=(const unique_ptr& x, nullptr_t) noexcept; + bool operator!=(const unique_ptr& x, nullptr_t) noexcept; // removed in C++20 template - bool operator!=(nullptr_t, const unique_ptr& y) noexcept; + bool operator!=(nullptr_t, const unique_ptr& y) noexcept; // removed in C++20 template bool operator<(const unique_ptr& x, nullptr_t); @@ -540,6 +546,10 @@ bool operator>=(const unique_ptr& x, nullptr_t); template bool operator>=(nullptr_t, const unique_ptr& y); +template + requires three_way_comparable::pointer> + compare_three_way_result_t::pointer> + operator<=>(const unique_ptr& x, nullptr_t); // C++20 class bad_weak_ptr : public std::exception diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp.pass.cpp @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// unique_ptr + +// template +// bool +// operator==(const unique_ptr& x, const unique_ptr& y); + +// template +// bool +// operator!=(const unique_ptr& x, const unique_ptr& y); + +// template +// bool +// operator< (const unique_ptr& x, const unique_ptr& y); + +// template +// bool +// operator> (const unique_ptr& x, const unique_ptr& y); + +// template +// bool +// operator<=(const unique_ptr& x, const unique_ptr& y); + +// template +// bool +// operator>=(const unique_ptr& x, const unique_ptr& y); + +// template +// requires three_way_comparable_with::pointer, +// typename unique_ptr::pointer> +// compare_three_way_result_t::pointer, +// typename unique_ptr::pointer> +// operator<=>(const unique_ptr& x, const unique_ptr& y); + +#include +#include + +#include "test_macros.h" +#include "deleter_types.h" +#include "test_comparisons.h" + +struct A { + static int count; + A() { ++count; } + A(const A&) { ++count; } + virtual ~A() { --count; } +}; + +int A::count = 0; + +struct B : public A { + static int count; + B() { ++count; } + B(const B& other) : A(other) { ++count; } + virtual ~B() { --count; } +}; + +int B::count = 0; + +int main(int, char**) { + AssertComparisonsReturnBool >(); +#if TEST_STD_VER > 17 + AssertOrderReturn>(); +#endif + + // Pointers of same type + { + A* ptr1 = new A; + A* ptr2 = new A; + const std::unique_ptr > p1(ptr1); + const std::unique_ptr > p2(ptr2); + + assert(!(p1 == p2)); + assert(p1 != p2); + assert((p1 < p2) == (ptr1 < ptr2)); + assert((p1 <= p2) == (ptr1 <= ptr2)); + assert((p1 > p2) == (ptr1 > ptr2)); + assert((p1 >= p2) == (ptr1 >= ptr2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) != std::strong_ordering::equal); + assert((p1 <=> p2) == (ptr1 <=> ptr2)); +#endif + } + // Pointers of different type + { + A* ptr1 = new A; + B* ptr2 = new B; + const std::unique_ptr > p1(ptr1); + const std::unique_ptr > p2(ptr2); + assert(!(p1 == p2)); + assert(p1 != p2); + assert((p1 < p2) == (ptr1 < ptr2)); + assert((p1 <= p2) == (ptr1 <= ptr2)); + assert((p1 > p2) == (ptr1 > ptr2)); + assert((p1 >= p2) == (ptr1 >= ptr2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) != std::strong_ordering::equal); + assert((p1 <=> p2) == (ptr1 <=> ptr2)); +#endif + } + // Pointers of same array type + { + A* ptr1 = new A[3]; + A* ptr2 = new A[3]; + const std::unique_ptr > p1(ptr1); + const std::unique_ptr > p2(ptr2); + assert(!(p1 == p2)); + assert(p1 != p2); + assert((p1 < p2) == (ptr1 < ptr2)); + assert((p1 <= p2) == (ptr1 <= ptr2)); + assert((p1 > p2) == (ptr1 > ptr2)); + assert((p1 >= p2) == (ptr1 >= ptr2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) != std::strong_ordering::equal); + assert((p1 <=> p2) == (ptr1 <=> ptr2)); +#endif + } + // Pointers of different array types + { + A* ptr1 = new A[3]; + B* ptr2 = new B[3]; + const std::unique_ptr > p1(ptr1); + const std::unique_ptr > p2(ptr2); + assert(!(p1 == p2)); + assert(p1 != p2); + assert((p1 < p2) == (ptr1 < ptr2)); + assert((p1 <= p2) == (ptr1 <= ptr2)); + assert((p1 > p2) == (ptr1 > ptr2)); + assert((p1 >= p2) == (ptr1 >= ptr2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) != std::strong_ordering::equal); + assert((p1 <=> p2) == (ptr1 <=> ptr2)); +#endif + } + // Default-constructed pointers of same type + { + const std::unique_ptr > p1; + const std::unique_ptr > p2; + assert(p1 == p2); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) == std::strong_ordering::equal); +#endif + } + // Default-constructed pointers of different type + { + const std::unique_ptr > p1; + const std::unique_ptr > p2; + assert(p1 == p2); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) == std::strong_ordering::equal); +#endif + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp_nullptr.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp_nullptr.pass.cpp --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp_nullptr.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp_nullptr.pass.cpp @@ -19,54 +19,72 @@ // template // bool operator!=(nullptr_t, const unique_ptr& y) noexcept; // template -// bool operator<(const unique_ptr& x, nullptr_t) noexcept; +// bool operator<(const unique_ptr& x, nullptr_t); // template -// bool operator<(nullptr_t, const unique_ptr& y) noexcept; +// bool operator<(nullptr_t, const unique_ptr& y); // template -// bool operator<=(const unique_ptr& x, nullptr_t) noexcept; +// bool operator<=(const unique_ptr& x, nullptr_t); // template -// bool operator<=(nullptr_t, const unique_ptr& y) noexcept; +// bool operator<=(nullptr_t, const unique_ptr& y); // template -// bool operator>(const unique_ptr& x, nullptr_t) noexcept; +// bool operator>(const unique_ptr& x, nullptr_t); // template -// bool operator>(nullptr_t, const unique_ptr& y) noexcept; +// bool operator>(nullptr_t, const unique_ptr& y); // template -// bool operator>=(const unique_ptr& x, nullptr_t) noexcept; +// bool operator>=(const unique_ptr& x, nullptr_t); // template -// bool operator>=(nullptr_t, const unique_ptr& y) noexcept; +// bool operator>=(nullptr_t, const unique_ptr& y); +// template +// requires three_­way_­comparable::pointer> +// constexpr compare_three_way_result_t::pointer> +// operator<=>(const unique_ptr& x, nullptr_t); // C++20 #include #include #include "test_macros.h" - -void do_nothing(int*) {} +#include "test_comparisons.h" int main(int, char**) { - const std::unique_ptr p1(new int(1)); - assert(!(p1 == nullptr)); - assert(!(nullptr == p1)); - assert(!(p1 < nullptr)); - assert( (nullptr < p1)); - assert(!(p1 <= nullptr)); - assert( (nullptr <= p1)); - assert( (p1 > nullptr)); - assert(!(nullptr > p1)); - assert( (p1 >= nullptr)); - assert(!(nullptr >= p1)); + AssertEqualityAreNoexcept, nullptr_t>(); + AssertEqualityAreNoexcept >(); + AssertComparisonsReturnBool, nullptr_t>(); + AssertComparisonsReturnBool >(); +#if TEST_STD_VER > 17 + AssertOrderReturn>(); +#endif - const std::unique_ptr p2; - assert( (p2 == nullptr)); - assert( (nullptr == p2)); - assert(!(p2 < nullptr)); - assert(!(nullptr < p2)); - assert( (p2 <= nullptr)); - assert( (nullptr <= p2)); - assert(!(p2 > nullptr)); - assert(!(nullptr > p2)); - assert( (p2 >= nullptr)); - assert( (nullptr >= p2)); + const std::unique_ptr p1(new int(1)); + assert(!(p1 == nullptr)); + assert(!(nullptr == p1)); + assert(!(p1 < nullptr)); + assert((nullptr < p1)); + assert(!(p1 <= nullptr)); + assert((nullptr <= p1)); + assert((p1 > nullptr)); + assert(!(nullptr > p1)); + assert((p1 >= nullptr)); + assert(!(nullptr >= p1)); +#if TEST_STD_VER > 17 + assert((nullptr <=> p1) == std::strong_ordering::less); + assert((p1 <=> nullptr) == std::strong_ordering::greater); +#endif + + const std::unique_ptr p2; + assert((p2 == nullptr)); + assert((nullptr == p2)); + assert(!(p2 < nullptr)); + assert(!(nullptr < p2)); + assert((p2 <= nullptr)); + assert((nullptr <= p2)); + assert(!(p2 > nullptr)); + assert(!(nullptr > p2)); + assert((p2 >= nullptr)); + assert((nullptr >= p2)); +#if TEST_STD_VER > 17 + assert((nullptr <=> p2) == std::strong_ordering::equivalent); +#endif return 0; } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/eq.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/eq.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/eq.pass.cpp +++ /dev/null @@ -1,88 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// - -// unique_ptr - -// template -// bool -// operator==(const unique_ptr& x, const unique_ptr& y); - -// template -// bool -// operator!=(const unique_ptr& x, const unique_ptr& y); - -#include -#include - -#include "test_macros.h" -#include "deleter_types.h" - -struct A -{ - static int count; - A() {++count;} - A(const A&) {++count;} - virtual ~A() {--count;} -}; - -int A::count = 0; - -struct B - : public A -{ - static int count; - B() {++count;} - B(const B& other) : A(other) {++count;} - virtual ~B() {--count;} -}; - -int B::count = 0; - -int main(int, char**) -{ - { - const std::unique_ptr > p1(new A); - const std::unique_ptr > p2(new A); - assert(!(p1 == p2)); - assert(p1 != p2); - } - { - const std::unique_ptr > p1(new A); - const std::unique_ptr > p2(new B); - assert(!(p1 == p2)); - assert(p1 != p2); - } - { - const std::unique_ptr > p1(new A[3]); - const std::unique_ptr > p2(new A[3]); - assert(!(p1 == p2)); - assert(p1 != p2); - } - { - const std::unique_ptr > p1(new A[3]); - const std::unique_ptr > p2(new B[3]); - assert(!(p1 == p2)); - assert(p1 != p2); - } - { - const std::unique_ptr > p1; - const std::unique_ptr > p2; - assert(p1 == p2); - assert(!(p1 != p2)); - } - { - const std::unique_ptr > p1; - const std::unique_ptr > p2; - assert(p1 == p2); - assert(!(p1 != p2)); - } - - return 0; -} diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/rel.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/rel.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/rel.pass.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// - -// unique_ptr - -// template -// bool -// operator< (const unique_ptr& x, const unique_ptr& y); - -// template -// bool -// operator> (const unique_ptr& x, const unique_ptr& y); - -// template -// bool -// operator<=(const unique_ptr& x, const unique_ptr& y); - -// template -// bool -// operator>=(const unique_ptr& x, const unique_ptr& y); - -#include -#include - -#include "test_macros.h" -#include "deleter_types.h" - -struct A -{ - static int count; - A() {++count;} - A(const A&) {++count;} - virtual ~A() {--count;} -}; - -int A::count = 0; - -struct B - : public A -{ - static int count; - B() {++count;} - B(const B& other) : A(other) {++count;} - virtual ~B() {--count;} -}; - -int B::count = 0; - -int main(int, char**) -{ - { - const std::unique_ptr > p1(new A); - const std::unique_ptr > p2(new A); - assert((p1 < p2) == !(p1 > p2)); - assert((p1 < p2) == (p1 <= p2)); - assert((p1 < p2) == !(p1 >= p2)); - } - { - const std::unique_ptr > p1(new A); - const std::unique_ptr > p2(new B); - assert((p1 < p2) == !(p1 > p2)); - assert((p1 < p2) == (p1 <= p2)); - assert((p1 < p2) == !(p1 >= p2)); - } - { - const std::unique_ptr > p1(new A[3]); - const std::unique_ptr > p2(new A[3]); - assert((p1 < p2) == !(p1 > p2)); - assert((p1 < p2) == (p1 <= p2)); - assert((p1 < p2) == !(p1 >= p2)); - } - { - const std::unique_ptr > p1(new A[3]); - const std::unique_ptr > p2(new B[3]); - assert((p1 < p2) == !(p1 > p2)); - assert((p1 < p2) == (p1 <= p2)); - assert((p1 < p2) == !(p1 >= p2)); - } - { - const std::unique_ptr > p1; - const std::unique_ptr > p2; - assert((p1 < p2) == (p1 > p2)); - assert((p1 < p2) == !(p1 <= p2)); - assert((p1 < p2) == !(p1 >= p2)); - } - { - const std::unique_ptr > p1; - const std::unique_ptr > p2; - assert((p1 < p2) == (p1 > p2)); - assert((p1 < p2) == !(p1 <= p2)); - assert((p1 < p2) == !(p1 >= p2)); - } - - return 0; -}