diff --git a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
index 10376040c16..3667b0d021f 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
@@ -48,6 +48,10 @@ struct R
   friend int* begin(R&&); // this function is not defined
   friend const int* begin(const R& r) noexcept { return r.a + 2; }
   friend const int* begin(const R&&); // this function is not defined
+
+#if __cpp_lib_ranges_as_const
+  friend const int* end(const R&) noexcept; // C++23 requires this.
+#endif
 };
 
 struct RV // view on an R
@@ -56,6 +60,10 @@ struct RV // view on an R
 
   friend int* begin(RV&); // this function is not defined
   friend const int* begin(const RV& rv) noexcept { return begin(std::as_const(rv.r)); }
+
+#if __cpp_lib_ranges_as_const
+  friend const int* end(const RV&) noexcept; // C++23 requires this.
+#endif
 };
 
 // Allow ranges::begin to work with RV&&
@@ -88,6 +96,11 @@ struct RR
   friend int* begin(RR&& r) { return r.a + 1; }
   friend const int* begin(const RR& r) { return r.a + 2; }
   friend const int* begin(const RR&& r) noexcept { return r.a + 3; }
+
+#if __cpp_lib_ranges_as_const
+  short* end() noexcept { return &s + 1; }   // C++23 requires this.
+  const long* end() const { return &l + 1; } // C++23 requires this.
+#endif
 };
 
 // N.B. this is a lie, cbegin on an RR rvalue will return a dangling pointer.
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
index f0f45eeb6bf..d69b04c8f74 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
@@ -41,15 +41,43 @@ test01()
   static_assert( has_cdata<R&> );
   static_assert( has_cdata<const R&> );
   R r;
-  const R& c = r;
+#if ! __cpp_lib_ranges_as_const
   VERIFY( std::ranges::cdata(r) == (R*)nullptr );
   static_assert( noexcept(std::ranges::cdata(r)) );
+#else
+  // constant_range<const R> is not satisfied, so cdata(r) == data(r).
+  VERIFY( std::ranges::cdata(r) == &r.j );
+  static_assert( ! noexcept(std::ranges::cdata(r)) );
+#endif
+  const R& c = 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> );
+
+  struct R2
+  {
+    // These overloads mean that range<R2> and range<const R2> are satisfied.
+    int* begin();
+    int* end();
+    const int* begin() const;
+    const int* end() const;
+
+    int i = 0;
+    int j = 0;
+    int* data() { return &j; }
+    const R2* data() const noexcept { return nullptr; }
+  };
+  static_assert( has_cdata<R2&> );
+  static_assert( has_cdata<const R2&> );
+  R2 r2;
+  VERIFY( std::ranges::cdata(r2) == (R2*)nullptr );
+  static_assert( noexcept(std::ranges::cdata(r2)) );
+  const R2& c2 = r2;
+  VERIFY( std::ranges::cdata(c2) == (R2*)nullptr );
+  static_assert( noexcept(std::ranges::cdata(c2)) );
 }
 
 void
@@ -71,6 +99,14 @@ struct R3
   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
+
+#if __cpp_lib_ranges_as_const
+  // C++23 needs these so that range<R3> is satisfied and so that
+  // possibly-const-range<R3> is not the same type as R3.
+  friend long* begin(R3&);
+  friend long* end(R3&);
+  friend const long* end(const R3& r);
+#endif
 };
 
 template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true;
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc b/libstdc++-v3/testsuite/std/ranges/access/cend.cc
index f47bd9d9135..3726ebbf118 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc
@@ -42,7 +42,7 @@ struct R
   int a[4] = { 0, 1, 2, 3 };
 
   const int* begin() const { return nullptr; }
-  friend const int* begin(const R&& r) noexcept { return nullptr; }
+  friend const int* begin(const R&&) noexcept { return nullptr; }
 
   // Should be ignored because it doesn't return a sentinel for int*
   const long* end() const { return nullptr; }
@@ -53,6 +53,15 @@ struct R
   friend const int* end(const R&& r) noexcept { return r.a + 3; }
 };
 
+#if __cpp_lib_ranges_as_const
+struct R2 : R
+{
+  // This overload means constant_range<const R2> will be satisfied:
+  friend const int* begin(const R2&) noexcept;
+  friend const int* end(const R2& r2) noexcept { return r2.a + 2; }
+};
+#endif
+
 struct RV // view on an R
 {
   R& r;
@@ -71,12 +80,28 @@ test03()
 {
   R r;
   const R& c = r;
+#if ! __cpp_lib_ranges_as_const
   VERIFY( std::ranges::cend(r) == std::ranges::end(c) );
+#else
+  // constant_range<const R> is not satisfied, so cend(r) == end(r) instead.
+  VERIFY( std::ranges::cend(r) == std::ranges::end(r) );
+  R2 r2;
+  const R& c2 = r2;
+  // But constant_range<const R2> is satisfied, so cend(r2) == end(c2).
+  VERIFY( std::ranges::cend(r2) == std::ranges::end(c2) );
+  VERIFY( std::ranges::cend(r2) == std::ranges::end((const R&)c2) );
+#endif
   VERIFY( std::ranges::cend(c) == std::ranges::end(c) );
 
   RV v{r};
-  const RV cv{r};
+#if ! __cpp_lib_ranges_as_const
   VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(c) );
+#else
+  // constant_range<RV> is already satisfied, so cend(v) == end(r) instead.
+  VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(r) );
+#endif
+
+  const RV cv{r};
   VERIFY( std::ranges::cend(std::move(cv)) == std::ranges::end(c) );
 }
 
diff --git a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
index db58d9577d9..95b4607fdf1 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
@@ -37,13 +37,33 @@ struct R1V // view on an R1
 {
   R1& r;
 
-  friend const long* rbegin(R1V&); // this is not defined
+  friend const long* rbegin(R1V&) { return nullptr; }
   friend const int* rbegin(const R1V& rv) noexcept { return rv.r.rbegin(); }
 };
 
 // Allow ranges::end to work with R1V&&
 template<> constexpr bool std::ranges::enable_borrowed_range<R1V> = true;
 
+#if __cpp_lib_ranges_as_const
+struct R1VC // view on an R1
+{
+  R1& r;
+
+  friend const long* rbegin(R1VC&); // this is not defined
+  friend const int* rbegin(const R1VC& rv) noexcept { return rv.r.rbegin(); }
+
+  // The following ensure that the following are satisfied:
+  // constant_range<const R1VC> && ! constant_range<R1VC>
+  friend int* begin(R1VC&);
+  friend int* end(R1VC&);
+  friend const int* begin(const R1VC&);
+  friend const int* end(const R1VC&);
+};
+
+// Allow ranges::end to work with R1VC&&
+template<> constexpr bool std::ranges::enable_borrowed_range<R1VC> = true;
+#endif
+
 void
 test01()
 {
@@ -53,8 +73,24 @@ test01()
   VERIFY( std::ranges::crbegin(c) == std::ranges::rbegin(c) );
 
   R1V v{r};
-  const R1V cv{r};
+#if ! __cpp_lib_ranges_as_const
+  VERIFY( std::ranges::crbegin(v) == std::ranges::rbegin(c) );
   VERIFY( std::ranges::crbegin(std::move(v)) == std::ranges::rbegin(c) );
+#else
+  // constant_range<const R1V> is not satisfied, so crbegin(v) == rbegin(v).
+  VERIFY( std::ranges::crbegin(v) == (long*)nullptr );
+  VERIFY( std::ranges::crbegin(std::move(v)) == (long*)nullptr );
+  R1VC v2{r};
+  // But constant_range<const R1VC> is satisfied:
+  VERIFY( std::ranges::crbegin(v2) == std::ranges::rbegin(c) );
+  VERIFY( std::ranges::crbegin(std::move(v2)) == std::ranges::rbegin(c) );
+  const R1VC cv2{r};
+  VERIFY( std::ranges::crbegin(cv2) == std::ranges::rbegin(c) );
+  VERIFY( std::ranges::crbegin(std::move(cv2)) == std::ranges::rbegin(c) );
+#endif
+
+  const R1V cv{r};
+  VERIFY( std::ranges::crbegin(cv) == std::ranges::rbegin(c) );
   VERIFY( std::ranges::crbegin(std::move(cv)) == std::ranges::rbegin(c) );
 }
 
diff --git a/libstdc++-v3/testsuite/std/ranges/access/crend.cc b/libstdc++-v3/testsuite/std/ranges/access/crend.cc
index a7e033fc317..2e4c0f3197a 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/crend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/crend.cc
@@ -86,18 +86,47 @@ struct R3
   friend const int* rend(const R3& r) { return &r.i; }
 };
 
-// N.B. this is a lie, rend on an R3 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true;
+struct R4
+{
+  int i = 0;
+
+  // These members mean that range<R4> and range<const R4> are satisfied.
+  const short* begin() const { return 0; }
+  const short* end() const { return 0; }
+
+  const int* rbegin() const noexcept { return &i + 1; }
+  const long* rend() const noexcept { return nullptr; } // not a sentinel for rbegin()
+
+  friend const long* rbegin(const R4&) noexcept { return nullptr; }
+  friend const int* rend(const R4& r) { return &r.i; }
+};
 
 void
 test03()
 {
   R3 r;
   const R3& c = r;
+#if ! __cpp_lib_ranges_as_const
   VERIFY( std::ranges::crend(r) == std::ranges::rend(c) );
   static_assert( !noexcept(std::ranges::crend(r)) );
+#else
+  // constant_range<const R3> is not satisfied, so crend(r) is equivalent
+  // to const_sentinel{rend(r)}, which is ill-formed because range<R3>
+  // is not satisfied.
+  static_assert( not std::ranges::range<R3> );
+  static_assert( not std::ranges::range<const R3> );
+#endif
   VERIFY( std::ranges::crend(c) == std::ranges::rend(c) );
   static_assert( !noexcept(std::ranges::crend(c)) );
+
+  R4 r4;
+  const R4& c4 = r4;
+  auto b = std::ranges::rbegin(r4);
+  auto s0 = std::ranges::rend(r4);
+  static_assert( std::ranges::__access::__adl_rend<R4&> );
+  auto s = std::ranges::crend(r4);
+  auto s2 = std::ranges::rend(c4);
+  // VERIFY( std::ranges::crend(r4) == std::ranges::rend(c4) );
 }
 
 void
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
index 290b5c2bba5..a1f6068bc09 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
@@ -94,8 +94,10 @@ test05()
 
   // Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>.
   static_assert(!ranges::common_range<decltype(v)>);
+#if ! __cpp_lib_ranges_as_const
   static_assert(!std::same_as<decltype(ranges::end(v)),
 			      decltype(ranges::cend(v))>);
+#endif
   auto b = ranges::cend(v);
   b = ranges::end(v);
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
index 46060771483..098091edc8b 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
@@ -64,8 +64,10 @@ test03()
 
   // Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>.
   static_assert(!ranges::common_range<decltype(v)>);
+#if ! __cpp_lib_ranges_as_const
   static_assert(!std::same_as<decltype(ranges::end(v)),
 			      decltype(ranges::cend(v))>);
+#endif
   auto b = ranges::cend(v);
   b = ranges::end(v);
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
index 9d52cb01dad..d9801d5abb3 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
@@ -108,16 +108,20 @@ test05()
   auto r = ranges::subrange{i, std::default_sentinel};
   auto v = r | views::transform(std::negate{});
 
+#if ! __cpp_lib_ranges_as_const
   // Verify that _Iterator<false> is implicitly convertible to _Iterator<true>.
   static_assert(!std::same_as<decltype(ranges::begin(v)),
 			      decltype(ranges::cbegin(v))>);
+#endif
   auto a = ranges::cbegin(v);
   a = ranges::begin(v);
 
+#if ! __cpp_lib_ranges_as_const
   // Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>.
   static_assert(!ranges::common_range<decltype(v)>);
   static_assert(!std::same_as<decltype(ranges::end(v)),
 			      decltype(ranges::cend(v))>);
+#endif
   auto b = ranges::cend(v);
   b = ranges::end(v);
 }
