Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
61e16a8
[libc++] P2944R3: Constrained comparisions - the `optional` and `refe…
H-G-Hristov Apr 30, 2025
37b9041
NFC refactoring of `std::expected` tests
H-G-Hristov May 9, 2025
47b9765
Tests + fixes
H-G-Hristov May 10, 2025
58149a6
Cleanup
H-G-Hristov May 10, 2025
4e3c8c6
Refactorings
H-G-Hristov May 10, 2025
e94dd67
Fixed formatting
H-G-Hristov May 10, 2025
ab801b4
Include generator script results
H-G-Hristov May 10, 2025
77fb360
Try to fix CI
H-G-Hristov May 10, 2025
f0bfc2b
Update libcxx/test/std/utilities/utility/pairs/pairs.spec/comparison.…
H-G-Hristov May 10, 2025
35c0631
Try to fix CI
H-G-Hristov May 10, 2025
4f009b5
Fix `<optional>`
H-G-Hristov May 10, 2025
f81457f
Try to fix CI
H-G-Hristov May 10, 2025
7181c8c
More fixes
H-G-Hristov May 10, 2025
3a63752
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jun 4, 2025
b181c67
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jun 15, 2025
c41d7c9
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jun 15, 2025
046b20b
Cleanup
H-G-Hristov Jun 15, 2025
3f92762
Cleanup
H-G-Hristov Jun 15, 2025
0fa7e0b
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jun 25, 2025
3f119ca
Addressed review comments
H-G-Hristov Jun 25, 2025
b1bed3d
Fix CI
H-G-Hristov Jun 25, 2025
a1dd21d
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jun 25, 2025
1f314a7
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jun 25, 2025
1042f68
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jun 25, 2025
db31473
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jun 29, 2025
1cd741d
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jul 6, 2025
ec658e9
Review comments
H-G-Hristov Jul 6, 2025
1123f57
Implemented `__is_core_convertible_v`
H-G-Hristov Jul 10, 2025
6089762
Try to fix CI
H-G-Hristov Jul 10, 2025
98e1413
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
H-G-Hristov Jul 10, 2025
cbe7f92
Apply suggestions from code review
Zingam Jul 10, 2025
eedb32f
Update libcxx/include/__type_traits/is_core_convertible.h
Zingam Jul 10, 2025
4d9faa5
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
Zingam Jul 10, 2025
61b03bd
Merge branch 'main' into hgh/libcxx/P2944R3-optional-constrained-equa…
Zingam Jul 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"`P2248R8 <https://wg21.link/P2248R8>`__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","",""
"`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","",""
"`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","",""
"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional`` and ``tuple``'s equality overload from P2165R4 are not yet implemented"
"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``tuple``'s equality overload from P2165R4 are not yet implemented."
"`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","",""
"`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19",""
"","","","","",""
Expand Down
7 changes: 7 additions & 0 deletions libcxx/include/__type_traits/is_core_convertible.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ template <class _Tp, class _Up>
struct __is_core_convertible<_Tp, _Up, decltype(static_cast<void (*)(_Up)>(0)(static_cast<_Tp (*)()>(0)()))>
: true_type {};

#if _LIBCPP_STD_VER >= 17

template <class _Tp>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use __is_core_convertible directly? The additional instantiations might not be needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to introduce __is_core_convertible_v first and implement __is_core_convertible with it, then use __is_core_convertible_v<decltype(...), bool> in the constraints.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@frederick-vs-ja I implemented __is_core_convertible_v for C++17 onward similar to other traits. I don't understand why you suggest to do it in reverse? Everything seems fine as it is right now. Also we have the concept __core_convertible_to, do we want to keep it or replace it with __is_core_convertible_v for insignificant code reduction (of redundancy)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable templates are better on compiler throughput than class template, and we're even relying on using variable template in C++03 mode as an extension. So I guess it would be better to have __is_core_convertible_v in old modes (and perform SFINAE in it) and use __is_core_convertible only with _And and its friends.

inline constexpr bool __is_convertible_to_bool_v = __is_core_convertible<_Tp, bool>::value;

#endif

#if _LIBCPP_STD_VER >= 20

template <class _Tp, class _Up>
Expand Down
118 changes: 61 additions & 57 deletions libcxx/include/optional
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ namespace std {
# include <__type_traits/is_assignable.h>
# include <__type_traits/is_constructible.h>
# include <__type_traits/is_convertible.h>
# include <__type_traits/is_core_convertible.h>
# include <__type_traits/is_destructible.h>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
Expand Down Expand Up @@ -982,11 +983,12 @@ public:
template <class _Tp>
optional(_Tp) -> optional<_Tp>;

// Comparisons between optionals
template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>, int> = 0>
// [optional.relops] Relational operators

template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y) {
if (static_cast<bool>(__x) != static_cast<bool>(__y))
return false;
Expand All @@ -995,10 +997,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const
return *__x == *__y;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y) {
if (static_cast<bool>(__x) != static_cast<bool>(__y))
return true;
Expand All @@ -1010,7 +1012,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const
template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>, int> = 0>
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>())>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y) {
if (!static_cast<bool>(__y))
return false;
Expand All @@ -1022,7 +1024,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const o
template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>, int> = 0>
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>())>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y) {
if (!static_cast<bool>(__x))
return false;
Expand All @@ -1031,10 +1033,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const o
return *__x > *__y;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y) {
if (!static_cast<bool>(__x))
return true;
Expand All @@ -1043,10 +1045,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const
return *__x <= *__y;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y) {
if (!static_cast<bool>(__y))
return true;
Expand All @@ -1067,7 +1069,8 @@ operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) {

# endif // _LIBCPP_STD_VER >= 20

// Comparisons with nullopt
// [optional.nullops] Comparison with nullopt

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, nullopt_t) noexcept {
return !static_cast<bool>(__x);
Expand Down Expand Up @@ -1139,99 +1142,100 @@ _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>&

# endif // _LIBCPP_STD_VER <= 17

// Comparisons with T
template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>, int> = 0>
// [optional.comp.with.t] Comparison with T

template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) {
return static_cast<bool>(__x) ? *__x == __v : false;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) {
return static_cast<bool>(__x) ? __v == *__x : false;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) {
return static_cast<bool>(__x) ? *__x != __v : true;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) {
return static_cast<bool>(__x) ? __v != *__x : true;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>, int> = 0>
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>())>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) {
return static_cast<bool>(__x) ? *__x < __v : true;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>, int> = 0>
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>())>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) {
return static_cast<bool>(__x) ? __v < *__x : false;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) {
return static_cast<bool>(__x) ? *__x <= __v : true;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) {
return static_cast<bool>(__x) ? __v <= *__x : false;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>, int> = 0>
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>())>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) {
return static_cast<bool>(__x) ? *__x > __v : false;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>, int> = 0>
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>())>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) {
return static_cast<bool>(__x) ? __v > *__x : true;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) {
return static_cast<bool>(__x) ? *__x >= __v : false;
}

template <
class _Tp,
class _Up,
enable_if_t<is_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>, int> = 0>
template < class _Tp,
class _Up,
enable_if_t<__is_convertible_to_bool_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>())>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) {
return static_cast<bool>(__x) ? __v >= *__x : true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,29 @@

#include <optional>

#include "test_comparisons.h"
#include "test_macros.h"

#if TEST_STD_VER >= 26

// Test SFINAE.

static_assert(HasOperatorEqual<int, std::optional<int>>);
static_assert(HasOperatorEqual<int, std::optional<EqualityComparable>>);
static_assert(HasOperatorEqual<EqualityComparable, std::optional<EqualityComparable>>);

static_assert(!HasOperatorEqual<NonComparable, std::optional<NonComparable>>);
static_assert(!HasOperatorEqual<NonComparable, std::optional<EqualityComparable>>);

static_assert(HasOperatorEqual<std::optional<int>, int>);
static_assert(HasOperatorEqual<std::optional<EqualityComparable>, int>);
static_assert(HasOperatorEqual<std::optional<EqualityComparable>, EqualityComparable>);

static_assert(!HasOperatorEqual<std::optional<NonComparable>, NonComparable>);
static_assert(!HasOperatorEqual<std::optional<EqualityComparable>, NonComparable>);

#endif

using std::optional;

struct X {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,28 @@

#include <optional>

#include "test_comparisons.h"
#include "test_macros.h"

#if TEST_STD_VER >= 26

// Test SFINAE.
static_assert(HasOperatorGreaterThan<std::optional<ThreeWayComparable>, int>);
static_assert(HasOperatorGreaterThan<std::optional<ThreeWayComparable>, ThreeWayComparable>);

static_assert(!HasOperatorGreaterThan<std::optional<NonComparable>, NonComparable>);
static_assert(!HasOperatorGreaterThan<std::optional<ThreeWayComparable>, NonComparable>);
static_assert(!HasOperatorGreaterThan<std::optional<NonComparable>, ThreeWayComparable>);

static_assert(HasOperatorGreaterThan<int, std::optional<ThreeWayComparable>>);
static_assert(HasOperatorGreaterThan<ThreeWayComparable, std::optional<ThreeWayComparable>>);

static_assert(!HasOperatorGreaterThan<NonComparable, std::optional<NonComparable>>);
static_assert(!HasOperatorGreaterThan<NonComparable, std::optional<ThreeWayComparable>>);
static_assert(!HasOperatorGreaterThan<ThreeWayComparable, std::optional<NonComparable>>);

#endif

using std::optional;

struct X {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,28 @@

#include <optional>

#include "test_comparisons.h"
#include "test_macros.h"

#if TEST_STD_VER >= 26

// Test SFINAE.
static_assert(HasOperatorGreaterThanEqual<std::optional<ThreeWayComparable>, int>);
static_assert(HasOperatorGreaterThanEqual<std::optional<ThreeWayComparable>, ThreeWayComparable>);

static_assert(!HasOperatorGreaterThanEqual<std::optional<NonComparable>, NonComparable>);
static_assert(!HasOperatorGreaterThanEqual<std::optional<ThreeWayComparable>, NonComparable>);
static_assert(!HasOperatorGreaterThanEqual<std::optional<NonComparable>, ThreeWayComparable>);

static_assert(HasOperatorGreaterThanEqual<int, std::optional<ThreeWayComparable>>);
static_assert(HasOperatorGreaterThanEqual<ThreeWayComparable, std::optional<ThreeWayComparable>>);

static_assert(!HasOperatorGreaterThanEqual<NonComparable, std::optional<NonComparable>>);
static_assert(!HasOperatorGreaterThanEqual<NonComparable, std::optional<ThreeWayComparable>>);
static_assert(!HasOperatorGreaterThanEqual<ThreeWayComparable, std::optional<NonComparable>>);

#endif

using std::optional;

struct X {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,28 @@

#include <optional>

#include "test_comparisons.h"
#include "test_macros.h"

#if TEST_STD_VER >= 26

// Test SFINAE.
static_assert(HasOperatorLessThanEqual<std::optional<ThreeWayComparable>, int>);
static_assert(HasOperatorLessThanEqual<std::optional<ThreeWayComparable>, ThreeWayComparable>);

static_assert(!HasOperatorLessThanEqual<std::optional<NonComparable>, NonComparable>);
static_assert(!HasOperatorLessThanEqual<std::optional<ThreeWayComparable>, NonComparable>);
static_assert(!HasOperatorLessThanEqual<std::optional<NonComparable>, ThreeWayComparable>);

static_assert(HasOperatorLessThanEqual<int, std::optional<ThreeWayComparable>>);
static_assert(HasOperatorLessThanEqual<ThreeWayComparable, std::optional<ThreeWayComparable>>);

static_assert(!HasOperatorLessThanEqual<NonComparable, std::optional<NonComparable>>);
static_assert(!HasOperatorLessThanEqual<NonComparable, std::optional<ThreeWayComparable>>);
static_assert(!HasOperatorLessThanEqual<ThreeWayComparable, std::optional<NonComparable>>);

#endif

using std::optional;

struct X {
Expand Down
Loading
Loading