libstdc++: Implement P1878R1 "Constraining Readable Types"

Message ID 20200207170939.GA1108334@redhat.com
State New
Headers show
Series
  • libstdc++: Implement P1878R1 "Constraining Readable Types"
Related show

Commit Message

Jonathan Wakely Feb. 7, 2020, 5:09 p.m.
* include/bits/iterator_concepts.h (iter_difference_t, iter_value_t):
	Use remove_cvref_t.
	(readable_traits): Rename to indirectly_readable_traits.
	(readable): Rename to indirectly_readable.
	(writable): Rename to indirectly_writable.
	(__detail::__iter_exchange_move): Do not use remove_reference_t.
	(indirectly_swappable): Adjust requires expression parameter types.
	expression.
	* include/bits/ranges_algo.h (ranges::transform, ranges::replace)
	(ranges::replace_if, ranges::generate_n, ranges::generate)
	(ranges::remove): Use new name for writable.
	* include/bits/stl_iterator.h (__detail::__common_iter_has_arrow):
	Use new name for readable.
	* include/ext/pointer.h (readable_traits<_Pointer_adapter<P>>): Use
	new name for readable_traits.
	* testsuite/24_iterators/associated_types/readable.traits.cc: Likewise.
	* testsuite/24_iterators/indirect_callable/projected.cc: Adjust for
	new definition of indirectly_readable.

Tested powerpc64le-linux, committed to master.

I think this finishes our C++20 Ranges implementation!
commit c8dd2446f597e6d1581414a9c02ff329285181a9
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Feb 6 11:21:25 2020 +0000

    libstdc++: Implement P1878R1 "Constraining Readable Types"
    
            * include/bits/iterator_concepts.h (iter_difference_t, iter_value_t):
            Use remove_cvref_t.
            (readable_traits): Rename to indirectly_readable_traits.
            (readable): Rename to indirectly_readable.
            (writable): Rename to indirectly_writable.
            (__detail::__iter_exchange_move): Do not use remove_reference_t.
            (indirectly_swappable): Adjust requires expression parameter types.
            expression.
            * include/bits/ranges_algo.h (ranges::transform, ranges::replace)
            (ranges::replace_if, ranges::generate_n, ranges::generate)
            (ranges::remove): Use new name for writable.
            * include/bits/stl_iterator.h (__detail::__common_iter_has_arrow):
            Use new name for readable.
            * include/ext/pointer.h (readable_traits<_Pointer_adapter<P>>): Use
            new name for readable_traits.
            * testsuite/24_iterators/associated_types/readable.traits.cc: Likewise.
            * testsuite/24_iterators/indirect_callable/projected.cc: Adjust for
            new definition of indirectly_readable.

Patch

diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h
index d9b8958d0a7..04c862a4b97 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -173,11 +173,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     // ITER_TRAITS
     template<typename _Iter, typename _Tp = _Iter>
       using __iter_traits = typename __iter_traits_impl<_Iter, _Tp>::type;
+
+    template<typename _Tp>
+      using __iter_diff_t = typename
+	__iter_traits<_Tp, incrementable_traits<_Tp>>::difference_type;
   } // namespace __detail
 
   template<typename _Tp>
-    using iter_difference_t = typename
-      __detail::__iter_traits<_Tp, incrementable_traits<_Tp>>::difference_type;
+    using iter_difference_t = __detail::__iter_diff_t<remove_cvref_t<_Tp>>;
 
   namespace __detail
   {
@@ -188,35 +191,41 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { using value_type = remove_cv_t<_Tp>; };
   } // namespace __detail
 
-  template<typename> struct readable_traits { };
+  template<typename> struct indirectly_readable_traits { };
 
   template<typename _Tp>
-    struct readable_traits<_Tp*>
+    struct indirectly_readable_traits<_Tp*>
     : __detail::__cond_value_type<_Tp>
     { };
 
   template<typename _Iter> requires is_array_v<_Iter>
-    struct readable_traits<_Iter>
+    struct indirectly_readable_traits<_Iter>
     { using value_type = remove_cv_t<remove_extent_t<_Iter>>; };
 
   template<typename _Iter>
-    struct readable_traits<const _Iter>
-    : readable_traits<_Iter>
+    struct indirectly_readable_traits<const _Iter>
+    : indirectly_readable_traits<_Iter>
     { };
 
   template<typename _Tp> requires requires { typename _Tp::value_type; }
-    struct readable_traits<_Tp>
+    struct indirectly_readable_traits<_Tp>
     : __detail::__cond_value_type<typename _Tp::value_type>
     { };
 
   template<typename _Tp> requires requires { typename _Tp::element_type; }
-    struct readable_traits<_Tp>
+    struct indirectly_readable_traits<_Tp>
     : __detail::__cond_value_type<typename _Tp::element_type>
     { };
 
+  namespace __detail
+  {
+    template<typename _Tp>
+      using __iter_value_t = typename
+	__iter_traits<_Tp, indirectly_readable_traits<_Tp>>::value_type;
+  } // namespace __detail
+
   template<typename _Tp>
-    using iter_value_t = typename
-      __detail::__iter_traits<_Tp, readable_traits<_Tp>>::value_type;
+    using iter_value_t = __detail::__iter_value_t<remove_cvref_t<_Tp>>;
 
   namespace __detail
   {
@@ -235,11 +244,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	&& requires(_Iter __it)
 	{
 	  typename incrementable_traits<_Iter>::difference_type;
-	  typename readable_traits<_Iter>::value_type;
+	  typename indirectly_readable_traits<_Iter>::value_type;
 	  typename common_reference_t<iter_reference_t<_Iter>&&,
-		   typename readable_traits<_Iter>::value_type&>;
+		   typename indirectly_readable_traits<_Iter>::value_type&>;
 	  typename common_reference_t<decltype(*__it++)&&,
-		   typename readable_traits<_Iter>::value_type&>;
+		   typename indirectly_readable_traits<_Iter>::value_type&>;
 	  requires signed_integral<typename incrementable_traits<_Iter>::difference_type>;
 	};
 
@@ -248,7 +257,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	&& constructible_from<_Iter>
 	&& is_lvalue_reference_v<iter_reference_t<_Iter>>
 	&& same_as<remove_cvref_t<iter_reference_t<_Iter>>,
-		   typename readable_traits<_Iter>::value_type>
+		   typename indirectly_readable_traits<_Iter>::value_type>
 	&& requires(_Iter __it)
 	{
 	  {  __it++ } -> convertible_to<const _Iter&>;
@@ -290,6 +299,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _Iter>
       concept __iter_without_nested_types = !__iter_with_nested_types<_Iter>;
 
+    // FIXME: These have to be at namespace-scope because of PR 92103.
     template<typename _Iter, bool __use_arrow = false>
       struct __ptr
       { using type = void; };
@@ -376,7 +386,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       using iterator_category = typename __detail::__cat<_Iterator>::type;
       using value_type
-	= typename readable_traits<_Iterator>::value_type;
+	= typename indirectly_readable_traits<_Iterator>::value_type;
       using difference_type
 	= typename incrementable_traits<_Iterator>::difference_type;
       using pointer	      = typename __detail::__ptr<_Iterator, true>::type;
@@ -429,15 +439,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     // ITER_CONCEPT
     template<typename _Iter>
       using __iter_concept = typename __iter_concept_impl<_Iter>::type;
-  } // namespace __detail
 
-  /// Requirements for types that are readable by applying operator*.
   template<typename _In>
-    concept readable = requires
+    concept __indirectly_readable_impl = requires(const _In __in)
       {
 	typename iter_value_t<_In>;
 	typename iter_reference_t<_In>;
 	typename iter_rvalue_reference_t<_In>;
+	{ *__in } -> same_as<iter_reference_t<_In>>;
+	{ ranges::iter_move(__in) } -> same_as<iter_rvalue_reference_t<_In>>;
       }
       && common_reference_with<iter_reference_t<_In>&&, iter_value_t<_In>&>
       && common_reference_with<iter_reference_t<_In>&&,
@@ -445,13 +455,20 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       && common_reference_with<iter_rvalue_reference_t<_In>&&,
 			       const iter_value_t<_In>&>;
 
-  template<readable _Tp>
+  } // namespace __detail
+
+  /// Requirements for types that are readable by applying operator*.
+  template<typename _In>
+    concept indirectly_readable
+      = __detail::__indirectly_readable_impl<remove_cvref_t<_In>>;
+
+  template<indirectly_readable _Tp>
     using iter_common_reference_t
       = common_reference_t<iter_reference_t<_Tp>, iter_value_t<_Tp>&>;
 
   /// Requirements for writing a value into an iterator's referenced object.
   template<typename _Out, typename _Tp>
-    concept writable = requires(_Out&& __o, _Tp&& __t)
+    concept indirectly_writable = requires(_Out&& __o, _Tp&& __t)
       {
 	*__o = std::forward<_Tp>(__t);
 	*std::forward<_Out>(__o) = std::forward<_Tp>(__t);
@@ -523,13 +540,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _Iter>
     concept input_iterator = input_or_output_iterator<_Iter>
-      && readable<_Iter>
+      && indirectly_readable<_Iter>
       && requires { typename __detail::__iter_concept<_Iter>; }
       && derived_from<__detail::__iter_concept<_Iter>, input_iterator_tag>;
 
   template<typename _Iter, typename _Tp>
     concept output_iterator = input_or_output_iterator<_Iter>
-      && writable<_Iter, _Tp>
+      && indirectly_writable<_Iter, _Tp>
       && requires(_Iter __i, _Tp&& __t) { *__i++ = std::forward<_Tp>(__t); };
 
   template<typename _Iter>
@@ -579,7 +596,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // [indirectcallable.indirectinvocable], indirect callables
 
   template<typename _Fn, typename _Iter>
-    concept indirectly_unary_invocable = readable<_Iter>
+    concept indirectly_unary_invocable = indirectly_readable<_Iter>
       && copy_constructible<_Fn> && invocable<_Fn&, iter_value_t<_Iter>&>
       && invocable<_Fn&, iter_reference_t<_Iter>>
       && invocable<_Fn&, iter_common_reference_t<_Iter>>
@@ -587,7 +604,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			       invoke_result_t<_Fn&, iter_reference_t<_Iter>>>;
 
   template<typename _Fn, typename _Iter>
-    concept indirectly_regular_unary_invocable = readable<_Iter>
+    concept indirectly_regular_unary_invocable = indirectly_readable<_Iter>
       && copy_constructible<_Fn>
       && regular_invocable<_Fn&, iter_value_t<_Iter>&>
       && regular_invocable<_Fn&, iter_reference_t<_Iter>>
@@ -596,13 +613,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			       invoke_result_t<_Fn&, iter_reference_t<_Iter>>>;
 
   template<typename _Fn, typename _Iter>
-    concept indirect_unary_predicate = readable<_Iter>
+    concept indirect_unary_predicate = indirectly_readable<_Iter>
       && copy_constructible<_Fn> && predicate<_Fn&, iter_value_t<_Iter>&>
       && predicate<_Fn&, iter_reference_t<_Iter>>
       && predicate<_Fn&, iter_common_reference_t<_Iter>>;
 
   template<typename _Fn, typename _I1, typename _I2>
-    concept indirect_binary_predicate = readable<_I1> && readable<_I2>
+    concept indirect_binary_predicate
+      = indirectly_readable<_I1> && indirectly_readable<_I2>
       && copy_constructible<_Fn>
       && predicate<_Fn&, iter_value_t<_I1>&, iter_value_t<_I2>&>
       && predicate<_Fn&, iter_value_t<_I1>&, iter_reference_t<_I2>>
@@ -612,7 +630,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		   iter_common_reference_t<_I2>>;
 
   template<typename _Fn, typename _I1, typename _I2 = _I1>
-    concept indirect_equivalence_relation = readable<_I1> && readable<_I2>
+    concept indirect_equivalence_relation
+      = indirectly_readable<_I1> && indirectly_readable<_I2>
       && copy_constructible<_Fn>
       && equivalence_relation<_Fn&, iter_value_t<_I1>&, iter_value_t<_I2>&>
       && equivalence_relation<_Fn&, iter_value_t<_I1>&, iter_reference_t<_I2>>
@@ -623,7 +642,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			      iter_common_reference_t<_I2>>;
 
   template<typename _Fn, typename _I1, typename _I2 = _I1>
-    concept indirect_strict_weak_order = readable<_I1> && readable<_I2>
+    concept indirect_strict_weak_order
+      = indirectly_readable<_I1> && indirectly_readable<_I2>
       && copy_constructible<_Fn>
       && strict_weak_order<_Fn&, iter_value_t<_I1>&, iter_value_t<_I2>&>
       && strict_weak_order<_Fn&, iter_value_t<_I1>&, iter_reference_t<_I2>>
@@ -633,12 +653,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			   iter_common_reference_t<_I2>>;
 
   template<typename _Fn, typename... _Is>
-    requires (readable<_Is> && ...)
+    requires (indirectly_readable<_Is> && ...)
       && invocable<_Fn, iter_reference_t<_Is>...>
     using indirect_result_t = invoke_result_t<_Fn, iter_reference_t<_Is>...>;
 
   /// [projected], projected
-  template<readable _Iter, indirectly_regular_unary_invocable<_Iter> _Proj>
+  template<indirectly_readable _Iter,
+	   indirectly_regular_unary_invocable<_Iter> _Proj>
     struct projected
     {
       using value_type = remove_cvref_t<indirect_result_t<_Proj&, _Iter>>;
@@ -655,23 +676,24 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// [alg.req.ind.move], concept `indirectly_movable`
 
   template<typename _In, typename _Out>
-    concept indirectly_movable = readable<_In>
-      && writable<_Out, iter_rvalue_reference_t<_In>>;
+    concept indirectly_movable = indirectly_readable<_In>
+      && indirectly_writable<_Out, iter_rvalue_reference_t<_In>>;
 
   template<typename _In, typename _Out>
     concept indirectly_movable_storable = indirectly_movable<_In, _Out>
-      && writable<_Out, iter_value_t<_In>> && movable<iter_value_t<_In>>
+      && indirectly_writable<_Out, iter_value_t<_In>>
+      && movable<iter_value_t<_In>>
       && constructible_from<iter_value_t<_In>, iter_rvalue_reference_t<_In>>
       && assignable_from<iter_value_t<_In>&, iter_rvalue_reference_t<_In>>;
 
   /// [alg.req.ind.copy], concept `indirectly_copyable`
   template<typename _In, typename _Out>
-    concept indirectly_copyable = readable<_In>
-      && writable<_Out, iter_reference_t<_In>>;
+    concept indirectly_copyable = indirectly_readable<_In>
+      && indirectly_writable<_Out, iter_reference_t<_In>>;
 
   template<typename _In, typename _Out>
     concept indirectly_copyable_storable = indirectly_copyable<_In, _Out>
-      && writable<_Out, const iter_value_t<_In>&>
+      && indirectly_writable<_Out, const iter_value_t<_In>&>
       && copyable<iter_value_t<_In>>
       && constructible_from<iter_value_t<_In>, iter_reference_t<_In>>
       && assignable_from<iter_value_t<_In>&, iter_reference_t<_In>>;
@@ -692,12 +714,12 @@  namespace ranges
 	};
 
     template<typename _Xp, typename _Yp>
-      constexpr iter_value_t<remove_reference_t<_Xp>>
+      constexpr iter_value_t<_Xp>
       __iter_exchange_move(_Xp&& __x, _Yp&& __y)
-      noexcept(noexcept(iter_value_t<remove_reference_t<_Xp>>(iter_move(__x)))
+      noexcept(noexcept(iter_value_t<_Xp>(iter_move(__x)))
 	       && noexcept(*__x = iter_move(__y)))
       {
-	iter_value_t<remove_reference_t<_Xp>> __old_value(iter_move(__x));
+	iter_value_t<_Xp> __old_value(iter_move(__x));
 	*__x = iter_move(__y);
 	return __old_value;
       }
@@ -712,8 +734,9 @@  namespace ranges
 	  if constexpr (__adl_iswap<_Tp, _Up>)
 	    return noexcept(iter_swap(std::declval<_Tp>(),
 				      std::declval<_Up>()));
-	  else if constexpr (readable<_Tp> && readable<_Up>
-	    && swappable_with<iter_reference_t<_Tp>, iter_reference_t<_Up>>)
+	  else if constexpr (indirectly_readable<_Tp>
+	      && indirectly_readable<_Up>
+	      && swappable_with<iter_reference_t<_Tp>, iter_reference_t<_Up>>)
 	    return noexcept(ranges::swap(*std::declval<_Tp>(),
 					 *std::declval<_Up>()));
 	  else
@@ -725,8 +748,8 @@  namespace ranges
     public:
       template<typename _Tp, typename _Up>
 	requires __adl_iswap<_Tp, _Up>
-	|| (readable<remove_reference_t<_Tp>>
-	    && readable<remove_reference_t<_Up>>
+	|| (indirectly_readable<remove_reference_t<_Tp>>
+	    && indirectly_readable<remove_reference_t<_Up>>
 	    && swappable_with<iter_reference_t<_Tp>, iter_reference_t<_Up>>)
 	|| (indirectly_movable_storable<_Tp, _Up>
 	    && indirectly_movable_storable<_Up, _Tp>)
@@ -736,8 +759,9 @@  namespace ranges
 	{
 	  if constexpr (__adl_iswap<_Tp, _Up>)
 	    iter_swap(static_cast<_Tp&&>(__e1), static_cast<_Up&&>(__e2));
-	  else if constexpr (readable<_Tp> && readable<_Up>
-	    && swappable_with<iter_reference_t<_Tp>, iter_reference_t<_Up>>)
+	  else if constexpr (indirectly_readable<_Tp>
+	      && indirectly_readable<_Up>
+	      && swappable_with<iter_reference_t<_Tp>, iter_reference_t<_Up>>)
 	    ranges::swap(*__e1, *__e2);
 	  else
 	    *__e1 = __iter_exchange_move(__e2, __e1);
@@ -754,8 +778,9 @@  namespace ranges
 
   /// [alg.req.ind.swap], concept `indirectly_swappable`
   template<typename _I1, typename _I2 = _I1>
-    concept indirectly_swappable = readable<_I1> && readable<_I2>
-      && requires(_I1& __i1, _I2& __i2)
+    concept indirectly_swappable
+      = indirectly_readable<_I1> && indirectly_readable<_I2>
+      && requires(const _I1 __i1, const _I2 __i2)
       {
 	ranges::iter_swap(__i1, __i1);
 	ranges::iter_swap(__i2, __i2);
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 927c83c55b7..e065ff2a974 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1219,7 +1219,9 @@  namespace ranges
   template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	   weakly_incrementable _Out,
 	   copy_constructible _Fp, typename _Proj = identity>
-    requires writable<_Out, indirect_result_t<_Fp&, projected<_Iter, _Proj>>>
+    requires indirectly_writable<_Out,
+				 indirect_result_t<_Fp&,
+				   projected<_Iter, _Proj>>>
     constexpr unary_transform_result<_Iter, _Out>
     transform(_Iter __first1, _Sent __last1, _Out __result,
 	      _Fp __op, _Proj __proj = {})
@@ -1231,9 +1233,9 @@  namespace ranges
 
   template<input_range _Range, weakly_incrementable _Out,
 	   copy_constructible _Fp, typename _Proj = identity>
-    requires writable<_Out,
-		      indirect_result_t<_Fp&, projected<iterator_t<_Range>,
-						      _Proj>>>
+    requires indirectly_writable<_Out,
+				 indirect_result_t<_Fp&,
+				   projected<iterator_t<_Range>, _Proj>>>
     constexpr unary_transform_result<safe_iterator_t<_Range>, _Out>
     transform(_Range&& __r, _Out __result, _Fp __op, _Proj __proj = {})
     {
@@ -1268,8 +1270,10 @@  namespace ranges
 	   input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
 	   weakly_incrementable _Out, copy_constructible _Fp,
 	   typename _Proj1 = identity, typename _Proj2 = identity>
-    requires writable<_Out, indirect_result_t<_Fp&, projected<_Iter1, _Proj1>,
-					   projected<_Iter2, _Proj2>>>
+    requires indirectly_writable<_Out,
+				 indirect_result_t<_Fp&,
+				   projected<_Iter1, _Proj1>,
+				   projected<_Iter2, _Proj2>>>
     constexpr binary_transform_result<_Iter1, _Iter2, _Out>
     transform(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
 	      _Out __result, _Fp __binary_op,
@@ -1286,11 +1290,10 @@  namespace ranges
   template<input_range _Range1, input_range _Range2,
 	   weakly_incrementable _Out, copy_constructible _Fp,
 	   typename _Proj1 = identity, typename _Proj2 = identity>
-    requires writable<_Out, indirect_result_t<_Fp&,
-					      projected<iterator_t<_Range1>,
-							_Proj1>,
-					      projected<iterator_t<_Range2>,
-							_Proj2>>>
+    requires indirectly_writable<_Out,
+				 indirect_result_t<_Fp&,
+				   projected<iterator_t<_Range1>, _Proj1>,
+				   projected<iterator_t<_Range2>, _Proj2>>>
     constexpr binary_transform_result<safe_iterator_t<_Range1>,
 				      safe_iterator_t<_Range2>, _Out>
     transform(_Range1&& __r1, _Range2&& __r2, _Out __result,
@@ -1304,9 +1307,9 @@  namespace ranges
 
   template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	   typename _Tp1, typename _Tp2, typename _Proj = identity>
-    requires writable<_Iter, const _Tp2&> &&
-	     indirect_binary_predicate<ranges::equal_to,
-				       projected<_Iter, _Proj>, const _Tp1*>
+    requires indirectly_writable<_Iter, const _Tp2&>
+      && indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>,
+				   const _Tp1*>
     constexpr _Iter
     replace(_Iter __first, _Sent __last,
 	    const _Tp1& __old_value, const _Tp2& __new_value,
@@ -1320,10 +1323,10 @@  namespace ranges
 
   template<input_range _Range,
 	   typename _Tp1, typename _Tp2, typename _Proj = identity>
-    requires writable<iterator_t<_Range>, const _Tp2&> &&
-	     indirect_binary_predicate<ranges::equal_to,
-				       projected<iterator_t<_Range>, _Proj>,
-						 const _Tp1*>
+    requires indirectly_writable<iterator_t<_Range>, const _Tp2&>
+      && indirect_binary_predicate<ranges::equal_to,
+				   projected<iterator_t<_Range>, _Proj>,
+				   const _Tp1*>
     constexpr safe_iterator_t<_Range>
     replace(_Range&& __r,
 	    const _Tp1& __old_value, const _Tp2& __new_value,
@@ -1336,7 +1339,7 @@  namespace ranges
   template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	   typename _Tp, typename _Proj = identity,
 	   indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
-    requires writable<_Iter, const _Tp&>
+    requires indirectly_writable<_Iter, const _Tp&>
     constexpr _Iter
     replace_if(_Iter __first, _Sent __last,
 	       _Pred __pred, const _Tp& __new_value, _Proj __proj = {})
@@ -1349,7 +1352,7 @@  namespace ranges
 
   template<input_range _Range, typename _Tp, typename _Proj = identity,
 	   indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
-    requires writable<iterator_t<_Range>, const _Tp&>
+    requires indirectly_writable<iterator_t<_Range>, const _Tp&>
     constexpr safe_iterator_t<_Range>
     replace_if(_Range&& __r,
 	       _Pred __pred, const _Tp& __new_value, _Proj __proj = {})
@@ -1496,7 +1499,8 @@  namespace ranges
     }
 
   template<input_or_output_iterator _Out, copy_constructible _Fp>
-    requires invocable<_Fp&> && writable<_Out, invoke_result_t<_Fp&>>
+    requires invocable<_Fp&>
+      && indirectly_writable<_Out, invoke_result_t<_Fp&>>
     constexpr _Out
     generate_n(_Out __first, iter_difference_t<_Out> __n, _Fp __gen)
     {
@@ -1507,7 +1511,8 @@  namespace ranges
 
   template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent,
 	   copy_constructible _Fp>
-    requires invocable<_Fp&> && writable<_Out, invoke_result_t<_Fp&>>
+    requires invocable<_Fp&>
+      && indirectly_writable<_Out, invoke_result_t<_Fp&>>
     constexpr _Out
     generate(_Out __first, _Sent __last, _Fp __gen)
     {
@@ -1573,10 +1578,10 @@  namespace ranges
     }
 
   template<forward_range _Range, typename _Tp, typename _Proj = identity>
-    requires permutable<iterator_t<_Range>> &&
-	     indirect_binary_predicate<ranges::equal_to,
-				       projected<iterator_t<_Range>, _Proj>,
-				       const _Tp*>
+    requires permutable<iterator_t<_Range>>
+      && indirect_binary_predicate<ranges::equal_to,
+				   projected<iterator_t<_Range>, _Proj>,
+				   const _Tp*>
     constexpr safe_subrange_t<_Range>
     remove(_Range&& __r, const _Tp& __value, _Proj __proj = {})
     {
diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index 46804656801..4e70672924b 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1417,7 +1417,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       };
 
     template<typename _It>
-      concept __common_iter_has_arrow = readable<const _It>
+      concept __common_iter_has_arrow = indirectly_readable<const _It>
 	&& (requires(const _It& __it) { __it.operator->(); }
 	    || is_reference_v<iter_reference_t<_It>>
 	    || constructible_from<iter_value_t<_It>, iter_reference_t<_It>>);
diff --git a/libstdc++-v3/include/ext/pointer.h b/libstdc++-v3/include/ext/pointer.h
index 02d3e60169f..aef622e2e23 100644
--- a/libstdc++-v3/include/ext/pointer.h
+++ b/libstdc++-v3/include/ext/pointer.h
@@ -47,7 +47,7 @@ 
 # include <bits/ptr_traits.h>
 #endif
 #if __cplusplus > 201703L
-# include <iterator> // for readable_traits
+# include <iterator> // for indirectly_readable_traits
 #endif
 
 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
@@ -598,11 +598,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
 #if __cpp_lib_concepts
-  template<typename _Storage_policy>
-    struct readable_traits<__gnu_cxx::_Pointer_adapter<_Storage_policy>>
+  template<typename _Policy>
+    struct indirectly_readable_traits<__gnu_cxx::_Pointer_adapter<_Policy>>
     {
       using value_type
-	= typename __gnu_cxx::_Pointer_adapter<_Storage_policy>::value_type;
+	= typename __gnu_cxx::_Pointer_adapter<_Policy>::value_type;
     };
 #endif
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/testsuite/24_iterators/associated_types/readable.traits.cc b/libstdc++-v3/testsuite/24_iterators/associated_types/readable.traits.cc
index 724e6eaa02a..b503b0cdc1e 100644
--- a/libstdc++-v3/testsuite/24_iterators/associated_types/readable.traits.cc
+++ b/libstdc++-v3/testsuite/24_iterators/associated_types/readable.traits.cc
@@ -24,9 +24,9 @@  struct none;
 
 template<typename T>
   concept has_readable_traits_type
-    = requires { typename std::readable_traits<T>::value_type; };
+    = requires { typename std::indirectly_readable_traits<T>::value_type; };
 
-// Check std::readable_traits<T>::value_type is U (or doesn't exist).
+// Check std::indirectly_readable_traits<T>::value_type is U (or doesn't exist).
 template<typename T, typename U>
   concept check_readable_traits
     = (has_readable_traits_type<T> != std::same_as<U, none>);
@@ -62,7 +62,7 @@  static_assert( check_readable_traits<const D, none> );
 
 struct E { };
 template<>
-  struct std::readable_traits<E> { using value_type = long; };
+  struct std::indirectly_readable_traits<E> { using value_type = long; };
 static_assert( check_readable_traits<E, long> );
 static_assert( check_readable_traits<const E, long> );
 
@@ -103,7 +103,7 @@  static_assert( check_alias<F, std::iterator_traits<F>::value_type> );
 
 struct G { };
 template<>
-  struct std::readable_traits<G> { using value_type = G; };
+  struct std::indirectly_readable_traits<G> { using value_type = G; };
 template<>
   struct std::iterator_traits<G> { using value_type = int; };
 // iterator_traits<G> is specialized, so use its value_type.
@@ -111,7 +111,7 @@  static_assert( check_alias<G, std::iterator_traits<G>::value_type> );
 
 struct H { };
 template<>
-  struct std::readable_traits<H> { using value_type = H; };
+  struct std::indirectly_readable_traits<H> { using value_type = H; };
 template<>
   struct std::iterator_traits<H>
   {
@@ -128,8 +128,8 @@  struct I
   using value_type = I;
 };
 // iterator_traits<I> is not specialized, and no standard specialization
-// matches, so use readable_traits.
-static_assert( check_alias<I, std::readable_traits<I>::value_type> );
+// matches, so use indirectly_readable_traits.
+static_assert( check_alias<I, std::indirectly_readable_traits<I>::value_type> );
 
 struct J
 {
diff --git a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
index 3f01677856a..f6e4afb7dc9 100644
--- a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
+++ b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
@@ -29,9 +29,11 @@  static_assert(std::same_as<decltype(*std::declval<const PI<int*>&>()), int&>);
 struct X
 {
   using value_type = char*;
-  char* const& operator*() &;
+  char* const& operator*() const;
 };
-static_assert( std::readable<X> );
+static_assert( std::indirectly_readable<X> );
+static_assert( std::indirectly_readable<X&> );
+static_assert( std::indirectly_readable<const X> );
 static_assert(std::same_as<PI<X>::value_type, char*>);
 static_assert(std::same_as<decltype(*std::declval<PI<X>&>()), char* const&>);