[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