Skip to content

[libc++] P2167R3: Improved Proposed Wording for LWG 2114 #109102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 2, 2024
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/Cxx23Papers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
"`P1202R5 <https://wg21.link/P1202R5>`__","Asymmetric Fences","2022-11 (Kona)","","",""
"`P1264R2 <https://wg21.link/P1264R2>`__","Revising the wording of ``stream`` input operations","2022-11 (Kona)","|Complete|","9.0",""
"`P1478R8 <https://wg21.link/P1478R8>`__","``Byte-wise`` ``atomic`` ``memcpy``","2022-11 (Kona)","","",""
"`P2167R3 <https://wg21.link/P2167R3>`__","Improved Proposed Wording for LWG 2114","2022-11 (Kona)","","",""
"`P2167R3 <https://wg21.link/P2167R3>`__","Improved Proposed Wording for LWG 2114","2022-11 (Kona)","|Complete|","20.0","The `[cmp.alg] <https://eel.is/c++draft/cmp.alg>`__ part is implemented as a DR against C++20. MSVC STL does the same. Other parts are Nothing To Do."
"`P2396R1 <https://wg21.link/P2396R1>`__","Concurrency TS 2 fixes ","2022-11 (Kona)","","",""
"`P2505R5 <https://wg21.link/P2505R5>`__","Monadic Functions for ``std::expected``","2022-11 (Kona)","|Complete|","17.0",""
"`P2539R4 <https://wg21.link/P2539R4>`__","Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?","2022-11 (Kona)","|Complete|","18.0",""
Expand Down
23 changes: 11 additions & 12 deletions libcxx/include/__compare/compare_partial_order_fallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <__compare/ordering.h>
#include <__compare/partial_order.h>
#include <__concepts/boolean_testable.h>
#include <__config>
#include <__type_traits/decay.h>
#include <__type_traits/is_same.h>
Expand All @@ -37,18 +38,16 @@ struct __fn {
}

template <class _Tp, class _Up>
requires is_same_v<decay_t<_Tp>, decay_t<_Up>>
_LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(noexcept(
std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? partial_ordering::equivalent
: std::forward<_Tp>(__t) < std::forward<_Up>(__u) ? partial_ordering::less
: std::forward<_Up>(__u) < std::forward<_Tp>(__t)
? partial_ordering::greater
: partial_ordering::unordered))
-> decltype(std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? partial_ordering::equivalent
: std::forward<_Tp>(__t) < std::forward<_Up>(__u) ? partial_ordering::less
: std::forward<_Up>(__u) < std::forward<_Tp>(__t)
? partial_ordering::greater
: partial_ordering::unordered) {
requires is_same_v<decay_t<_Tp>, decay_t<_Up>> && requires(_Tp&& __t, _Up&& __u) {
{ std::forward<_Tp>(__t) == std::forward<_Up>(__u) } -> __boolean_testable;
{ std::forward<_Tp>(__t) < std::forward<_Up>(__u) } -> __boolean_testable;
{ std::forward<_Up>(__u) < std::forward<_Tp>(__t) } -> __boolean_testable;
}
_LIBCPP_HIDE_FROM_ABI static constexpr partial_ordering __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(
noexcept(std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? partial_ordering::equivalent
: std::forward<_Tp>(__t) < std::forward<_Up>(__u) ? partial_ordering::less
: std::forward<_Up>(__u) < std::forward<_Tp>(__t) ? partial_ordering::greater
: partial_ordering::unordered)) {
return std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? partial_ordering::equivalent
: std::forward<_Tp>(__t) < std::forward<_Up>(__u) ? partial_ordering::less
: std::forward<_Up>(__u) < std::forward<_Tp>(__t)
Expand Down
19 changes: 9 additions & 10 deletions libcxx/include/__compare/compare_strong_order_fallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <__compare/ordering.h>
#include <__compare/strong_order.h>
#include <__concepts/boolean_testable.h>
#include <__config>
#include <__type_traits/decay.h>
#include <__type_traits/is_same.h>
Expand All @@ -37,16 +38,14 @@ struct __fn {
}

template <class _Tp, class _Up>
requires is_same_v<decay_t<_Tp>, decay_t<_Up>>
_LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(noexcept(
std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? strong_ordering::equal
: std::forward<_Tp>(__t) < std::forward<_Up>(__u)
? strong_ordering::less
: strong_ordering::greater))
-> decltype(std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? strong_ordering::equal
: std::forward<_Tp>(__t) < std::forward<_Up>(__u)
? strong_ordering::less
: strong_ordering::greater) {
requires is_same_v<decay_t<_Tp>, decay_t<_Up>> && requires(_Tp&& __t, _Up&& __u) {
{ std::forward<_Tp>(__t) == std::forward<_Up>(__u) } -> __boolean_testable;
{ std::forward<_Tp>(__t) < std::forward<_Up>(__u) } -> __boolean_testable;
}
_LIBCPP_HIDE_FROM_ABI static constexpr strong_ordering __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(
noexcept(std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? strong_ordering::equal
: std::forward<_Tp>(__t) < std::forward<_Up>(__u) ? strong_ordering::less
: strong_ordering::greater)) {
return std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? strong_ordering::equal
: std::forward<_Tp>(__t) < std::forward<_Up>(__u)
? strong_ordering::less
Expand Down
14 changes: 7 additions & 7 deletions libcxx/include/__compare/compare_weak_order_fallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <__compare/ordering.h>
#include <__compare/weak_order.h>
#include <__concepts/boolean_testable.h>
#include <__config>
#include <__type_traits/decay.h>
#include <__type_traits/is_same.h>
Expand All @@ -37,16 +38,15 @@ struct __fn {
}

template <class _Tp, class _Up>
requires is_same_v<decay_t<_Tp>, decay_t<_Up>>
_LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(noexcept(
requires is_same_v<decay_t<_Tp>, decay_t<_Up>> && requires(_Tp&& __t, _Up&& __u) {
{ std::forward<_Tp>(__t) == std::forward<_Up>(__u) } -> __boolean_testable;
{ std::forward<_Tp>(__t) < std::forward<_Up>(__u) } -> __boolean_testable;
}
_LIBCPP_HIDE_FROM_ABI static constexpr weak_ordering __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(noexcept(
std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? weak_ordering::equivalent
: std::forward<_Tp>(__t) < std::forward<_Up>(__u)
? weak_ordering::less
: weak_ordering::greater))
-> decltype(std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? weak_ordering::equivalent
: std::forward<_Tp>(__t) < std::forward<_Up>(__u)
? weak_ordering::less
: weak_ordering::greater) {
: weak_ordering::greater)) {
return std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? weak_ordering::equivalent
: std::forward<_Tp>(__t) < std::forward<_Up>(__u)
? weak_ordering::less
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,44 @@ namespace N2 {
friend bool operator<(const VC2&, VC2&);
friend bool operator<(VC2&, const VC2&);
};

enum class comparison_result_kind : bool {
convertible_bool,
boolean_testable,
};

template <comparison_result_kind K>
struct comparison_result {
bool value;

constexpr operator bool() const noexcept { return value; }

constexpr auto operator!() const noexcept {
if constexpr (K == comparison_result_kind::boolean_testable) {
return comparison_result{!value};
}
}
};

template <comparison_result_kind EqKind, comparison_result_kind LeKind>
struct boolean_tested_type {
friend constexpr comparison_result<EqKind> operator==(boolean_tested_type, boolean_tested_type) noexcept {
return comparison_result<EqKind>{true};
}

friend constexpr comparison_result<LeKind> operator<(boolean_tested_type, boolean_tested_type) noexcept {
return comparison_result<LeKind>{false};
}
};

using test_only_convertible =
boolean_tested_type<comparison_result_kind::convertible_bool, comparison_result_kind::convertible_bool>;
using test_eq_boolean_testable =
boolean_tested_type<comparison_result_kind::boolean_testable, comparison_result_kind::convertible_bool>;
using test_le_boolean_testable =
boolean_tested_type<comparison_result_kind::convertible_bool, comparison_result_kind::boolean_testable>;
using test_boolean_testable =
boolean_tested_type<comparison_result_kind::boolean_testable, comparison_result_kind::boolean_testable>;
}

constexpr bool test_2()
Expand Down Expand Up @@ -306,6 +344,21 @@ constexpr bool test_2()
assert( has_partial_order(cvc, vc));
assert(!has_partial_order(vc, cvc));
}
{
// P2167R3 as modified by the intent of LWG3465:
// All of decltype(e == f), decltype(e < f), and decltype(f < e) need to be well-formed and boolean-testable.
N2::test_only_convertible tc;
N2::test_eq_boolean_testable teq;
N2::test_le_boolean_testable tle;
N2::test_boolean_testable tbt;

assert(!has_partial_order(tc, tc));
assert(!has_partial_order(teq, teq));
assert(!has_partial_order(tle, tle));
assert(has_partial_order(tbt, tbt));

assert(std::compare_partial_order_fallback(tbt, tbt) == std::partial_ordering::equivalent);
}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,44 @@ namespace N2 {
friend bool operator<(const VC2&, VC2&);
friend bool operator<(VC2&, const VC2&);
};

enum class comparison_result_kind : bool {
convertible_bool,
boolean_testable,
};

template <comparison_result_kind K>
struct comparison_result {
bool value;

constexpr operator bool() const noexcept { return value; }

constexpr auto operator!() const noexcept {
if constexpr (K == comparison_result_kind::boolean_testable) {
return comparison_result{!value};
}
}
};

template <comparison_result_kind EqKind, comparison_result_kind LeKind>
struct boolean_tested_type {
friend constexpr comparison_result<EqKind> operator==(boolean_tested_type, boolean_tested_type) noexcept {
return comparison_result<EqKind>{true};
}

friend constexpr comparison_result<LeKind> operator<(boolean_tested_type, boolean_tested_type) noexcept {
return comparison_result<LeKind>{false};
}
};

using test_only_convertible =
boolean_tested_type<comparison_result_kind::convertible_bool, comparison_result_kind::convertible_bool>;
using test_eq_boolean_testable =
boolean_tested_type<comparison_result_kind::boolean_testable, comparison_result_kind::convertible_bool>;
using test_le_boolean_testable =
boolean_tested_type<comparison_result_kind::convertible_bool, comparison_result_kind::boolean_testable>;
using test_boolean_testable =
boolean_tested_type<comparison_result_kind::boolean_testable, comparison_result_kind::boolean_testable>;
}

constexpr bool test_2()
Expand Down Expand Up @@ -506,6 +544,20 @@ constexpr bool test_2()
assert( has_strong_order(cvc, vc));
assert(!has_strong_order(vc, cvc));
}
{
// P2167R3: Both decltype(e == f) and decltype(e < f) need to be well-formed and boolean-testable.
N2::test_only_convertible tc;
N2::test_eq_boolean_testable teq;
N2::test_le_boolean_testable tle;
N2::test_boolean_testable tbt;

assert(!has_strong_order(tc, tc));
assert(!has_strong_order(teq, teq));
assert(!has_strong_order(tle, tle));
assert(has_strong_order(tbt, tbt));

assert(std::compare_strong_order_fallback(tbt, tbt) == std::strong_ordering::equal);
}
return true;
}

Expand All @@ -515,13 +567,17 @@ int main(int, char**)
test_1_2();
test_1_3<float>();
test_1_3<double>();
// test_1_3<long double>(); // UNIMPLEMENTED
#ifdef TEST_LONG_DOUBLE_IS_DOUBLE
test_1_3<long double>(); // UNIMPLEMENTED when long double is a distinct type
#endif
test_1_4();
test_2();

static_assert(test_1_3<float>());
static_assert(test_1_3<double>());
// static_assert(test_1_3<long double>()); // UNIMPLEMENTED
#ifdef TEST_LONG_DOUBLE_IS_DOUBLE
static_assert(test_1_3<long double>()); // UNIMPLEMENTED when long double is a distinct type
#endif
static_assert(test_1_4());
static_assert(test_2());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,44 @@ namespace N2 {
friend bool operator<(const VC2&, VC2&);
friend bool operator<(VC2&, const VC2&);
};

enum class comparison_result_kind : bool {
convertible_bool,
boolean_testable,
};

template <comparison_result_kind K>
struct comparison_result {
bool value;

constexpr operator bool() const noexcept { return value; }

constexpr auto operator!() const noexcept {
if constexpr (K == comparison_result_kind::boolean_testable) {
return comparison_result{!value};
}
}
};

template <comparison_result_kind EqKind, comparison_result_kind LeKind>
struct boolean_tested_type {
friend constexpr comparison_result<EqKind> operator==(boolean_tested_type, boolean_tested_type) noexcept {
return comparison_result<EqKind>{true};
}

friend constexpr comparison_result<LeKind> operator<(boolean_tested_type, boolean_tested_type) noexcept {
return comparison_result<LeKind>{false};
}
};

using test_only_convertible =
boolean_tested_type<comparison_result_kind::convertible_bool, comparison_result_kind::convertible_bool>;
using test_eq_boolean_testable =
boolean_tested_type<comparison_result_kind::boolean_testable, comparison_result_kind::convertible_bool>;
using test_le_boolean_testable =
boolean_tested_type<comparison_result_kind::convertible_bool, comparison_result_kind::boolean_testable>;
using test_boolean_testable =
boolean_tested_type<comparison_result_kind::boolean_testable, comparison_result_kind::boolean_testable>;
}

constexpr bool test_2()
Expand Down Expand Up @@ -553,6 +591,20 @@ constexpr bool test_2()
assert( has_weak_order(cvc, vc));
assert(!has_weak_order(vc, cvc));
}
{
// P2167R3: Both decltype(e == f) and decltype(e < f) need to be well-formed and boolean-testable.
N2::test_only_convertible tc;
N2::test_eq_boolean_testable teq;
N2::test_le_boolean_testable tle;
N2::test_boolean_testable tbt;

assert(!has_weak_order(tc, tc));
assert(!has_weak_order(teq, teq));
assert(!has_weak_order(tle, tle));
assert(has_weak_order(tbt, tbt));

assert(std::compare_weak_order_fallback(tbt, tbt) == std::weak_ordering::equivalent);
}
return true;
}

Expand Down
Loading