Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/Cxx26Issues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"`LWG4027 <https://wg21.link/LWG4027>`__","``possibly-const-range`` should prefer returning ``const R&``","2024-11 (Wrocław)","","","`#118342 <https://github.com/llvm/llvm-project/issues/118342>`__",""
"`LWG4044 <https://wg21.link/LWG4044>`__","Confusing requirements for ``std::print`` on POSIX platforms","2024-11 (Wrocław)","","","`#118343 <https://github.com/llvm/llvm-project/issues/118343>`__",""
"`LWG4064 <https://wg21.link/LWG4064>`__","Clarify that ``std::launder`` is not needed when using the result of ``std::memcpy``","2024-11 (Wrocław)","","","`#118344 <https://github.com/llvm/llvm-project/issues/118344>`__",""
"`LWG4072 <https://wg21.link/LWG4072>`__","``std::optional`` comparisons: constrain harder","2024-11 (Wrocław)","","","`#118345 <https://github.com/llvm/llvm-project/issues/118345>`__",""
"`LWG4072 <https://wg21.link/LWG4072>`__","``std::optional`` comparisons: constrain harder","2024-11 (Wrocław)","|Complete|","24","`#118345 <https://github.com/llvm/llvm-project/issues/118345>`__",""
"`LWG4084 <https://wg21.link/LWG4084>`__","``std::fixed`` ignores ``std::uppercase``","2024-11 (Wrocław)","|Complete|","","`#118346 <https://github.com/llvm/llvm-project/issues/118346>`__",""
"`LWG4085 <https://wg21.link/LWG4085>`__","``ranges::generate_random``'s helper lambda should specify the return type","2024-11 (Wrocław)","","","`#118347 <https://github.com/llvm/llvm-project/issues/118347>`__",""
"`LWG4088 <https://wg21.link/LWG4088>`__","``println`` ignores the locale imbued in ``std::ostream``","2024-11 (Wrocław)","|Complete|","18","`#118348 <https://github.com/llvm/llvm-project/issues/118348>`__",""
Expand Down
65 changes: 41 additions & 24 deletions libcxx/include/__optional/comparison.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <__compare/ordering.h>
#include <__compare/three_way_comparable.h>
#include <__config>
#include <__optional/common.h>
#include <__optional/nullopt_t.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_constructible.h>
Expand Down Expand Up @@ -201,7 +202,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>&
template <
class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
enable_if_t<!__is_std_optional_v<_Up> &&
__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) {
if (__x.has_value())
Expand All @@ -212,7 +214,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const
template <
class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
enable_if_t<!__is_std_optional_v<_Tp> &&
__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) {
if (__x.has_value())
Expand All @@ -223,7 +226,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_
template <
class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
enable_if_t<!__is_std_optional_v<_Up> &&
__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) {
if (__x.has_value())
Expand All @@ -234,28 +238,33 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const
template <
class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
enable_if_t<!__is_std_optional_v<_Tp> &&
__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) {
if (__x.has_value())
return __v != *__x;
return true;
}

template < class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
int> = 0>
template <
class _Tp,
class _Up,
enable_if_t<!__is_std_optional_v<_Up> &&
__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) {
if (__x.has_value())
return *__x < __v;
return true;
}

template < class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
int> = 0>
template <
class _Tp,
class _Up,
enable_if_t<!__is_std_optional_v<_Tp> &&
__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) {
if (__x.has_value())
return __v < *__x;
Expand All @@ -265,7 +274,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_U
template <
class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
enable_if_t<!__is_std_optional_v<_Up> &&
__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) {
if (__x.has_value())
Expand All @@ -276,28 +286,33 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const
template <
class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
enable_if_t<!__is_std_optional_v<_Tp> &&
__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) {
if (__x.has_value())
return __v <= *__x;
return false;
}

template < class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
int> = 0>
template <
class _Tp,
class _Up,
enable_if_t<!__is_std_optional_v<_Up> &&
__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) {
if (__x.has_value())
return *__x > __v;
return false;
}

template < class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
int> = 0>
template <
class _Tp,
class _Up,
enable_if_t<!__is_std_optional_v<_Tp> &&
__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) {
if (__x.has_value())
return __v > *__x;
Expand All @@ -307,7 +322,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_U
template <
class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
enable_if_t<!__is_std_optional_v<_Up> &&
__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) {
if (__x.has_value())
Expand All @@ -318,7 +334,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const
template <
class _Tp,
class _Up,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
enable_if_t<!__is_std_optional_v<_Tp> &&
__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) {
if (__x.has_value())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@

#if TEST_STD_VER >= 26

struct tester {};

template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator==(const tester& a, const T& t) {
return t.compare(a) == 0;
}
template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator==(const T& t, const tester& a) {
return t.compare(a) == 0;
}

template <class T, class U>
constexpr std::optional<bool> try_cmp_eq(const T& t, const U& u) {
if constexpr (requires { t == u; })
return t == u;
else
return {};
}

// Test SFINAE.

static_assert(HasOperatorEqual<int, std::optional<int>>);
Expand All @@ -35,6 +54,10 @@ static_assert(HasOperatorEqual<std::optional<EqualityComparable>, EqualityCompar
static_assert(!HasOperatorEqual<std::optional<NonComparable>, NonComparable>);
static_assert(!HasOperatorEqual<std::optional<EqualityComparable>, NonComparable>);

// LWG4072: avoid ambiguity with optional's own comparison operators
static_assert(try_cmp_eq(std::optional<int>{}, std::optional<tester>{}) == std::optional<bool>{});
static_assert(try_cmp_eq(std::optional<int>{}, std::optional<int>{}) == std::optional<bool>{true});

#endif

using std::optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@

#if TEST_STD_VER >= 26

struct tester {};

template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator>(const tester& a, const T& t) {
return t.compare(a) < 0;
}
template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator>(const T& t, const tester& a) {
return t.compare(a) > 0;
}

template <class T, class U>
constexpr std::optional<bool> try_cmp_gt(const T& t, const U& u) {
if constexpr (requires { t > u; })
return t > u;
else
return {};
}

// Test SFINAE.
static_assert(HasOperatorGreaterThan<std::optional<ThreeWayComparable>, int>);
static_assert(HasOperatorGreaterThan<std::optional<ThreeWayComparable>, ThreeWayComparable>);
Expand All @@ -34,6 +53,10 @@ static_assert(!HasOperatorGreaterThan<NonComparable, std::optional<NonComparable
static_assert(!HasOperatorGreaterThan<NonComparable, std::optional<ThreeWayComparable>>);
static_assert(!HasOperatorGreaterThan<ThreeWayComparable, std::optional<NonComparable>>);

// LWG4072: avoid ambiguity with optional's own comparison operators
static_assert(try_cmp_gt(std::optional<int>{}, std::optional<tester>{}) == std::optional<bool>{});
static_assert(try_cmp_gt(std::optional<int>{}, std::optional<int>{}) == std::optional<bool>{false});

#endif

using std::optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@

#if TEST_STD_VER >= 26

struct tester {};

template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator>=(const tester& a, const T& t) {
return t.compare(a) <= 0;
}
template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator>=(const T& t, const tester& a) {
return t.compare(a) >= 0;
}

template <class T, class U>
constexpr std::optional<bool> try_cmp_gteq(const T& t, const U& u) {
if constexpr (requires { t >= u; })
return t >= u;
else
return {};
}

// Test SFINAE.
static_assert(HasOperatorGreaterThanEqual<std::optional<ThreeWayComparable>, int>);
static_assert(HasOperatorGreaterThanEqual<std::optional<ThreeWayComparable>, ThreeWayComparable>);
Expand All @@ -34,6 +53,10 @@ static_assert(!HasOperatorGreaterThanEqual<NonComparable, std::optional<NonCompa
static_assert(!HasOperatorGreaterThanEqual<NonComparable, std::optional<ThreeWayComparable>>);
static_assert(!HasOperatorGreaterThanEqual<ThreeWayComparable, std::optional<NonComparable>>);

// LWG4072: avoid ambiguity with optional's own comparison operators
static_assert(try_cmp_gteq(std::optional<int>{}, std::optional<tester>{}) == std::optional<bool>{});
static_assert(try_cmp_gteq(std::optional<int>{}, std::optional<int>{}) == std::optional<bool>{true});

#endif

using std::optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@

#if TEST_STD_VER >= 26

struct tester {};

template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator<=(const tester& a, const T& t) {
return t.compare(a) >= 0;
}
template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator<=(const T& t, const tester& a) {
return t.compare(a) <= 0;
}

template <class T, class U>
constexpr std::optional<bool> try_cmp_lteq(const T& t, const U& u) {
if constexpr (requires { t <= u; })
return t <= u;
else
return {};
}

// Test SFINAE.
static_assert(HasOperatorLessThanEqual<std::optional<ThreeWayComparable>, int>);
static_assert(HasOperatorLessThanEqual<std::optional<ThreeWayComparable>, ThreeWayComparable>);
Expand All @@ -34,6 +53,10 @@ static_assert(!HasOperatorLessThanEqual<NonComparable, std::optional<NonComparab
static_assert(!HasOperatorLessThanEqual<NonComparable, std::optional<ThreeWayComparable>>);
static_assert(!HasOperatorLessThanEqual<ThreeWayComparable, std::optional<NonComparable>>);

// LWG4072: avoid ambiguity with optional's own comparison operators
static_assert(try_cmp_lteq(std::optional<int>{}, std::optional<tester>{}) == std::optional<bool>{});
static_assert(try_cmp_lteq(std::optional<int>{}, std::optional<int>{}) == std::optional<bool>{true});

#endif

using std::optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@

#if TEST_STD_VER >= 26

struct tester {};

template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator<(const tester& a, const T& t) {
return t.compare(a) > 0;
}
template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator<(const T& t, const tester& a) {
return t.compare(a) < 0;
}

template <class T, class U>
constexpr std::optional<bool> try_cmp_lt(const T& t, const U& u) {
if constexpr (requires { t < u; })
return t < u;
else
return {};
}

// Test SFINAE.
static_assert(HasOperatorLessThan<std::optional<ThreeWayComparable>, int>);
static_assert(HasOperatorLessThan<std::optional<ThreeWayComparable>, ThreeWayComparable>);
Expand All @@ -34,6 +53,10 @@ static_assert(!HasOperatorLessThan<NonComparable, std::optional<NonComparable>>)
static_assert(!HasOperatorLessThan<NonComparable, std::optional<ThreeWayComparable>>);
static_assert(!HasOperatorLessThan<ThreeWayComparable, std::optional<NonComparable>>);

// LWG4072: avoid ambiguity with optional's own comparison operators
static_assert(try_cmp_lt(std::optional<int>{}, std::optional<tester>{}) == std::optional<bool>{});
static_assert(try_cmp_lt(std::optional<int>{}, std::optional<int>{}) == std::optional<bool>{false});

#endif

using std::optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@

#if TEST_STD_VER >= 26

struct tester {};

template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator!=(const tester& a, const T& t) {
return t.compare(a) != 0;
}
template <class T, std::enable_if_t<std::is_class_v<T>, int> = 0> // intentionally underconstrained
constexpr bool operator!=(const T& t, const tester& a) {
return t.compare(a) != 0;
}

template <class T, class U>
constexpr std::optional<bool> try_cmp_neq(const T& t, const U& u) {
if constexpr (requires { t != u; })
return t != u;
else
return {};
}

// Test SFINAE.

static_assert(HasOperatorNotEqual<int, std::optional<int>>);
Expand All @@ -35,6 +54,10 @@ static_assert(HasOperatorNotEqual<std::optional<EqualityComparable>, EqualityCom
static_assert(!HasOperatorNotEqual<std::optional<NonComparable>, NonComparable>);
static_assert(!HasOperatorNotEqual<std::optional<EqualityComparable>, NonComparable>);

// LWG4072: avoid ambiguity with optional's own comparison operators
static_assert(try_cmp_neq(std::optional<int>{}, std::optional<tester>{}) == std::optional<bool>{});
static_assert(try_cmp_neq(std::optional<int>{}, std::optional<int>{}) == std::optional<bool>{false});

#endif

using std::optional;
Expand Down
Loading