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 @@ -28,7 +28,7 @@ "`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|" -"`3427 `__","``operator<=>(const shared_ptr&, nullptr_t)`` definition ill-formed","November 2020","","","|spaceship|" +"`3427 `__","``operator<=>(const shared_ptr&, nullptr_t)`` definition ill-formed","November 2020","|Complete|","16.0","|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|","" "`3437 `__","``__cpp_lib_polymorphic_allocator`` is in the wrong header","November 2020","|Complete|","14.0" 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 @@ -26,7 +26,7 @@ | `[variant.monostate.relops] `_","| monostate | variant",None,Kent Ross,|In Progress| | `[unique.ptr.special] `_,| `unique_ptr `_,[comparisons.three.way],Adrian Vogelsgesang,|In Progress| -| `[util.smartptr.shared.cmp] `_,| `shared_ptr `_,[comparisons.three.way],Adrian Vogelsgesang,|In Progress| +| `[util.smartptr.shared.cmp] `_,| `shared_ptr `_,[comparisons.three.way],Adrian Vogelsgesang,|Complete| | `[type.index.members] `_,| type_index,None,Unassigned,|Not Started| | `[charconv.syn] `_,| to_chars_result,None,Mark de Wever,|Complete| | `[charconv.syn] `_,| from_chars_result,None,Mark de Wever,|Complete| diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -11,6 +11,8 @@ #define _LIBCPP___MEMORY_SHARED_PTR_H #include <__availability> +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> #include <__config> #include <__functional/binary_function.h> #include <__functional/operations.h> @@ -1184,6 +1186,8 @@ return __x.get() == __y.get(); } +#if _LIBCPP_STD_VER <= 17 + template inline _LIBCPP_INLINE_VISIBILITY bool @@ -1230,6 +1234,17 @@ return !(__x < __y); } +#endif // _LIBCPP_STD_VER <= 17 + +#if _LIBCPP_STD_VER > 17 +template +_LIBCPP_HIDE_FROM_ABI strong_ordering +operator<=>(shared_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) noexcept +{ + return compare_three_way()(__x.get(), __y.get()); +} +#endif + template inline _LIBCPP_INLINE_VISIBILITY bool @@ -1238,6 +1253,8 @@ return !__x; } +#if _LIBCPP_STD_VER <= 17 + template inline _LIBCPP_INLINE_VISIBILITY bool @@ -1326,6 +1343,17 @@ return !(nullptr < __x); } +#endif // _LIBCPP_STD_VER <= 17 + +#if _LIBCPP_STD_VER > 17 +template +_LIBCPP_HIDE_FROM_ABI strong_ordering +operator<=>(shared_ptr<_Tp> const& __x, nullptr_t) noexcept +{ + return compare_three_way()(__x.get(), static_cast::element_type*>(nullptr)); +} +#endif + template inline _LIBCPP_INLINE_VISIBILITY void diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -617,40 +617,44 @@ template bool operator==(shared_ptr const& a, shared_ptr const& b) noexcept; template - bool operator!=(shared_ptr const& a, shared_ptr const& b) noexcept; + bool operator!=(shared_ptr const& a, shared_ptr const& b) noexcept; // removed in C++20 template - bool operator<(shared_ptr const& a, shared_ptr const& b) noexcept; + bool operator<(shared_ptr const& a, shared_ptr const& b) noexcept; // removed in C++20 template - bool operator>(shared_ptr const& a, shared_ptr const& b) noexcept; + bool operator>(shared_ptr const& a, shared_ptr const& b) noexcept; // removed in C++20 template - bool operator<=(shared_ptr const& a, shared_ptr const& b) noexcept; + bool operator<=(shared_ptr const& a, shared_ptr const& b) noexcept; // removed in C++20 template - bool operator>=(shared_ptr const& a, shared_ptr const& b) noexcept; + bool operator>=(shared_ptr const& a, shared_ptr const& b) noexcept; // removed in C++20 +template + strong_ordering operator<=>(shared_ptr const& a, shared_ptr const& b) noexcept; // C++20 template bool operator==(const shared_ptr& x, nullptr_t) noexcept; template - bool operator==(nullptr_t, const shared_ptr& y) noexcept; + bool operator==(nullptr_t, const shared_ptr& y) noexcept; // removed in C++20 template - bool operator!=(const shared_ptr& x, nullptr_t) noexcept; + bool operator!=(const shared_ptr& x, nullptr_t) noexcept; // removed in C++20 template - bool operator!=(nullptr_t, const shared_ptr& y) noexcept; + bool operator!=(nullptr_t, const shared_ptr& y) noexcept; // removed in C++20 template - bool operator<(const shared_ptr& x, nullptr_t) noexcept; + bool operator<(const shared_ptr& x, nullptr_t) noexcept; // removed in C++20 template -bool operator<(nullptr_t, const shared_ptr& y) noexcept; + bool operator<(nullptr_t, const shared_ptr& y) noexcept; // removed in C++20 template - bool operator<=(const shared_ptr& x, nullptr_t) noexcept; + bool operator<=(const shared_ptr& x, nullptr_t) noexcept; // removed in C++20 template - bool operator<=(nullptr_t, const shared_ptr& y) noexcept; + bool operator<=(nullptr_t, const shared_ptr& y) noexcept; // removed in C++20 template - bool operator>(const shared_ptr& x, nullptr_t) noexcept; + bool operator>(const shared_ptr& x, nullptr_t) noexcept; // removed in C++20 template - bool operator>(nullptr_t, const shared_ptr& y) noexcept; + bool operator>(nullptr_t, const shared_ptr& y) noexcept; // removed in C++20 template - bool operator>=(const shared_ptr& x, nullptr_t) noexcept; + bool operator>=(const shared_ptr& x, nullptr_t) noexcept; // removed in C++20 template - bool operator>=(nullptr_t, const shared_ptr& y) noexcept; + bool operator>=(nullptr_t, const shared_ptr& y) noexcept; // removed in C++20 +template + strong_ordering operator<=>(shared_ptr const& x, nullptr_t) noexcept; // C++20 // shared_ptr specialized algorithms: template void swap(shared_ptr& a, shared_ptr& b) noexcept; diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp.pass.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// shared_ptr + +// template bool operator==(const shared_ptr& a, const shared_ptr& b); +// template bool operator!=(const shared_ptr& a, const shared_ptr& b); +// template bool operator< (const shared_ptr& a, const shared_ptr& b); +// template bool operator<=(const shared_ptr& a, const shared_ptr& b); +// template bool operator> (const shared_ptr& a, const shared_ptr& b); +// template bool operator>=(const shared_ptr& a, const shared_ptr& b); +// 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 "test_comparisons.h" + +void do_nothing(int*) {} + +int main(int, char**) { + AssertComparisonsAreNoexcept >(); + AssertComparisonsReturnBool >(); +#if TEST_STD_VER > 17 + AssertOrderAreNoexcept>(); + AssertOrderReturn>(); +#endif + + int* ptr1(new int); + int* ptr2(new int); + const std::shared_ptr p1(ptr1); + const std::shared_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 + + // The deleter does not influence the comparisons + // of the `shared_ptr` + const std::shared_ptr p3(ptr2, do_nothing); + assert(p2 == p3); + assert(!(p1 == p3)); + assert(!(p2 != p3)); + assert(p1 != p3); + assert((p1 < p3) == (ptr1 < ptr2)); + assert((p1 <= p3) == (ptr1 <= ptr2)); + assert((p1 > p3) == (ptr1 > ptr2)); + assert((p1 >= p3) == (ptr1 >= ptr2)); +#if TEST_STD_VER > 17 + assert((p2 <=> p3) == std::strong_ordering::equal); + assert((p1 <=> p3) != std::strong_ordering::equal); + assert((p1 <=> p3) == (ptr1 <=> ptr2)); +#endif + + return 0; +} diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp @@ -34,39 +34,58 @@ // bool operator>=(const shared_ptr& x, nullptr_t) noexcept; // template // bool operator>=(nullptr_t, const shared_ptr& y) noexcept; +// template +// strong_ordering operator<=>(shared_ptr const& x, nullptr_t) noexcept; // C++20 #include #include #include "test_macros.h" +#include "test_comparisons.h" void do_nothing(int*) {} int main(int, char**) { - const std::shared_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)); + AssertComparisonsAreNoexcept, nullptr_t>(); + AssertComparisonsAreNoexcept >(); + AssertComparisonsReturnBool, nullptr_t>(); + AssertComparisonsReturnBool >(); +#if TEST_STD_VER > 17 + AssertOrderAreNoexcept>(); + AssertOrderReturn>(); +#endif - const std::shared_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::shared_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::shared_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/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/eq.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/eq.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/eq.pass.cpp +++ /dev/null @@ -1,34 +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 -// -//===----------------------------------------------------------------------===// - -// - -// shared_ptr - -// template bool operator==(const shared_ptr& a, const shared_ptr& b); -// template bool operator!=(const shared_ptr& a, const shared_ptr& b); - -#include -#include - -#include "test_macros.h" - -void do_nothing(int*) {} - -int main(int, char**) -{ - int* ptr1(new int); - int* ptr2(new int); - const std::shared_ptr p1(ptr1); - const std::shared_ptr p2(ptr2); - const std::shared_ptr p3(ptr2, do_nothing); - assert(p1 != p2); - assert(p2 == p3); - - return 0; -} diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/lt.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/lt.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/lt.pass.cpp +++ /dev/null @@ -1,33 +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 -// -//===----------------------------------------------------------------------===// - -// - -// shared_ptr - -// template bool operator<(const shared_ptr& a, const shared_ptr& b); - -#include -#include - -#include "test_macros.h" - -void do_nothing(int*) {} - -int main(int, char**) -{ - int* ptr1(new int); - int* ptr2(new int); - const std::shared_ptr p1(ptr1); - const std::shared_ptr p2(ptr2); - const std::shared_ptr p3(ptr2, do_nothing); - assert((p1 < p2) == (ptr1 < ptr2)); - assert(!(p2 < p3) && !(p3 < p2)); - - return 0; -}