public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-3768] libstdc++: Relax range adaptors for move-only types (P2494R2)
@ 2023-09-07  7:11 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2023-09-07  7:11 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:9f41791eff82d5f41f16204cf092b7888b6c7a8d

commit r14-3768-g9f41791eff82d5f41f16204cf092b7888b6c7a8d
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Sep 5 22:07:22 2023 +0100

    libstdc++: Relax range adaptors for move-only types (P2494R2)
    
    This is a C++23 feature that relaxes the constraints on some range
    adaptors, to support move-only types.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/version.def (ranges): Update value.
            * include/bits/version.h: Regenerate.
            * include/std/ranges (__detail::__boxable): Use
            move_constructible instead of copy_constructible for C++23.
            (__detail::__box<T>): Adjust constraints for partial
            specialization.
            (single_view, transform_view): Use __box_constructible instead
            of copy_constructible in constraints.
            (zip_transform_view, adjacent_transform_view, repeat_view): Use
            move_constructible instead of copy_constructible in constraints.
            * testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Check
            construction from move-only argument.
            * testsuite/std/ranges/adaptors/transform.cc: Likewise.
            * testsuite/std/ranges/repeat/1.cc: Likewise.
            * testsuite/std/ranges/single_view.cc: Likewise.
            * testsuite/std/ranges/zip_transform/1.cc: Likewise.
            * testsuite/std/ranges/version_c++23.cc: Adjust expected value
            of __cpp_lib_ranges.

Diff:
---
 libstdc++-v3/include/bits/version.def              |  2 +-
 libstdc++-v3/include/bits/version.h                |  4 +-
 libstdc++-v3/include/std/ranges                    | 72 +++++++++++++++-------
 .../std/ranges/adaptors/adjacent_transform/1.cc    | 14 +++++
 .../testsuite/std/ranges/adaptors/transform.cc     | 19 ++++++
 libstdc++-v3/testsuite/std/ranges/repeat/1.cc      | 12 ++++
 libstdc++-v3/testsuite/std/ranges/single_view.cc   | 17 +++++
 libstdc++-v3/testsuite/std/ranges/version_c++23.cc |  2 +-
 .../testsuite/std/ranges/zip_transform/1.cc        | 14 +++++
 9 files changed, 131 insertions(+), 25 deletions(-)

diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 80c13d4a447e..44b916e38974 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1045,7 +1045,7 @@ ftms = {
 ftms = {
   name = ranges;
   values = {
-    v = 202202;
+    v = 202207;
     cxxmin = 23;
     extra_cond = "__glibcxx_concepts";
   };
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 5bddb4b8adc6..9fada98eee3f 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1290,9 +1290,9 @@
 // from version.def line 1046
 #if !defined(__cpp_lib_ranges)
 # if (__cplusplus >= 202302L) && (__glibcxx_concepts)
-#  define __glibcxx_ranges 202202L
+#  define __glibcxx_ranges 202207L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges)
-#   define __cpp_lib_ranges 202202L
+#   define __cpp_lib_ranges 202207L
 #  endif
 # elif (__cplusplus >= 202002L) && (__glibcxx_concepts)
 #  define __glibcxx_ranges 202110L
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 3477323d8711..1d529a886bec 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -106,8 +106,14 @@ namespace ranges
 
   namespace __detail
   {
+#if __cpp_lib_ranges >= 202207L // C++ >= 23
+    // P2494R2 Relaxing range adaptors to allow for move only types
+    template<typename _Tp>
+      concept __boxable = move_constructible<_Tp> && is_object_v<_Tp>;
+#else
     template<typename _Tp>
       concept __boxable = copy_constructible<_Tp> && is_object_v<_Tp>;
+#endif
 
     template<__boxable _Tp>
       struct __box : std::optional<_Tp>
@@ -132,7 +138,7 @@ namespace ranges
 	constexpr __box&
 	operator=(const __box& __that)
 	noexcept(is_nothrow_copy_constructible_v<_Tp>)
-	requires (!copyable<_Tp>)
+	requires (!copyable<_Tp>) && copy_constructible<_Tp>
 	{
 	  if (this != std::__addressof(__that))
 	    {
@@ -160,13 +166,22 @@ namespace ranges
 	}
       };
 
-    // For types which are already copyable, this specialization of the
-    // copyable wrapper stores the object directly without going through
-    // std::optional.  It provides just the subset of the primary template's
-    // API that we currently use.
+    template<typename _Tp>
+      concept __boxable_copyable
+	= copy_constructible<_Tp>
+	    && (copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp>
+				    && is_nothrow_copy_constructible_v<_Tp>));
+    template<typename _Tp>
+      concept __boxable_movable
+	= (!copy_constructible<_Tp>)
+	    && (movable<_Tp> || is_nothrow_move_constructible_v<_Tp>);
+
+    // For types which are already copyable (or since C++23, movable)
+    // this specialization of the box wrapper stores the object directly
+    // without going through std::optional.  It provides just the subset of
+    // the primary template's API that we currently use.
     template<__boxable _Tp>
-      requires copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp>
-				 && is_nothrow_copy_constructible_v<_Tp>)
+      requires __boxable_copyable<_Tp> || __boxable_movable<_Tp>
       struct __box<_Tp>
       {
       private:
@@ -178,6 +193,7 @@ namespace ranges
 	constexpr explicit
 	__box(const _Tp& __t)
 	noexcept(is_nothrow_copy_constructible_v<_Tp>)
+	requires copy_constructible<_Tp>
 	: _M_value(__t)
 	{ }
 
@@ -198,12 +214,13 @@ namespace ranges
 	__box(const __box&) = default;
 	__box(__box&&) = default;
 	__box& operator=(const __box&) requires copyable<_Tp> = default;
-	__box& operator=(__box&&) requires copyable<_Tp> = default;
+	__box& operator=(__box&&) requires movable<_Tp> = default;
 
 	// When _Tp is nothrow_copy_constructible but not copy_assignable,
 	// copy assignment is implemented via destroy-then-copy-construct.
 	constexpr __box&
 	operator=(const __box& __that) noexcept
+	requires (!copyable<_Tp>) && copy_constructible<_Tp>
 	{
 	  static_assert(is_nothrow_copy_constructible_v<_Tp>);
 	  if (this != std::__addressof(__that))
@@ -217,6 +234,7 @@ namespace ranges
 	// Likewise for move assignment.
 	constexpr __box&
 	operator=(__box&& __that) noexcept
+	requires (!movable<_Tp>)
 	{
 	  static_assert(is_nothrow_move_constructible_v<_Tp>);
 	  if (this != std::__addressof(__that))
@@ -250,7 +268,12 @@ namespace ranges
   } // namespace __detail
 
   /// A view that contains exactly one element.
-  template<copy_constructible _Tp> requires is_object_v<_Tp>
+#if __cpp_lib_ranges >= 202207L // C++ >= 23
+  template<move_constructible _Tp>
+#else
+  template<copy_constructible _Tp>
+#endif
+    requires is_object_v<_Tp>
     class single_view : public view_interface<single_view<_Tp>>
     {
     public:
@@ -259,6 +282,7 @@ namespace ranges
       constexpr explicit
       single_view(const _Tp& __t)
       noexcept(is_nothrow_copy_constructible_v<_Tp>)
+      requires copy_constructible<_Tp>
       : _M_value(__t)
       { }
 
@@ -1147,7 +1171,8 @@ namespace views::__adaptor
     };
 } // namespace views::__adaptor
 
-#if __cplusplus > 202002L
+#if __cpp_lib_ranges >= 202202L
+  // P2387R3 Pipe support for user-defined range adaptors
   template<typename _Derived>
     requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
     class range_adaptor_closure
@@ -1751,7 +1776,11 @@ namespace views::__adaptor
     inline constexpr _Filter filter;
   } // namespace views
 
+#if __cpp_lib_ranges >= 202207L // C++ >= 23
+  template<input_range _Vp, move_constructible _Fp>
+#else
   template<input_range _Vp, copy_constructible _Fp>
+#endif
     requires view<_Vp> && is_object_v<_Fp>
       && regular_invocable<_Fp&, range_reference_t<_Vp>>
       && std::__detail::__can_reference<invoke_result_t<_Fp&,
@@ -4623,7 +4652,7 @@ namespace views::__adaptor
 	return input_iterator_tag{};
     }
 
-    template<copy_constructible _Fp, input_range... _Ws>
+    template<move_constructible _Fp, input_range... _Ws>
       requires (view<_Ws> && ...) && (sizeof...(_Ws) > 0) && is_object_v<_Fp>
 	&& regular_invocable<_Fp&, range_reference_t<_Ws>...>
 	&& std::__detail::__can_reference<invoke_result_t<_Fp&, range_reference_t<_Ws>...>>
@@ -4894,7 +4923,7 @@ namespace views::__adaptor
 	= typename iterator_traits<iterator_t<__maybe_const_t<_Const, _Range>>>::iterator_category;
   }
 
-  template<copy_constructible _Fp, input_range... _Vs>
+  template<move_constructible _Fp, input_range... _Vs>
     requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) && is_object_v<_Fp>
       && regular_invocable<_Fp&, range_reference_t<_Vs>...>
       && std::__detail::__can_reference<invoke_result_t<_Fp&, range_reference_t<_Vs>...>>
@@ -5001,7 +5030,7 @@ namespace views::__adaptor
   template<class _Fp, class... Rs>
     zip_transform_view(_Fp, Rs&&...) -> zip_transform_view<_Fp, views::all_t<Rs>...>;
 
-  template<copy_constructible _Fp, input_range... _Vs>
+  template<move_constructible _Fp, input_range... _Vs>
     requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) && is_object_v<_Fp>
       && regular_invocable<_Fp&, range_reference_t<_Vs>...>
       && std::__detail::__can_reference<invoke_result_t<_Fp&, range_reference_t<_Vs>...>>
@@ -5131,7 +5160,7 @@ namespace views::__adaptor
     { return __x._M_inner - __y._M_inner; }
   };
 
-  template<copy_constructible _Fp, input_range... _Vs>
+  template<move_constructible _Fp, input_range... _Vs>
     requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) && is_object_v<_Fp>
       && regular_invocable<_Fp&, range_reference_t<_Vs>...>
       && std::__detail::__can_reference<invoke_result_t<_Fp&, range_reference_t<_Vs>...>>
@@ -5338,7 +5367,7 @@ namespace views::__adaptor
 
     friend class adjacent_view;
 
-    template<forward_range _Wp, copy_constructible _Fp, size_t _Mm>
+    template<forward_range _Wp, move_constructible _Fp, size_t _Mm>
       requires view<_Wp> && (_Mm > 0) && is_object_v<_Fp>
         && regular_invocable<__detail::__unarize<_Fp&, _Mm>, range_reference_t<_Wp>>
         && std::__detail::__can_reference<invoke_result_t<__detail::__unarize<_Fp&, _Mm>,
@@ -5580,7 +5609,7 @@ namespace views::__adaptor
     inline constexpr auto pairwise = adjacent<2>;
   }
 
-  template<forward_range _Vp, copy_constructible _Fp, size_t _Nm>
+  template<forward_range _Vp, move_constructible _Fp, size_t _Nm>
    requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
      && regular_invocable<__detail::__unarize<_Fp&, _Nm>, range_reference_t<_Vp>>
      && std::__detail::__can_reference<invoke_result_t<__detail::__unarize<_Fp&, _Nm>,
@@ -5650,7 +5679,7 @@ namespace views::__adaptor
     { return _M_inner.size(); }
   };
 
-  template<forward_range _Vp, copy_constructible _Fp, size_t _Nm>
+  template<forward_range _Vp, move_constructible _Fp, size_t _Nm>
    requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
      && regular_invocable<__detail::__unarize<_Fp&, _Nm>, range_reference_t<_Vp>>
      && std::__detail::__can_reference<invoke_result_t<__detail::__unarize<_Fp&, _Nm>,
@@ -5819,7 +5848,7 @@ namespace views::__adaptor
     { return __x._M_inner - __y._M_inner; }
   };
 
-  template<forward_range _Vp, copy_constructible _Fp, size_t _Nm>
+  template<forward_range _Vp, move_constructible _Fp, size_t _Nm>
    requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
      && regular_invocable<__detail::__unarize<_Fp&, _Nm>, range_reference_t<_Vp>>
      && std::__detail::__can_reference<invoke_result_t<__detail::__unarize<_Fp&, _Nm>,
@@ -7528,8 +7557,8 @@ namespace views::__adaptor
   } // namespace views
 #endif // __cpp_lib_ranges_join_with
 
-#ifdef __cpp_lib_ranges_repeat // C++ >= 32
-  template<copy_constructible _Tp, semiregular _Bound = unreachable_sentinel_t>
+#ifdef __cpp_lib_ranges_repeat // C++ >= 23
+  template<move_constructible _Tp, semiregular _Bound = unreachable_sentinel_t>
     requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
       && (__detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>)
   class repeat_view : public view_interface<repeat_view<_Tp, _Bound>>
@@ -7552,6 +7581,7 @@ namespace views::__adaptor
 
     constexpr explicit
     repeat_view(const _Tp& __value, _Bound __bound = _Bound())
+    requires copy_constructible<_Tp>
     : _M_value(__value), _M_bound(__bound)
     {
       if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
@@ -7594,7 +7624,7 @@ namespace views::__adaptor
   template<typename _Tp, typename _Bound>
     repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>;
 
-  template<copy_constructible _Tp, semiregular _Bound>
+  template<move_constructible _Tp, semiregular _Bound>
     requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
       && (__detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>)
   class repeat_view<_Tp, _Bound>::_Iterator
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
index 07f20b702dd2..c32c639e8154 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
@@ -97,10 +97,24 @@ test03()
   return true;
 }
 
+void
+test04()
+{
+  extern int x[5];
+  struct move_only {
+    move_only() { }
+    move_only(move_only&&) { }
+    int operator()(int i, int j) const { return i + j; }
+  };
+  // P2494R2 Relaxing range adaptors to allow for move only types
+  static_assert( requires { views::pairwise_transform(x, move_only{}); } );
+}
+
 int
 main()
 {
   static_assert(test01());
   static_assert(test02());
   static_assert(test03());
+  test04();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
index e89ae4f9f3f2..9d52cb01dadb 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
@@ -175,6 +175,24 @@ test08()
   static_assert(!requires { views::all | transform; });
 }
 
+template<auto transform = views::transform>
+void
+test09()
+{
+  extern int x[5];
+  struct move_only {
+    move_only() { }
+    move_only(move_only&&) { }
+    int operator()(int i) const { return i; }
+  };
+#if __cpp_lib_ranges >= 202207L
+  // P2494R2 Relaxing range adaptors to allow for move only types
+  static_assert( requires { transform(x, move_only{}); } );
+#else
+  static_assert( ! requires { transform(x, move_only{}); } );
+#endif
+}
+
 int
 main()
 {
@@ -186,4 +204,5 @@ main()
   test06();
   test07();
   test08();
+  test09();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
index 07b70891042c..c62122c078f3 100644
--- a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
@@ -127,6 +127,17 @@ test05()
   ranges::repeat_view<int> r;
 }
 
+void
+test06()
+{
+  struct move_only {
+    move_only() { }
+    move_only(move_only&&) { }
+  };
+  // P2494R2 Relaxing range adaptors to allow for move only types
+  static_assert( requires { views::repeat(move_only{}, 2); } );
+}
+
 int
 main()
 {
@@ -135,4 +146,5 @@ main()
   static_assert(test03());
   static_assert(test04());
   test05();
+  test06();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/single_view.cc b/libstdc++-v3/testsuite/std/ranges/single_view.cc
index 38a3946ca43c..8dfe6bb4bd1d 100644
--- a/libstdc++-v3/testsuite/std/ranges/single_view.cc
+++ b/libstdc++-v3/testsuite/std/ranges/single_view.cc
@@ -123,6 +123,22 @@ test07()
   static_assert(!requires { single(uncopyable{}); });
 }
 
+template<auto single = std::views::single>
+void
+test08()
+{
+  struct move_only {
+    move_only() { }
+    move_only(move_only&&) { }
+  };
+#if __cpp_lib_ranges >= 202207L
+  // P2494R2 Relaxing range adaptors to allow for move only types
+  static_assert( requires { single(move_only{}); } );
+#else
+  static_assert( ! requires { single(move_only{}); } );
+#endif
+}
+
 int main()
 {
   test01();
@@ -132,4 +148,5 @@ int main()
   test05();
   test06();
   test07();
+  test08();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/version_c++23.cc b/libstdc++-v3/testsuite/std/ranges/version_c++23.cc
index e8342fa986a8..8e4a8b466aab 100644
--- a/libstdc++-v3/testsuite/std/ranges/version_c++23.cc
+++ b/libstdc++-v3/testsuite/std/ranges/version_c++23.cc
@@ -4,7 +4,7 @@
 #include <version>
 
 #if __STDC_HOSTED__
-# if __cpp_lib_ranges != 202202L
+# if __cpp_lib_ranges != 202207L
 #  error "Feature-test macro __cpp_lib_ranges has wrong value in <version>"
 # endif
 #endif
diff --git a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
index 5ea24c578a8b..d858b02f1999 100644
--- a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
@@ -99,10 +99,24 @@ test03()
   return true;
 }
 
+void
+test04()
+{
+  extern int x[5];
+  struct move_only {
+    move_only() { }
+    move_only(move_only&&) { }
+    int operator()(int i, int j) const { return i + j; }
+  };
+  // P2494R2 Relaxing range adaptors to allow for move only types
+  static_assert( requires { views::zip_transform(move_only{}, x, x); } );
+}
+
 int
 main()
 {
   static_assert(test01());
   static_assert(test02());
   static_assert(test03());
+  test04();
 }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-09-07  7:11 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-07  7:11 [gcc r14-3768] libstdc++: Relax range adaptors for move-only types (P2494R2) Jonathan Wakely

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).