[libc++] Implement `thread::id` comparators as free functions

So far, the `thread::id` comparators were implemented as hidden friends.
This was non-conforming and lead to incorrectly rejected C++ code, as
can be seen in the linked Github issue.

Fixes https://github.com/llvm/llvm-project/issues/56187

Differential Revision: https://reviews.llvm.org/D131430
This commit is contained in:
Adrian Vogelsgesang 2022-07-31 16:12:42 -07:00 committed by Adrian Vogelsgesang
parent 8ea1cf3111
commit 2d34cb74b5
4 changed files with 54 additions and 29 deletions

View File

@ -48,6 +48,12 @@ Deprecations and Removals
Upcoming Deprecations and Removals
----------------------------------
API Changes
-----------
- The comparison operators on ``thread::id`` are now defined as free-standing
functions instead of as hidden friends, in conformance with the C++ standard.
Also see `issue 56187 <https://github.com/llvm/llvm-project/issues/56187>`_.
ABI Affecting Changes
---------------------

View File

@ -613,36 +613,12 @@ public:
_LIBCPP_INLINE_VISIBILITY
__thread_id() _NOEXCEPT : __id_(0) {}
friend _LIBCPP_INLINE_VISIBILITY
bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT
{ // don't pass id==0 to underlying routines
if (__x.__id_ == 0) return __y.__id_ == 0;
if (__y.__id_ == 0) return false;
return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
}
friend _LIBCPP_INLINE_VISIBILITY
bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT
{return !(__x == __y);}
friend _LIBCPP_INLINE_VISIBILITY
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_);
}
friend _LIBCPP_INLINE_VISIBILITY
bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT
{return !(__y < __x);}
friend _LIBCPP_INLINE_VISIBILITY
bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT
{return __y < __x ;}
friend _LIBCPP_INLINE_VISIBILITY
bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT
{return !(__x < __y);}
_LIBCPP_INLINE_VISIBILITY
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;
template<class _CharT, class _Traits>
friend
_LIBCPP_INLINE_VISIBILITY
@ -658,6 +634,35 @@ private:
friend struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>;
};
inline _LIBCPP_HIDE_FROM_ABI
bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
// Don't pass id==0 to underlying routines
if (__x.__id_ == 0)
return __y.__id_ == 0;
if (__y.__id_ == 0)
return false;
return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
}
inline _LIBCPP_HIDE_FROM_ABI
bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT {
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_);
}
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); }
namespace this_thread
{

View File

@ -31,5 +31,11 @@ int main(int, char**)
assert(!(id1 == id0));
assert( (id1 != id0));
return 0;
// 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;
}

View File

@ -42,5 +42,13 @@ int main(int, char**)
assert( (id0 >= id2));
}
return 0;
// 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;
}