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 @@ -78,4 +78,4 @@ | `[fs.path.nonmember] `_,| `filesystem::path `_,None,Adrian Vogelsgesang,|In Progress| | `[fs.dir.entry.obs] `_,| `filesystem::directory_entry `_,None,Adrian Vogelsgesang,|In Progress| | `[re.submatch.op] `_,| sub_match,None,Mark de Wever,|In Progress| -| `[thread.thread.id] `_,| `thread::id `_,None,Adrian Vogelsgesang,|In Progress| +| `[thread.thread.id] `_,| `thread::id `_,None,Adrian Vogelsgesang,|Complete| diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support --- a/libcxx/include/__threading_support +++ b/libcxx/include/__threading_support @@ -13,6 +13,7 @@ #include <__availability> #include <__chrono/convert_to_timespec.h> #include <__chrono/duration.h> +#include <__compare/ordering.h> #include <__config> #include <__thread/poll_with_backoff.h> #include @@ -609,6 +610,14 @@ // on other platforms. We assume 0 works everywhere for now. __libcpp_thread_id __id_; + static _LIBCPP_HIDE_FROM_ABI + bool __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT + { // id==0 is always less than any other thread_id + if (__x.__id_ == 0) return __y.__id_ != 0; + if (__y.__id_ == 0) return false; + return __libcpp_thread_id_less(__x.__id_, __y.__id_); + } + public: _LIBCPP_INLINE_VISIBILITY __thread_id() _NOEXCEPT : __id_(0) {} @@ -617,7 +626,11 @@ void __reset() { __id_ = 0; } friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT; - friend _LIBCPP_HIDE_FROM_ABI bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT; +#if _LIBCPP_STD_VER <= 17 + friend _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT; +#else // _LIBCPP_STD_VER <= 17 + friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept; +#endif // _LIBCPP_STD_VER <= 17 template friend @@ -644,25 +657,35 @@ return __libcpp_thread_id_equal(__x.__id_, __y.__id_); } +#if _LIBCPP_STD_VER <= 17 + inline _LIBCPP_HIDE_FROM_ABI bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT { - return !(__x == __y); + return !(__x == __y); } inline _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT { - // id==0 is always less than any other thread_id - if (__x.__id_ == 0) - return __y.__id_ != 0; - if (__y.__id_ == 0) - return false; - return __libcpp_thread_id_less(__x.__id_, __y.__id_); + return __thread_id::__lt_impl(__x.__id_, __y.__id_); } inline _LIBCPP_HIDE_FROM_ABI bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT { return !(__y < __x); } inline _LIBCPP_HIDE_FROM_ABI bool operator>(__thread_id __x, __thread_id __y) _NOEXCEPT { return __y < __x; } inline _LIBCPP_HIDE_FROM_ABI bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT { return !(__x < __y); } +#else // _LIBCPP_STD_VER <= 17 + +inline _LIBCPP_HIDE_FROM_ABI +strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept { + if (__x == __y) + return strong_ordering::equal; + if (__thread_id::__lt_impl(__x, __y)) + return strong_ordering::less; + return strong_ordering::greater; +} + +#endif // _LIBCPP_STD_VER <= 17 + namespace this_thread { diff --git a/libcxx/include/thread b/libcxx/include/thread --- a/libcxx/include/thread +++ b/libcxx/include/thread @@ -53,11 +53,12 @@ }; bool operator==(thread::id x, thread::id y) noexcept; -bool operator!=(thread::id x, thread::id y) noexcept; -bool operator< (thread::id x, thread::id y) noexcept; -bool operator<=(thread::id x, thread::id y) noexcept; -bool operator> (thread::id x, thread::id y) noexcept; -bool operator>=(thread::id x, thread::id y) noexcept; +bool operator!=(thread::id x, thread::id y) noexcept; // removed in C++20 +bool operator< (thread::id x, thread::id y) noexcept; // removed in C++20 +bool operator<=(thread::id x, thread::id y) noexcept; // removed in C++20 +bool operator> (thread::id x, thread::id y) noexcept; // removed in C++20 +bool operator>=(thread::id x, thread::id y) noexcept; // removed in C++20 +strong_ordering operator<=>(thread::id x, thread::id y) noexcept; // C++20 template basic_ostream& diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: no-threads + +// + +// class thread::id + +// bool operator==(thread::id x, thread::id y) noexcept; +// bool operator!=(thread::id x, thread::id y) noexcept; +// bool operator< (thread::id x, thread::id y) noexcept; +// bool operator<=(thread::id x, thread::id y) noexcept; +// bool operator> (thread::id x, thread::id y) noexcept; +// bool operator>=(thread::id x, thread::id y) noexcept; +// strong_ordering operator<=>(thread::id x, thread::id y) noexcept; + +#include +#include + +#include "test_macros.h" +#include "test_comparisons.h" + +int main(int, char**) { + AssertComparisonsAreNoexcept(); + AssertComparisonsReturnBool(); +#if TEST_STD_VER > 17 + AssertOrderAreNoexcept(); + AssertOrderReturn(); +#endif + + std::thread::id id1; + std::thread::id id2; + std::thread::id id3 = std::this_thread::get_id(); + + // `id1` and `id2` should compare equal + assert(testComparisons(id1, id2, /*isEqual*/ true, /*isLess*/ false)); +#if TEST_STD_VER > 17 + assert(testOrder(id1, id2, std::strong_ordering::equal)); +#endif + + // Test `t1` and `t3` which are not equal + bool isLess = id1 < id3; + assert(testComparisons(id1, id3, /*isEqual*/ false, isLess)); +#if TEST_STD_VER > 17 + assert(testOrder(id1, id3, isLess ? std::strong_ordering::less : std::strong_ordering::greater)); +#endif + + // Regression tests for https://github.com/llvm/llvm-project/issues/56187 + // libc++ previously declared the comparison operators as hidden friends + // which was non-conforming. + assert(std::operator==(id1, id2)); +#if TEST_STD_VER <= 17 + assert(!std::operator!=(id1, id2)); + assert(!std::operator<(id1, id2)); + assert(std::operator<=(id1, id2)); + assert(!std::operator>(id1, id2)); + assert(std::operator>=(id1, id2)); +#else + assert(std::operator<=>(id1, id2) == std::strong_ordering::equal); +#endif + + return 0; +} diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp +++ /dev/null @@ -1,41 +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 -// -//===----------------------------------------------------------------------===// -// -// UNSUPPORTED: no-threads - -// - -// class thread::id - -// bool operator==(thread::id x, thread::id y); -// bool operator!=(thread::id x, thread::id y); - -#include -#include - -#include "test_macros.h" - -int main(int, char**) -{ - std::thread::id id0; - std::thread::id id1; - id1 = id0; - assert( (id1 == id0)); - assert(!(id1 != id0)); - id1 = std::this_thread::get_id(); - assert(!(id1 == id0)); - assert( (id1 != id0)); - - // Regression tests for https://github.com/llvm/llvm-project/issues/56187 - // libc++ previously declared the comparison operators as hidden friends - // which was non-conforming. - assert(!std::operator==(id1, id0)); - assert(std::operator!=(id1, id0)); - - return 0; -} diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp +++ /dev/null @@ -1,54 +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 -// -//===----------------------------------------------------------------------===// -// -// UNSUPPORTED: no-threads - -// - -// class thread::id - -// bool operator< (thread::id x, thread::id y); -// bool operator<=(thread::id x, thread::id y); -// bool operator> (thread::id x, thread::id y); -// bool operator>=(thread::id x, thread::id y); - -#include -#include - -#include "test_macros.h" - -int main(int, char**) -{ - std::thread::id id0; - std::thread::id id1; - std::thread::id id2 = std::this_thread::get_id(); - assert(!(id0 < id1)); - assert( (id0 <= id1)); - assert(!(id0 > id1)); - assert( (id0 >= id1)); - assert(!(id0 == id2)); - if (id0 < id2) { - assert( (id0 <= id2)); - assert(!(id0 > id2)); - assert(!(id0 >= id2)); - } else { - assert(!(id0 <= id2)); - assert( (id0 > id2)); - assert( (id0 >= id2)); - } - - // Regression tests for https://github.com/llvm/llvm-project/issues/56187 - // libc++ previously declared the comparison operators as hidden friends - // which was non-conforming. - assert(!std::operator<(id0, id1)); - assert(std::operator<=(id0, id1)); - assert(!std::operator>(id0, id1)); - assert(std::operator>=(id0, id1)); - - return 0; -}