diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h
index 8f97a5d8789..f4e94a6263b 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -925,8 +925,11 @@ namespace ranges
   struct default_sentinel_t { };
   inline constexpr default_sentinel_t default_sentinel{};
 
-  namespace __detail
+  // This is the namespace for [range.access] CPOs.
+  namespace ranges::__cust_access
   {
+    using std::__detail::__class_or_enum;
+
     template<typename _Tp>
       constexpr decay_t<_Tp>
       __decay_copy(_Tp&& __t)
@@ -936,9 +939,11 @@ namespace ranges
     template<typename _Tp>
       concept __member_begin = requires(_Tp& __t)
 	{
-	  { __detail::__decay_copy(__t.begin()) } -> input_or_output_iterator;
+	  { __cust_access::__decay_copy(__t.begin()) }
+	    -> input_or_output_iterator;
 	};
 
+    // Poison pills so that unqualified lookup doesn't find std::begin.
     void begin(auto&) = delete;
     void begin(const auto&) = delete;
 
@@ -946,7 +951,8 @@ namespace ranges
       concept __adl_begin = __class_or_enum<remove_reference_t<_Tp>>
 	&& requires(_Tp& __t)
 	{
-	  { __detail::__decay_copy(begin(__t)) } -> input_or_output_iterator;
+	  { __cust_access::__decay_copy(begin(__t)) }
+	    -> input_or_output_iterator;
 	};
 
     // Simplified version of std::ranges::begin that only supports lvalues,
@@ -954,24 +960,23 @@ namespace ranges
     template<typename _Tp>
       requires is_array_v<_Tp> || __member_begin<_Tp&> || __adl_begin<_Tp&>
       auto
-      __ranges_begin(_Tp& __t)
+      __begin(_Tp& __t)
       {
 	if constexpr (is_array_v<_Tp>)
-	  {
-	    static_assert(sizeof(remove_all_extents_t<_Tp>) != 0,
-			  "not array of incomplete type");
-	    return __t + 0;
-	  }
+	  return __t + 0;
 	else if constexpr (__member_begin<_Tp&>)
 	  return __t.begin();
 	else
 	  return begin(__t);
       }
+  } // namespace ranges::__cust_access
 
+  namespace __detail
+  {
     // Implementation of std::ranges::iterator_t, without using ranges::begin.
     template<typename _Tp>
       using __range_iter_t
-	= decltype(__detail::__ranges_begin(std::declval<_Tp&>()));
+	= decltype(ranges::__cust_access::__begin(std::declval<_Tp&>()));
 
   } // namespace __detail
 
diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
index 32d664f1a86..17a421a4927 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -89,10 +89,6 @@ namespace ranges
   namespace __cust_access
   {
     using std::ranges::__detail::__maybe_borrowed_range;
-    using std::__detail::__class_or_enum;
-    using std::__detail::__decay_copy;
-    using std::__detail::__member_begin;
-    using std::__detail::__adl_begin;
 
     struct _Begin
     {
@@ -114,13 +110,11 @@ namespace ranges
 	requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
 	  || __adl_begin<_Tp>
 	constexpr auto
-	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
 	    {
 	      static_assert(is_lvalue_reference_v<_Tp>);
-	      using _Up = remove_all_extents_t<remove_reference_t<_Tp>>;
-	      static_assert(sizeof(_Up) != 0, "not array of incomplete type");
 	      return __t + 0;
 	    }
 	  else if constexpr (__member_begin<_Tp>)
@@ -137,6 +131,7 @@ namespace ranges
 	    -> sentinel_for<decltype(_Begin{}(std::forward<_Tp>(__t)))>;
 	};
 
+    // Poison pills so that unqualified lookup doesn't find std::end.
     void end(auto&) = delete;
     void end(const auto&) = delete;
 
@@ -165,10 +160,10 @@ namespace ranges
 
     public:
       template<__maybe_borrowed_range _Tp>
-	requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
-	|| __adl_end<_Tp>
+	requires is_bounded_array_v<remove_reference_t<_Tp>>
+	  || __member_end<_Tp> || __adl_end<_Tp>
 	constexpr auto
-	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
 	    {
@@ -182,12 +177,15 @@ namespace ranges
 	}
     };
 
-    template<typename _Tp>
+    // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&.
+    template<typename _To, typename _Tp>
       constexpr decltype(auto)
-      __as_const(_Tp&& __t) noexcept
+      __as_const(_Tp& __t) noexcept
       {
-	if constexpr (is_lvalue_reference_v<_Tp>)
-	  return static_cast<const remove_reference_t<_Tp>&>(__t);
+	static_assert(std::is_same_v<_To&, _Tp&>);
+
+	if constexpr (is_lvalue_reference_v<_To>)
+	  return const_cast<const _Tp&>(__t);
 	else
 	  return static_cast<const _Tp&&>(__t);
       }
@@ -197,10 +195,10 @@ namespace ranges
       template<typename _Tp>
 	constexpr auto
 	operator()(_Tp&& __e) const
-	noexcept(noexcept(_Begin{}(__cust_access::__as_const((_Tp&&)__e))))
-	requires requires { _Begin{}(__cust_access::__as_const((_Tp&&)__e)); }
+	noexcept(noexcept(_Begin{}(__cust_access::__as_const<_Tp>(__e))))
+	requires requires { _Begin{}(__cust_access::__as_const<_Tp>(__e)); }
 	{
-	  return _Begin{}(__cust_access::__as_const(std::forward<_Tp>(__e)));
+	  return _Begin{}(__cust_access::__as_const<_Tp>(__e));
 	}
     };
 
@@ -209,10 +207,10 @@ namespace ranges
       template<typename _Tp>
 	constexpr auto
 	operator()(_Tp&& __e) const
-	noexcept(noexcept(_End{}(__cust_access::__as_const((_Tp&&)__e))))
-	requires requires { _End{}(__cust_access::__as_const((_Tp&&)__e)); }
+	noexcept(noexcept(_End{}(__cust_access::__as_const<_Tp>(__e))))
+	requires requires { _End{}(__cust_access::__as_const<_Tp>(__e)); }
 	{
-	  return _End{}(__cust_access::__as_const(std::forward<_Tp>(__e)));
+	  return _End{}(__cust_access::__as_const<_Tp>(__e));
 	}
     };
 
@@ -268,7 +266,7 @@ namespace ranges
 	requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
 	constexpr auto
 	operator()(_Tp&& __t) const
-	noexcept(_S_noexcept<_Tp>())
+	noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (__member_rbegin<_Tp>)
 	    return __t.rbegin();
@@ -326,7 +324,7 @@ namespace ranges
 	requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
 	constexpr auto
 	operator()(_Tp&& __t) const
-	noexcept(_S_noexcept<_Tp>())
+	noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (__member_rend<_Tp>)
 	    return __t.rend();
@@ -342,10 +340,10 @@ namespace ranges
       template<typename _Tp>
 	constexpr auto
 	operator()(_Tp&& __e) const
-	noexcept(noexcept(_RBegin{}(__cust_access::__as_const((_Tp&&)__e))))
-	requires requires { _RBegin{}(__cust_access::__as_const((_Tp&&)__e)); }
+	noexcept(noexcept(_RBegin{}(__cust_access::__as_const<_Tp>(__e))))
+	requires requires { _RBegin{}(__cust_access::__as_const<_Tp>(__e)); }
 	{
-	  return _RBegin{}(__cust_access::__as_const(std::forward<_Tp>(__e)));
+	  return _RBegin{}(__cust_access::__as_const<_Tp>(__e));
 	}
     };
 
@@ -354,19 +352,18 @@ namespace ranges
       template<typename _Tp>
 	constexpr auto
 	operator()(_Tp&& __e) const
-	noexcept(noexcept(_REnd{}(__cust_access::__as_const((_Tp&&)__e))))
-	requires requires { _REnd{}(__cust_access::__as_const((_Tp&&)__e)); }
+	noexcept(noexcept(_REnd{}(__cust_access::__as_const<_Tp>(__e))))
+	requires requires { _REnd{}(__cust_access::__as_const<_Tp>(__e)); }
 	{
-	  return _REnd{}(__cust_access::__as_const(std::forward<_Tp>(__e)));
+	  return _REnd{}(__cust_access::__as_const<_Tp>(__e));
 	}
     };
 
     template<typename _Tp>
       concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
-	&& requires(_Tp&& __t)
+	&& requires(_Tp& __t)
 	{
-	  { __decay_copy(std::forward<_Tp>(__t).size()) }
-	    -> __detail::__is_integer_like;
+	  { __decay_copy(__t.size()) } -> __detail::__is_integer_like;
 	};
 
     void size(auto&) = delete;
@@ -375,19 +372,19 @@ namespace ranges
     template<typename _Tp>
       concept __adl_size = __class_or_enum<remove_reference_t<_Tp>>
 	&& !disable_sized_range<remove_cvref_t<_Tp>>
-	&& requires(_Tp&& __t)
+	&& requires(_Tp& __t)
 	{
-	  { __decay_copy(size(std::forward<_Tp>(__t))) }
-	    -> __detail::__is_integer_like;
+	  { __decay_copy(size(__t)) } -> __detail::__is_integer_like;
 	};
 
     template<typename _Tp>
-      concept __sentinel_size = requires(_Tp&& __t)
+      concept __sentinel_size = requires(_Tp& __t)
 	{
-	  { _Begin{}(std::forward<_Tp>(__t)) } -> forward_iterator;
+	  { _Begin{}(__t) } -> forward_iterator;
 
-	  { _End{}(std::forward<_Tp>(__t)) }
-	    -> sized_sentinel_for<decltype(_Begin{}(std::forward<_Tp>(__t)))>;
+	  { _End{}(__t) } -> sized_sentinel_for<decltype(_Begin{}(__t))>;
+
+	  __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
 	};
 
     struct _Size
@@ -400,12 +397,12 @@ namespace ranges
 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
 	    return true;
 	  else if constexpr (__member_size<_Tp>)
-	    return noexcept(__decay_copy(std::declval<_Tp>().size()));
+	    return noexcept(__decay_copy(std::declval<_Tp&>().size()));
 	  else if constexpr (__adl_size<_Tp>)
-	    return noexcept(__decay_copy(size(std::declval<_Tp>())));
+	    return noexcept(__decay_copy(size(std::declval<_Tp&>())));
 	  else if constexpr (__sentinel_size<_Tp>)
-	    return noexcept(_End{}(std::declval<_Tp>())
-			    - _Begin{}(std::declval<_Tp>()));
+	    return noexcept(_End{}(std::declval<_Tp&>())
+			    - _Begin{}(std::declval<_Tp&>()));
 	}
 
     public:
@@ -413,39 +410,30 @@ namespace ranges
 	requires is_bounded_array_v<remove_reference_t<_Tp>>
 	  || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
 	constexpr auto
-	operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
-	    {
-	      return extent_v<remove_reference_t<_Tp>>;
-	    }
+	    return extent_v<remove_reference_t<_Tp>>;
 	  else if constexpr (__member_size<_Tp>)
-	    return std::forward<_Tp>(__e).size();
+	    return __t.size();
 	  else if constexpr (__adl_size<_Tp>)
-	    return size(std::forward<_Tp>(__e));
+	    return size(__t);
 	  else if constexpr (__sentinel_size<_Tp>)
-	    return __detail::__to_unsigned_like(
-		_End{}(std::forward<_Tp>(__e))
-		- _Begin{}(std::forward<_Tp>(__e)));
+	    return __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
 	}
     };
 
     struct _SSize
     {
       template<typename _Tp>
-	requires requires (_Tp&& __e)
-	  {
-	    _Begin{}(std::forward<_Tp>(__e));
-	    _Size{}(std::forward<_Tp>(__e));
-	  }
+	requires requires (_Tp& __t) { _Size{}(__t); }
 	constexpr auto
-	operator()(_Tp&& __e) const
-	noexcept(noexcept(_Size{}(std::forward<_Tp>(__e))))
+	operator()(_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
 	{
-	  using __iter_type = decltype(_Begin{}(std::forward<_Tp>(__e)));
+	  using __iter_type = decltype(_Begin{}(__t));
 	  using __diff_type = iter_difference_t<__iter_type>;
 	  using __gnu_cxx::__int_traits;
-	  auto __size = _Size{}(std::forward<_Tp>(__e));
+	  auto __size = _Size{}(__t);
 	  if constexpr (integral<__diff_type>)
 	    {
 	      if constexpr (__int_traits<__diff_type>::__digits
@@ -457,19 +445,17 @@ namespace ranges
     };
 
     template<typename _Tp>
-      concept __member_empty = requires(_Tp&& __t)
-	{ bool(std::forward<_Tp>(__t).empty()); };
+      concept __member_empty = requires(_Tp& __t) { bool(__t.empty()); };
 
     template<typename _Tp>
-      concept __size0_empty = requires(_Tp&& __t)
-	{ _Size{}(std::forward<_Tp>(__t)) == 0; };
+      concept __size0_empty = requires(_Tp& __t) { _Size{}(__t) == 0; };
 
     template<typename _Tp>
-      concept __eq_iter_empty = requires(_Tp&& __t)
+      concept __eq_iter_empty = requires(_Tp& __t)
 	{
-	  { _Begin{}(std::forward<_Tp>(__t)) } -> forward_iterator;
-	  bool(_Begin{}(std::forward<_Tp>(__t))
-	      == _End{}(std::forward<_Tp>(__t)));
+	  { _Begin{}(__t) } -> forward_iterator;
+
+	  bool(_Begin{}(__t) == _End{}(__t));
 	};
 
     struct _Empty
@@ -480,28 +466,27 @@ namespace ranges
 	_S_noexcept()
 	{
 	  if constexpr (__member_empty<_Tp>)
-	    return noexcept(std::declval<_Tp>().empty());
+	    return noexcept(std::declval<_Tp&>().empty());
 	  else if constexpr (__size0_empty<_Tp>)
-	    return noexcept(_Size{}(std::declval<_Tp>()) == 0);
+	    return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
 	  else
-	    return noexcept(bool(_Begin{}(std::declval<_Tp>())
-		== _End{}(std::declval<_Tp>())));
+	    return noexcept(bool(_Begin{}(std::declval<_Tp&>())
+		== _End{}(std::declval<_Tp&>())));
 	}
 
     public:
       template<typename _Tp>
 	requires __member_empty<_Tp> || __size0_empty<_Tp>
-	|| __eq_iter_empty<_Tp>
+	  || __eq_iter_empty<_Tp>
 	constexpr bool
-	operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
 	{
 	  if constexpr (__member_empty<_Tp>)
-	    return bool(std::forward<_Tp>(__e).empty());
+	    return bool(__t.empty());
 	  else if constexpr (__size0_empty<_Tp>)
-	    return _Size{}(std::forward<_Tp>(__e)) == 0;
+	    return _Size{}(__t) == 0;
 	  else
-	    return bool(_Begin{}(std::forward<_Tp>(__e))
-		== _End{}(std::forward<_Tp>(__e)));
+	    return bool(_Begin{}(__t) == _End{}(__t));
 	}
     };
 
@@ -510,12 +495,12 @@ namespace ranges
 				    && is_object_v<remove_pointer_t<_Tp>>;
 
     template<typename _Tp>
-      concept __member_data = is_lvalue_reference_v<_Tp>
-	&& requires(_Tp __t) { { __t.data() } -> __pointer_to_object; };
+      concept __member_data
+	= requires(_Tp& __t) { { __t.data() } -> __pointer_to_object; };
 
     template<typename _Tp>
-      concept __begin_data = requires(_Tp&& __t)
-	{ { _Begin{}(std::forward<_Tp>(__t)) } -> contiguous_iterator; };
+      concept __begin_data = requires(_Tp& __t)
+	{ { _Begin{}(__t) } -> contiguous_iterator; };
 
     struct _Data
     {
@@ -525,21 +510,21 @@ namespace ranges
 	_S_noexcept()
 	{
 	  if constexpr (__member_data<_Tp>)
-	    return noexcept(__decay_copy(std::declval<_Tp>().data()));
+	    return noexcept(__decay_copy(std::declval<_Tp&>().data()));
 	  else
-	    return noexcept(_Begin{}(std::declval<_Tp>()));
+	    return noexcept(_Begin{}(std::declval<_Tp&>()));
 	}
 
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_data<_Tp> || __begin_data<_Tp>
 	constexpr auto
-	operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>())
+	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
 	{
 	  if constexpr (__member_data<_Tp>)
-	    return __e.data();
+	    return __t.data();
 	  else
-	    return std::to_address(_Begin{}(std::forward<_Tp>(__e)));
+	    return std::to_address(_Begin{}(__t));
 	}
     };
 
@@ -548,10 +533,10 @@ namespace ranges
       template<typename _Tp>
 	constexpr auto
 	operator()(_Tp&& __e) const
-	noexcept(noexcept(_Data{}(__cust_access::__as_const((_Tp&&)__e))))
-	requires requires { _Data{}(__cust_access::__as_const((_Tp&&)__e)); }
+	noexcept(noexcept(_Data{}(__cust_access::__as_const<_Tp>(__e))))
+	requires requires { _Data{}(__cust_access::__as_const<_Tp>(__e)); }
 	{
-	  return _Data{}(__cust_access::__as_const(std::forward<_Tp>(__e)));
+	  return _Data{}(__cust_access::__as_const<_Tp>(__e));
 	}
     };
 
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
index bea27ccaed2..2dfb6830789 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
@@ -21,6 +21,10 @@
 #include <ranges>
 #include <testsuite_hooks.h>
 
+template<typename T>
+  concept has_cdata
+    = requires (T&& t) { std::ranges::cdata(std::forward<T>(t)); };
+
 void
 test01()
 {
@@ -31,12 +35,18 @@ test01()
     int* data() { return &j; }
     const R* data() const noexcept { return nullptr; }
   };
+  static_assert( has_cdata<R&> );
+  static_assert( has_cdata<const R&> );
   R r;
   const R& c = r;
   VERIFY( std::ranges::cdata(r) == (R*)nullptr );
   static_assert( noexcept(std::ranges::cdata(r)) );
   VERIFY( std::ranges::cdata(c) == (R*)nullptr );
   static_assert( noexcept(std::ranges::cdata(c)) );
+
+  // not lvalues and not borrowed ranges
+  static_assert( !has_cdata<R> );
+  static_assert( !has_cdata<const R> );
 }
 
 void
@@ -44,28 +54,36 @@ test02()
 {
   int a[] = { 0, 1 };
   VERIFY( std::ranges::cdata(a) == a + 0 );
+
+  static_assert( has_cdata<int(&)[2]> );
+  static_assert( !has_cdata<int(&&)[2]> );
 }
 
-struct R
+struct R3
 {
-  long l = 0;
+  static inline int i = 0;
+  static inline long l = 0;
 
-  int* data() const { return nullptr; }
-  friend long* begin(R&& r); // this function is not defined
-  friend const long* begin(const R& r) { return &r.l; }
-  friend const short* begin(const R&&); // not defined
+  int* data() &; // this function is not defined
+  friend long* begin(R3&& r); // not defined
+  friend const long* begin(const R3& r) { return &r.l; }
+  friend const short* begin(const R3&&); // not defined
 };
 
-// This is a lie, ranges::begin(R&&) returns a dangling iterator.
-template<> constexpr bool std::ranges::enable_borrowed_range<R> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true;
 
 void
 test03()
 {
-  R r;
-  const R& c = r;
+  static_assert( has_cdata<R3&> );
+  static_assert( has_cdata<R3> );  // borrowed range
+  static_assert( has_cdata<const R3&> );
+  static_assert( has_cdata<const R3> );  // borrowed range
+
+  R3 r;
+  const R3& c = r;
   VERIFY( std::ranges::cdata(r) == std::ranges::data(c) );
-  VERIFY( std::ranges::cdata(std::move(r)) == std::ranges::begin(c) );
+  VERIFY( std::ranges::cdata(std::move(r)) == std::ranges::data(c) );
   VERIFY( std::ranges::cdata(std::move(c)) == std::ranges::begin(c) );
 }
 
diff --git a/libstdc++-v3/testsuite/std/ranges/access/data.cc b/libstdc++-v3/testsuite/std/ranges/access/data.cc
index 40d3027a7df..237bbcc76c5 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/data.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/data.cc
@@ -22,6 +22,10 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+template<typename T>
+  concept has_data
+    = requires (T&& t) { std::ranges::data(std::forward<T>(t)); };
+
 void
 test01()
 {
@@ -32,12 +36,18 @@ test01()
     int* data() { return &j; }
     const R* data() const noexcept { return nullptr; }
   };
+  static_assert( has_data<R&> );
+  static_assert( has_data<const R&> );
   R r;
   const R& c = r;
   VERIFY( std::ranges::data(r) == &r.j );
   static_assert( !noexcept(std::ranges::data(r)) );
   VERIFY( std::ranges::data(c) == (R*)nullptr );
   static_assert( noexcept(std::ranges::data(c)) );
+
+  // not lvalues and not borrowed ranges
+  static_assert( !has_data<R> );
+  static_assert( !has_data<const R> );
 }
 
 
@@ -49,31 +59,42 @@ test02()
 
   __gnu_test::test_range<int, __gnu_test::contiguous_iterator_wrapper> r(a);
   VERIFY( std::ranges::data(r) == std::to_address(std::ranges::begin(r)) );
+
+  static_assert( has_data<int(&)[2]> );
+  static_assert( has_data<decltype(r)&> );
+  static_assert( !has_data<int(&&)[2]> );
+  static_assert( !has_data<decltype(r)&&> );
 }
 
 struct R3
 {
-  long l = 0;
+  static inline int i;
+  static inline long l;
 
-  int* data() const { return nullptr; }
-  friend long* begin(R3& r) { return &r.l; }
-  friend const long* begin(const R3& r) { return &r.l + 1; }
+  int* data() & { return &i; }
+  friend long* begin(const R3& r) { return &l; }
+  friend const short* begin(const R3&&); // not defined
 };
 
-// N.B. this is a lie, begin on an R3 rvalue will return a dangling pointer.
 template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true;
 
 void
 test03()
 {
+  static_assert( has_data<R3&> );
+  static_assert( has_data<R3> );  // borrowed range
+  static_assert( has_data<const R3&> );
+  static_assert( has_data<const R3> );  // borrowed range
+
   R3 r;
   const R3& c = r;
-  // r.data() can only be used on an lvalue, but ranges::begin(R3&&) is OK
-  // because R3 satisfies ranges::borrowed_range.
-  VERIFY( std::ranges::data(std::move(r)) == std::to_address(std::ranges::begin(std::move(r))) );
-  VERIFY( std::ranges::data(std::move(c)) == std::to_address(std::ranges::begin(std::move(c))) );
+  // PR libstdc++/100824
+  // ranges::data should treat the subexpression as an lvalue
+  VERIFY( std::ranges::data(std::move(r)) == &R3::i );
+  VERIFY( std::ranges::data(std::move(c)) == &R3::l );
 }
 
+
 int
 main()
 {
diff --git a/libstdc++-v3/testsuite/std/ranges/access/empty.cc b/libstdc++-v3/testsuite/std/ranges/access/empty.cc
index 1cddffa95a9..9044dd155da 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/empty.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/empty.cc
@@ -35,7 +35,9 @@ test01()
   constexpr R r;
   static_assert( !std::ranges::empty(r) );
   static_assert( same_as<decltype(std::ranges::empty(r)), bool> );
-  static_assert( std::ranges::empty(std::move(r)) );
+  // PR libstdc++/100824
+  // ranges::empty should treat the subexpression as an lvalue
+  static_assert( !std::ranges::empty(std::move(r)) );
   static_assert( same_as<decltype(std::ranges::empty(std::move(r))), bool> );
 }
 
@@ -68,9 +70,29 @@ test02()
   VERIFY( !std::ranges::empty(so) );
 }
 
+void
+test03()
+{
+  // PR libstdc++/100824
+  // ranges::empty should treat the subexpression as an lvalue
+
+  struct R
+  {
+    constexpr bool empty() & { return true; }
+  };
+  static_assert( std::ranges::empty(R{}) );
+
+  struct R2
+  {
+    constexpr unsigned size() & { return 0; }
+  };
+  static_assert( std::ranges::empty(R2{}) );
+}
+
 int
 main()
 {
   test01();
   test02();
+  test03();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/access/size.cc b/libstdc++-v3/testsuite/std/ranges/access/size.cc
index 729308570ea..f25a1cb9ddb 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/size.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/size.cc
@@ -76,12 +76,14 @@ test03()
   const R3& c = r;
   VERIFY( std::ranges::size(r) == 1 );
   static_assert( noexcept(std::ranges::size(r)) );
-  VERIFY( std::ranges::size(std::move(r)) == 3U );
-  static_assert( !noexcept(std::ranges::size(std::move(r))) );
+  // PR libstdc++/100824
+  // ranges::size should treat the subexpression as an lvalue
+  VERIFY( std::ranges::size(std::move(r)) == 1 );
+  static_assert( noexcept(std::ranges::size(std::move(r))) );
   VERIFY( std::ranges::size(c) == 2L );
   static_assert( !noexcept(std::ranges::size(c)) );
-  VERIFY( std::ranges::size(std::move(c)) == 4UL );
-  static_assert( noexcept(std::ranges::size(std::move(c))) );
+  VERIFY( std::ranges::size(std::move(c)) == 2L );
+  static_assert( !noexcept(std::ranges::size(std::move(c))) );
 }
 
 void
@@ -109,6 +111,15 @@ test05()
   VERIFY( std::ranges::size(r) == 1 );
 }
 
+void
+test06()
+{
+  // PR libstdc++/100824
+  // ranges::size should treat the subexpression as an lvalue
+  struct R { constexpr int size() & { return 42; } };
+  static_assert( std::ranges::size(R{}) == 42 );
+}
+
 int
 main()
 {
@@ -117,4 +128,5 @@ main()
   test03();
   test04();
   test05();
+  test06();
 }
