From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id B073D3858D38; Tue, 6 Jun 2023 22:58:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B073D3858D38 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1686092310; bh=/3T3A9gRcttOTF/17PltLAcjyZvoyr1Tohg2wyA59Rc=; h=From:To:Subject:Date:From; b=lJmC8Reikg1VaTTOuswe9zxyXslhwfAssK6GKr0ag8Oz2zVd9uPG99lrT7fpUdd4c d8J4TqxPoj5iHLueC+X9/ksdn36gS9IuIrsFr07hf8H8nhcqmFkBA0B70EXx6CqPSp f5xLvKr4br+DZLQ3jBvSUR0b4dvuK+YpFbyFQ9T4= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-7422] libstdc++: Implement LWG 3877 for std::expected monadic ops X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/releases/gcc-13 X-Git-Oldrev: 044ee48215fd7eca1f1680758cd27574ff274417 X-Git-Newrev: b14121a2ac6dc36dcd3053f8a672ec3bb7ab6695 Message-Id: <20230606225830.B073D3858D38@sourceware.org> Date: Tue, 6 Jun 2023 22:58:30 +0000 (GMT) List-Id: https://gcc.gnu.org/g:b14121a2ac6dc36dcd3053f8a672ec3bb7ab6695 commit r13-7422-gb14121a2ac6dc36dcd3053f8a672ec3bb7ab6695 Author: Jonathan Wakely Date: Tue May 16 22:40:42 2023 +0100 libstdc++: Implement LWG 3877 for std::expected monadic ops This was approved in Issaquah 2023. As well as fixing the value categories, this fixes the fact that we were incorrectly testing E instead of T in the or_else constraints. libstdc++-v3/ChangeLog: * include/std/expected (expected::and_then, expected::or_else) (expected::transform, expected::transform_error): Fix exception specifications as per LWG 3877. (expected::and_then, expected::transform): Likewise. * testsuite/20_util/expected/lwg3877.cc: New test. (cherry picked from commit ba490492e51834db645a3165d14f2ba0af62a8c7) Diff: --- libstdc++-v3/include/std/expected | 48 ++++++++-------- libstdc++-v3/testsuite/20_util/expected/lwg3877.cc | 64 ++++++++++++++++++++++ 2 files changed, 88 insertions(+), 24 deletions(-) diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected index c6d26b0d224..5ea0d6a7cb9 100644 --- a/libstdc++-v3/include/std/expected +++ b/libstdc++-v3/include/std/expected @@ -840,7 +840,7 @@ namespace __expected // monadic operations - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Er, _Er&> constexpr auto and_then(_Fn&& __f) & { @@ -854,7 +854,7 @@ namespace __expected return _Up(unexpect, error()); } - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Er, const _Er&> constexpr auto and_then(_Fn&& __f) const & { @@ -868,7 +868,7 @@ namespace __expected return _Up(unexpect, error()); } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Er, _Er> constexpr auto and_then(_Fn&& __f) && { @@ -883,7 +883,7 @@ namespace __expected } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Er, const _Er> constexpr auto and_then(_Fn&& __f) const && { @@ -897,7 +897,7 @@ namespace __expected return _Up(unexpect, std::move(error())); } - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Tp, _Tp&> constexpr auto or_else(_Fn&& __f) & { @@ -911,7 +911,7 @@ namespace __expected return std::__invoke(std::forward<_Fn>(__f), error()); } - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Tp, const _Tp&> constexpr auto or_else(_Fn&& __f) const & { @@ -926,7 +926,7 @@ namespace __expected } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Tp, _Tp> constexpr auto or_else(_Fn&& __f) && { @@ -940,7 +940,7 @@ namespace __expected return std::__invoke(std::forward<_Fn>(__f), std::move(error())); } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Tp, const _Tp> constexpr auto or_else(_Fn&& __f) const && { @@ -954,7 +954,7 @@ namespace __expected return std::__invoke(std::forward<_Fn>(__f), std::move(error())); } - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Er, _Er&> constexpr auto transform(_Fn&& __f) & { @@ -970,7 +970,7 @@ namespace __expected return _Res(unexpect, std::move(error())); } - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Er, const _Er&> constexpr auto transform(_Fn&& __f) const & { @@ -986,7 +986,7 @@ namespace __expected return _Res(unexpect, std::move(error())); } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Er, _Er> constexpr auto transform(_Fn&& __f) && { @@ -1002,7 +1002,7 @@ namespace __expected return _Res(unexpect, std::move(error())); } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Er, const _Er> constexpr auto transform(_Fn&& __f) const && { @@ -1018,7 +1018,7 @@ namespace __expected return _Res(unexpect, std::move(error())); } - template requires is_copy_constructible_v<_Tp> + template requires is_constructible_v<_Tp, _Tp&> constexpr auto transform_error(_Fn&& __f) & { @@ -1034,7 +1034,7 @@ namespace __expected }); } - template requires is_copy_constructible_v<_Tp> + template requires is_constructible_v<_Tp, const _Tp&> constexpr auto transform_error(_Fn&& __f) const & { @@ -1050,7 +1050,7 @@ namespace __expected }); } - template requires is_move_constructible_v<_Tp> + template requires is_constructible_v<_Tp, _Tp> constexpr auto transform_error(_Fn&& __f) && { @@ -1066,7 +1066,7 @@ namespace __expected }); } - template requires is_move_constructible_v<_Tp> + template requires is_constructible_v<_Tp, const _Tp> constexpr auto transform_error(_Fn&& __f) const && { @@ -1519,7 +1519,7 @@ namespace __expected // monadic operations - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Er, _Er&> constexpr auto and_then(_Fn&& __f) & { @@ -1533,7 +1533,7 @@ namespace __expected return _Up(unexpect, error()); } - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Er, const _Er&> constexpr auto and_then(_Fn&& __f) const & { @@ -1547,7 +1547,7 @@ namespace __expected return _Up(unexpect, error()); } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Er, _Er> constexpr auto and_then(_Fn&& __f) && { @@ -1561,7 +1561,7 @@ namespace __expected return _Up(unexpect, std::move(error())); } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Er, const _Er> constexpr auto and_then(_Fn&& __f) const && { @@ -1631,7 +1631,7 @@ namespace __expected return std::__invoke(std::forward<_Fn>(__f), std::move(error())); } - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Er, _Er&> constexpr auto transform(_Fn&& __f) & { @@ -1644,7 +1644,7 @@ namespace __expected return _Res(unexpect, error()); } - template requires is_copy_constructible_v<_Er> + template requires is_constructible_v<_Er, const _Er&> constexpr auto transform(_Fn&& __f) const & { @@ -1657,7 +1657,7 @@ namespace __expected return _Res(unexpect, error()); } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Er, _Er> constexpr auto transform(_Fn&& __f) && { @@ -1670,7 +1670,7 @@ namespace __expected return _Res(unexpect, std::move(error())); } - template requires is_move_constructible_v<_Er> + template requires is_constructible_v<_Er, const _Er> constexpr auto transform(_Fn&& __f) const && { diff --git a/libstdc++-v3/testsuite/20_util/expected/lwg3877.cc b/libstdc++-v3/testsuite/20_util/expected/lwg3877.cc new file mode 100644 index 00000000000..556d8d5dc9e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/expected/lwg3877.cc @@ -0,0 +1,64 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include + +struct T1 +{ +}; + +struct T2 +{ + T2(const T2&) = delete; +}; + +struct T3 +{ + T3(const T3&) = delete; + T3(T3&&) = delete; + T3(T3&) { } + T3(const T3&&) { } +}; + +template +concept Has_or_else = requires(Exp&& exp, F f) { + std::forward(exp).or_else(f); +}; + +using E1 = std::expected; +static_assert( Has_or_else ); +static_assert( Has_or_else ); +static_assert( Has_or_else ); +static_assert( Has_or_else ); + +using E2 = std::expected; +static_assert( !Has_or_else ); +static_assert( !Has_or_else ); +static_assert( !Has_or_else ); +static_assert( !Has_or_else ); + +using E3 = std::expected; +static_assert( Has_or_else ); +static_assert( !Has_or_else ); +static_assert( Has_or_else ); // uses or_else(F) const && +static_assert( Has_or_else ); + +template +concept Has_transform_error = requires(Exp&& exp, F f) { + std::forward(exp).transform_error(f); +}; + +static_assert( Has_transform_error ); +static_assert( Has_transform_error ); +static_assert( Has_transform_error ); +static_assert( Has_transform_error ); + +static_assert( !Has_transform_error ); +static_assert( !Has_transform_error ); +static_assert( !Has_transform_error ); +static_assert( !Has_transform_error ); + +static_assert( Has_transform_error ); +static_assert( !Has_transform_error ); +static_assert( Has_transform_error ); // uses transform_error(F) const && +static_assert( Has_transform_error );