[libcxx-commits] [libcxx] 5a3309f - [libcxx][ranges] adds `range` access CPOs

Christopher Di Bella via libcxx-commits libcxx-commits at lists.llvm.org
Fri Apr 30 09:57:06 PDT 2021


Author: Christopher Di Bella
Date: 2021-04-30T16:56:42Z
New Revision: 5a3309f8257690838d8dbc8c973cdc90a32dba33

URL: https://github.com/llvm/llvm-project/commit/5a3309f8257690838d8dbc8c973cdc90a32dba33
DIFF: https://github.com/llvm/llvm-project/commit/5a3309f8257690838d8dbc8c973cdc90a32dba33.diff

LOG: [libcxx][ranges] adds `range` access CPOs

* `std::ranges::begin`
* `std::ranges::cbegin`
* `std::ranges::end`
* `std::ranges::cend`
* `std::ranges::iterator` (required for `end`)

Implements parts of:
    * P0896R4 The One Ranges Proposal`

Co-author: @zoecarver

Depends on D90999, D100160.

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

Added: 
    libcxx/include/__ranges/access.h
    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/containers/views/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/input.output/filesystems/class.directory_iterator/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.access/range.access.begin/begin.pass.cpp
    libcxx/test/std/ranges/range.access/range.access.begin/incomplete.compile.verify.cpp
    libcxx/test/std/ranges/range.access/range.access.cbegin/cbegin.compile.pass.cpp
    libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify copy.cpp
    libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify.cpp
    libcxx/test/std/ranges/range.access/range.access.cend/cend.compile.pass.cpp
    libcxx/test/std/ranges/range.access/range.access.cend/incomplete.compile.verify.cpp
    libcxx/test/std/ranges/range.access/range.access.end/end.cpp
    libcxx/test/std/ranges/range.access/range.access.end/incomplete.compile.verify.cpp
    libcxx/test/std/ranges/range.range/iterator_t.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
    libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp
    libcxx/test/support/test_range.h

Modified: 
    libcxx/include/CMakeLists.txt
    libcxx/include/module.modulemap
    libcxx/include/ranges
    libcxx/include/type_traits

Removed: 
    


################################################################################
diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 51586e0aa8e5f..0bcaa191e5274 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -35,6 +35,7 @@ set(files
   __mutex_base
   __node_handle
   __nullptr
+  __ranges/access.h
   __ranges/enable_borrowed_range.h
   __split_buffer
   __sso_allocator
@@ -150,6 +151,7 @@ set(files
   random
   ranges
   ratio
+  ranges
   regex
   scoped_allocator
   semaphore

diff  --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h
new file mode 100644
index 0000000000000..e2c201b2a81f6
--- /dev/null
+++ b/libcxx/include/__ranges/access.h
@@ -0,0 +1,218 @@
+// -*- C++ -*-
+//===------------------------ __ranges/begin.h ----------------------------===//
+//
+// 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_ACCESS_H
+#define _LIBCPP___RANGES_ACCESS_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+// clang-format off
+
+namespace ranges {
+  template <class _Tp>
+  concept __can_borrow =
+      is_lvalue_reference_v<_Tp> || enable_borrowed_range<remove_cvref_t<_Tp> >;
+
+  template<class _Tp>
+  concept __is_complete = requires { sizeof(_Tp); };
+} // namespace ranges
+
+// [range.access.begin]
+namespace ranges::__begin {
+  template <class _Tp>
+  concept __member_begin =
+    __can_borrow<_Tp> &&
+    requires(_Tp&& __t) {
+      { _VSTD::__decay_copy(__t.begin()) } -> input_or_output_iterator;
+    };
+
+  void begin(auto&) = delete;
+  void begin(const auto&) = delete;
+
+  template <class _Tp>
+  concept __unqualified_begin =
+    !__member_begin<_Tp> &&
+    __can_borrow<_Tp> &&
+    __class_or_enum<remove_cvref_t<_Tp> > &&
+    requires(_Tp && __t) {
+      { _VSTD::__decay_copy(begin(__t)) } -> input_or_output_iterator;
+    };
+
+  struct __fn {
+    template <class _Tp>
+    requires is_array_v<remove_cv_t<_Tp>>
+    [[nodiscard]] constexpr auto operator()(_Tp& __t) const noexcept {
+      constexpr bool __complete = __is_complete<iter_value_t<_Tp> >;
+      if constexpr (__complete) { // used to disable cryptic diagnostic
+        return __t + 0;
+      }
+      else {
+        static_assert(__complete, "`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type.");
+      }
+    }
+
+    template <class _Tp>
+    requires __member_begin<_Tp>
+    [[nodiscard]] constexpr auto operator()(_Tp&& __t) const
+    noexcept(noexcept(_VSTD::__decay_copy(__t.begin())))
+    {
+      return __t.begin();
+    }
+
+    template <class _Tp>
+    requires __unqualified_begin<_Tp>
+    [[nodiscard]] constexpr auto operator()(_Tp&& __t) const
+    noexcept(noexcept(_VSTD::__decay_copy(begin(__t))))
+    {
+      return begin(__t);
+    }
+
+    void operator()(auto&&) const = delete;
+  };
+} // namespace ranges::__begin
+
+namespace ranges {
+  inline namespace __cpo {
+    inline constexpr auto begin = __begin::__fn{};
+  } // namespace __cpo
+
+  template <class _Tp>
+  using iterator_t = decltype(ranges::begin(declval<_Tp&>()));
+} // namespace ranges
+
+// [range.access.end]
+namespace ranges::__end {
+  template <class _Tp>
+  concept __member_end =
+    __can_borrow<_Tp> &&
+    requires(_Tp&& __t) {
+      typename iterator_t<_Tp>;
+      { _VSTD::__decay_copy(_VSTD::forward<_Tp>(__t).end()) } -> sentinel_for<iterator_t<_Tp> >;
+    };
+
+  void end(auto&) = delete;
+  void end(const auto&) = delete;
+
+  template <class _Tp>
+  concept __unqualified_end =
+    !__member_end<_Tp> &&
+    __can_borrow<_Tp> &&
+    __class_or_enum<remove_cvref_t<_Tp> > &&
+    requires(_Tp && __t) {
+      typename iterator_t<_Tp>;
+      { _VSTD::__decay_copy(end(_VSTD::forward<_Tp>(__t))) } -> sentinel_for<iterator_t<_Tp> >;
+    };
+
+  class __fn {
+  public:
+    template <class _Tp, size_t _Np>
+    [[nodiscard]] constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept {
+      constexpr bool __complete = __is_complete<remove_cv_t<_Tp> >;
+      if constexpr (__complete) { // used to disable cryptic diagnostic
+        return __t + _Np;
+      }
+      else {
+        static_assert(__complete, "`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type.");
+      }
+    }
+
+    template <class _Tp>
+    requires __member_end<_Tp>
+    [[nodiscard]] constexpr auto operator()(_Tp&& __t) const
+    noexcept(noexcept(_VSTD::__decay_copy(__t.end())))
+    {
+      return _VSTD::forward<_Tp>(__t).end();
+    }
+
+    template <class _Tp>
+    requires __unqualified_end<_Tp>
+    [[nodiscard]] constexpr auto operator()(_Tp&& __t) const
+    noexcept(noexcept(_VSTD::__decay_copy(end(__t))))
+    {
+      return end(__t);
+    }
+
+    void operator()(auto&&) const = delete;
+  };
+} // namespace ranges::__end
+
+namespace ranges::inline __cpo {
+  inline constexpr auto end = __end::__fn{};
+} // namespace ranges::__cpo
+
+namespace ranges::__cbegin {
+  struct __fn {
+    template <class _Tp>
+    requires invocable<decltype(ranges::begin), _Tp const&>
+    [[nodiscard]] constexpr auto operator()(_Tp& __t) const
+    noexcept(noexcept(ranges::begin(_VSTD::as_const(__t))))
+    {
+      return ranges::begin(_VSTD::as_const(__t));
+    }
+
+    template <class _Tp>
+    requires is_rvalue_reference_v<_Tp> && invocable<decltype(ranges::begin), _Tp const&&>
+    [[nodiscard]] constexpr auto operator()(_Tp&& __t) const
+    noexcept(noexcept(ranges::begin(static_cast<_Tp const&&>(__t))))
+    {
+      return ranges::begin(static_cast<_Tp const&&>(__t));
+    }
+  };
+} // namespace ranges::__cbegin
+
+namespace ranges::inline __cpo {
+  inline constexpr auto cbegin = __cbegin::__fn{};
+} // namespace ranges::__cpo
+
+namespace ranges::__cend {
+  struct __fn {
+    template <class _Tp>
+    requires invocable<decltype(ranges::end), _Tp const&>
+    [[nodiscard]] constexpr auto operator()(_Tp& __t) const
+    noexcept(noexcept(ranges::end(_VSTD::as_const(__t))))
+    {
+      return ranges::end(_VSTD::as_const(__t));
+    }
+
+    template <class _Tp>
+    requires is_rvalue_reference_v<_Tp> && invocable<decltype(ranges::end), _Tp const&&>
+    [[nodiscard]] constexpr auto operator()(_Tp&& __t) const
+    noexcept(noexcept(ranges::end(static_cast<_Tp const&&>(__t))))
+    {
+      return ranges::end(static_cast<_Tp const&&>(__t));
+    }
+  };
+} // namespace ranges::__cend
+
+namespace ranges::inline __cpo {
+  inline constexpr auto cend = __cend::__fn{};
+} // namespace ranges::__cpo
+
+// clang-format off
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_ACCESS_H

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index c970082b56005..f1f2410f7dc07 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -411,6 +411,9 @@ module std [system] {
   }
   module ranges {
     header "ranges"
+    export compare
+    export initializer_list
+    export iterator
     export *
   }
   module ratio {

diff  --git a/libcxx/include/ranges b/libcxx/include/ranges
index 3bcb62be28d41..64feb76d03523 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -17,14 +17,26 @@
 #include <iterator>             // see [iterator.synopsis]
 
 namespace std::ranges {
+  inline namespace unspecified {
+    // [range.access], range access
+    inline constexpr unspecified begin = unspecified;
+    inline constexpr unspecified end = unspecified;
+    inline constexpr unspecified cbegin = unspecified;
+    inline constexpr unspecified cend = unspecified;
+  }
+
   // [range.range], ranges
   template<class T>
     inline constexpr bool enable_borrowed_range = false;
+
+  template<class T>
+    using iterator_t = decltype(ranges::begin(declval<T&>()));
 }
 
 */
 
 #include <__config>
+#include <__ranges/access.h>
 #include <__ranges/enable_borrowed_range.h>
 #include <compare>          // Required by the standard.
 #include <initializer_list> // Required by the standard.

diff  --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index e68021ea9b1a5..7978f7ba93f3f 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -2814,6 +2814,9 @@ template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 typename decay<_Tp>::type
 __decay_copy(_Tp&& __t)
+#if _LIBCPP_STD_VER > 17
+noexcept(is_nothrow_convertible_v<_Tp, remove_reference_t<_Tp>>)
+#endif
 {
     return _VSTD::forward<_Tp>(__t);
 }

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
new file mode 100644
index 0000000000000..04d8d63ab03ad
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// map
+
+#include <map>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::map<int, int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..c076d16c7a6ea
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// multimap
+
+#include <map>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::multimap<int, int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..da82cba43c440
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// multiset
+
+#include <set>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::multiset<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..66ec7b3974d41
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// set
+
+#include <set>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::set<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..35fb25c626d23
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// array
+
+#include <array>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::array<int, 10>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::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
new file mode 100644
index 0000000000000..07601dc08eba1
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// deque
+
+#include <deque>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::deque<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..40f62a7b7b22b
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// forward_list
+
+#include <forward_list>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::forward_list<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..9230e6a2e4803
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// list
+
+#include <list>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::list<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..d72535c5e2a65
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// vector
+
+#include <vector>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::vector<bool>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..d5a635330627c
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// vector
+
+#include <vector>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::vector<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..968f5189185b6
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// unordered_map
+
+#include <unordered_map>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::unordered_map<int, int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..f8cfa03e4d1f7
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// unordered_multimap
+
+#include <unordered_map>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::unordered_multimap<int, int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..267cd6fd506ff
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// unordered_multiset
+
+#include <unordered_set>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::unordered_multiset<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

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
new file mode 100644
index 0000000000000..e3a2e4b61fd8c
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// unordered_multiset
+
+#include <unordered_set>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::unordered_set<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
+static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

diff  --git a/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp
new file mode 100644
index 0000000000000..216faf3673f8f
--- /dev/null
+++ b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// span
+
+#include <span>
+
+#include <concepts>
+#include <ranges>
+
+using range = std::span<int>;
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);

diff  --git a/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp
new file mode 100644
index 0000000000000..c7cfc4d0bc528
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// directory_iterator, recursive_directory_iterator
+
+#include "filesystem_include.h"
+
+#include <concepts>
+#include <ranges>
+
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<fs::directory_iterator>, fs::directory_iterator>);
+static_assert(std::same_as<stdr::iterator_t<fs::directory_iterator const>, fs::directory_iterator>);
+static_assert(std::same_as<stdr::iterator_t<fs::recursive_directory_iterator>, fs::recursive_directory_iterator>);
+static_assert(std::same_as<stdr::iterator_t<fs::recursive_directory_iterator const>, fs::recursive_directory_iterator>);

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
new file mode 100644
index 0000000000000..a3c55c4d7449e
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// path
+
+#include "filesystem_include.h"
+
+#include <concepts>
+#include <ranges>
+
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<fs::path>, fs::path::iterator>);
+static_assert(std::same_as<stdr::iterator_t<fs::path const>, fs::path::const_iterator>);

diff  --git a/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp
new file mode 100644
index 0000000000000..167b7861512ec
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp
@@ -0,0 +1,263 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// std::ranges::begin
+
+#include <ranges>
+
+#include <cassert>
+#include "test_macros.h"
+#include "test_iterators.h"
+
+using RangeBeginT = decltype(std::ranges::begin)&;
+using RangeCBeginT = decltype(std::ranges::cbegin)&;
+
+static int globalBuff[8];
+
+struct Incomplete;
+
+static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[10]>);
+static_assert( std::is_invocable_v<RangeBeginT, int (&)[10]>);
+static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[]>);
+static_assert( std::is_invocable_v<RangeBeginT, int (&)[]>);
+
+struct BeginMember {
+  int x;
+  constexpr const int *begin() const { return &x; }
+};
+
+// Ensure that we can't call with rvalues with borrowing disabled.
+static_assert( std::is_invocable_v<RangeBeginT,  BeginMember &>);
+static_assert( std::is_invocable_v<RangeBeginT,  BeginMember const&>);
+static_assert(!std::is_invocable_v<RangeBeginT,  BeginMember &&>);
+static_assert( std::is_invocable_v<RangeCBeginT, BeginMember &>);
+static_assert( std::is_invocable_v<RangeCBeginT, BeginMember const&>);
+
+constexpr bool testArray() {
+  int a[2];
+  assert(std::ranges::begin(a) == a);
+  assert(std::ranges::cbegin(a) == a);
+
+  int b[2][2];
+  assert(std::ranges::begin(b) == b);
+  assert(std::ranges::cbegin(b) == b);
+
+  BeginMember c[2];
+  assert(std::ranges::begin(c) == c);
+  assert(std::ranges::cbegin(c) == c);
+
+  return true;
+}
+
+struct BeginMemberFunction {
+  int x;
+  constexpr const int *begin() const { return &x; }
+  friend constexpr int *begin(BeginMemberFunction const& bf);
+};
+
+struct BeginMemberReturnsInt {
+  int begin() const;
+};
+
+static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsInt const&>);
+
+struct BeginMemberReturnsVoidPtr {
+  const void *begin() const;
+};
+
+static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsVoidPtr const&>);
+
+struct Empty { };
+struct EmptyBeginMember {
+  Empty begin() const;
+};
+struct EmptyPtrBeginMember {
+  Empty x;
+  constexpr const Empty *begin() const { return &x; }
+};
+
+static_assert(!std::is_invocable_v<RangeBeginT, EmptyBeginMember const&>);
+
+struct PtrConvertible {
+  operator int*() const;
+};
+struct PtrConvertibleBeginMember {
+  PtrConvertible begin() const;
+};
+
+static_assert(!std::is_invocable_v<RangeBeginT, PtrConvertibleBeginMember const&>);
+
+struct NonConstBeginMember {
+  int x;
+  constexpr int *begin() { return &x; }
+};
+
+static_assert( std::is_invocable_v<RangeBeginT,  NonConstBeginMember &>);
+static_assert(!std::is_invocable_v<RangeBeginT,  NonConstBeginMember const&>);
+static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember &>);
+static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember const&>);
+
+struct EnabledBorrowingBeginMember {
+  constexpr int *begin() const { return &globalBuff[0]; }
+};
+
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingBeginMember> = true;
+
+constexpr bool testBeginMember() {
+  BeginMember a;
+  assert(std::ranges::begin(a) == &a.x);
+  assert(std::ranges::cbegin(a) == &a.x);
+
+  NonConstBeginMember b;
+  assert(std::ranges::begin(b) == &b.x);
+
+  EnabledBorrowingBeginMember c;
+  assert(std::ranges::begin(std::move(c)) == &globalBuff[0]);
+
+  BeginMemberFunction d;
+  assert(std::ranges::begin(d) == &d.x);
+  assert(std::ranges::cbegin(d) == &d.x);
+
+  EmptyPtrBeginMember e;
+  assert(std::ranges::begin(e) == &e.x);
+  assert(std::ranges::cbegin(e) == &e.x);
+
+  return true;
+}
+
+struct BeginFunction {
+  int x;
+  friend constexpr const int *begin(BeginFunction const& bf) { return &bf.x; }
+};
+
+static_assert( std::is_invocable_v<RangeBeginT,  BeginFunction const&>);
+static_assert(!std::is_invocable_v<RangeBeginT,  BeginFunction &&>);
+static_assert(!std::is_invocable_v<RangeBeginT,  BeginFunction &>);
+static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
+static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
+
+struct BeginFunctionWithDataMember {
+  int x;
+  int begin;
+  friend constexpr const int *begin(BeginFunctionWithDataMember const& bf) { return &bf.x; }
+};
+
+struct BeginFunctionWithPrivateBeginMember : private BeginMember {
+  int y;
+  friend constexpr const int *begin(BeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; }
+};
+
+struct BeginFunctionReturnsEmptyPtr {
+  Empty x;
+  friend constexpr const Empty *begin(BeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
+};
+
+struct BeginFunctionByValue {
+  friend constexpr int *begin(BeginFunctionByValue) { return &globalBuff[1]; }
+};
+
+static_assert(!std::is_invocable_v<RangeCBeginT, BeginFunctionByValue>);
+
+struct BeginFunctionEnabledBorrowing {
+  friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; }
+};
+
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BeginFunctionEnabledBorrowing> = true;
+
+struct BeginFunctionReturnsInt {
+  friend constexpr int begin(BeginFunctionReturnsInt const&);
+};
+
+static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsInt const&>);
+
+struct BeginFunctionReturnsVoidPtr {
+  friend constexpr void *begin(BeginFunctionReturnsVoidPtr const&);
+};
+
+static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsVoidPtr const&>);
+
+struct BeginFunctionReturnsEmpty {
+  friend constexpr Empty begin(BeginFunctionReturnsEmpty const&);
+};
+
+static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsEmpty const&>);
+
+struct BeginFunctionReturnsPtrConvertible {
+  friend constexpr PtrConvertible begin(BeginFunctionReturnsPtrConvertible const&);
+};
+
+static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsPtrConvertible const&>);
+
+constexpr bool testBeginFunction() {
+  const BeginFunction a{};
+  assert(std::ranges::begin(a) == &a.x);
+  BeginFunction aa{};
+  assert(std::ranges::cbegin(aa) == &aa.x);
+
+  BeginFunctionByValue b;
+  assert(std::ranges::begin(b) == &globalBuff[1]);
+  assert(std::ranges::cbegin(b) == &globalBuff[1]);
+
+  BeginFunctionEnabledBorrowing c;
+  assert(std::ranges::begin(std::move(c)) == &globalBuff[2]);
+
+  const BeginFunctionReturnsEmptyPtr d{};
+  assert(std::ranges::begin(d) == &d.x);
+  BeginFunctionReturnsEmptyPtr dd{};
+  assert(std::ranges::cbegin(dd) == &dd.x);
+
+  const BeginFunctionWithDataMember e{};
+  assert(std::ranges::begin(e) == &e.x);
+  BeginFunctionWithDataMember ee{};
+  assert(std::ranges::cbegin(ee) == &ee.x);
+
+  const BeginFunctionWithPrivateBeginMember f{};
+  assert(std::ranges::begin(f) == &f.y);
+  BeginFunctionWithPrivateBeginMember ff{};
+  assert(std::ranges::cbegin(ff) == &ff.y);
+
+  return true;
+}
+
+template<class T>
+struct NoThrowMemberBegin {
+  T begin() noexcept;
+  T begin() const noexcept;
+};
+
+template<class T>
+struct NoThrowADLBegin {
+  friend T begin(NoThrowADLBegin&) noexcept;
+  friend T begin(NoThrowADLBegin const&) noexcept;
+};
+ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
+ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberBegin<int*>&>()));
+ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberBegin<ThrowingIterator<int> >&>()));
+ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLBegin<int*>&>()));
+ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLBegin<ThrowingIterator<int> >&>()));
+
+
+int main(int, char**) {
+  testArray();
+  static_assert(testArray());
+
+  testBeginMember();
+  static_assert(testBeginMember());
+
+  testBeginFunction();
+  static_assert(testBeginFunction());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.access/range.access.begin/incomplete.compile.verify.cpp b/libcxx/test/std/ranges/range.access/range.access.begin/incomplete.compile.verify.cpp
new file mode 100644
index 0000000000000..b6646e293fdcd
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.begin/incomplete.compile.verify.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// unspecified begin;
+
+#include <ranges>
+
+#include <type_traits>
+
+using begin_t = decltype(std::ranges::begin);
+
+// clang-format off
+template <class T>
+requires(!std::invocable<begin_t&, T>)
+void f() {}
+// clang-format on
+
+void test() {
+  struct incomplete;
+  f<incomplete(&)[]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+  f<incomplete(&)[10]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+  f<incomplete(&)[2][2]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+
+  // This is okay because calling `std::ranges::begin` on any rvalue is ill-formed.
+  f<incomplete(&&)[10]>();
+}

diff  --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/cbegin.compile.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/cbegin.compile.pass.cpp
new file mode 100644
index 0000000000000..92e92f232f7c7
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/cbegin.compile.pass.cpp
@@ -0,0 +1 @@
+// Tested in begin.pass.cpp.

diff  --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify copy.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify copy.cpp
new file mode 100644
index 0000000000000..81114e07b487c
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify copy.cpp	
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// unspecified begin;
+
+#include <ranges>
+
+#include <type_traits>
+
+using cbegin_t = decltype(std::ranges::cbegin);
+
+// clang-format off
+template <class T>
+requires(!std::invocable<cbegin_t&, T>)
+void f() {}
+// clang-format on
+
+void test() {
+  struct incomplete;
+  f<incomplete(&)[]>();
+  // expected-error@*:* {{"`std::ranges::cbegin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+  f<incomplete(&)[10]>();
+  // expected-error@*:* {{"`std::ranges::cbegin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+  f<incomplete(&)[2][2]>();
+  // expected-error@*:* {{"`std::ranges::cbegin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+
+  // This is okay because calling `std::ranges::cbegin` on any rvalue is ill-formed.
+  f<incomplete(&&)[10]>();
+}

diff  --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify.cpp
new file mode 100644
index 0000000000000..362c3e989e9c8
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// ranges::cbegin;
+
+#include <ranges>
+
+#include <type_traits>
+
+using cbegin_t = decltype(std::ranges::cbegin);
+
+// clang-format off
+template <class T>
+requires(!std::invocable<cbegin_t&, T>)
+void f() {}
+// clang-format on
+
+void test() {
+  struct incomplete;
+  f<incomplete(&)[10]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+
+  // This is okay because calling `std::ranges::end` on any rvalue is ill-formed.
+  f<incomplete(&&)[10]>();
+}

diff  --git a/libcxx/test/std/ranges/range.access/range.access.cend/cend.compile.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cend/cend.compile.pass.cpp
new file mode 100644
index 0000000000000..924fea790e63c
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.cend/cend.compile.pass.cpp
@@ -0,0 +1 @@
+// Tested in end.pass.cpp.

diff  --git a/libcxx/test/std/ranges/range.access/range.access.cend/incomplete.compile.verify.cpp b/libcxx/test/std/ranges/range.access/range.access.cend/incomplete.compile.verify.cpp
new file mode 100644
index 0000000000000..94a1067426ada
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.cend/incomplete.compile.verify.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// unspecified begin;
+
+#include <ranges>
+
+#include <type_traits>
+
+using cend_t = decltype(std::ranges::cend);
+
+// clang-format off
+template <class T>
+requires(!std::invocable<cend_t&, T>)
+void f() {}
+// clang-format on
+
+void test() {
+  struct incomplete;
+  f<incomplete(&)[]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  f<incomplete(&)[10]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -3 {{no matching function for call to 'f'}}
+  f<incomplete(&)[2][2]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+
+  // This is okay because calling `std::ranges::end` on any rvalue is ill-formed.
+  f<incomplete(&&)[10]>();
+}

diff  --git a/libcxx/test/std/ranges/range.access/range.access.end/end.cpp b/libcxx/test/std/ranges/range.access/range.access.end/end.cpp
new file mode 100644
index 0000000000000..a7adbbbdd15ed
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.end/end.cpp
@@ -0,0 +1,309 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// std::ranges::end
+
+#include <ranges>
+
+#include <cassert>
+#include "test_macros.h"
+#include "test_iterators.h"
+
+using RangeEndT = decltype(std::ranges::end)&;
+using RangeCEndT = decltype(std::ranges::cend)&;
+
+static int globalBuff[8];
+
+static_assert(!std::is_invocable_v<RangeEndT, int (&&)[]>);
+static_assert(!std::is_invocable_v<RangeEndT, int (&)[]>);
+static_assert(!std::is_invocable_v<RangeEndT, int (&&)[10]>);
+static_assert( std::is_invocable_v<RangeEndT, int (&)[10]>);
+
+struct EndMember {
+  int x;
+  constexpr const int *begin() const { return nullptr; }
+  constexpr const int *end() const { return &x; }
+};
+
+// Ensure that we can't call with rvalues with borrowing disabled.
+static_assert( std::is_invocable_v<RangeEndT,  EndMember &>);
+static_assert( std::is_invocable_v<RangeEndT,  EndMember const&>);
+static_assert(!std::is_invocable_v<RangeEndT,  EndMember &&>);
+static_assert( std::is_invocable_v<RangeCEndT, EndMember &>);
+static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>);
+
+constexpr bool testArray() {
+  int a[2];
+  assert(std::ranges::end(a) == a + 2);
+  assert(std::ranges::cend(a) == a + 2);
+
+  int b[2][2];
+  assert(std::ranges::end(b) == b + 2);
+  assert(std::ranges::cend(b) == b + 2);
+
+  EndMember c[2];
+  assert(std::ranges::end(c) == c + 2);
+  assert(std::ranges::cend(c) == c + 2);
+
+  return true;
+}
+
+struct EndMemberFunction {
+  int x;
+  constexpr const int *begin() const { return nullptr; }
+  constexpr const int *end() const { return &x; }
+  friend constexpr int *end(EndMemberFunction const&);
+};
+
+struct EndMemberReturnsInt {
+  int begin() const;
+  int end() const;
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsInt const&>);
+
+struct EndMemberReturnsVoidPtr {
+  const void *begin() const;
+  const void *end() const;
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsVoidPtr const&>);
+
+struct Empty { };
+struct EmptyEndMember {
+  Empty begin() const;
+  Empty end() const;
+};
+struct EmptyPtrEndMember {
+  Empty x;
+  constexpr const Empty *begin() const { return nullptr; }
+  constexpr const Empty *end() const { return &x; }
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, EmptyEndMember const&>);
+
+struct PtrConvertible {
+  operator int*() const;
+};
+struct PtrConvertibleEndMember {
+  PtrConvertible begin() const;
+  PtrConvertible end() const;
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, PtrConvertibleEndMember const&>);
+
+struct NoBeginMember {
+  constexpr const int *end();
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, NoBeginMember const&>);
+
+struct NonConstEndMember {
+  int x;
+  constexpr int *begin() { return nullptr; }
+  constexpr int *end() { return &x; }
+};
+
+static_assert( std::is_invocable_v<RangeEndT,  NonConstEndMember &>);
+static_assert(!std::is_invocable_v<RangeEndT,  NonConstEndMember const&>);
+static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>);
+static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>);
+
+struct EnabledBorrowingEndMember {
+  constexpr int *begin() const { return nullptr; }
+  constexpr int *end() const { return &globalBuff[0]; }
+};
+
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingEndMember> = true;
+
+constexpr bool testEndMember() {
+  EndMember a;
+  assert(std::ranges::end(a) == &a.x);
+  assert(std::ranges::cend(a) == &a.x);
+
+  NonConstEndMember b;
+  assert(std::ranges::end(b) == &b.x);
+
+  EnabledBorrowingEndMember c;
+  assert(std::ranges::end(std::move(c)) == &globalBuff[0]);
+
+  EndMemberFunction d;
+  assert(std::ranges::end(d) == &d.x);
+  assert(std::ranges::cend(d) == &d.x);
+
+  EmptyPtrEndMember e;
+  assert(std::ranges::end(e) == &e.x);
+  assert(std::ranges::cend(e) == &e.x);
+
+  return true;
+}
+
+struct EndFunction {
+  int x;
+  friend constexpr const int *begin(EndFunction const&) { return nullptr; }
+  friend constexpr const int *end(EndFunction const& bf) { return &bf.x; }
+};
+
+static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);
+static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
+
+static_assert( std::is_invocable_v<RangeEndT,  EndFunction const&>);
+static_assert(!std::is_invocable_v<RangeEndT,  EndFunction &&>);
+static_assert(!std::is_invocable_v<RangeEndT,  EndFunction &>);
+static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
+static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
+
+struct EndFunctionWithDataMember {
+  int x;
+  int end;
+  friend constexpr const int *begin(EndFunctionWithDataMember const&) { return nullptr; }
+  friend constexpr const int *end(EndFunctionWithDataMember const& bf) { return &bf.x; }
+};
+
+struct EndFunctionWithPrivateEndMember : private EndMember {
+  int y;
+  friend constexpr const int *begin(EndFunctionWithPrivateEndMember const&) { return nullptr; }
+  friend constexpr const int *end(EndFunctionWithPrivateEndMember const& bf) { return &bf.y; }
+};
+
+struct EndFunctionReturnsEmptyPtr {
+  Empty x;
+  friend constexpr const Empty *begin(EndFunctionReturnsEmptyPtr const&) { return nullptr; }
+  friend constexpr const Empty *end(EndFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
+};
+
+struct EndFunctionByValue {
+  friend constexpr int *begin(EndFunctionByValue) { return nullptr; }
+  friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; }
+};
+
+static_assert(!std::is_invocable_v<RangeCEndT, EndFunctionByValue>);
+
+struct EndFunctionEnabledBorrowing {
+  friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; }
+  friend constexpr int *end(EndFunctionEnabledBorrowing) { return &globalBuff[2]; }
+};
+
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<EndFunctionEnabledBorrowing> = true;
+
+struct EndFunctionReturnsInt {
+  friend constexpr int begin(EndFunctionReturnsInt const&);
+  friend constexpr int end(EndFunctionReturnsInt const&);
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsInt const&>);
+
+struct EndFunctionReturnsVoidPtr {
+  friend constexpr void *begin(EndFunctionReturnsVoidPtr const&);
+  friend constexpr void *end(EndFunctionReturnsVoidPtr const&);
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsVoidPtr const&>);
+
+struct EndFunctionReturnsEmpty {
+  friend constexpr Empty begin(EndFunctionReturnsEmpty const&);
+  friend constexpr Empty end(EndFunctionReturnsEmpty const&);
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsEmpty const&>);
+
+struct EndFunctionReturnsPtrConvertible {
+  friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&);
+  friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&);
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsPtrConvertible const&>);
+
+struct NoBeginFunction {
+  friend constexpr const int *end(NoBeginFunction const&);
+};
+
+static_assert(!std::is_invocable_v<RangeEndT, NoBeginFunction const&>);
+
+struct BeginMemberEndFunction {
+  int x;
+  constexpr const int *begin() const { return nullptr; }
+  friend constexpr const int *end(BeginMemberEndFunction const& bf) { return &bf.x; }
+};
+
+constexpr bool testEndFunction() {
+  const EndFunction a{};
+  assert(std::ranges::end(a) == &a.x);
+  EndFunction aa{};
+  assert(std::ranges::cend(aa) == &aa.x);
+
+  EndFunctionByValue b;
+  assert(std::ranges::end(b) == &globalBuff[1]);
+  assert(std::ranges::cend(b) == &globalBuff[1]);
+
+  EndFunctionEnabledBorrowing c;
+  assert(std::ranges::end(std::move(c)) == &globalBuff[2]);
+
+  const EndFunctionReturnsEmptyPtr d{};
+  assert(std::ranges::end(d) == &d.x);
+  EndFunctionReturnsEmptyPtr dd{};
+  assert(std::ranges::cend(dd) == &dd.x);
+
+  const EndFunctionWithDataMember e{};
+  assert(std::ranges::end(e) == &e.x);
+  EndFunctionWithDataMember ee{};
+  assert(std::ranges::cend(ee) == &ee.x);
+
+  const EndFunctionWithPrivateEndMember f{};
+  assert(std::ranges::end(f) == &f.y);
+  EndFunctionWithPrivateEndMember ff{};
+  assert(std::ranges::cend(ff) == &ff.y);
+
+  const BeginMemberEndFunction g{};
+  assert(std::ranges::end(g) == &g.x);
+  BeginMemberEndFunction gg{};
+  assert(std::ranges::cend(gg) == &gg.x);
+
+  return true;
+}
+
+template<class T>
+struct NoThrowMemberEnd {
+  T begin() noexcept;
+  T begin() const noexcept;
+  T end() noexcept;
+  T end() const noexcept;
+};
+
+template<class T>
+struct NoThrowADLEnd {
+  friend T begin(NoThrowADLEnd&) noexcept;
+  friend T begin(NoThrowADLEnd const&) noexcept;
+  friend T end(NoThrowADLEnd&) noexcept;
+  friend T end(NoThrowADLEnd const&) noexcept;
+};
+ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
+ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberEnd<int*>&>()));
+ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberEnd<ThrowingIterator<int> >&>()));
+ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLEnd<int*>&>()));
+ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLEnd<ThrowingIterator<int> >&>()));
+
+int main(int, char**) {
+  testArray();
+  static_assert(testArray());
+
+  testEndMember();
+  static_assert(testEndMember());
+
+  testEndFunction();
+  static_assert(testEndFunction());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.access/range.access.end/incomplete.compile.verify.cpp b/libcxx/test/std/ranges/range.access/range.access.end/incomplete.compile.verify.cpp
new file mode 100644
index 0000000000000..347b148de3921
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/range.access.end/incomplete.compile.verify.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// unspecified begin;
+
+#include <ranges>
+
+#include <type_traits>
+
+using end_t = decltype(std::ranges::end);
+
+// clang-format off
+template <class T>
+requires(!std::invocable<end_t&, T>)
+void f() {}
+// clang-format on
+
+void test() {
+  struct incomplete;
+  f<incomplete(&)[]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  f<incomplete(&)[10]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -3 {{no matching function for call to 'f'}}
+  f<incomplete(&)[2][2]>();
+  // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}}
+  // expected-error at -2 {{no matching function for call to 'f'}}
+
+  // This is okay because calling `std::ranges::end` on any rvalue is ill-formed.
+  f<incomplete(&&)[10]>();
+}

diff  --git a/libcxx/test/std/ranges/range.range/iterator_t.compile.pass.cpp b/libcxx/test/std/ranges/range.range/iterator_t.compile.pass.cpp
new file mode 100644
index 0000000000000..2ff9d6da65420
--- /dev/null
+++ b/libcxx/test/std/ranges/range.range/iterator_t.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: gcc-10
+// XFAIL: msvc && clang
+
+// template<class T>
+// using iterator_t = decltype(ranges::begin(declval<T&>()));
+
+#include <ranges>
+
+#include <concepts>
+
+#include "test_range.h"
+
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<test_range<input_iterator> >, input_iterator<int*> >);
+static_assert(std::same_as<stdr::iterator_t<test_range<input_iterator> const>, input_iterator<int const*> >);
+
+static_assert(std::same_as<stdr::iterator_t<test_non_const_range<input_iterator> >, input_iterator<int*> >);
+
+static_assert(std::same_as<stdr::iterator_t<test_common_range<input_iterator> >, input_iterator<int*> >);
+static_assert(std::same_as<stdr::iterator_t<test_common_range<input_iterator> const>, input_iterator<int const*> >);
+
+static_assert(std::same_as<stdr::iterator_t<test_non_const_common_range<input_iterator> >, input_iterator<int*> >);

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
new file mode 100644
index 0000000000000..6eed856594b08
--- /dev/null
+++ b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// match_results
+
+#include <regex>
+
+#include <concepts>
+#include <ranges>
+
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<std::cmatch>, std::cmatch::iterator>);
+static_assert(std::same_as<stdr::iterator_t<std::cmatch const>, std::cmatch::const_iterator>);

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
new file mode 100644
index 0000000000000..634a8ccde884b
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// string
+
+#include <string>
+
+#include <concepts>
+#include <ranges>
+
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<std::string>, std::string::iterator>);
+static_assert(std::same_as<stdr::iterator_t<std::string const>, std::string::const_iterator>);

diff  --git a/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp
new file mode 100644
index 0000000000000..7395d42ef7284
--- /dev/null
+++ b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// XFAIL: msvc && clang
+
+// string_view
+
+#include <string_view>
+
+#include <concepts>
+#include <ranges>
+
+namespace stdr = std::ranges;
+
+static_assert(std::same_as<stdr::iterator_t<std::string_view>, std::string_view::iterator>);
+static_assert(std::same_as<stdr::iterator_t<std::string_view const>, std::string_view::const_iterator>);

diff  --git a/libcxx/test/support/test_range.h b/libcxx/test/support/test_range.h
new file mode 100644
index 0000000000000..0619767afe95a
--- /dev/null
+++ b/libcxx/test/support/test_range.h
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 LIBCXX_TEST_SUPPORT_TEST_RANGE_H
+#define LIBCXX_TEST_SUPPORT_TEST_RANGE_H
+
+#include <iterator>
+#include <ranges>
+
+#include "test_iterators.h"
+
+#ifdef _LIBCPP_HAS_NO_RANGES
+#error "test/suppoort/test_range.h" can only be included in builds supporting ranges
+#endif
+
+struct sentinel {
+  bool operator==(std::input_or_output_iterator auto) const;
+};
+
+// clang-format off
+template <template <class...> class I>
+requires std::input_or_output_iterator<I<int*> >
+struct test_range {
+  I<int*> begin();
+  I<int const*> begin() const;
+  sentinel end();
+  sentinel end() const;
+};
+
+template <template <class...> class I>
+requires std::input_or_output_iterator<I<int*> >
+struct test_non_const_range {
+  I<int*> begin();
+  sentinel end();
+};
+
+template <template <class...> class I>
+requires std::input_or_output_iterator<I<int*> >
+struct test_common_range {
+  I<int*> begin();
+  I<int const*> begin() const;
+  I<int*> end();
+  I<int*> end() const;
+};
+
+template <template <class...> class I>
+requires std::input_or_output_iterator<I<int*> >
+struct test_non_const_common_range {
+  I<int*> begin();
+  I<int*> end();
+};
+
+// clang-format on
+
+#endif // LIBCXX_TEST_SUPPORT_TEST_RANGE_H


        


More information about the libcxx-commits mailing list