-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[libc++] P3379R1: Constrain std::expected
equality operators
#117664
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
Conversation
@llvm/pr-subscribers-libcxx Author: Xiaoyang Liu (xiaoyang-sde) ChangesFull diff: https://github.com/llvm/llvm-project/pull/117664.diff 1 Files Affected:
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 3d3f11967ee746..7dc0248fcd72f9 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -10,6 +10,7 @@
#define _LIBCPP___EXPECTED_EXPECTED_H
#include <__assert>
+#include <__concepts/convertible_to.h>
#include <__config>
#include <__expected/bad_expected_access.h>
#include <__expected/unexpect.h>
@@ -1139,7 +1140,11 @@ class expected : private __expected_base<_Tp, _Err> {
// [expected.object.eq], equality operators
template <class _T2, class _E2>
- requires(!is_void_v<_T2>)
+ requires(!is_void_v<_T2> &&
+ requires(const _Tp& __tp, const _T2& __t2, const _Err& __err, const _E2& __e2) {
+ { __tp == __t2 } -> convertible_to<bool>;
+ { __err == __e2 } -> convertible_to<bool>;
+ })
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) {
if (__x.__has_val() != __y.__has_val()) {
return false;
@@ -1153,11 +1158,18 @@ class expected : private __expected_base<_Tp, _Err> {
}
template <class _T2>
+ requires(!__is_std_expected<_T2>::value &&
+ requires(const _Tp& __tp, const _T2& __t2) {
+ { __tp == __t2 } -> convertible_to<bool>;
+ })
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) {
return __x.__has_val() && static_cast<bool>(__x.__val() == __v);
}
template <class _E2>
+ requires requires(const _Err& __err, const _E2& __e2) {
+ { __err == __e2 } -> convertible_to<bool>;
+ }
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) {
return !__x.__has_val() && static_cast<bool>(__x.__unex() == __e.error());
}
@@ -1850,7 +1862,10 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
// [expected.void.eq], equality operators
template <class _T2, class _E2>
- requires is_void_v<_T2>
+ requires(is_void_v<_T2> &&
+ requires(const _Err& __err, const _E2& __e2) {
+ { __err == __e2 } -> convertible_to<bool>;
+ })
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) {
if (__x.__has_val() != __y.__has_val()) {
return false;
@@ -1860,6 +1875,9 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
}
template <class _E2>
+ requires requires(const _Err& __err, const _E2& __e2) {
+ { __err == __e2 } -> convertible_to<bool>;
+ }
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) {
return !__x.__has_val() && static_cast<bool>(__x.__unex() == __y.error());
}
|
Should we backport this to C++23? If so, perhaps we should also backport the constraints introduced by P2944R3 to old modes. |
requires(!is_void_v<_T2>) | ||
requires(!is_void_v<_T2> && | ||
requires(const _Tp& __tp, const _T2& __t2, const _Err& __err, const _E2& __e2) { | ||
{ __tp == __t2 } -> convertible_to<bool>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The convertible_to
concept is stricter than the plain "(implicitly) convertible to". The latter can be expressed by __is_core_convertible
in <__type_traits/is_core_convertible.h>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we can have the following.
Internal concept __core_convertible_to
in the <__concepts/core_convertible_to.h>
internal header
#ifndef _LIBCPP___CONCEPTS_CORE_CONVERTIBLE_TO_H
#define _LIBCPP___CONCEPTS_CORE_CONVERTIBLE_TO_H
#include <__config>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
// [conv.general]/3 says "E is convertible to T" whenever "T t=E;" is well-formed.
// We can't test for that, but we can test implicit convertibility by passing it
// to a function. Unlike std::convertible_to, __core_convertible_to doesn't test
// static_cast or handle cv void, while accepting move-only types.
template <class _Tp, class _Up>
concept __core_convertible_to = requires {
// rejects function and array types which are adjusted to pointer types in parameter lists
static_cast<_Up (*)()>(nullptr)();
static_cast<void (*)(_Up)>(nullptr)(static_cast<_Tp (*)()>(nullptr)());
};
#endif
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___CONCEPTS_CORE_CONVERTIBLE_TO_H
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for writing this! I'll take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you like to draft a patch for this header if you have time? I can rebase and use your header. This will ensure that you receive credit for your work! Otherwise, I can include it in this patch myself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we used __boolean_testable
to implement the constraints for operator==
in std::reference_wrapper
. (https://github.com/llvm/llvm-project/blob/main/libcxx/include/__functional/reference_wrapper.h#L75-L81)
Should we consider making them consistent?
@frederick-vs-ja |
Yes. I think these changes should be handled consistently. |
@frederick-vs-ja @mordante To continue on the above: Do you think "constrained equality operators" as defined in https://wg21.link/P3379R1 and https://wg21.link/p2944r3 should be implemented as DR? |
The paper was not voted in as a DR so we should not apply it as a DR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xiaoyang-sde do you still want to work on this PR?
@@ -45,6 +45,7 @@ Implemented Papers | |||
- ``std::jthread`` and ``<stop_token>`` are not guarded behind ``-fexperimental-library`` anymore | |||
- P2674R1: A trait for implicit lifetime types (`Github <https://github.com/llvm/llvm-project/issues/105259>`__) | |||
- P0429R9: A Standard ``flat_map`` is partially implemented and ``flat_map`` is provided (`Github <https://github.com/llvm/llvm-project/issues/105190>`__) | |||
- P3379R1: Constrain ``std::expected`` equality operators |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The paper number is R0, please adjust all references in the PR
- P3379R1: Constrain ``std::expected`` equality operators | |
- P3379R0: Constrain ``std::expected`` equality operators |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a D3379R1 draft but I forgot to publish it, and we voted on R0. The only difference is that R1 said to add __cpp_lib_constrained_equality
in <expected>
. That addition got done editorially: cplusplus/draft#7449
It looks like this PR neither bumps the macro value nor adds the macro to <expected>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've submitted brevzin/sd6#28 to update SD-6.
In https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115939#c3 @jwakely said that
And P3379R0 is the paper. libstdc++ treated it as DR against C++23 (gcc-mirror/gcc@0515b24). |
I think the constrained comparisons for For libstdc++ we also treated the tuple/optional/variant parts of P2944 as a DR against C++20. I didn't apply them further back because without defaulted comparisons I don't think it really matters whether the comparisons are constrained (and because I'm lazy and I didn't want to implement the constraints without concepts and spaceship). So for consistency, I treated the I did not add comparisons for P2944 should probably have been two separate papers: one paper adding new comparisons and another paper constraining existing comparisons, instead of doing the latter as a drive-by fix. |
Sorry! I've been a bit busy lately, so feel free to take this over! |
…36672) Implements https://wg21.link/P2944R3 (partially): - [pairs.spec](https://eel.is/c++draft/pairs.spec) Related issues: - Related to #105424 - Related to #118135 - PR #135759 - PR #117664 Closes: [#136763](#136763) # References - https://eel.is/c++draft/concept.booleantestable - https://eel.is/c++draft/concept.equalitycomparable --------- Co-authored-by: Hristo Hristov <[email protected]> Co-authored-by: Nikolas Klauser <[email protected]>
@xiaoyang-sde Since there is a more up-to-date PR, let's close this. I'll wait a couple of days and I'll close it if nobody objects. |
…vm#136672) Implements https://wg21.link/P2944R3 (partially): - [pairs.spec](https://eel.is/c++draft/pairs.spec) Related issues: - Related to llvm#105424 - Related to llvm#118135 - PR llvm#135759 - PR llvm#117664 Closes: [llvm#136763](llvm#136763) # References - https://eel.is/c++draft/concept.booleantestable - https://eel.is/c++draft/concept.equalitycomparable --------- Co-authored-by: Hristo Hristov <[email protected]> Co-authored-by: Nikolas Klauser <[email protected]>
…vm#136672) Implements https://wg21.link/P2944R3 (partially): - [pairs.spec](https://eel.is/c++draft/pairs.spec) Related issues: - Related to llvm#105424 - Related to llvm#118135 - PR llvm#135759 - PR llvm#117664 Closes: [llvm#136763](llvm#136763) # References - https://eel.is/c++draft/concept.booleantestable - https://eel.is/c++draft/concept.equalitycomparable --------- Co-authored-by: Hristo Hristov <[email protected]> Co-authored-by: Nikolas Klauser <[email protected]>
…vm#136672) Implements https://wg21.link/P2944R3 (partially): - [pairs.spec](https://eel.is/c++draft/pairs.spec) Related issues: - Related to llvm#105424 - Related to llvm#118135 - PR llvm#135759 - PR llvm#117664 Closes: [llvm#136763](llvm#136763) # References - https://eel.is/c++draft/concept.booleantestable - https://eel.is/c++draft/concept.equalitycomparable --------- Co-authored-by: Hristo Hristov <[email protected]> Co-authored-by: Nikolas Klauser <[email protected]>
…perator (#136672) Implements https://wg21.link/P2944R3 (partially): - [pairs.spec](https://eel.is/c++draft/pairs.spec) Related issues: - Related to #105424 - Related to #118135 - PR llvm/llvm-project#135759 - PR llvm/llvm-project#117664 Closes: [#136763](llvm/llvm-project#136763) # References - https://eel.is/c++draft/concept.booleantestable - https://eel.is/c++draft/concept.equalitycomparable --------- Co-authored-by: Hristo Hristov <[email protected]> Co-authored-by: Nikolas Klauser <[email protected]>
…vm#136672) Implements https://wg21.link/P2944R3 (partially): - [pairs.spec](https://eel.is/c++draft/pairs.spec) Related issues: - Related to llvm#105424 - Related to llvm#118135 - PR llvm#135759 - PR llvm#117664 Closes: [llvm#136763](llvm#136763) # References - https://eel.is/c++draft/concept.booleantestable - https://eel.is/c++draft/concept.equalitycomparable --------- Co-authored-by: Hristo Hristov <[email protected]> Co-authored-by: Nikolas Klauser <[email protected]>
Introduction
This patch attempts to implement P3379R1. P3379R1 proposes adding constraints to the equality operators for
std::expected
, aligning it with other standard library types likepair
,tuple
,optional
, andvariant
.Reference
std::expected
equality operators