[libcxx-commits] [libcxx] [libc++] P2944R3: Constrained comparisions - `optional` (PR #144249)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jun 15 15:54:45 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Hristo Hristov (H-G-Hristov)
<details>
<summary>Changes</summary>
Partially implements [P2944R3](https://wg21.link/P2944R3) which adds constrained comparisons to std::optional.
Closes #<!-- -->136767
# References
[optional.relops](https://wg21.link/optional.relops)
[optional.comp.with.t](https://wg21.link/optional.comp.with.t)
---
Patch is 31.41 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144249.diff
15 Files Affected:
- (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1)
- (modified) libcxx/include/optional (+205-21)
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/equal.pass.cpp (+21)
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/greater.pass.cpp (+20)
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/greater_equal.pass.cpp (+20)
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/less_equal.pass.cpp (+20)
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/less_than.pass.cpp (+20)
- (modified) libcxx/test/std/utilities/optional/optional.comp_with_t/not_equal.pass.cpp (+21)
- (modified) libcxx/test/std/utilities/optional/optional.relops/equal.pass.cpp (+14)
- (modified) libcxx/test/std/utilities/optional/optional.relops/greater_equal.pass.cpp (+13)
- (modified) libcxx/test/std/utilities/optional/optional.relops/greater_than.pass.cpp (+13)
- (modified) libcxx/test/std/utilities/optional/optional.relops/less_equal.pass.cpp (+13)
- (modified) libcxx/test/std/utilities/optional/optional.relops/less_than.pass.cpp (+13)
- (modified) libcxx/test/std/utilities/optional/optional.relops/not_equal.pass.cpp (+14)
- (modified) libcxx/test/support/test_comparisons.h (+41)
``````````diff
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 8a0417e120d75..77d09bebe3462 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -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``, ``tuple`` and ``variant`` are not yet implemented"
+"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``tuple`` and ``variant`` 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",""
"","","","","",""
diff --git a/libcxx/include/optional b/libcxx/include/optional
index fa32d75ef86dd..68053bdfb5df3 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -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>
@@ -982,12 +983,23 @@ public:
template <class _Tp>
optional(_Tp) -> optional<_Tp>;
-// Comparisons between optionals
+// [optional.relops] Relational operators
+
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y)
+# if _LIBCPP_STD_VER >= 26
+ requires requires {
+ { *__x == *__y } -> __core_convertible_to<bool>;
+ }
+# endif
+{
if (static_cast<bool>(__x) != static_cast<bool>(__y))
return false;
if (!static_cast<bool>(__x))
@@ -995,11 +1007,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const
return *__x == *__y;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y)
+# if _LIBCPP_STD_VER >= 26
+ requires requires {
+ { *__x != *__y } -> __core_convertible_to<bool>;
+ }
+# endif
+{
if (static_cast<bool>(__x) != static_cast<bool>(__y))
return true;
if (!static_cast<bool>(__x))
@@ -1007,11 +1029,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const
return *__x != *__y;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y)
+# if _LIBCPP_STD_VER >= 26
+ requires requires {
+ { *__x < *__y } -> __core_convertible_to<bool>;
+ }
+# endif
+{
if (!static_cast<bool>(__y))
return false;
if (!static_cast<bool>(__x))
@@ -1019,11 +1051,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const o
return *__x < *__y;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y)
+# if _LIBCPP_STD_VER >= 26
+ requires requires {
+ { *__x > *__y } -> __core_convertible_to<bool>;
+ }
+# endif
+{
if (!static_cast<bool>(__x))
return false;
if (!static_cast<bool>(__y))
@@ -1031,11 +1073,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const o
return *__x > *__y;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y)
+# if _LIBCPP_STD_VER >= 26
+ requires requires {
+ { *__x <= *__y } -> __core_convertible_to<bool>;
+ }
+# endif
+{
if (!static_cast<bool>(__x))
return true;
if (!static_cast<bool>(__y))
@@ -1043,11 +1095,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const
return *__x <= *__y;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y)
+# if _LIBCPP_STD_VER >= 26
+ requires requires {
+ { *__x >= *__y } -> __core_convertible_to<bool>;
+ }
+# endif
+{
if (!static_cast<bool>(__y))
return true;
if (!static_cast<bool>(__x))
@@ -1067,7 +1129,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);
@@ -1139,100 +1202,221 @@ _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
+
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Up>::value) && requires {
+ { *__x == __v } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? *__x == __v : false;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Tp>::value) && requires {
+ { __v == *__x } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? __v == *__x : false;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Up>::value) && requires {
+ { *__x != __v } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? *__x != __v : true;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Tp>::value) && requires {
+ { __v != *__x } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? __v != *__x : true;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Up>::value) && requires {
+ { *__x < __v } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? *__x < __v : true;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Tp>::value) && requires {
+ { __v < *__x } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? __v < *__x : false;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Up>::value) && requires {
+ { *__x <= __v } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? *__x <= __v : true;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Tp>::value) && requires {
+ { __v <= *__x } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? __v <= *__x : false;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Up>::value) && requires {
+ { *__x > __v } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? *__x > __v : false;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Tp>::value) && requires {
+ { __v > *__x } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? __v > *__x : true;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Up>::value) && requires {
+ { *__x >= __v } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? *__x >= __v : false;
}
+# if _LIBCPP_STD_VER >= 26
+template < class _Tp, class _Up>
+# else
template <
class _Tp,
class _Up,
enable_if_t<is_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) {
+# endif
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x)
+# if _LIBCPP_STD_VER >= 26
+ requires(!__is_std_optional<_Tp>::value) && requires {
+ { __v >= *__x } -> __core_convertible_to<bool>;
+ }
+# endif
+{
return static_cast<bool>(__x) ? __v >= *__x : true;
}
diff --git a/libcxx/test/std/utilities/optional/optional.comp_with_t/equal.pass.cpp b/libcxx/test/std/utilities/optional/optional.comp_with_t/equal.pass.cpp
index 0636da7bcdf23..54965b270dcce 100644
--- a/libcxx/test/std/utilities/optional/optional.comp_with_t/equal.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.comp_with_t/equal.pass.cpp
@@ -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 {
diff --git a/libcxx/test/std/utilities/optional/optional.comp_with_t/greater.pass.cpp b/libcxx/test/std/utilities/optional/optional.comp_with_t/greater.pass.cpp
index 2010157a8d011..b63b85b000930 100644
--- a/libcxx/test/std/utilities/optional/optional.comp_with_t/greater.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.comp_with_t/greater.pass.cpp
@@ -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 {
diff --git a/libcxx/test/std/utilities/optional/optional.comp_with_t/greater_equal.pass.cpp b/libcxx/test/std/utilities/optional/optional.comp_with_t/greater_equal.pass.cpp
index 2e1e9b9316111..bb1a8c551d3d5 100644
--- a/libcxx/test/std/utilities/optional/optional.comp_with_t/greater_equal.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.comp_with_t/greater_equal.pass.cpp
@@ -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 {
diff --git a/libcxx/test/std/utilities/optional/optional.comp_with_t/less_equal.pass.cpp b/libcxx/test/std/utilities/optional/optional.comp_with_t/less_equal.pass.cpp
index 7026c24de5dbf..8b08ec3deea5a 100644
--- a/libcxx/test/std/utilities/optional/optional.comp_with_t/less_equal.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.comp_with_t/less_equal.pass.cpp
@@ -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>...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/144249
More information about the libcxx-commits
mailing list