From: Jonathan Wakely Date: Wed, 28 Aug 2024 11:01:18 +0000 (+0100) Subject: libstdc++: Constrain std::expected comparisons (P3379R0) X-Git-Tag: basepoints/gcc-16~5216 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0515b2436b7c7e5e391eae7edc42173c52bab61d;p=thirdparty%2Fgcc.git libstdc++: Constrain std::expected comparisons (P3379R0) 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. --- diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 477651f358a2..4fa820a5a4ab 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 342ee6b4c7a0..fdbee8161d9e 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 d4a4bc175415..7de2aeffc70c 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 #ifdef __cpp_lib_expected // C++ >= 23 && __cpp_concepts >= 202002L @@ -1152,10 +1153,15 @@ namespace __expected template requires (!is_void_v<_Up>) + && requires (const _Tp& __t, const _Up& __u, + const _Er& __e, const _Er2& __e2) { + { __t == __u } -> convertible_to; + { __e == __e2 } -> convertible_to; + } 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 + requires (!__expected::__is_expected<_Up>) + && requires (const _Tp& __t, const _Up& __u) { + { __t == __u } -> convertible_to; + } 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 + requires requires (const _Er& __e, const _Er2& __e2) { + { __e == __e2 } -> convertible_to; + } 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 requires is_void_v<_Up> + && requires (const _Er& __e, const _Er2& __e2) { + { __e == __e2 } -> convertible_to; + } 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 + requires requires (const _Er& __e, const _Er2& __e2) { + { __e == __e2 } -> convertible_to; + } 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 000000000000..7f6cefae7487 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc @@ -0,0 +1,181 @@ +// { dg-do compile { target c++23 } } + +#include + +#ifndef __cpp_lib_constrained_equality +# error "Feature-test macro for constrained_equality missing in " +#elif __cpp_lib_constrained_equality < 202411L // TODO: use final value +# error "Feature-test macro for constrained_equality has wrong value" +#endif + +template +concept eq_comparable += requires (const std::expected& t, const std::expected& u) { + t == u; +}; + +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); + +struct A { }; +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); + +struct B { }; +void operator==(B, B); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); + +struct C { }; +bool operator==(C, C); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( eq_comparable ); + +struct D { }; +int operator==(D, D); +bool operator!=(D, D) = delete; +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( ! eq_comparable ); + +struct E { }; +bool operator==(/* not-const */ E&, const E&); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); + +bool operator==(A, B); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); + +int operator==(C, D); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( eq_comparable ); + +template +concept eq_comparable_val += requires (const std::expected& t, const U& u) { + t == u; +}; + +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( ! eq_comparable_val ); + +static_assert( ! eq_comparable_val ); +static_assert( ! eq_comparable_val ); +static_assert( ! eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( ! eq_comparable_val ); + +static_assert( ! eq_comparable_val ); +static_assert( ! eq_comparable_val ); +static_assert( ! eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( ! eq_comparable_val ); + +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( ! eq_comparable_val ); + +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( ! eq_comparable_val ); +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); + +static_assert( ! eq_comparable_val ); +static_assert( ! eq_comparable_val ); +static_assert( ! eq_comparable_val ); +static_assert( eq_comparable_val ); + +static_assert( eq_comparable_val ); +static_assert( eq_comparable_val ); + +static_assert( eq_comparable_val ); +static_assert( ! eq_comparable_val ); + +template +concept eq_comparable_unex += requires (const std::expected& t, const std::unexpected& u) { + t == u; +}; + +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); + +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); + +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); + +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); + +static_assert( eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); + +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); + +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); +static_assert( eq_comparable_unex ); + +static_assert( eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); +static_assert( eq_comparable_unex ); +static_assert( ! eq_comparable_unex ); diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc index 0e3256180084..3e3932579286 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 a35dbd265a78..dabe35ff7469 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 47035ab18bab..994d4a491a1a 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 95e8f754d1ed..fbe10e0ba03d 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