Tested x86_64-linux. Pushed to trunk. -- >8 --
This proposal of mine has been approved by LEWG and forwarded to LWG. I expect it to be voted into the draft without significant changes. libstdc++-v3/ChangeLog: * include/bits/version.def (constrained_equality): Bump value. * include/bits/version.h: Regenerate. * include/std/expected (operator==): Add constraints and noexcept specifiers. * testsuite/20_util/optional/relops/constrained.cc: Adjust check for feature test macro. * testsuite/20_util/pair/comparison_operators/constrained.cc: Likewise. * testsuite/20_util/tuple/comparison_operators/constrained.cc: Likewise. * testsuite/20_util/variant/relops/constrained.cc: Likewise. * testsuite/20_util/expected/equality_constrained.cc: New test. --- libstdc++-v3/include/bits/version.def | 2 +- libstdc++-v3/include/bits/version.h | 4 +- libstdc++-v3/include/std/expected | 31 ++- .../20_util/expected/equality_constrained.cc | 181 ++++++++++++++++++ .../20_util/optional/relops/constrained.cc | 2 +- .../pair/comparison_operators/constrained.cc | 2 +- .../tuple/comparison_operators/constrained.cc | 2 +- .../20_util/variant/relops/constrained.cc | 2 +- 8 files changed, 213 insertions(+), 13 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 477651f358a..4fa820a5a4a 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1256,7 +1256,7 @@ ftms = { ftms = { name = constrained_equality; values = { - v = 202403; + v = 202411; // FIXME: 202403 for P2944R3, ??? for P3379R0 cxxmin = 20; extra_cond = "__glibcxx_three_way_comparison"; }; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 342ee6b4c7a..fdbee8161d9 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -1392,9 +1392,9 @@ #if !defined(__cpp_lib_constrained_equality) # if (__cplusplus >= 202002L) && (__glibcxx_three_way_comparison) -# define __glibcxx_constrained_equality 202403L +# define __glibcxx_constrained_equality 202411L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_constrained_equality) -# define __cpp_lib_constrained_equality 202403L +# define __cpp_lib_constrained_equality 202411L # endif # endif #endif /* !defined(__cpp_lib_constrained_equality) && defined(__glibcxx_want_constrained_equality) */ diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected index d4a4bc17541..7de2aeffc70 100644 --- a/libstdc++-v3/include/std/expected +++ b/libstdc++-v3/include/std/expected @@ -35,6 +35,7 @@ #define __glibcxx_want_expected #define __glibcxx_want_freestanding_expected +#define __glibcxx_want_constrained_equality #include <bits/version.h> #ifdef __cpp_lib_expected // C++ >= 23 && __cpp_concepts >= 202002L @@ -1152,10 +1153,15 @@ namespace __expected template<typename _Up, typename _Er2> requires (!is_void_v<_Up>) + && requires (const _Tp& __t, const _Up& __u, + const _Er& __e, const _Er2& __e2) { + { __t == __u } -> convertible_to<bool>; + { __e == __e2 } -> convertible_to<bool>; + } friend constexpr bool operator==(const expected& __x, const expected<_Up, _Er2>& __y) - // FIXME: noexcept(noexcept(bool(*__x == *__y)) - // && noexcept(bool(__x.error() == __y.error()))) + noexcept(noexcept(bool(*__x == *__y)) + && noexcept(bool(__x.error() == __y.error()))) { if (__x.has_value()) return __y.has_value() && bool(*__x == *__y); @@ -1164,15 +1170,22 @@ namespace __expected } template<typename _Up> + requires (!__expected::__is_expected<_Up>) + && requires (const _Tp& __t, const _Up& __u) { + { __t == __u } -> convertible_to<bool>; + } friend constexpr bool operator==(const expected& __x, const _Up& __v) - // FIXME: noexcept(noexcept(bool(*__x == __v))) + noexcept(noexcept(bool(*__x == __v))) { return __x.has_value() && bool(*__x == __v); } template<typename _Er2> + requires requires (const _Er& __e, const _Er2& __e2) { + { __e == __e2 } -> convertible_to<bool>; + } friend constexpr bool operator==(const expected& __x, const unexpected<_Er2>& __e) - // FIXME: noexcept(noexcept(bool(__x.error() == __e.error()))) + noexcept(noexcept(bool(__x.error() == __e.error()))) { return !__x.has_value() && bool(__x.error() == __e.error()); } friend constexpr void @@ -1819,9 +1832,12 @@ namespace __expected template<typename _Up, typename _Er2> requires is_void_v<_Up> + && requires (const _Er& __e, const _Er2& __e2) { + { __e == __e2 } -> convertible_to<bool>; + } friend constexpr bool operator==(const expected& __x, const expected<_Up, _Er2>& __y) - // FIXME: noexcept(noexcept(bool(__x.error() == __y.error()))) + noexcept(noexcept(bool(__x.error() == __y.error()))) { if (__x.has_value()) return __y.has_value(); @@ -1830,9 +1846,12 @@ namespace __expected } template<typename _Er2> + requires requires (const _Er& __e, const _Er2& __e2) { + { __e == __e2 } -> convertible_to<bool>; + } friend constexpr bool operator==(const expected& __x, const unexpected<_Er2>& __e) - // FIXME: noexcept(noexcept(bool(__x.error() == __e.error()))) + noexcept(noexcept(bool(__x.error() == __e.error()))) { return !__x.has_value() && bool(__x.error() == __e.error()); } friend constexpr void diff --git a/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc b/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc new file mode 100644 index 00000000000..7f6cefae748 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc @@ -0,0 +1,181 @@ +// { dg-do compile { target c++23 } } + +#include <expected> + +#ifndef __cpp_lib_constrained_equality +# error "Feature-test macro for constrained_equality missing in <expected>" +#elif __cpp_lib_constrained_equality < 202411L // TODO: use final value +# error "Feature-test macro for constrained_equality has wrong value" +#endif + +template<typename T, typename U = T, typename E = int, typename E2 = E> +concept eq_comparable += requires (const std::expected<T, E>& t, const std::expected<U, E2>& u) { + t == u; +}; + +static_assert( eq_comparable<int> ); +static_assert( eq_comparable<int, long> ); +static_assert( eq_comparable<short, int> ); +static_assert( eq_comparable<int, long, unsigned int, unsigned long> ); +static_assert( eq_comparable<void, const void> ); + +struct A { }; +static_assert( ! eq_comparable<A> ); +static_assert( ! eq_comparable<A, A> ); +static_assert( ! eq_comparable<A, int> ); +static_assert( ! eq_comparable<int, int, A> ); +static_assert( ! eq_comparable<int, int, int, A> ); +static_assert( ! eq_comparable<void, const void, A> ); + +struct B { }; +void operator==(B, B); +static_assert( ! eq_comparable<B> ); +static_assert( ! eq_comparable<B, B> ); +static_assert( ! eq_comparable<B, int> ); +static_assert( ! eq_comparable<int, int, B> ); +static_assert( ! eq_comparable<int, int, int, B> ); +static_assert( ! eq_comparable<void, void, B> ); + +struct C { }; +bool operator==(C, C); +static_assert( eq_comparable<C> ); +static_assert( eq_comparable<C, C> ); +static_assert( eq_comparable<C, C> ); +static_assert( eq_comparable<C, C, C> ); +static_assert( eq_comparable<int, int, C> ); +static_assert( ! eq_comparable<C, C, A, A> ); +static_assert( ! eq_comparable<C, C, A, int> ); +static_assert( eq_comparable<void, void, C> ); + +struct D { }; +int operator==(D, D); +bool operator!=(D, D) = delete; +static_assert( eq_comparable<D> ); +static_assert( eq_comparable<D, D> ); +static_assert( eq_comparable<int, int, D> ); +static_assert( eq_comparable<D, D, D> ); +static_assert( ! eq_comparable<D, D, D, int> ); + +struct E { }; +bool operator==(/* not-const */ E&, const E&); +static_assert( ! eq_comparable<E> ); +static_assert( ! eq_comparable<E, E> ); +static_assert( ! eq_comparable<E, E> ); +static_assert( ! eq_comparable<int, int, E> ); + +bool operator==(A, B); +static_assert( eq_comparable<A, B> ); +static_assert( eq_comparable<B, A> ); +static_assert( eq_comparable<int, long, B, A> ); + +int operator==(C, D); +static_assert( eq_comparable<C, D> ); +static_assert( eq_comparable<D, C> ); +static_assert( eq_comparable<int, int, C, D> ); +static_assert( eq_comparable<int, int, D, C> ); +static_assert( eq_comparable<const void, void, C, D> ); +static_assert( eq_comparable<const void, void, D, C> ); + +template<typename T, typename U = T, typename E = int> +concept eq_comparable_val += requires (const std::expected<T, E>& t, const U& u) { + t == u; +}; + +static_assert( eq_comparable_val<int> ); +static_assert( eq_comparable_val<int, long> ); +static_assert( eq_comparable_val<short, int> ); +static_assert( eq_comparable_val<int, long, unsigned> ); +static_assert( ! eq_comparable_val<void, const void> ); + +static_assert( ! eq_comparable_val<A> ); +static_assert( ! eq_comparable_val<A, A> ); +static_assert( ! eq_comparable_val<A, int> ); +static_assert( eq_comparable_val<int, int, A> ); +static_assert( ! eq_comparable_val<void, A> ); + +static_assert( ! eq_comparable_val<B> ); +static_assert( ! eq_comparable_val<B, B> ); +static_assert( ! eq_comparable_val<B, int> ); +static_assert( eq_comparable_val<int, int, B> ); +static_assert( ! eq_comparable_val<void, B> ); + +static_assert( eq_comparable_val<C> ); +static_assert( eq_comparable_val<C, C> ); +static_assert( eq_comparable_val<C, C> ); +static_assert( eq_comparable_val<C, C, C> ); +static_assert( eq_comparable_val<int, int, C> ); +static_assert( eq_comparable_val<C, C, A> ); +static_assert( ! eq_comparable_val<void, C> ); + +static_assert( eq_comparable_val<D> ); +static_assert( eq_comparable_val<D, D> ); +static_assert( ! eq_comparable_val<D, int> ); +static_assert( eq_comparable_val<int, int, D> ); +static_assert( eq_comparable_val<D, D, D> ); + +static_assert( ! eq_comparable_val<E> ); +static_assert( ! eq_comparable_val<E, E> ); +static_assert( ! eq_comparable_val<E, int> ); +static_assert( eq_comparable_val<int, int, E> ); + +static_assert( eq_comparable_val<A, B> ); +static_assert( eq_comparable_val<B, A> ); + +static_assert( eq_comparable_val<C, D> ); +static_assert( ! eq_comparable_val<D, C> ); + +template<typename E, typename U, typename T = int> +concept eq_comparable_unex += requires (const std::expected<T, E>& t, const std::unexpected<U>& u) { + t == u; +}; + +static_assert( eq_comparable_unex<int, int> ); +static_assert( eq_comparable_unex<int, long> ); +static_assert( eq_comparable_unex<short, int> ); +static_assert( eq_comparable_unex<int, int, void> ); +static_assert( eq_comparable_unex<int, long, void> ); +static_assert( eq_comparable_unex<short, int, void> ); + +static_assert( ! eq_comparable_unex<A, A> ); +static_assert( ! eq_comparable_unex<A, int> ); +static_assert( ! eq_comparable_unex<int, A> ); +static_assert( ! eq_comparable_unex<A, A, void> ); +static_assert( ! eq_comparable_unex<A, int, void> ); +static_assert( ! eq_comparable_unex<int, A, void> ); + +static_assert( ! eq_comparable_unex<B, B> ); +static_assert( ! eq_comparable_unex<B, int> ); +static_assert( ! eq_comparable_unex<int, B> ); +static_assert( ! eq_comparable_unex<B, B, void> ); +static_assert( ! eq_comparable_unex<B, int, void> ); +static_assert( ! eq_comparable_unex<int, B, void> ); + +static_assert( eq_comparable_unex<C, C> ); +static_assert( eq_comparable_unex<C, C, void> ); + +static_assert( eq_comparable_unex<D, D> ); +static_assert( ! eq_comparable_unex<D, int> ); +static_assert( ! eq_comparable_unex<int, D> ); +static_assert( eq_comparable_unex<D, D, void> ); +static_assert( ! eq_comparable_unex<D, int, void> ); +static_assert( ! eq_comparable_unex<int, D, void> ); + +static_assert( ! eq_comparable_unex<E, E> ); +static_assert( ! eq_comparable_unex<E, int> ); +static_assert( ! eq_comparable_unex<int, E> ); +static_assert( ! eq_comparable_unex<E, E, void> ); +static_assert( ! eq_comparable_unex<E, int, void> ); +static_assert( ! eq_comparable_unex<int, E, void> ); + +static_assert( eq_comparable_unex<A, B> ); +static_assert( eq_comparable_unex<B, A> ); +static_assert( eq_comparable_unex<A, B, void> ); +static_assert( eq_comparable_unex<B, A, void> ); + +static_assert( eq_comparable_unex<C, D> ); +static_assert( ! eq_comparable_unex<D, C> ); +static_assert( eq_comparable_unex<C, D, void> ); +static_assert( ! eq_comparable_unex<D, C, void> ); diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc index 0e325618008..3e393257928 100644 --- a/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc +++ b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc @@ -4,7 +4,7 @@ #ifndef __cpp_lib_constrained_equality # error "Feature-test macro for constrained_equality missing" -#elif __cpp_lib_constrained_equality != 202403 +#elif __cpp_lib_constrained_equality < 202403L # error "Feature-test macro for constrained_equality has wrong value" #endif diff --git a/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc b/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc index a35dbd265a7..dabe35ff746 100644 --- a/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc +++ b/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc @@ -4,7 +4,7 @@ #ifndef __cpp_lib_constrained_equality # error "Feature-test macro for constrained_equality missing" -#elif __cpp_lib_constrained_equality != 202403 +#elif __cpp_lib_constrained_equality < 202403L # error "Feature-test macro for constrained_equality has wrong value" #endif diff --git a/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc index 47035ab18ba..994d4a491a1 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc @@ -4,7 +4,7 @@ #ifndef __cpp_lib_constrained_equality # error "Feature-test macro for constrained_equality missing" -#elif __cpp_lib_constrained_equality != 202403 +#elif __cpp_lib_constrained_equality < 202403L # error "Feature-test macro for constrained_equality has wrong value" #endif diff --git a/libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc b/libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc index 95e8f754d1e..fbe10e0ba03 100644 --- a/libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc +++ b/libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc @@ -4,7 +4,7 @@ #ifndef __cpp_lib_constrained_equality # error "Feature-test macro for constrained_equality missing" -#elif __cpp_lib_constrained_equality != 202403 +#elif __cpp_lib_constrained_equality < 202403L # error "Feature-test macro for constrained_equality has wrong value" #endif -- 2.46.2