Skip to content
Merged
Show file tree
Hide file tree
Changes from 31 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
13 changes: 8 additions & 5 deletions libcxx/include/__type_traits/is_core_convertible.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,23 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// and __is_core_convertible<immovable-type,immovable-type> is true in C++17 and later.

template <class _Tp, class _Up, class = void>
struct __is_core_convertible : false_type {};
inline const bool __is_core_convertible_v = false;

template <class _Tp, class _Up>
struct __is_core_convertible<_Tp, _Up, decltype(static_cast<void (*)(_Up)>(0)(static_cast<_Tp (*)()>(0)()))>
: true_type {};
inline const bool
__is_core_convertible_v<_Tp, _Up, decltype(static_cast<void (*)(_Up)>(0)(static_cast<_Tp (*)()>(0)()))> = true;

template <class _Tp, class _Up>
using __is_core_convertible _LIBCPP_NODEBUG = integral_constant<bool, __is_core_convertible_v<_Tp, _Up> >;
Comment on lines +33 to +34
Copy link
Contributor

Choose a reason for hiding this comment

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

It's a bit unusual to just use an alias template instead of inheritance from the bool_constant. But this should be fine since no compilation failures happens, and is possibly better due to reduction of instantiation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, the difference between inheritance and aliasing seems to be laziness of instantiation. If it's confirmed that shortcut instantiation is not so that desired, we can even remove __is_core_convertible and consistently use __is_core_convertible_v. (The changes should belong to another PR, though.)


#if _LIBCPP_STD_VER >= 20

template <class _Tp, class _Up>
concept __core_convertible_to = __is_core_convertible<_Tp, _Up>::value;
concept __core_convertible_to = __is_core_convertible_v<_Tp, _Up>;

#endif // _LIBCPP_STD_VER >= 20

template <class _Tp, class _Up, bool = __is_core_convertible<_Tp, _Up>::value>
template <class _Tp, class _Up, bool = __is_core_convertible_v<_Tp, _Up>>
inline const bool __is_nothrow_core_convertible_v = false;

#ifndef _LIBCPP_CXX03_LANG
Expand Down
94 changes: 55 additions & 39 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,13 @@ public:
template <class _Tp>
optional(_Tp) -> optional<_Tp>;

// Comparisons between optionals
// [optional.relops] Relational operators

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_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
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 @@ -998,7 +1001,8 @@ _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_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
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 @@ -1007,10 +1011,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_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
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 @@ -1019,10 +1023,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_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
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 @@ -1034,7 +1038,8 @@ _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_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
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 @@ -1046,7 +1051,8 @@ _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_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
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 +1073,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 +1146,108 @@ _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>&

# endif // _LIBCPP_STD_VER <= 17

// Comparisons with T
// [optional.comp.with.t] Comparison 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>
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
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_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
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