[libcxx-commits] [libcxx] 67151d0 - [libc++] [ranges] Implement P2415R2 owning_view.

Arthur O'Dwyer via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jan 13 09:30:28 PST 2022


Author: Arthur O'Dwyer
Date: 2022-01-13T12:29:41-05:00
New Revision: 67151d029bdb933c006535f94bd3e625307a6cfa

URL: https://github.com/llvm/llvm-project/commit/67151d029bdb933c006535f94bd3e625307a6cfa
DIFF: https://github.com/llvm/llvm-project/commit/67151d029bdb933c006535f94bd3e625307a6cfa.diff

LOG: [libc++] [ranges] Implement P2415R2 owning_view.

"What is a view?"
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2415r2.html
https://github.com/cplusplus/draft/pull/5010/files

This was a late-breaking (Oct 2021) change to C++20.
The only thing missing from this patch is that we're supposed
to bump the feature-test macro from
    #define __cpp_lib_ranges 202106L
to
    #define __cpp_lib_ranges 202110L
but we can't do that because we don't implement all of 202106 Ranges yet.

Differential Revision: https://reviews.llvm.org/D116894

Added: 
    libcxx/include/__ranges/owning_view.h
    libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp

Modified: 
    libcxx/docs/Status/Cxx20Papers.csv
    libcxx/docs/Status/RangesIssues.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/__ranges/all.h
    libcxx/include/__ranges/concepts.h
    libcxx/include/module.modulemap
    libcxx/include/ranges
    libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp
    libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp
    libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp

Removed: 
    libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp


################################################################################
diff  --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index 3caca78f36f30..d0927e09426ce 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -202,6 +202,6 @@
 "`P2367R0 <https://wg21.link/P2367R0>`__","LWG",Remove misuses of list-initialization from Clause 24,"June 2021","",""
 "","","","","",""
 "`P2372R3 <https://wg21.link/P2372R3>`__","LWG","Fixing locale handling in chrono formatters","October 2021","",""
-"`P2415R2 <https://wg21.link/P2415R2>`__","LWG","What is a ``view``","October 2021","",""
+"`P2415R2 <https://wg21.link/P2415R2>`__","LWG","What is a ``view``","October 2021","|Complete|","14.0"
 "`P2418R2 <https://wg21.link/P2418R2>`__","LWG","Add support for ``std::generator``-like types to ``std::format``","October 2021","",""
 "`P2432R1 <https://wg21.link/P2432R1>`__","LWG","Fix ``istream_view``","October 2021","",""

diff  --git a/libcxx/docs/Status/RangesIssues.csv b/libcxx/docs/Status/RangesIssues.csv
index 5081fbf4628c0..7948148b6c6be 100644
--- a/libcxx/docs/Status/RangesIssues.csv
+++ b/libcxx/docs/Status/RangesIssues.csv
@@ -29,5 +29,5 @@
 `P2281R1 <https://wg21.link/P2281R1>`__,Clarifying range adaptor objects,,
 `P2367R0 <https://wg21.link/P2367R0>`__,Remove misuses of list-initialization from Clause 24,,
 
-`P2415 <https://wg21.link/P2415>`__,"What is a ``view``",,
+`P2415 <https://wg21.link/P2415>`__,"What is a ``view``",|Complete|,14.0
 `P2432 <https://wg21.link/P2432>`__,"Fix ``istream_view``",,

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 30708599751cd..26edb72482886 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -326,6 +326,7 @@ set(files
   __ranges/iota_view.h
   __ranges/join_view.h
   __ranges/non_propagating_cache.h
+  __ranges/owning_view.h
   __ranges/range_adaptor.h
   __ranges/ref_view.h
   __ranges/reverse_view.h

diff  --git a/libcxx/include/__ranges/all.h b/libcxx/include/__ranges/all.h
index ccc77258ba10a..90327da81460a 100644
--- a/libcxx/include/__ranges/all.h
+++ b/libcxx/include/__ranges/all.h
@@ -14,9 +14,9 @@
 #include <__iterator/iterator_traits.h>
 #include <__ranges/access.h>
 #include <__ranges/concepts.h>
+#include <__ranges/owning_view.h>
 #include <__ranges/range_adaptor.h>
 #include <__ranges/ref_view.h>
-#include <__ranges/subrange.h>
 #include <__utility/auto_cast.h>
 #include <__utility/declval.h>
 #include <__utility/forward.h>
@@ -56,12 +56,12 @@ namespace __all {
     template<class _Tp>
       requires (!ranges::view<decay_t<_Tp>> &&
                 !requires (_Tp&& __t) { ranges::ref_view{_VSTD::forward<_Tp>(__t)}; } &&
-                 requires (_Tp&& __t) { ranges::subrange{_VSTD::forward<_Tp>(__t)}; })
+                 requires (_Tp&& __t) { ranges::owning_view{_VSTD::forward<_Tp>(__t)}; })
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
     constexpr auto operator()(_Tp&& __t) const
-      noexcept(noexcept(ranges::subrange{_VSTD::forward<_Tp>(__t)}))
+      noexcept(noexcept(ranges::owning_view{_VSTD::forward<_Tp>(__t)}))
     {
-      return ranges::subrange{_VSTD::forward<_Tp>(__t)};
+      return ranges::owning_view{_VSTD::forward<_Tp>(__t)};
     }
   };
 }

diff  --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index bad23c8c4bfbe..fa31074ab6581 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -9,6 +9,9 @@
 #ifndef _LIBCPP___RANGES_CONCEPTS_H
 #define _LIBCPP___RANGES_CONCEPTS_H
 
+#include <__concepts/constructible.h>
+#include <__concepts/movable.h>
+#include <__concepts/same_as.h>
 #include <__config>
 #include <__iterator/concepts.h>
 #include <__iterator/incrementable_traits.h>
@@ -20,7 +23,7 @@
 #include <__ranges/enable_borrowed_range.h>
 #include <__ranges/enable_view.h>
 #include <__ranges/size.h>
-#include <concepts>
+#include <initializer_list>
 #include <type_traits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -114,12 +117,20 @@ namespace ranges {
   template <class _Tp>
   concept common_range = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>;
 
-  template<class _Tp>
+  template <class _Tp>
+  inline constexpr bool __is_std_initializer_list = false;
+
+  template <class _Ep>
+  inline constexpr bool __is_std_initializer_list<initializer_list<_Ep>> = true;
+
+  template <class _Tp>
   concept viewable_range =
-    range<_Tp> && (
-      (view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>) ||
-      (!view<remove_cvref_t<_Tp>> && borrowed_range<_Tp>)
-    );
+    range<_Tp> &&
+    ((view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>) ||
+     (!view<remove_cvref_t<_Tp>> &&
+      (is_lvalue_reference_v<_Tp> ||
+       (movable<remove_reference_t<_Tp>> && !__is_std_initializer_list<remove_cvref_t<_Tp>>))));
+
 } // namespace ranges
 
 #endif // !defined(_LIBCPP_HAS_NO_RANGES)

diff  --git a/libcxx/include/__ranges/owning_view.h b/libcxx/include/__ranges/owning_view.h
new file mode 100644
index 0000000000000..29182d2d8e46e
--- /dev/null
+++ b/libcxx/include/__ranges/owning_view.h
@@ -0,0 +1,81 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef _LIBCPP___RANGES_OWNING_VIEW_H
+#define _LIBCPP___RANGES_OWNING_VIEW_H
+
+#include <__concepts/constructible.h>
+#include <__concepts/movable.h>
+#include <__config>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/data.h>
+#include <__ranges/empty.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/size.h>
+#include <__ranges/view_interface.h>
+#include <__utility/move.h>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+namespace ranges {
+  template<range _Rp>
+    requires movable<_Rp> && (!__is_std_initializer_list<remove_cvref_t<_Rp>>)
+  class owning_view : public view_interface<owning_view<_Rp>> {
+    _Rp __r_ = _Rp();
+
+public:
+    owning_view() requires default_initializable<_Rp> = default;
+    _LIBCPP_HIDE_FROM_ABI constexpr owning_view(_Rp&& __r) : __r_(_VSTD::move(__r)) {}
+
+    owning_view(owning_view&&) = default;
+    owning_view& operator=(owning_view&&) = default;
+
+    _LIBCPP_HIDE_FROM_ABI constexpr _Rp& base() & noexcept { return __r_; }
+    _LIBCPP_HIDE_FROM_ABI constexpr const _Rp& base() const& noexcept { return __r_; }
+    _LIBCPP_HIDE_FROM_ABI constexpr _Rp&& base() && noexcept { return _VSTD::move(__r_); }
+    _LIBCPP_HIDE_FROM_ABI constexpr const _Rp&& base() const&& noexcept { return _VSTD::move(__r_); }
+
+    _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Rp> begin() { return ranges::begin(__r_); }
+    _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Rp> end() { return ranges::end(__r_); }
+    _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range<const _Rp> { return ranges::begin(__r_); }
+    _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range<const _Rp> { return ranges::end(__r_); }
+
+    _LIBCPP_HIDE_FROM_ABI constexpr bool empty() requires requires { ranges::empty(__r_); }
+      { return ranges::empty(__r_); }
+    _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const requires requires { ranges::empty(__r_); }
+      { return ranges::empty(__r_); }
+
+    _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_Rp>
+      { return ranges::size(__r_); }
+    _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range<const _Rp>
+      { return ranges::size(__r_); }
+
+    _LIBCPP_HIDE_FROM_ABI constexpr auto data() requires contiguous_range<_Rp>
+      { return ranges::data(__r_); }
+    _LIBCPP_HIDE_FROM_ABI constexpr auto data() const requires contiguous_range<const _Rp>
+      { return ranges::data(__r_); }
+  };
+
+  template<class _Tp>
+  inline constexpr bool enable_borrowed_range<owning_view<_Tp>> = enable_borrowed_range<_Tp>;
+
+} // namespace ranges
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___RANGES_OWNING_VIEW_H

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 828c9d55495fd..b514f96a6ff72 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -799,6 +799,7 @@ module std [system] {
       module iota_view              { private header "__ranges/iota_view.h" }
       module join_view              { private header "__ranges/join_view.h" }
       module non_propagating_cache  { private header "__ranges/non_propagating_cache.h" }
+      module owning_view            { private header "__ranges/owning_view.h" }
       module range_adaptor          { private header "__ranges/range_adaptor.h" }
       module ref_view               { private header "__ranges/ref_view.h" }
       module reverse_view           { private header "__ranges/reverse_view.h" }

diff  --git a/libcxx/include/ranges b/libcxx/include/ranges
index 707c7acd1b01e..eb4492376c5c3 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -135,6 +135,13 @@ namespace std::ranges {
   template<class T>
     inline constexpr bool enable_borrowed_range<ref_view<T>> = true;
 
+  template<range R>
+    requires see below
+  class owning_view;
+
+  template<class T>
+    inline constexpr bool enable_borrowed_range<owning_view<T>> = enable_borrowed_range<T>;
+
   // [range.drop], drop view
   template<view V>
     class drop_view;

diff  --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp
new file mode 100644
index 0000000000000..e68237cc5b686
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__ranges/owning_view.h'}}
+#include <__ranges/owning_view.h>

diff  --git a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
index d48ce88a15a7e..2cbda51d18c6c 100644
--- a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::view<range>);
 static_assert(!std::ranges::random_access_range<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
index 0c008e71df504..1d278b9f2547e 100644
--- a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::view<range>);
 static_assert(!std::ranges::random_access_range<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
index 84c41274a3131..fb6228bd4c8bc 100644
--- a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
@@ -26,7 +26,7 @@ static_assert(!std::ranges::view<range>);
 static_assert(!std::ranges::random_access_range<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
index 5853d9c2a1d9f..a1cfd5af5ed4d 100644
--- a/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
@@ -28,7 +28,7 @@ static_assert(std::ranges::input_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
index 8fdd9869f9393..4609f27702c29 100644
--- a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(std::ranges::random_access_range<range>);
 static_assert(std::ranges::contiguous_range<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(!std::ranges::view<range const>);
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
index ce3eea3c30c6f..3eecb02782edd 100644
--- a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::contiguous_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
index 8c29c2a223bc4..d1d3328b34c66 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(!std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
index 7354563fe4f4a..14d301aa50c43 100644
--- a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::view<range>);
 static_assert(!std::ranges::random_access_range<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
index b19c4afbe175d..167a6f956eb49 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::contiguous_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
index fe0053236ed3e..868b1224bed9f 100644
--- a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(std::ranges::contiguous_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
index 32e834691abf1..897e709699f76 100644
--- a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
index 01a1d34808dc8..27c5b7fd968b8 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
index 1557c99e31c09..b1f98ae1bed3f 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
index b9c96c7c317c6..0303de9e39c42 100644
--- a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
 static_assert(!std::ranges::view<range>);
 static_assert(std::ranges::sized_range<range>);
 static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
 
 static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
 static_assert(std::ranges::common_range<range const>);

diff  --git a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
index 77b46ab04a8b4..12f452c9e5e96 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
@@ -26,7 +26,7 @@ static_assert(!std::ranges::view<fs::path>);
 static_assert(!std::ranges::random_access_range<fs::path>);
 static_assert(!std::ranges::sized_range<fs::path>);
 static_assert(!std::ranges::borrowed_range<fs::path>);
-static_assert(!std::ranges::viewable_range<fs::path>);
+static_assert(std::ranges::viewable_range<fs::path>);
 
 static_assert(std::same_as<std::ranges::iterator_t<fs::path const>, fs::path::const_iterator>);
 static_assert(std::ranges::common_range<fs::path const>);

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp
index c24435af90d7b..2f28029d37e68 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp
@@ -67,13 +67,8 @@ template<>
 inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
 
 struct RandomAccessRange {
-  struct sentinel {
-    friend constexpr bool operator==(sentinel, const random_access_iterator<int*> rai) { return rai.base() == globalBuff + 8; }
-    friend constexpr std::ptr
diff _t operator-(sentinel, random_access_iterator<int*>) { return -8; }
-    friend constexpr std::ptr
diff _t operator-(random_access_iterator<int*>, sentinel) { return 8; }
-  };
-  constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{globalBuff}; }
-  constexpr sentinel end() { return {}; }
+  constexpr auto begin() { return random_access_iterator<int*>(globalBuff); }
+  constexpr auto end() { return sized_sentinel(random_access_iterator<int*>(globalBuff + 8)); }
 };
 template<>
 inline constexpr bool std::ranges::enable_borrowed_range<RandomAccessRange> = true;
@@ -114,32 +109,31 @@ constexpr bool test() {
     assert(std::ranges::begin(ref) == globalBuff + 2);
     assert(std::ranges::end(ref) == globalBuff + 8);
 
-    static_assert(!std::is_invocable_v<decltype(std::views::all), Range>);
-  }
+    auto own = std::views::all(std::move(range));
+    ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<Range>);
+    assert(std::ranges::begin(own) == globalBuff + 2);
+    assert(std::ranges::end(own) == globalBuff + 8);
 
-  {
-    const Range range(2);
-    auto ref = std::views::all(range);
-    static_assert(!noexcept(std::views::all(range)));
-    ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<const Range>);
-    assert(std::ranges::begin(ref) == globalBuff + 2);
-    assert(std::ranges::end(ref) == globalBuff + 8);
+    auto cref = std::views::all(std::as_const(range));
+    ASSERT_SAME_TYPE(decltype(cref), std::ranges::ref_view<const Range>);
+    assert(std::ranges::begin(cref) == globalBuff + 2);
+    assert(std::ranges::end(cref) == globalBuff + 8);
+
+    static_assert(!std::is_invocable_v<decltype(std::views::all), const Range&&>);
   }
 
   {
-    auto subrange = std::views::all(BorrowableRange(2));
-    static_assert(!noexcept(std::views::all(BorrowableRange(2))));
-    ASSERT_SAME_TYPE(decltype(subrange), std::ranges::subrange<int*>);
-    assert(std::ranges::begin(subrange) == globalBuff + 2);
-    assert(std::ranges::end(subrange) == globalBuff + 8);
+    auto own = std::views::all(BorrowableRange(2));
+    ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<BorrowableRange>);
+    assert(std::ranges::begin(own) == globalBuff + 2);
+    assert(std::ranges::end(own) == globalBuff + 8);
   }
 
   {
-    auto subrange = std::views::all(RandomAccessRange());
-    ASSERT_SAME_TYPE(decltype(subrange),
-                     std::ranges::subrange<random_access_iterator<int*>, RandomAccessRange::sentinel>);
-    assert(std::ranges::begin(subrange).base() == globalBuff);
-    assert(std::ranges::end(subrange) == std::ranges::begin(subrange) + 8);
+    auto own = std::views::all(RandomAccessRange());
+    ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<RandomAccessRange>);
+    assert(base(std::ranges::begin(own)) == globalBuff);
+    assert(base(base(std::ranges::end(own))) == globalBuff + 8);
   }
 
   // Check SFINAE friendliness of the call operator

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp
index 7db0c4a41bd8d..54d3af532ef69 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp
@@ -16,26 +16,49 @@
 #include <ranges>
 
 #include "test_iterators.h"
-#include "test_range.h"
 
-struct View : test_range<cpp20_input_iterator>, std::ranges::view_base { };
-struct Range : test_range<cpp20_input_iterator> { };
-struct BorrowableRange : test_range<forward_iterator> { };
+struct View : std::ranges::view_base {
+  int *begin() const;
+  int *end() const;
+};
+
+struct Range {
+  int *begin() const;
+  int *end() const;
+};
+
+struct BorrowableRange {
+  int *begin() const;
+  int *end() const;
+};
 template<>
 inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
 
+template <class T>
+concept HasAllT = requires {
+    typename std::views::all_t<T>;
+};
+
 // When T is a view, returns decay-copy(T)
 ASSERT_SAME_TYPE(std::views::all_t<View>, View);
 ASSERT_SAME_TYPE(std::views::all_t<View&>, View);
-ASSERT_SAME_TYPE(std::views::all_t<View const>, View);
-ASSERT_SAME_TYPE(std::views::all_t<View const&>, View);
+ASSERT_SAME_TYPE(std::views::all_t<View&&>, View);
+ASSERT_SAME_TYPE(std::views::all_t<const View>, View);
+ASSERT_SAME_TYPE(std::views::all_t<const View&>, View);
+ASSERT_SAME_TYPE(std::views::all_t<const View&&>, View);
 
 // Otherwise, when T is a reference to a range, returns ref_view<T>
 ASSERT_SAME_TYPE(std::views::all_t<Range&>, std::ranges::ref_view<Range>);
-ASSERT_SAME_TYPE(std::views::all_t<Range const&>, std::ranges::ref_view<Range const>);
+ASSERT_SAME_TYPE(std::views::all_t<const Range&>, std::ranges::ref_view<const Range>);
 ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange&>, std::ranges::ref_view<BorrowableRange>);
-ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange const&>, std::ranges::ref_view<BorrowableRange const>);
+ASSERT_SAME_TYPE(std::views::all_t<const BorrowableRange&>, std::ranges::ref_view<const BorrowableRange>);
 
-// Otherwise, returns subrange<iterator_t<T>, sentinel_t<R>>
-ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange>, std::ranges::subrange<forward_iterator<int*>, sentinel>);
-ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange const>, std::ranges::subrange<forward_iterator<int const*>, sentinel>);
+// Otherwise, returns owning_view<T>
+ASSERT_SAME_TYPE(std::views::all_t<Range>, std::ranges::owning_view<Range>);
+ASSERT_SAME_TYPE(std::views::all_t<Range&&>, std::ranges::owning_view<Range>);
+static_assert(!HasAllT<const Range>);
+static_assert(!HasAllT<const Range&&>);
+ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange>, std::ranges::owning_view<BorrowableRange>);
+ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange&&>, std::ranges::owning_view<BorrowableRange>);
+static_assert(!HasAllT<const BorrowableRange>);
+static_assert(!HasAllT<const BorrowableRange&&>);

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp
new file mode 100644
index 0000000000000..59cf1c0403207
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr R& base() & noexcept { return r_; }
+// constexpr const R& base() const& noexcept { return r_; }
+// constexpr R&& base() && noexcept { return std::move(r_); }
+// constexpr const R&& base() const&& noexcept { return std::move(r_); }
+
+#include <ranges>
+
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+
+struct Base {
+  int *begin() const;
+  int *end() const;
+};
+
+constexpr bool test()
+{
+  using OwningView = std::ranges::owning_view<Base>;
+  OwningView ov;
+  decltype(auto) b1 = static_cast<OwningView&>(ov).base();
+  decltype(auto) b2 = static_cast<OwningView&&>(ov).base();
+  decltype(auto) b3 = static_cast<const OwningView&>(ov).base();
+  decltype(auto) b4 = static_cast<const OwningView&&>(ov).base();
+
+  ASSERT_SAME_TYPE(decltype(b1), Base&);
+  ASSERT_SAME_TYPE(decltype(b2), Base&&);
+  ASSERT_SAME_TYPE(decltype(b3), const Base&);
+  ASSERT_SAME_TYPE(decltype(b4), const Base&&);
+
+  assert(&b1 == &b2);
+  assert(&b1 == &b3);
+  assert(&b1 == &b4);
+
+  ASSERT_NOEXCEPT(static_cast<OwningView&>(ov).base());
+  ASSERT_NOEXCEPT(static_cast<OwningView&&>(ov).base());
+  ASSERT_NOEXCEPT(static_cast<const OwningView&>(ov).base());
+  ASSERT_NOEXCEPT(static_cast<const OwningView&&>(ov).base());
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp
new file mode 100644
index 0000000000000..9319ac3b8986a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp
@@ -0,0 +1,133 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+
+// constexpr iterator_t<R> begin();
+// constexpr sentinel_t<R> end();
+// constexpr auto begin() const requires range<const R>;
+// constexpr auto end() const requires range<const R>;
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+struct Base {
+  constexpr int *begin() { return nullptr; }
+  constexpr auto end() { return sentinel_wrapper<int*>(nullptr); }
+  constexpr char *begin() const { return nullptr; }
+  constexpr auto end() const { return sentinel_wrapper<char*>(nullptr); }
+};
+static_assert(std::same_as<std::ranges::iterator_t<Base>, int*>);
+static_assert(std::same_as<std::ranges::sentinel_t<Base>, sentinel_wrapper<int*>>);
+static_assert(std::same_as<std::ranges::iterator_t<const Base>, char*>);
+static_assert(std::same_as<std::ranges::sentinel_t<const Base>, sentinel_wrapper<char*>>);
+
+struct NoConst {
+  int* begin();
+  sentinel_wrapper<int*> end();
+};
+
+struct DecayChecker {
+  int*& begin() const;
+  int*& end() const;
+};
+
+template <class T>
+concept HasBegin = requires (T t) {
+  t.begin();
+};
+
+template <class T>
+concept HasEnd = requires (T t) {
+  t.end();
+};
+
+constexpr bool test()
+{
+  {
+    using OwningView = std::ranges::owning_view<Base>;
+    OwningView ov;
+    std::same_as<int*> decltype(auto) b1 = static_cast<OwningView&>(ov).begin();
+    std::same_as<int*> decltype(auto) b2 = static_cast<OwningView&&>(ov).begin();
+    std::same_as<char*> decltype(auto) b3 = static_cast<const OwningView&>(ov).begin();
+    std::same_as<char*> decltype(auto) b4 = static_cast<const OwningView&&>(ov).begin();
+
+    std::same_as<sentinel_wrapper<int*>> decltype(auto) e1 = static_cast<OwningView&>(ov).end();
+    std::same_as<sentinel_wrapper<int*>> decltype(auto) e2 = static_cast<OwningView&&>(ov).end();
+    std::same_as<sentinel_wrapper<char*>> decltype(auto) e3 = static_cast<const OwningView&>(ov).end();
+    std::same_as<sentinel_wrapper<char*>> decltype(auto) e4 = static_cast<const OwningView&&>(ov).end();
+
+    assert(b1 == e1);
+    assert(b2 == e2);
+    assert(b3 == e3);
+    assert(b4 == e4);
+  }
+  {
+    // NoConst has non-const begin() and end(); so does the owning_view.
+    using OwningView = std::ranges::owning_view<NoConst>;
+    static_assert(HasBegin<OwningView&>);
+    static_assert(HasBegin<OwningView&&>);
+    static_assert(!HasBegin<const OwningView&>);
+    static_assert(!HasBegin<const OwningView&&>);
+    static_assert(HasEnd<OwningView&>);
+    static_assert(HasEnd<OwningView&&>);
+    static_assert(!HasEnd<const OwningView&>);
+    static_assert(!HasEnd<const OwningView&&>);
+  }
+  {
+    // DecayChecker's begin() and end() return references; make sure the owning_view decays them.
+    using OwningView = std::ranges::owning_view<DecayChecker>;
+    OwningView ov;
+    ASSERT_SAME_TYPE(decltype(ov.begin()), int*);
+    ASSERT_SAME_TYPE(decltype(ov.end()), int*);
+  }
+  {
+    // Test an empty view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a));
+    assert(ov.begin() == a);
+    assert(std::as_const(ov).begin() == a);
+    assert(ov.end() == a);
+    assert(std::as_const(ov).end() == a);
+  }
+  {
+    // Test a non-empty view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));
+    assert(ov.begin() == a);
+    assert(std::as_const(ov).begin() == a);
+    assert(ov.end() == a+1);
+    assert(std::as_const(ov).end() == a+1);
+  }
+  {
+    // Test a non-view.
+    std::array<int, 2> a = {1, 2};
+    auto ov = std::ranges::owning_view(std::move(a));
+    assert(ov.begin() != a.begin()); // because it points into the copy
+    assert(std::as_const(ov).begin() != a.begin());
+    assert(ov.end() != a.end());
+    assert(std::as_const(ov).end() != a.end());
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp
new file mode 100644
index 0000000000000..59cc12fd30aab
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// template<class T>
+//   inline constexpr bool enable_borrowed_range<owning_view<T>> = enable_borrowed_range<T>;
+
+#include <ranges>
+#include <cassert>
+
+struct Range {
+  int *begin() const;
+  int *end() const;
+};
+
+struct BorrowableRange {
+  int *begin() const;
+  int *end() const;
+};
+
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
+
+static_assert(!std::ranges::enable_borrowed_range<std::ranges::owning_view<Range>>);
+static_assert( std::ranges::enable_borrowed_range<std::ranges::owning_view<BorrowableRange>>);

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp
new file mode 100644
index 0000000000000..54778482398a1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp
@@ -0,0 +1,140 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// owning_view() requires default_initializable<R> = default;
+// constexpr owning_view(R&& t);
+
+#include <ranges>
+
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+struct DefaultConstructible {
+  int i;
+  constexpr explicit DefaultConstructible(int j = 42) : i(j) {}
+  int *begin() const;
+  int *end() const;
+};
+
+struct NotDefaultConstructible {
+  int i;
+  constexpr explicit NotDefaultConstructible(int j) : i(j) {}
+  int *begin() const;
+  int *end() const;
+};
+
+struct MoveChecker {
+  int i;
+  constexpr explicit MoveChecker(int j) : i(j) {}
+  constexpr MoveChecker(MoveChecker&& v) : i(std::exchange(v.i, -1)) {}
+  MoveChecker& operator=(MoveChecker&&);
+  int *begin() const;
+  int *end() const;
+};
+
+struct NoexceptChecker {
+  int *begin() const;
+  int *end() const;
+};
+
+constexpr bool test()
+{
+  {
+    using OwningView = std::ranges::owning_view<DefaultConstructible>;
+    static_assert(std::is_constructible_v<OwningView>);
+    static_assert(std::default_initializable<OwningView>);
+    static_assert(std::movable<OwningView>);
+    static_assert(std::is_trivially_move_constructible_v<OwningView>);
+    static_assert(std::is_trivially_move_assignable_v<OwningView>);
+    static_assert(!std::is_copy_constructible_v<OwningView>);
+    static_assert(!std::is_copy_assignable_v<OwningView>);
+    static_assert(!std::is_constructible_v<OwningView, int>);
+    static_assert(!std::is_constructible_v<OwningView, DefaultConstructible&>);
+    static_assert(std::is_constructible_v<OwningView, DefaultConstructible&&>);
+    static_assert(!std::is_convertible_v<int, OwningView>);
+    static_assert(std::is_convertible_v<DefaultConstructible&&, OwningView>);
+    {
+      OwningView ov;
+      assert(ov.base().i == 42);
+    }
+    {
+      OwningView ov = OwningView(DefaultConstructible(1));
+      assert(ov.base().i == 1);
+    }
+  }
+  {
+    using OwningView = std::ranges::owning_view<NotDefaultConstructible>;
+    static_assert(!std::is_constructible_v<OwningView>);
+    static_assert(!std::default_initializable<OwningView>);
+    static_assert(std::movable<OwningView>);
+    static_assert(std::is_trivially_move_constructible_v<OwningView>);
+    static_assert(std::is_trivially_move_assignable_v<OwningView>);
+    static_assert(!std::is_copy_constructible_v<OwningView>);
+    static_assert(!std::is_copy_assignable_v<OwningView>);
+    static_assert(!std::is_constructible_v<OwningView, int>);
+    static_assert(!std::is_constructible_v<OwningView, NotDefaultConstructible&>);
+    static_assert(std::is_constructible_v<OwningView, NotDefaultConstructible&&>);
+    static_assert(!std::is_convertible_v<int, OwningView>);
+    static_assert(std::is_convertible_v<NotDefaultConstructible&&, OwningView>);
+    {
+      OwningView ov = OwningView(NotDefaultConstructible(1));
+      assert(ov.base().i == 1);
+    }
+  }
+  {
+    using OwningView = std::ranges::owning_view<MoveChecker>;
+    static_assert(!std::is_constructible_v<OwningView>);
+    static_assert(!std::default_initializable<OwningView>);
+    static_assert(std::movable<OwningView>);
+    static_assert(!std::is_trivially_move_constructible_v<OwningView>);
+    static_assert(!std::is_trivially_move_assignable_v<OwningView>);
+    static_assert(!std::is_copy_constructible_v<OwningView>);
+    static_assert(!std::is_copy_assignable_v<OwningView>);
+    static_assert(!std::is_constructible_v<OwningView, int>);
+    static_assert(!std::is_constructible_v<OwningView, MoveChecker&>);
+    static_assert(std::is_constructible_v<OwningView, MoveChecker&&>);
+    static_assert(!std::is_convertible_v<int, OwningView>);
+    static_assert(std::is_convertible_v<MoveChecker&&, OwningView>);
+    {
+      // Check that the constructor does indeed move from the target object.
+      auto m = MoveChecker(42);
+      OwningView ov = OwningView(std::move(m));
+      assert(ov.base().i == 42);
+      assert(m.i == -1);
+    }
+  }
+  {
+    // Check that the defaulted constructors are (not) noexcept when appropriate.
+
+    static_assert( std::is_nothrow_constructible_v<NoexceptChecker>); // therefore,
+    static_assert( std::is_nothrow_constructible_v<std::ranges::owning_view<NoexceptChecker>>);
+    static_assert(!std::is_nothrow_constructible_v<DefaultConstructible>); // therefore,
+    static_assert(!std::is_nothrow_constructible_v<std::ranges::owning_view<DefaultConstructible>>);
+
+    static_assert( std::is_nothrow_move_constructible_v<NoexceptChecker>); // therefore,
+    static_assert( std::is_nothrow_move_constructible_v<std::ranges::owning_view<NoexceptChecker>>);
+    static_assert(!std::is_nothrow_move_constructible_v<MoveChecker>); // therefore,
+    static_assert(!std::is_nothrow_move_constructible_v<std::ranges::owning_view<MoveChecker>>);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp
new file mode 100644
index 0000000000000..65f224b24d287
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr auto data() requires contiguous_range<R>
+// constexpr auto data() const requires contiguous_range<const R>
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasData = requires (T t) {
+  t.data();
+};
+
+constexpr bool test()
+{
+  {
+    struct ContiguousIters {
+      contiguous_iterator<int*> begin();
+      sentinel_wrapper<contiguous_iterator<int*>> end();
+    };
+    using OwningView = std::ranges::owning_view<ContiguousIters>;
+    static_assert(std::ranges::contiguous_range<OwningView&>);
+    static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+    static_assert(HasData<OwningView&>);
+    static_assert(HasData<OwningView&&>);
+    static_assert(!HasData<const OwningView&>);
+    static_assert(!HasData<const OwningView&&>);
+  }
+  {
+    struct NoData {
+      random_access_iterator<int*> begin();
+      random_access_iterator<int*> end();
+    };
+    using OwningView = std::ranges::owning_view<NoData>;
+    static_assert(!HasData<OwningView&>);
+    static_assert(!HasData<OwningView&&>);
+    static_assert(!HasData<const OwningView&>);
+    static_assert(!HasData<const OwningView&&>);
+  }
+  {
+    // Test a view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));
+    assert(ov.data() == a);
+    assert(std::as_const(ov).data() == a);
+  }
+  {
+    // Test a non-view.
+    std::array<int, 2> a = {1, 2};
+    auto ov = std::ranges::owning_view(std::move(a));
+    assert(ov.data() != a.data()); // because it points into the copy
+    assert(std::as_const(ov).data() != a.data());
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp
new file mode 100644
index 0000000000000..cc3d85c8a2ebc
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr bool empty() requires requires { ranges::empty(r_); }
+// constexpr bool empty() const requires requires { ranges::empty(r_); }
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasEmpty = requires (T t) {
+  t.empty();
+};
+
+constexpr bool test()
+{
+  {
+    struct ComparableIters {
+      forward_iterator<int*> begin();
+      forward_iterator<int*> end();
+    };
+    using OwningView = std::ranges::owning_view<ComparableIters>;
+    static_assert(HasEmpty<OwningView&>);
+    static_assert(HasEmpty<OwningView&&>);
+    static_assert(!HasEmpty<const OwningView&>);
+    static_assert(!HasEmpty<const OwningView&&>);
+  }
+  {
+    struct NoEmpty {
+      cpp20_input_iterator<int*> begin();
+      sentinel_wrapper<cpp20_input_iterator<int*>> end();
+    };
+    static_assert(std::ranges::range<NoEmpty&>);
+    static_assert(!std::invocable<decltype(std::ranges::empty), NoEmpty&>);
+    static_assert(!std::ranges::range<const NoEmpty&>); // no begin/end
+    static_assert(!std::invocable<decltype(std::ranges::empty), const NoEmpty&>);
+    using OwningView = std::ranges::owning_view<NoEmpty>;
+    static_assert(!HasEmpty<OwningView&>);
+    static_assert(!HasEmpty<OwningView&&>);
+    static_assert(!HasEmpty<const OwningView&>);
+    static_assert(!HasEmpty<const OwningView&&>);
+  }
+  {
+    struct EmptyMember {
+      cpp20_input_iterator<int*> begin();
+      sentinel_wrapper<cpp20_input_iterator<int*>> end();
+      bool empty() const;
+    };
+    static_assert(std::ranges::range<EmptyMember&>);
+    static_assert(std::invocable<decltype(std::ranges::empty), EmptyMember&>);
+    static_assert(!std::ranges::range<const EmptyMember&>); // no begin/end
+    static_assert(std::invocable<decltype(std::ranges::empty), const EmptyMember&>);
+    using OwningView = std::ranges::owning_view<EmptyMember>;
+    static_assert(std::ranges::range<OwningView&>);
+    static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+    static_assert(HasEmpty<OwningView&>);
+    static_assert(HasEmpty<OwningView&&>);
+    static_assert(HasEmpty<const OwningView&>); // but it still has empty()
+    static_assert(HasEmpty<const OwningView&&>);
+  }
+  {
+    // Test an empty view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a));
+    assert(ov.empty());
+    assert(std::as_const(ov).empty());
+  }
+  {
+    // Test a non-empty view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));
+    assert(!ov.empty());
+    assert(!std::as_const(ov).empty());
+  }
+  {
+    // Test a non-view.
+    std::array<int, 2> a = {1, 2};
+    auto ov = std::ranges::owning_view(std::move(a));
+    assert(!ov.empty());
+    assert(!std::as_const(ov).empty());
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp
new file mode 100644
index 0000000000000..11e6090e9f8f5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr auto size() requires sized_range<R>
+// constexpr auto size() const requires sized_range<const R>
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasSize = requires (T t) {
+  t.size();
+};
+
+constexpr bool test()
+{
+  {
+    struct SubtractableIters {
+      forward_iterator<int*> begin();
+      sized_sentinel<forward_iterator<int*>> end();
+    };
+    using OwningView = std::ranges::owning_view<SubtractableIters>;
+    static_assert(std::ranges::sized_range<OwningView&>);
+    static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+    static_assert(HasSize<OwningView&>);
+    static_assert(HasSize<OwningView&&>);
+    static_assert(!HasSize<const OwningView&>);
+    static_assert(!HasSize<const OwningView&&>);
+  }
+  {
+    struct NoSize {
+      bidirectional_iterator<int*> begin();
+      bidirectional_iterator<int*> end();
+    };
+    using OwningView = std::ranges::owning_view<NoSize>;
+    static_assert(!HasSize<OwningView&>);
+    static_assert(!HasSize<OwningView&&>);
+    static_assert(!HasSize<const OwningView&>);
+    static_assert(!HasSize<const OwningView&&>);
+  }
+  {
+    struct SizeMember {
+      bidirectional_iterator<int*> begin();
+      bidirectional_iterator<int*> end();
+      int size() const;
+    };
+    using OwningView = std::ranges::owning_view<SizeMember>;
+    static_assert(std::ranges::sized_range<OwningView&>);
+    static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+    static_assert(HasSize<OwningView&>);
+    static_assert(HasSize<OwningView&&>);
+    static_assert(!HasSize<const OwningView&>); // not a range, therefore no size()
+    static_assert(!HasSize<const OwningView&&>);
+  }
+  {
+    // Test an empty view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a));
+    assert(ov.size() == 0);
+    assert(std::as_const(ov).size() == 0);
+  }
+  {
+    // Test a non-empty view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));
+    assert(ov.size() == 1);
+    assert(std::as_const(ov).size() == 1);
+  }
+  {
+    // Test a non-view.
+    std::array<int, 2> a = {1, 2};
+    auto ov = std::ranges::owning_view(std::move(a));
+    assert(ov.size() == 2);
+    assert(std::as_const(ov).size() == 2);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp
index 5f7fd83f1611e..852effb8d1bfd 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp
@@ -39,22 +39,29 @@ void testCTAD() {
     View v;
     Range r;
     BorrowedRange br;
+
     static_assert(std::same_as<
         decltype(std::ranges::common_view(v)),
         std::ranges::common_view<View>
     >);
+    static_assert(std::same_as<
+        decltype(std::ranges::common_view(std::move(v))),
+        std::ranges::common_view<View>
+    >);
     static_assert(std::same_as<
         decltype(std::ranges::common_view(r)),
         std::ranges::common_view<std::ranges::ref_view<Range>>
     >);
-    // std::ranges::common_view(std::move(r)) invalid. RValue range must be borrowed.
+    static_assert(std::same_as<
+        decltype(std::ranges::common_view(std::move(r))),
+        std::ranges::common_view<std::ranges::owning_view<Range>>
+    >);
     static_assert(std::same_as<
         decltype(std::ranges::common_view(br)),
         std::ranges::common_view<std::ranges::ref_view<BorrowedRange>>
     >);
     static_assert(std::same_as<
         decltype(std::ranges::common_view(std::move(br))),
-        std::ranges::common_view<std::ranges::subrange<
-          int *, sentinel_wrapper<int *>, std::ranges::subrange_kind::unsized>>
+        std::ranges::common_view<std::ranges::owning_view<BorrowedRange>>
     >);
 }

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp
index 84575c9c18977..98e9887fa73d9 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp
@@ -11,22 +11,56 @@
 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
 
 // template<class R>
-// drop_view(R&&, range_
diff erence_t<R>) -> drop_view<views::all_t<R>>;
+//   drop_view(R&&, range_
diff erence_t<R>) -> drop_view<views::all_t<R>>;
 
 #include <ranges>
+#include <cassert>
+#include <concepts>
 
-#include "test_macros.h"
-#include "types.h"
+struct View : std::ranges::view_base {
+  int *begin() const;
+  int *end() const;
+};
 
-namespace ranges = std::ranges;
+struct Range {
+  int *begin() const;
+  int *end() const;
+};
 
-static_assert(std::same_as<decltype(ranges::drop_view(MoveOnlyView(), 0)), ranges::drop_view<MoveOnlyView>>);
-static_assert(std::same_as<decltype(ranges::drop_view(CopyableView(), 0)), ranges::drop_view<CopyableView>>);
-static_assert(std::same_as<decltype(ranges::drop_view(ForwardView(), 0)), ranges::drop_view<ForwardView>>);
-static_assert(std::same_as<decltype(ranges::drop_view(InputView(), 0)), ranges::drop_view<InputView>>);
+struct BorrowedRange {
+  int *begin() const;
+  int *end() const;
+};
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
 
-static_assert(std::same_as<decltype(ranges::drop_view(std::declval<ForwardRange&>(), 0)),
-                           ranges::drop_view<ranges::ref_view<ForwardRange>>>);
+void testCTAD() {
+    View v;
+    Range r;
+    BorrowedRange br;
 
-static_assert(std::same_as<decltype(ranges::drop_view(BorrowableRange(), 0)),
-                           ranges::drop_view<ranges::subrange<int*>>>);
+    static_assert(std::same_as<
+        decltype(std::ranges::drop_view(v, 0)),
+        std::ranges::drop_view<View>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::drop_view(std::move(v), 0)),
+        std::ranges::drop_view<View>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::drop_view(r, 0)),
+        std::ranges::drop_view<std::ranges::ref_view<Range>>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::drop_view(std::move(r), 0)),
+        std::ranges::drop_view<std::ranges::owning_view<Range>>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::drop_view(br, 0)),
+        std::ranges::drop_view<std::ranges::ref_view<BorrowedRange>>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::drop_view(std::move(br), 0)),
+        std::ranges::drop_view<std::ranges::owning_view<BorrowedRange>>
+    >);
+}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
index a81fa03e15c21..f0dd9abc33723 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
@@ -15,58 +15,55 @@
 
 #include <ranges>
 
-#include "test_iterators.h"
+struct Child {
+  int *begin() const;
+  int *end() const;
+};
 
-template<class T>
 struct View : std::ranges::view_base {
-  // All friends here are defined to prevent GCC warnings.
-  friend T* begin(View&) { return nullptr; }
-  friend T* begin(View const&) { return nullptr; }
-  friend sentinel_wrapper<T*> end(View&) { return sentinel_wrapper<T*>(nullptr); }
-  friend sentinel_wrapper<T*> end(View const&) { return sentinel_wrapper<T*>(nullptr); }
+  Child *begin() const;
+  Child *end() const;
 };
 
-template<class T>
 struct Range {
-  friend T* begin(Range&) { return nullptr; }
-  friend T* begin(Range const&) { return nullptr; }
-  friend sentinel_wrapper<T*> end(Range&) { return sentinel_wrapper<T*>(nullptr); }
-  friend sentinel_wrapper<T*> end(Range const&) { return sentinel_wrapper<T*>(nullptr); }
+  Child *begin() const;
+  Child *end() const;
 };
 
-template<class T>
 struct BorrowedRange {
-  friend T* begin(BorrowedRange&) { return nullptr; }
-  friend T* begin(BorrowedRange const&) { return nullptr; }
-  friend sentinel_wrapper<T*> end(BorrowedRange&) { return sentinel_wrapper<T*>(nullptr); }
-  friend sentinel_wrapper<T*> end(BorrowedRange const&) { return sentinel_wrapper<T*>(nullptr); }
+  Child *begin() const;
+  Child *end() const;
 };
-
 template<>
-inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange<BorrowedRange<int>>> = true;
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
 
 void testCTAD() {
-    View<View<int>> v;
-    Range<Range<int>> r;
-    BorrowedRange<BorrowedRange<int>> br;
+    View v;
+    Range r;
+    BorrowedRange br;
 
     static_assert(std::same_as<
         decltype(std::ranges::join_view(v)),
-        std::ranges::join_view<View<View<int>>>
+        std::ranges::join_view<View>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::join_view(std::move(v))),
+        std::ranges::join_view<View>
     >);
     static_assert(std::same_as<
         decltype(std::ranges::join_view(r)),
-        std::ranges::join_view<std::ranges::ref_view<Range<Range<int>>>>
+        std::ranges::join_view<std::ranges::ref_view<Range>>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::join_view(std::move(r))),
+        std::ranges::join_view<std::ranges::owning_view<Range>>
     >);
-    // std::ranges::join_view(std::move(r)) invalid. RValue range must be borrowed.
     static_assert(std::same_as<
         decltype(std::ranges::join_view(br)),
-        std::ranges::join_view<std::ranges::ref_view<BorrowedRange<BorrowedRange<int>>>>
+        std::ranges::join_view<std::ranges::ref_view<BorrowedRange>>
     >);
     static_assert(std::same_as<
         decltype(std::ranges::join_view(std::move(br))),
-        std::ranges::join_view<std::ranges::subrange<BorrowedRange<int> *,
-                               sentinel_wrapper<BorrowedRange<int> *>,
-                               std::ranges::subrange_kind::unsized>>
+        std::ranges::join_view<std::ranges::owning_view<BorrowedRange>>
     >);
 }

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp
new file mode 100644
index 0000000000000..ea0caf474fa32
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// template<class R>
+//   reverse_view(R&&) -> reverse_view<views::all_t<R>>;
+
+#include <ranges>
+
+#include <concepts>
+#include <utility>
+
+#include "test_iterators.h"
+
+struct View : std::ranges::view_base {
+  int *begin() const;
+  int *end() const;
+};
+
+struct Range {
+  int *begin() const;
+  int *end() const;
+};
+
+struct BorrowedRange {
+  int *begin() const;
+  int *end() const;
+};
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
+
+void testCTAD() {
+    View v;
+    Range r;
+    BorrowedRange br;
+
+    static_assert(std::same_as<
+        decltype(std::ranges::reverse_view(v)),
+        std::ranges::reverse_view<View>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::reverse_view(std::move(v))),
+        std::ranges::reverse_view<View>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::reverse_view(r)),
+        std::ranges::reverse_view<std::ranges::ref_view<Range>>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::reverse_view(std::move(r))),
+        std::ranges::reverse_view<std::ranges::owning_view<Range>>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::reverse_view(br)),
+        std::ranges::reverse_view<std::ranges::ref_view<BorrowedRange>>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::reverse_view(std::move(br))),
+        std::ranges::reverse_view<std::ranges::owning_view<BorrowedRange>>
+    >);
+}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp
deleted file mode 100644
index bd02bf1a1d73c..0000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: libcpp-no-concepts
-// UNSUPPORTED: libcpp-has-no-incomplete-ranges
-
-// template<class R>
-//   reverse_view(R&&) -> reverse_view<views::all_t<R>>;
-
-#include <ranges>
-
-#include <concepts>
-#include <utility>
-
-#include "test_iterators.h"
-
-struct View : std::ranges::view_base {
-  friend int* begin(View&) { return nullptr; }
-  friend int* begin(View const&) { return nullptr; }
-  friend sentinel_wrapper<int*> end(View&) { return sentinel_wrapper<int*>(nullptr); }
-  friend sentinel_wrapper<int*> end(View const&) { return sentinel_wrapper<int*>(nullptr); }
-};
-
-struct Range {
-  friend int* begin(Range&) { return nullptr; }
-  friend int* begin(Range const&) { return nullptr; }
-  friend sentinel_wrapper<int*> end(Range&) { return sentinel_wrapper<int*>(nullptr); }
-  friend sentinel_wrapper<int*> end(Range const&) { return sentinel_wrapper<int*>(nullptr); }
-};
-
-struct BorrowedRange {
-  friend int* begin(BorrowedRange&) { return nullptr; }
-  friend int* begin(BorrowedRange const&) { return nullptr; }
-  friend sentinel_wrapper<int*> end(BorrowedRange&) { return sentinel_wrapper<int*>(nullptr); }
-  friend sentinel_wrapper<int*> end(BorrowedRange const&) { return sentinel_wrapper<int*>(nullptr); }
-};
-
-template<>
-inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
-
-int main(int, char**) {
-  View v;
-  Range r;
-  BorrowedRange br;
-
-  {
-    std::same_as<std::ranges::reverse_view<View>> auto x = std::ranges::reverse_view(v);
-    (void)x;
-  }
-  {
-    std::same_as<std::ranges::reverse_view<std::ranges::ref_view<Range>>> auto x = std::ranges::reverse_view(r);
-    (void)x;
-    // std::ranges::reverse_view(std::move(r)) is invalid. RValue range must be borrowed.
-  }
-  {
-    std::same_as<std::ranges::reverse_view<std::ranges::ref_view<BorrowedRange>>> auto x = std::ranges::reverse_view(br);
-    (void)x;
-  }
-  {
-    using Subrange = std::ranges::subrange<int *, sentinel_wrapper<int *>, std::ranges::subrange_kind::unsized>;
-    std::same_as<std::ranges::reverse_view<Subrange>> auto x = std::ranges::reverse_view(std::move(br));
-    (void)x;
-  }
-
-  return 0;
-}

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp
index bf326895758c7..419fad396caaa 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp
@@ -17,29 +17,20 @@
 #include <cassert>
 #include <concepts>
 
-#include "test_iterators.h"
-
 struct View : std::ranges::view_base {
-  friend int* begin(View&);
-  friend int* begin(View const&);
-  friend sentinel_wrapper<int*> end(View&);
-  friend sentinel_wrapper<int*> end(View const&);
+  int *begin() const;
+  int *end() const;
 };
 
 struct Range {
-  friend int* begin(Range&);
-  friend int* begin(Range const&);
-  friend sentinel_wrapper<int*> end(Range&);
-  friend sentinel_wrapper<int*> end(Range const&);
+  int *begin() const;
+  int *end() const;
 };
 
 struct BorrowedRange {
-  friend int* begin(BorrowedRange&);
-  friend int* begin(BorrowedRange const&);
-  friend sentinel_wrapper<int*> end(BorrowedRange&);
-  friend sentinel_wrapper<int*> end(BorrowedRange const&);
+  int *begin() const;
+  int *end() const;
 };
-
 template<>
 inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
 
@@ -47,22 +38,29 @@ void testCTAD() {
     View v;
     Range r;
     BorrowedRange br;
+
     static_assert(std::same_as<
         decltype(std::ranges::take_view(v, 0)),
         std::ranges::take_view<View>
     >);
+    static_assert(std::same_as<
+        decltype(std::ranges::take_view(std::move(v), 0)),
+        std::ranges::take_view<View>
+    >);
     static_assert(std::same_as<
         decltype(std::ranges::take_view(r, 0)),
         std::ranges::take_view<std::ranges::ref_view<Range>>
     >);
-    // std::ranges::take_view(std::move(r), 0) invalid. RValue range must be borrowed.
+    static_assert(std::same_as<
+        decltype(std::ranges::take_view(std::move(r), 0)),
+        std::ranges::take_view<std::ranges::owning_view<Range>>
+    >);
     static_assert(std::same_as<
         decltype(std::ranges::take_view(br, 0)),
         std::ranges::take_view<std::ranges::ref_view<BorrowedRange>>
     >);
     static_assert(std::same_as<
         decltype(std::ranges::take_view(std::move(br), 0)),
-        std::ranges::take_view<std::ranges::subrange<
-          int *, sentinel_wrapper<int *>, std::ranges::subrange_kind::unsized>>
+        std::ranges::take_view<std::ranges::owning_view<BorrowedRange>>
     >);
 }

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp
index c07c79452d956..086dc2fb471ae 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp
@@ -10,17 +10,62 @@
 // UNSUPPORTED: libcpp-no-concepts
 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
 
-// CTAD tests.
+// template<class R, class F>
+//   transform_view(R&&, F) -> transform_view<views::all_t<R>, F>;
 
 #include <ranges>
+#include <cassert>
 #include <concepts>
 
-#include "test_macros.h"
-#include "types.h"
+struct PlusOne {
+    int operator()(int x) const;
+};
 
-static_assert(std::same_as<decltype(std::ranges::transform_view(InputView(), PlusOne())),
-                           std::ranges::transform_view<InputView, PlusOne>>);
-static_assert(std::same_as<decltype(std::ranges::transform_view(std::declval<ForwardRange&>(), PlusOne())),
-                           std::ranges::transform_view<std::ranges::ref_view<ForwardRange>, PlusOne>>);
-static_assert(std::same_as<decltype(std::ranges::transform_view(BorrowableRange(), PlusOne())),
-                           std::ranges::transform_view<std::ranges::subrange<int*>, PlusOne>>);
+struct View : std::ranges::view_base {
+  int *begin() const;
+  int *end() const;
+};
+
+struct Range {
+  int *begin() const;
+  int *end() const;
+};
+
+struct BorrowedRange {
+  int *begin() const;
+  int *end() const;
+};
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
+
+void testCTAD() {
+    View v;
+    Range r;
+    BorrowedRange br;
+    PlusOne f;
+
+    static_assert(std::same_as<
+        decltype(std::ranges::transform_view(v, f)),
+        std::ranges::transform_view<View, PlusOne>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::transform_view(std::move(v), f)),
+        std::ranges::transform_view<View, PlusOne>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::transform_view(r, f)),
+        std::ranges::transform_view<std::ranges::ref_view<Range>, PlusOne>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::transform_view(std::move(r), f)),
+        std::ranges::transform_view<std::ranges::owning_view<Range>, PlusOne>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::transform_view(br, f)),
+        std::ranges::transform_view<std::ranges::ref_view<BorrowedRange>, PlusOne>
+    >);
+    static_assert(std::same_as<
+        decltype(std::ranges::transform_view(std::move(br), f)),
+        std::ranges::transform_view<std::ranges::owning_view<BorrowedRange>, PlusOne>
+    >);
+}

diff  --git a/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp
index bd16cea6fd1e4..e0d1c6511d402 100644
--- a/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp
@@ -23,50 +23,53 @@
 //  range<T>
 //  view<remove_cvref_t<T>>
 //  constructible_from<remove_cvref_t<T>, T>
-//  borrowed_range<T>
+//  lvalue_reference_t<T> || movable<remove_reference_t<T>>
+//  is-initializer-list<T>
 //
 // We test all the relevant combinations of satisfying/not satisfying those constraints.
 
-// viewable_range<T> is not satisfied for (range=false, view=*, constructible_from=*, borrowed_range=*)
+// viewable_range<T> is not satisfied for (range=false, view=*, constructible_from=*, lvalue-or-movable=*)
 struct T1 { };
 static_assert(!std::ranges::range<T1>);
 
 static_assert(!std::ranges::viewable_range<T1>);
 static_assert(!std::ranges::viewable_range<T1&>);
+static_assert(!std::ranges::viewable_range<T1&&>);
 static_assert(!std::ranges::viewable_range<T1 const>);
 static_assert(!std::ranges::viewable_range<T1 const&>);
+static_assert(!std::ranges::viewable_range<T1 const&&>);
 
-// viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=true)
+// viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=true)
 struct T2 : test_range<cpp20_input_iterator>, std::ranges::view_base {
   T2(T2 const&) = default;
 };
-template<> constexpr bool std::ranges::enable_borrowed_range<T2> = true;
 static_assert(std::ranges::range<T2>);
 static_assert(std::ranges::view<T2>);
 static_assert(std::constructible_from<T2, T2>);
-static_assert(std::ranges::borrowed_range<T2>);
 
 static_assert(std::ranges::viewable_range<T2>);
 static_assert(std::ranges::viewable_range<T2&>);
+static_assert(std::ranges::viewable_range<T2&&>);
 static_assert(std::ranges::viewable_range<T2 const>);
 static_assert(std::ranges::viewable_range<T2 const&>);
+static_assert(std::ranges::viewable_range<T2 const&&>);
 
-// viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=false)
+// viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=false)
 struct T3 : test_range<cpp20_input_iterator>, std::ranges::view_base {
   T3(T3 const&) = default;
 };
-template<> constexpr bool std::ranges::enable_borrowed_range<T3> = false;
 static_assert(std::ranges::range<T3>);
 static_assert(std::ranges::view<T3>);
 static_assert(std::constructible_from<T3, T3>);
-static_assert(!std::ranges::borrowed_range<T3>);
 
 static_assert(std::ranges::viewable_range<T3>);
 static_assert(std::ranges::viewable_range<T3&>);
+static_assert(std::ranges::viewable_range<T3&&>);
 static_assert(std::ranges::viewable_range<T3 const>);
 static_assert(std::ranges::viewable_range<T3 const&>);
+static_assert(std::ranges::viewable_range<T3 const&&>);
 
-// viewable_range<T> is not satisfied for (range=true, view=true, constructible_from=false, borrowed_range=true)
+// viewable_range<T> is not satisfied for (range=true, view=true, constructible_from=false, lvalue-or-movable=true)
 struct T4 : test_range<cpp20_input_iterator>, std::ranges::view_base {
   T4(T4 const&) = delete;
   T4(T4&&) = default;             // necessary to model view
@@ -75,53 +78,83 @@ struct T4 : test_range<cpp20_input_iterator>, std::ranges::view_base {
 static_assert(std::ranges::range<T4 const&>);
 static_assert(std::ranges::view<std::remove_cvref_t<T4 const&>>);
 static_assert(!std::constructible_from<std::remove_cvref_t<T4 const&>, T4 const&>);
-static_assert(std::ranges::borrowed_range<T4 const&>);
 
 static_assert(!std::ranges::viewable_range<T4 const&>);
 
-// A type that satisfies (range=true, view=true, constructible_from=false, borrowed_range=false) can't be formed
+// A type that satisfies (range=true, view=true, constructible_from=false, lvalue-or-movable=false) can't be formed,
+// because views are movable by definition
 
-// viewable_range<T> is satisfied for (range=true, view=false, constructible_from=true, borrowed_range=true)
+// viewable_range<T> is satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=true)...
 struct T5 : test_range<cpp20_input_iterator> { };
-template<> constexpr bool std::ranges::enable_borrowed_range<T5> = true;
-static_assert(std::ranges::range<T5>);
+static_assert( std::ranges::range<T5>);
 static_assert(!std::ranges::view<T5>);
-static_assert(std::constructible_from<T5, T5>);
-static_assert(std::ranges::borrowed_range<T5>);
-
-static_assert(std::ranges::viewable_range<T5>);
-
-// viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=true, borrowed_range=false)
-struct T6 : test_range<cpp20_input_iterator> { };
-template<> constexpr bool std::ranges::enable_borrowed_range<T6> = false;
-static_assert(std::ranges::range<T6>);
+static_assert( std::constructible_from<T5, T5>);
+static_assert( std::movable<T5>);
+static_assert(!std::movable<const T5>);
+
+static_assert( std::ranges::viewable_range<T5>); // movable
+static_assert( std::ranges::viewable_range<T5&>); // movable
+static_assert( std::ranges::viewable_range<T5&&>); // movable
+static_assert(!std::ranges::viewable_range<const T5>);
+static_assert( std::ranges::viewable_range<const T5&>); // lvalue
+static_assert(!std::ranges::viewable_range<const T5&&>);
+
+// ...but not if the (non-view, lvalue-or-movable) range is an initializer_list.
+static_assert( std::ranges::range<std::initializer_list<int>>);
+static_assert(!std::ranges::view<std::initializer_list<int>>);
+static_assert( std::constructible_from<std::initializer_list<int>, std::initializer_list<int>>);
+static_assert( std::movable<std::initializer_list<int>>);
+
+static_assert(!std::ranges::viewable_range<std::initializer_list<int>>);
+static_assert( std::ranges::viewable_range<std::initializer_list<int>&>);
+static_assert(!std::ranges::viewable_range<std::initializer_list<int>&&>);
+static_assert(!std::ranges::viewable_range<std::initializer_list<int> const>);
+static_assert( std::ranges::viewable_range<std::initializer_list<int> const&>);
+static_assert(!std::ranges::viewable_range<std::initializer_list<int> const&&>);
+
+// viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=false)
+struct T6 : test_range<cpp20_input_iterator> { T6(T6&&); T6& operator=(T6&&) = delete; };
+static_assert( std::ranges::range<T6>);
 static_assert(!std::ranges::view<T6>);
-static_assert(std::constructible_from<T6, T6>);
-static_assert(!std::ranges::borrowed_range<T6>);
+static_assert( std::constructible_from<T6, T6>);
+static_assert(!std::movable<T6>);
 
 static_assert(!std::ranges::viewable_range<T6>);
+static_assert( std::ranges::viewable_range<T6&>); // lvalue
+static_assert(!std::ranges::viewable_range<T6&&>);
+static_assert(!std::ranges::viewable_range<const T6>);
+static_assert( std::ranges::viewable_range<const T6&>); // lvalue
+static_assert(!std::ranges::viewable_range<const T6&&>);
 
-// viewable_range<T> is satisfied for (range=true, view=false, constructible_from=false, borrowed_range=true)
+// viewable_range<T> is satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=true)
 struct T7 : test_range<cpp20_input_iterator> {
   T7(T7 const&) = delete;
 };
 static_assert(std::ranges::range<T7&>);
 static_assert(!std::ranges::view<std::remove_cvref_t<T7&>>);
 static_assert(!std::constructible_from<std::remove_cvref_t<T7&>, T7&>);
-static_assert(std::ranges::borrowed_range<T7&>);
 
-static_assert(std::ranges::viewable_range<T7&>);
+static_assert(!std::ranges::viewable_range<T7>);
+static_assert( std::ranges::viewable_range<T7&>);
+static_assert(!std::ranges::viewable_range<T7&&>);
+static_assert(!std::ranges::viewable_range<const T7>);
+static_assert( std::ranges::viewable_range<const T7&>);
+static_assert(!std::ranges::viewable_range<const T7&&>);
 
-// A type that satisfies (range=true, view=false, constructible_from=false, borrowed_range=false) can't be formed
+// viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=false)
 struct T8 : test_range<cpp20_input_iterator> {
   T8(T8 const&) = delete;
 };
 static_assert(std::ranges::range<T8>);
 static_assert(!std::ranges::view<T8>);
 static_assert(!std::constructible_from<T8, T8>);
-static_assert(!std::ranges::borrowed_range<T8>);
 
 static_assert(!std::ranges::viewable_range<T8>);
+static_assert( std::ranges::viewable_range<T8&>);
+static_assert(!std::ranges::viewable_range<T8&&>);
+static_assert(!std::ranges::viewable_range<const T8>);
+static_assert( std::ranges::viewable_range<const T8&>);
+static_assert(!std::ranges::viewable_range<const T8&&>);
 
 // Test with a few degenerate types
 static_assert(!std::ranges::viewable_range<void>);
@@ -129,5 +162,7 @@ static_assert(!std::ranges::viewable_range<int>);
 static_assert(!std::ranges::viewable_range<int (*)(char)>);
 static_assert(!std::ranges::viewable_range<int[]>);
 static_assert(!std::ranges::viewable_range<int[10]>);
-static_assert(!std::ranges::viewable_range<int(&)[]>); // unbounded array is not a range
-static_assert( std::ranges::viewable_range<int(&)[10]>);
+static_assert(!std::ranges::viewable_range<int(&)[]>); // not a range
+static_assert( std::ranges::viewable_range<int(&)[10]>); // OK, lvalue
+static_assert(!std::ranges::viewable_range<int(&&)[]>);
+static_assert(!std::ranges::viewable_range<int(&&)[10]>);

diff  --git a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
index ec1b9b205fd24..3fdb29ee112d0 100644
--- a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
@@ -26,7 +26,7 @@ static_assert(std::ranges::contiguous_range<std::cmatch>);
 static_assert(!std::ranges::view<std::cmatch>);
 static_assert(std::ranges::sized_range<std::cmatch>);
 static_assert(!std::ranges::borrowed_range<std::cmatch>);
-static_assert(!std::ranges::viewable_range<std::cmatch>);
+static_assert(std::ranges::viewable_range<std::cmatch>);
 
 static_assert(std::same_as<std::ranges::iterator_t<std::cmatch const>, std::cmatch::const_iterator>);
 static_assert(std::ranges::common_range<std::cmatch const>);

diff  --git a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
index 0e34ded705f66..ad018c02f3f84 100644
--- a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
@@ -26,7 +26,7 @@ static_assert(std::ranges::contiguous_range<std::string>);
 static_assert(!std::ranges::view<std::string>);
 static_assert(std::ranges::sized_range<std::string>);
 static_assert(!std::ranges::borrowed_range<std::string>);
-static_assert(!std::ranges::viewable_range<std::string>);
+static_assert(std::ranges::viewable_range<std::string>);
 
 static_assert(std::same_as<std::ranges::iterator_t<std::string const>, std::string::const_iterator>);
 static_assert(std::ranges::common_range<std::string const>);


        


More information about the libcxx-commits mailing list