public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Jonathan Wakely <redi@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org
Subject: [gcc r13-7422] libstdc++: Implement LWG 3877 for std::expected monadic ops
Date: Tue,  6 Jun 2023 22:58:30 +0000 (GMT)	[thread overview]
Message-ID: <20230606225830.B073D3858D38@sourceware.org> (raw)

https://gcc.gnu.org/g:b14121a2ac6dc36dcd3053f8a672ec3bb7ab6695

commit r13-7422-gb14121a2ac6dc36dcd3053f8a672ec3bb7ab6695
Author: Jonathan Wakely <jwakely@redhat.com>
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<void, E>::and_then, expected<void, E>::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<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Er, _Er&>
 	constexpr auto
 	and_then(_Fn&& __f) &
 	{
@@ -854,7 +854,7 @@ namespace __expected
 	    return _Up(unexpect, error());
 	}
 
-      template<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> 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<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Er, _Er>
 	constexpr auto
 	and_then(_Fn&& __f) &&
 	{
@@ -883,7 +883,7 @@ namespace __expected
 	}
 
 
-      template<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> 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<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> 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<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Tp, const _Tp&>
 	constexpr auto
 	or_else(_Fn&& __f) const &
 	{
@@ -926,7 +926,7 @@ namespace __expected
 	}
 
 
-      template<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> 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<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> 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<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Er, _Er&>
 	constexpr auto
 	transform(_Fn&& __f) &
 	{
@@ -970,7 +970,7 @@ namespace __expected
 	    return _Res(unexpect, std::move(error()));
 	}
 
-      template<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> 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<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Er, _Er>
 	constexpr auto
 	transform(_Fn&& __f) &&
 	{
@@ -1002,7 +1002,7 @@ namespace __expected
 	    return _Res(unexpect, std::move(error()));
 	}
 
-      template<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> 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<typename _Fn> requires is_copy_constructible_v<_Tp>
+      template<typename _Fn> requires is_constructible_v<_Tp, _Tp&>
 	constexpr auto
 	transform_error(_Fn&& __f) &
 	{
@@ -1034,7 +1034,7 @@ namespace __expected
 			});
 	}
 
-      template<typename _Fn> requires is_copy_constructible_v<_Tp>
+      template<typename _Fn> requires is_constructible_v<_Tp, const _Tp&>
 	constexpr auto
 	transform_error(_Fn&& __f) const &
 	{
@@ -1050,7 +1050,7 @@ namespace __expected
 			});
 	}
 
-      template<typename _Fn> requires is_move_constructible_v<_Tp>
+      template<typename _Fn> requires is_constructible_v<_Tp, _Tp>
 	constexpr auto
 	transform_error(_Fn&& __f) &&
 	{
@@ -1066,7 +1066,7 @@ namespace __expected
 			});
 	}
 
-      template<typename _Fn> requires is_move_constructible_v<_Tp>
+      template<typename _Fn> requires is_constructible_v<_Tp, const _Tp>
 	constexpr auto
 	transform_error(_Fn&& __f) const &&
 	{
@@ -1519,7 +1519,7 @@ namespace __expected
 
       // monadic operations
 
-      template<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Er, _Er&>
 	constexpr auto
 	and_then(_Fn&& __f) &
 	{
@@ -1533,7 +1533,7 @@ namespace __expected
 	    return _Up(unexpect, error());
 	}
 
-     template<typename _Fn> requires is_copy_constructible_v<_Er>
+     template<typename _Fn> 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<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> 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<typename _Fn> requires is_move_constructible_v<_Er>
+       template<typename _Fn> 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<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Er, _Er&>
 	constexpr auto
 	transform(_Fn&& __f) &
 	{
@@ -1644,7 +1644,7 @@ namespace __expected
 	    return _Res(unexpect, error());
 	}
 
-      template<typename _Fn> requires is_copy_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
 	constexpr auto
 	transform(_Fn&& __f) const &
 	{
@@ -1657,7 +1657,7 @@ namespace __expected
 	    return _Res(unexpect, error());
 	}
 
-      template<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> requires is_constructible_v<_Er, _Er>
 	constexpr auto
 	transform(_Fn&& __f) &&
 	{
@@ -1670,7 +1670,7 @@ namespace __expected
 	    return _Res(unexpect, std::move(error()));
 	}
 
-      template<typename _Fn> requires is_move_constructible_v<_Er>
+      template<typename _Fn> 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 <expected>
+
+struct T1
+{
+};
+
+struct T2
+{
+  T2(const T2&) = delete;
+};
+
+struct T3
+{
+  T3(const T3&) = delete;
+  T3(T3&&) = delete;
+  T3(T3&) { }
+  T3(const T3&&) { }
+};
+
+template<typename Exp, typename F>
+concept Has_or_else = requires(Exp&& exp, F f) {
+  std::forward<Exp>(exp).or_else(f);
+};
+
+using E1 = std::expected<T1, int>;
+static_assert( Has_or_else<E1&, E1(int)> );
+static_assert( Has_or_else<const E1&, E1(int)> );
+static_assert( Has_or_else<E1&&, E1(int)> );
+static_assert( Has_or_else<const E1&&, E1(int)> );
+
+using E2 = std::expected<T2, int>;
+static_assert( !Has_or_else<E2&, E2(int)> );
+static_assert( !Has_or_else<const E2&, E2(int)> );
+static_assert( !Has_or_else<E2&&, E2(int)> );
+static_assert( !Has_or_else<const E2&&, E2(int)> );
+
+using E3 = std::expected<T3, int>;
+static_assert( Has_or_else<E3&, E3(int)> );
+static_assert( !Has_or_else<const E3&, E3(int)> );
+static_assert( Has_or_else<E3&&, E3(int)> ); // uses or_else(F) const &&
+static_assert( Has_or_else<const E3&&, E3(int)> );
+
+template<typename Exp, typename F>
+concept Has_transform_error = requires(Exp&& exp, F f) {
+  std::forward<Exp>(exp).transform_error(f);
+};
+
+static_assert( Has_transform_error<E1&, int(int)> );
+static_assert( Has_transform_error<const E1&, int(int)> );
+static_assert( Has_transform_error<E1&&, int(int)> );
+static_assert( Has_transform_error<const E1&&, int(int)> );
+
+static_assert( !Has_transform_error<E2&, int(int)> );
+static_assert( !Has_transform_error<const E2&, int(int)> );
+static_assert( !Has_transform_error<E2&&, int(int)> );
+static_assert( !Has_transform_error<const E2&&, int(int)> );
+
+static_assert( Has_transform_error<E3&, int(int)> );
+static_assert( !Has_transform_error<const E3&, int(int)> );
+static_assert( Has_transform_error<E3&&, int(int)> ); // uses transform_error(F) const &&
+static_assert( Has_transform_error<const E3&&, int(int)> );

                 reply	other threads:[~2023-06-06 22:58 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230606225830.B073D3858D38@sourceware.org \
    --to=redi@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    --cc=libstdc++-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).