[libcxx-commits] [libcxx] 67151d0 - [libc++] [ranges] Implement P2415R2 owning_view.
Arthur O'Dwyer via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 13 09:30:28 PST 2022
Author: Arthur O'Dwyer
Date: 2022-01-13T12:29:41-05:00
New Revision: 67151d029bdb933c006535f94bd3e625307a6cfa
URL: https://github.com/llvm/llvm-project/commit/67151d029bdb933c006535f94bd3e625307a6cfa
DIFF: https://github.com/llvm/llvm-project/commit/67151d029bdb933c006535f94bd3e625307a6cfa.diff
LOG: [libc++] [ranges] Implement P2415R2 owning_view.
"What is a view?"
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2415r2.html
https://github.com/cplusplus/draft/pull/5010/files
This was a late-breaking (Oct 2021) change to C++20.
The only thing missing from this patch is that we're supposed
to bump the feature-test macro from
#define __cpp_lib_ranges 202106L
to
#define __cpp_lib_ranges 202110L
but we can't do that because we don't implement all of 202106 Ranges yet.
Differential Revision: https://reviews.llvm.org/D116894
Added:
libcxx/include/__ranges/owning_view.h
libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp
libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp
Modified:
libcxx/docs/Status/Cxx20Papers.csv
libcxx/docs/Status/RangesIssues.csv
libcxx/include/CMakeLists.txt
libcxx/include/__ranges/all.h
libcxx/include/__ranges/concepts.h
libcxx/include/module.modulemap
libcxx/include/ranges
libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp
libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp
libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
Removed:
libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp
################################################################################
diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index 3caca78f36f30..d0927e09426ce 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -202,6 +202,6 @@
"`P2367R0 <https://wg21.link/P2367R0>`__","LWG",Remove misuses of list-initialization from Clause 24,"June 2021","",""
"","","","","",""
"`P2372R3 <https://wg21.link/P2372R3>`__","LWG","Fixing locale handling in chrono formatters","October 2021","",""
-"`P2415R2 <https://wg21.link/P2415R2>`__","LWG","What is a ``view``","October 2021","",""
+"`P2415R2 <https://wg21.link/P2415R2>`__","LWG","What is a ``view``","October 2021","|Complete|","14.0"
"`P2418R2 <https://wg21.link/P2418R2>`__","LWG","Add support for ``std::generator``-like types to ``std::format``","October 2021","",""
"`P2432R1 <https://wg21.link/P2432R1>`__","LWG","Fix ``istream_view``","October 2021","",""
diff --git a/libcxx/docs/Status/RangesIssues.csv b/libcxx/docs/Status/RangesIssues.csv
index 5081fbf4628c0..7948148b6c6be 100644
--- a/libcxx/docs/Status/RangesIssues.csv
+++ b/libcxx/docs/Status/RangesIssues.csv
@@ -29,5 +29,5 @@
`P2281R1 <https://wg21.link/P2281R1>`__,Clarifying range adaptor objects,,
`P2367R0 <https://wg21.link/P2367R0>`__,Remove misuses of list-initialization from Clause 24,,
-`P2415 <https://wg21.link/P2415>`__,"What is a ``view``",,
+`P2415 <https://wg21.link/P2415>`__,"What is a ``view``",|Complete|,14.0
`P2432 <https://wg21.link/P2432>`__,"Fix ``istream_view``",,
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 30708599751cd..26edb72482886 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -326,6 +326,7 @@ set(files
__ranges/iota_view.h
__ranges/join_view.h
__ranges/non_propagating_cache.h
+ __ranges/owning_view.h
__ranges/range_adaptor.h
__ranges/ref_view.h
__ranges/reverse_view.h
diff --git a/libcxx/include/__ranges/all.h b/libcxx/include/__ranges/all.h
index ccc77258ba10a..90327da81460a 100644
--- a/libcxx/include/__ranges/all.h
+++ b/libcxx/include/__ranges/all.h
@@ -14,9 +14,9 @@
#include <__iterator/iterator_traits.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
+#include <__ranges/owning_view.h>
#include <__ranges/range_adaptor.h>
#include <__ranges/ref_view.h>
-#include <__ranges/subrange.h>
#include <__utility/auto_cast.h>
#include <__utility/declval.h>
#include <__utility/forward.h>
@@ -56,12 +56,12 @@ namespace __all {
template<class _Tp>
requires (!ranges::view<decay_t<_Tp>> &&
!requires (_Tp&& __t) { ranges::ref_view{_VSTD::forward<_Tp>(__t)}; } &&
- requires (_Tp&& __t) { ranges::subrange{_VSTD::forward<_Tp>(__t)}; })
+ requires (_Tp&& __t) { ranges::owning_view{_VSTD::forward<_Tp>(__t)}; })
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
constexpr auto operator()(_Tp&& __t) const
- noexcept(noexcept(ranges::subrange{_VSTD::forward<_Tp>(__t)}))
+ noexcept(noexcept(ranges::owning_view{_VSTD::forward<_Tp>(__t)}))
{
- return ranges::subrange{_VSTD::forward<_Tp>(__t)};
+ return ranges::owning_view{_VSTD::forward<_Tp>(__t)};
}
};
}
diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index bad23c8c4bfbe..fa31074ab6581 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -9,6 +9,9 @@
#ifndef _LIBCPP___RANGES_CONCEPTS_H
#define _LIBCPP___RANGES_CONCEPTS_H
+#include <__concepts/constructible.h>
+#include <__concepts/movable.h>
+#include <__concepts/same_as.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/incrementable_traits.h>
@@ -20,7 +23,7 @@
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/enable_view.h>
#include <__ranges/size.h>
-#include <concepts>
+#include <initializer_list>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -114,12 +117,20 @@ namespace ranges {
template <class _Tp>
concept common_range = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>;
- template<class _Tp>
+ template <class _Tp>
+ inline constexpr bool __is_std_initializer_list = false;
+
+ template <class _Ep>
+ inline constexpr bool __is_std_initializer_list<initializer_list<_Ep>> = true;
+
+ template <class _Tp>
concept viewable_range =
- range<_Tp> && (
- (view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>) ||
- (!view<remove_cvref_t<_Tp>> && borrowed_range<_Tp>)
- );
+ range<_Tp> &&
+ ((view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>) ||
+ (!view<remove_cvref_t<_Tp>> &&
+ (is_lvalue_reference_v<_Tp> ||
+ (movable<remove_reference_t<_Tp>> && !__is_std_initializer_list<remove_cvref_t<_Tp>>))));
+
} // namespace ranges
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
diff --git a/libcxx/include/__ranges/owning_view.h b/libcxx/include/__ranges/owning_view.h
new file mode 100644
index 0000000000000..29182d2d8e46e
--- /dev/null
+++ b/libcxx/include/__ranges/owning_view.h
@@ -0,0 +1,81 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef _LIBCPP___RANGES_OWNING_VIEW_H
+#define _LIBCPP___RANGES_OWNING_VIEW_H
+
+#include <__concepts/constructible.h>
+#include <__concepts/movable.h>
+#include <__config>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/data.h>
+#include <__ranges/empty.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/size.h>
+#include <__ranges/view_interface.h>
+#include <__utility/move.h>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+namespace ranges {
+ template<range _Rp>
+ requires movable<_Rp> && (!__is_std_initializer_list<remove_cvref_t<_Rp>>)
+ class owning_view : public view_interface<owning_view<_Rp>> {
+ _Rp __r_ = _Rp();
+
+public:
+ owning_view() requires default_initializable<_Rp> = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr owning_view(_Rp&& __r) : __r_(_VSTD::move(__r)) {}
+
+ owning_view(owning_view&&) = default;
+ owning_view& operator=(owning_view&&) = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr _Rp& base() & noexcept { return __r_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Rp& base() const& noexcept { return __r_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr _Rp&& base() && noexcept { return _VSTD::move(__r_); }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Rp&& base() const&& noexcept { return _VSTD::move(__r_); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Rp> begin() { return ranges::begin(__r_); }
+ _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Rp> end() { return ranges::end(__r_); }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range<const _Rp> { return ranges::begin(__r_); }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range<const _Rp> { return ranges::end(__r_); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool empty() requires requires { ranges::empty(__r_); }
+ { return ranges::empty(__r_); }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const requires requires { ranges::empty(__r_); }
+ { return ranges::empty(__r_); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_Rp>
+ { return ranges::size(__r_); }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range<const _Rp>
+ { return ranges::size(__r_); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto data() requires contiguous_range<_Rp>
+ { return ranges::data(__r_); }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto data() const requires contiguous_range<const _Rp>
+ { return ranges::data(__r_); }
+ };
+
+ template<class _Tp>
+ inline constexpr bool enable_borrowed_range<owning_view<_Tp>> = enable_borrowed_range<_Tp>;
+
+} // namespace ranges
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___RANGES_OWNING_VIEW_H
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 828c9d55495fd..b514f96a6ff72 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -799,6 +799,7 @@ module std [system] {
module iota_view { private header "__ranges/iota_view.h" }
module join_view { private header "__ranges/join_view.h" }
module non_propagating_cache { private header "__ranges/non_propagating_cache.h" }
+ module owning_view { private header "__ranges/owning_view.h" }
module range_adaptor { private header "__ranges/range_adaptor.h" }
module ref_view { private header "__ranges/ref_view.h" }
module reverse_view { private header "__ranges/reverse_view.h" }
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 707c7acd1b01e..eb4492376c5c3 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -135,6 +135,13 @@ namespace std::ranges {
template<class T>
inline constexpr bool enable_borrowed_range<ref_view<T>> = true;
+ template<range R>
+ requires see below
+ class owning_view;
+
+ template<class T>
+ inline constexpr bool enable_borrowed_range<owning_view<T>> = enable_borrowed_range<T>;
+
// [range.drop], drop view
template<view V>
class drop_view;
diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp
new file mode 100644
index 0000000000000..e68237cc5b686
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__ranges/owning_view.h'}}
+#include <__ranges/owning_view.h>
diff --git a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
index d48ce88a15a7e..2cbda51d18c6c 100644
--- a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::view<range>);
static_assert(!std::ranges::random_access_range<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
index 0c008e71df504..1d278b9f2547e 100644
--- a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::view<range>);
static_assert(!std::ranges::random_access_range<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
index 84c41274a3131..fb6228bd4c8bc 100644
--- a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
@@ -26,7 +26,7 @@ static_assert(!std::ranges::view<range>);
static_assert(!std::ranges::random_access_range<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
index 5853d9c2a1d9f..a1cfd5af5ed4d 100644
--- a/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp
@@ -28,7 +28,7 @@ static_assert(std::ranges::input_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::bidirectional_range<range const>);
diff --git a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
index 8fdd9869f9393..4609f27702c29 100644
--- a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(std::ranges::random_access_range<range>);
static_assert(std::ranges::contiguous_range<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(!std::ranges::view<range const>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
diff --git a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
index ce3eea3c30c6f..3eecb02782edd 100644
--- a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::contiguous_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
index 8c29c2a223bc4..d1d3328b34c66 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(!std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
index 7354563fe4f4a..14d301aa50c43 100644
--- a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::view<range>);
static_assert(!std::ranges::random_access_range<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
index b19c4afbe175d..167a6f956eb49 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::contiguous_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
index fe0053236ed3e..868b1224bed9f 100644
--- a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(std::ranges::contiguous_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
index 32e834691abf1..897e709699f76 100644
--- a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
index 01a1d34808dc8..27c5b7fd968b8 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
index 1557c99e31c09..b1f98ae1bed3f 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
index b9c96c7c317c6..0303de9e39c42 100644
--- a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
@@ -27,7 +27,7 @@ static_assert(!std::ranges::bidirectional_range<range>);
static_assert(!std::ranges::view<range>);
static_assert(std::ranges::sized_range<range>);
static_assert(!std::ranges::borrowed_range<range>);
-static_assert(!std::ranges::viewable_range<range>);
+static_assert(std::ranges::viewable_range<range>);
static_assert(std::same_as<std::ranges::iterator_t<range const>, range::const_iterator>);
static_assert(std::ranges::common_range<range const>);
diff --git a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
index 77b46ab04a8b4..12f452c9e5e96 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
@@ -26,7 +26,7 @@ static_assert(!std::ranges::view<fs::path>);
static_assert(!std::ranges::random_access_range<fs::path>);
static_assert(!std::ranges::sized_range<fs::path>);
static_assert(!std::ranges::borrowed_range<fs::path>);
-static_assert(!std::ranges::viewable_range<fs::path>);
+static_assert(std::ranges::viewable_range<fs::path>);
static_assert(std::same_as<std::ranges::iterator_t<fs::path const>, fs::path::const_iterator>);
static_assert(std::ranges::common_range<fs::path const>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp
index c24435af90d7b..2f28029d37e68 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp
@@ -67,13 +67,8 @@ template<>
inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
struct RandomAccessRange {
- struct sentinel {
- friend constexpr bool operator==(sentinel, const random_access_iterator<int*> rai) { return rai.base() == globalBuff + 8; }
- friend constexpr std::ptr
diff _t operator-(sentinel, random_access_iterator<int*>) { return -8; }
- friend constexpr std::ptr
diff _t operator-(random_access_iterator<int*>, sentinel) { return 8; }
- };
- constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{globalBuff}; }
- constexpr sentinel end() { return {}; }
+ constexpr auto begin() { return random_access_iterator<int*>(globalBuff); }
+ constexpr auto end() { return sized_sentinel(random_access_iterator<int*>(globalBuff + 8)); }
};
template<>
inline constexpr bool std::ranges::enable_borrowed_range<RandomAccessRange> = true;
@@ -114,32 +109,31 @@ constexpr bool test() {
assert(std::ranges::begin(ref) == globalBuff + 2);
assert(std::ranges::end(ref) == globalBuff + 8);
- static_assert(!std::is_invocable_v<decltype(std::views::all), Range>);
- }
+ auto own = std::views::all(std::move(range));
+ ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<Range>);
+ assert(std::ranges::begin(own) == globalBuff + 2);
+ assert(std::ranges::end(own) == globalBuff + 8);
- {
- const Range range(2);
- auto ref = std::views::all(range);
- static_assert(!noexcept(std::views::all(range)));
- ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<const Range>);
- assert(std::ranges::begin(ref) == globalBuff + 2);
- assert(std::ranges::end(ref) == globalBuff + 8);
+ auto cref = std::views::all(std::as_const(range));
+ ASSERT_SAME_TYPE(decltype(cref), std::ranges::ref_view<const Range>);
+ assert(std::ranges::begin(cref) == globalBuff + 2);
+ assert(std::ranges::end(cref) == globalBuff + 8);
+
+ static_assert(!std::is_invocable_v<decltype(std::views::all), const Range&&>);
}
{
- auto subrange = std::views::all(BorrowableRange(2));
- static_assert(!noexcept(std::views::all(BorrowableRange(2))));
- ASSERT_SAME_TYPE(decltype(subrange), std::ranges::subrange<int*>);
- assert(std::ranges::begin(subrange) == globalBuff + 2);
- assert(std::ranges::end(subrange) == globalBuff + 8);
+ auto own = std::views::all(BorrowableRange(2));
+ ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<BorrowableRange>);
+ assert(std::ranges::begin(own) == globalBuff + 2);
+ assert(std::ranges::end(own) == globalBuff + 8);
}
{
- auto subrange = std::views::all(RandomAccessRange());
- ASSERT_SAME_TYPE(decltype(subrange),
- std::ranges::subrange<random_access_iterator<int*>, RandomAccessRange::sentinel>);
- assert(std::ranges::begin(subrange).base() == globalBuff);
- assert(std::ranges::end(subrange) == std::ranges::begin(subrange) + 8);
+ auto own = std::views::all(RandomAccessRange());
+ ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<RandomAccessRange>);
+ assert(base(std::ranges::begin(own)) == globalBuff);
+ assert(base(base(std::ranges::end(own))) == globalBuff + 8);
}
// Check SFINAE friendliness of the call operator
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp
index 7db0c4a41bd8d..54d3af532ef69 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp
@@ -16,26 +16,49 @@
#include <ranges>
#include "test_iterators.h"
-#include "test_range.h"
-struct View : test_range<cpp20_input_iterator>, std::ranges::view_base { };
-struct Range : test_range<cpp20_input_iterator> { };
-struct BorrowableRange : test_range<forward_iterator> { };
+struct View : std::ranges::view_base {
+ int *begin() const;
+ int *end() const;
+};
+
+struct Range {
+ int *begin() const;
+ int *end() const;
+};
+
+struct BorrowableRange {
+ int *begin() const;
+ int *end() const;
+};
template<>
inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
+template <class T>
+concept HasAllT = requires {
+ typename std::views::all_t<T>;
+};
+
// When T is a view, returns decay-copy(T)
ASSERT_SAME_TYPE(std::views::all_t<View>, View);
ASSERT_SAME_TYPE(std::views::all_t<View&>, View);
-ASSERT_SAME_TYPE(std::views::all_t<View const>, View);
-ASSERT_SAME_TYPE(std::views::all_t<View const&>, View);
+ASSERT_SAME_TYPE(std::views::all_t<View&&>, View);
+ASSERT_SAME_TYPE(std::views::all_t<const View>, View);
+ASSERT_SAME_TYPE(std::views::all_t<const View&>, View);
+ASSERT_SAME_TYPE(std::views::all_t<const View&&>, View);
// Otherwise, when T is a reference to a range, returns ref_view<T>
ASSERT_SAME_TYPE(std::views::all_t<Range&>, std::ranges::ref_view<Range>);
-ASSERT_SAME_TYPE(std::views::all_t<Range const&>, std::ranges::ref_view<Range const>);
+ASSERT_SAME_TYPE(std::views::all_t<const Range&>, std::ranges::ref_view<const Range>);
ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange&>, std::ranges::ref_view<BorrowableRange>);
-ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange const&>, std::ranges::ref_view<BorrowableRange const>);
+ASSERT_SAME_TYPE(std::views::all_t<const BorrowableRange&>, std::ranges::ref_view<const BorrowableRange>);
-// Otherwise, returns subrange<iterator_t<T>, sentinel_t<R>>
-ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange>, std::ranges::subrange<forward_iterator<int*>, sentinel>);
-ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange const>, std::ranges::subrange<forward_iterator<int const*>, sentinel>);
+// Otherwise, returns owning_view<T>
+ASSERT_SAME_TYPE(std::views::all_t<Range>, std::ranges::owning_view<Range>);
+ASSERT_SAME_TYPE(std::views::all_t<Range&&>, std::ranges::owning_view<Range>);
+static_assert(!HasAllT<const Range>);
+static_assert(!HasAllT<const Range&&>);
+ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange>, std::ranges::owning_view<BorrowableRange>);
+ASSERT_SAME_TYPE(std::views::all_t<BorrowableRange&&>, std::ranges::owning_view<BorrowableRange>);
+static_assert(!HasAllT<const BorrowableRange>);
+static_assert(!HasAllT<const BorrowableRange&&>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp
new file mode 100644
index 0000000000000..59cf1c0403207
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr R& base() & noexcept { return r_; }
+// constexpr const R& base() const& noexcept { return r_; }
+// constexpr R&& base() && noexcept { return std::move(r_); }
+// constexpr const R&& base() const&& noexcept { return std::move(r_); }
+
+#include <ranges>
+
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+
+struct Base {
+ int *begin() const;
+ int *end() const;
+};
+
+constexpr bool test()
+{
+ using OwningView = std::ranges::owning_view<Base>;
+ OwningView ov;
+ decltype(auto) b1 = static_cast<OwningView&>(ov).base();
+ decltype(auto) b2 = static_cast<OwningView&&>(ov).base();
+ decltype(auto) b3 = static_cast<const OwningView&>(ov).base();
+ decltype(auto) b4 = static_cast<const OwningView&&>(ov).base();
+
+ ASSERT_SAME_TYPE(decltype(b1), Base&);
+ ASSERT_SAME_TYPE(decltype(b2), Base&&);
+ ASSERT_SAME_TYPE(decltype(b3), const Base&);
+ ASSERT_SAME_TYPE(decltype(b4), const Base&&);
+
+ assert(&b1 == &b2);
+ assert(&b1 == &b3);
+ assert(&b1 == &b4);
+
+ ASSERT_NOEXCEPT(static_cast<OwningView&>(ov).base());
+ ASSERT_NOEXCEPT(static_cast<OwningView&&>(ov).base());
+ ASSERT_NOEXCEPT(static_cast<const OwningView&>(ov).base());
+ ASSERT_NOEXCEPT(static_cast<const OwningView&&>(ov).base());
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp
new file mode 100644
index 0000000000000..9319ac3b8986a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp
@@ -0,0 +1,133 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+
+// constexpr iterator_t<R> begin();
+// constexpr sentinel_t<R> end();
+// constexpr auto begin() const requires range<const R>;
+// constexpr auto end() const requires range<const R>;
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+struct Base {
+ constexpr int *begin() { return nullptr; }
+ constexpr auto end() { return sentinel_wrapper<int*>(nullptr); }
+ constexpr char *begin() const { return nullptr; }
+ constexpr auto end() const { return sentinel_wrapper<char*>(nullptr); }
+};
+static_assert(std::same_as<std::ranges::iterator_t<Base>, int*>);
+static_assert(std::same_as<std::ranges::sentinel_t<Base>, sentinel_wrapper<int*>>);
+static_assert(std::same_as<std::ranges::iterator_t<const Base>, char*>);
+static_assert(std::same_as<std::ranges::sentinel_t<const Base>, sentinel_wrapper<char*>>);
+
+struct NoConst {
+ int* begin();
+ sentinel_wrapper<int*> end();
+};
+
+struct DecayChecker {
+ int*& begin() const;
+ int*& end() const;
+};
+
+template <class T>
+concept HasBegin = requires (T t) {
+ t.begin();
+};
+
+template <class T>
+concept HasEnd = requires (T t) {
+ t.end();
+};
+
+constexpr bool test()
+{
+ {
+ using OwningView = std::ranges::owning_view<Base>;
+ OwningView ov;
+ std::same_as<int*> decltype(auto) b1 = static_cast<OwningView&>(ov).begin();
+ std::same_as<int*> decltype(auto) b2 = static_cast<OwningView&&>(ov).begin();
+ std::same_as<char*> decltype(auto) b3 = static_cast<const OwningView&>(ov).begin();
+ std::same_as<char*> decltype(auto) b4 = static_cast<const OwningView&&>(ov).begin();
+
+ std::same_as<sentinel_wrapper<int*>> decltype(auto) e1 = static_cast<OwningView&>(ov).end();
+ std::same_as<sentinel_wrapper<int*>> decltype(auto) e2 = static_cast<OwningView&&>(ov).end();
+ std::same_as<sentinel_wrapper<char*>> decltype(auto) e3 = static_cast<const OwningView&>(ov).end();
+ std::same_as<sentinel_wrapper<char*>> decltype(auto) e4 = static_cast<const OwningView&&>(ov).end();
+
+ assert(b1 == e1);
+ assert(b2 == e2);
+ assert(b3 == e3);
+ assert(b4 == e4);
+ }
+ {
+ // NoConst has non-const begin() and end(); so does the owning_view.
+ using OwningView = std::ranges::owning_view<NoConst>;
+ static_assert(HasBegin<OwningView&>);
+ static_assert(HasBegin<OwningView&&>);
+ static_assert(!HasBegin<const OwningView&>);
+ static_assert(!HasBegin<const OwningView&&>);
+ static_assert(HasEnd<OwningView&>);
+ static_assert(HasEnd<OwningView&&>);
+ static_assert(!HasEnd<const OwningView&>);
+ static_assert(!HasEnd<const OwningView&&>);
+ }
+ {
+ // DecayChecker's begin() and end() return references; make sure the owning_view decays them.
+ using OwningView = std::ranges::owning_view<DecayChecker>;
+ OwningView ov;
+ ASSERT_SAME_TYPE(decltype(ov.begin()), int*);
+ ASSERT_SAME_TYPE(decltype(ov.end()), int*);
+ }
+ {
+ // Test an empty view.
+ int a[] = {1};
+ auto ov = std::ranges::owning_view(std::ranges::subrange(a, a));
+ assert(ov.begin() == a);
+ assert(std::as_const(ov).begin() == a);
+ assert(ov.end() == a);
+ assert(std::as_const(ov).end() == a);
+ }
+ {
+ // Test a non-empty view.
+ int a[] = {1};
+ auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));
+ assert(ov.begin() == a);
+ assert(std::as_const(ov).begin() == a);
+ assert(ov.end() == a+1);
+ assert(std::as_const(ov).end() == a+1);
+ }
+ {
+ // Test a non-view.
+ std::array<int, 2> a = {1, 2};
+ auto ov = std::ranges::owning_view(std::move(a));
+ assert(ov.begin() != a.begin()); // because it points into the copy
+ assert(std::as_const(ov).begin() != a.begin());
+ assert(ov.end() != a.end());
+ assert(std::as_const(ov).end() != a.end());
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp
new file mode 100644
index 0000000000000..59cc12fd30aab
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// template<class T>
+// inline constexpr bool enable_borrowed_range<owning_view<T>> = enable_borrowed_range<T>;
+
+#include <ranges>
+#include <cassert>
+
+struct Range {
+ int *begin() const;
+ int *end() const;
+};
+
+struct BorrowableRange {
+ int *begin() const;
+ int *end() const;
+};
+
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
+
+static_assert(!std::ranges::enable_borrowed_range<std::ranges::owning_view<Range>>);
+static_assert( std::ranges::enable_borrowed_range<std::ranges::owning_view<BorrowableRange>>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp
new file mode 100644
index 0000000000000..54778482398a1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp
@@ -0,0 +1,140 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// owning_view() requires default_initializable<R> = default;
+// constexpr owning_view(R&& t);
+
+#include <ranges>
+
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+struct DefaultConstructible {
+ int i;
+ constexpr explicit DefaultConstructible(int j = 42) : i(j) {}
+ int *begin() const;
+ int *end() const;
+};
+
+struct NotDefaultConstructible {
+ int i;
+ constexpr explicit NotDefaultConstructible(int j) : i(j) {}
+ int *begin() const;
+ int *end() const;
+};
+
+struct MoveChecker {
+ int i;
+ constexpr explicit MoveChecker(int j) : i(j) {}
+ constexpr MoveChecker(MoveChecker&& v) : i(std::exchange(v.i, -1)) {}
+ MoveChecker& operator=(MoveChecker&&);
+ int *begin() const;
+ int *end() const;
+};
+
+struct NoexceptChecker {
+ int *begin() const;
+ int *end() const;
+};
+
+constexpr bool test()
+{
+ {
+ using OwningView = std::ranges::owning_view<DefaultConstructible>;
+ static_assert(std::is_constructible_v<OwningView>);
+ static_assert(std::default_initializable<OwningView>);
+ static_assert(std::movable<OwningView>);
+ static_assert(std::is_trivially_move_constructible_v<OwningView>);
+ static_assert(std::is_trivially_move_assignable_v<OwningView>);
+ static_assert(!std::is_copy_constructible_v<OwningView>);
+ static_assert(!std::is_copy_assignable_v<OwningView>);
+ static_assert(!std::is_constructible_v<OwningView, int>);
+ static_assert(!std::is_constructible_v<OwningView, DefaultConstructible&>);
+ static_assert(std::is_constructible_v<OwningView, DefaultConstructible&&>);
+ static_assert(!std::is_convertible_v<int, OwningView>);
+ static_assert(std::is_convertible_v<DefaultConstructible&&, OwningView>);
+ {
+ OwningView ov;
+ assert(ov.base().i == 42);
+ }
+ {
+ OwningView ov = OwningView(DefaultConstructible(1));
+ assert(ov.base().i == 1);
+ }
+ }
+ {
+ using OwningView = std::ranges::owning_view<NotDefaultConstructible>;
+ static_assert(!std::is_constructible_v<OwningView>);
+ static_assert(!std::default_initializable<OwningView>);
+ static_assert(std::movable<OwningView>);
+ static_assert(std::is_trivially_move_constructible_v<OwningView>);
+ static_assert(std::is_trivially_move_assignable_v<OwningView>);
+ static_assert(!std::is_copy_constructible_v<OwningView>);
+ static_assert(!std::is_copy_assignable_v<OwningView>);
+ static_assert(!std::is_constructible_v<OwningView, int>);
+ static_assert(!std::is_constructible_v<OwningView, NotDefaultConstructible&>);
+ static_assert(std::is_constructible_v<OwningView, NotDefaultConstructible&&>);
+ static_assert(!std::is_convertible_v<int, OwningView>);
+ static_assert(std::is_convertible_v<NotDefaultConstructible&&, OwningView>);
+ {
+ OwningView ov = OwningView(NotDefaultConstructible(1));
+ assert(ov.base().i == 1);
+ }
+ }
+ {
+ using OwningView = std::ranges::owning_view<MoveChecker>;
+ static_assert(!std::is_constructible_v<OwningView>);
+ static_assert(!std::default_initializable<OwningView>);
+ static_assert(std::movable<OwningView>);
+ static_assert(!std::is_trivially_move_constructible_v<OwningView>);
+ static_assert(!std::is_trivially_move_assignable_v<OwningView>);
+ static_assert(!std::is_copy_constructible_v<OwningView>);
+ static_assert(!std::is_copy_assignable_v<OwningView>);
+ static_assert(!std::is_constructible_v<OwningView, int>);
+ static_assert(!std::is_constructible_v<OwningView, MoveChecker&>);
+ static_assert(std::is_constructible_v<OwningView, MoveChecker&&>);
+ static_assert(!std::is_convertible_v<int, OwningView>);
+ static_assert(std::is_convertible_v<MoveChecker&&, OwningView>);
+ {
+ // Check that the constructor does indeed move from the target object.
+ auto m = MoveChecker(42);
+ OwningView ov = OwningView(std::move(m));
+ assert(ov.base().i == 42);
+ assert(m.i == -1);
+ }
+ }
+ {
+ // Check that the defaulted constructors are (not) noexcept when appropriate.
+
+ static_assert( std::is_nothrow_constructible_v<NoexceptChecker>); // therefore,
+ static_assert( std::is_nothrow_constructible_v<std::ranges::owning_view<NoexceptChecker>>);
+ static_assert(!std::is_nothrow_constructible_v<DefaultConstructible>); // therefore,
+ static_assert(!std::is_nothrow_constructible_v<std::ranges::owning_view<DefaultConstructible>>);
+
+ static_assert( std::is_nothrow_move_constructible_v<NoexceptChecker>); // therefore,
+ static_assert( std::is_nothrow_move_constructible_v<std::ranges::owning_view<NoexceptChecker>>);
+ static_assert(!std::is_nothrow_move_constructible_v<MoveChecker>); // therefore,
+ static_assert(!std::is_nothrow_move_constructible_v<std::ranges::owning_view<MoveChecker>>);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp
new file mode 100644
index 0000000000000..65f224b24d287
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr auto data() requires contiguous_range<R>
+// constexpr auto data() const requires contiguous_range<const R>
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasData = requires (T t) {
+ t.data();
+};
+
+constexpr bool test()
+{
+ {
+ struct ContiguousIters {
+ contiguous_iterator<int*> begin();
+ sentinel_wrapper<contiguous_iterator<int*>> end();
+ };
+ using OwningView = std::ranges::owning_view<ContiguousIters>;
+ static_assert(std::ranges::contiguous_range<OwningView&>);
+ static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+ static_assert(HasData<OwningView&>);
+ static_assert(HasData<OwningView&&>);
+ static_assert(!HasData<const OwningView&>);
+ static_assert(!HasData<const OwningView&&>);
+ }
+ {
+ struct NoData {
+ random_access_iterator<int*> begin();
+ random_access_iterator<int*> end();
+ };
+ using OwningView = std::ranges::owning_view<NoData>;
+ static_assert(!HasData<OwningView&>);
+ static_assert(!HasData<OwningView&&>);
+ static_assert(!HasData<const OwningView&>);
+ static_assert(!HasData<const OwningView&&>);
+ }
+ {
+ // Test a view.
+ int a[] = {1};
+ auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));
+ assert(ov.data() == a);
+ assert(std::as_const(ov).data() == a);
+ }
+ {
+ // Test a non-view.
+ std::array<int, 2> a = {1, 2};
+ auto ov = std::ranges::owning_view(std::move(a));
+ assert(ov.data() != a.data()); // because it points into the copy
+ assert(std::as_const(ov).data() != a.data());
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp
new file mode 100644
index 0000000000000..cc3d85c8a2ebc
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr bool empty() requires requires { ranges::empty(r_); }
+// constexpr bool empty() const requires requires { ranges::empty(r_); }
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasEmpty = requires (T t) {
+ t.empty();
+};
+
+constexpr bool test()
+{
+ {
+ struct ComparableIters {
+ forward_iterator<int*> begin();
+ forward_iterator<int*> end();
+ };
+ using OwningView = std::ranges::owning_view<ComparableIters>;
+ static_assert(HasEmpty<OwningView&>);
+ static_assert(HasEmpty<OwningView&&>);
+ static_assert(!HasEmpty<const OwningView&>);
+ static_assert(!HasEmpty<const OwningView&&>);
+ }
+ {
+ struct NoEmpty {
+ cpp20_input_iterator<int*> begin();
+ sentinel_wrapper<cpp20_input_iterator<int*>> end();
+ };
+ static_assert(std::ranges::range<NoEmpty&>);
+ static_assert(!std::invocable<decltype(std::ranges::empty), NoEmpty&>);
+ static_assert(!std::ranges::range<const NoEmpty&>); // no begin/end
+ static_assert(!std::invocable<decltype(std::ranges::empty), const NoEmpty&>);
+ using OwningView = std::ranges::owning_view<NoEmpty>;
+ static_assert(!HasEmpty<OwningView&>);
+ static_assert(!HasEmpty<OwningView&&>);
+ static_assert(!HasEmpty<const OwningView&>);
+ static_assert(!HasEmpty<const OwningView&&>);
+ }
+ {
+ struct EmptyMember {
+ cpp20_input_iterator<int*> begin();
+ sentinel_wrapper<cpp20_input_iterator<int*>> end();
+ bool empty() const;
+ };
+ static_assert(std::ranges::range<EmptyMember&>);
+ static_assert(std::invocable<decltype(std::ranges::empty), EmptyMember&>);
+ static_assert(!std::ranges::range<const EmptyMember&>); // no begin/end
+ static_assert(std::invocable<decltype(std::ranges::empty), const EmptyMember&>);
+ using OwningView = std::ranges::owning_view<EmptyMember>;
+ static_assert(std::ranges::range<OwningView&>);
+ static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+ static_assert(HasEmpty<OwningView&>);
+ static_assert(HasEmpty<OwningView&&>);
+ static_assert(HasEmpty<const OwningView&>); // but it still has empty()
+ static_assert(HasEmpty<const OwningView&&>);
+ }
+ {
+ // Test an empty view.
+ int a[] = {1};
+ auto ov = std::ranges::owning_view(std::ranges::subrange(a, a));
+ assert(ov.empty());
+ assert(std::as_const(ov).empty());
+ }
+ {
+ // Test a non-empty view.
+ int a[] = {1};
+ auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));
+ assert(!ov.empty());
+ assert(!std::as_const(ov).empty());
+ }
+ {
+ // Test a non-view.
+ std::array<int, 2> a = {1, 2};
+ auto ov = std::ranges::owning_view(std::move(a));
+ assert(!ov.empty());
+ assert(!std::as_const(ov).empty());
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp
new file mode 100644
index 0000000000000..11e6090e9f8f5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr auto size() requires sized_range<R>
+// constexpr auto size() const requires sized_range<const R>
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasSize = requires (T t) {
+ t.size();
+};
+
+constexpr bool test()
+{
+ {
+ struct SubtractableIters {
+ forward_iterator<int*> begin();
+ sized_sentinel<forward_iterator<int*>> end();
+ };
+ using OwningView = std::ranges::owning_view<SubtractableIters>;
+ static_assert(std::ranges::sized_range<OwningView&>);
+ static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+ static_assert(HasSize<OwningView&>);
+ static_assert(HasSize<OwningView&&>);
+ static_assert(!HasSize<const OwningView&>);
+ static_assert(!HasSize<const OwningView&&>);
+ }
+ {
+ struct NoSize {
+ bidirectional_iterator<int*> begin();
+ bidirectional_iterator<int*> end();
+ };
+ using OwningView = std::ranges::owning_view<NoSize>;
+ static_assert(!HasSize<OwningView&>);
+ static_assert(!HasSize<OwningView&&>);
+ static_assert(!HasSize<const OwningView&>);
+ static_assert(!HasSize<const OwningView&&>);
+ }
+ {
+ struct SizeMember {
+ bidirectional_iterator<int*> begin();
+ bidirectional_iterator<int*> end();
+ int size() const;
+ };
+ using OwningView = std::ranges::owning_view<SizeMember>;
+ static_assert(std::ranges::sized_range<OwningView&>);
+ static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+ static_assert(HasSize<OwningView&>);
+ static_assert(HasSize<OwningView&&>);
+ static_assert(!HasSize<const OwningView&>); // not a range, therefore no size()
+ static_assert(!HasSize<const OwningView&&>);
+ }
+ {
+ // Test an empty view.
+ int a[] = {1};
+ auto ov = std::ranges::owning_view(std::ranges::subrange(a, a));
+ assert(ov.size() == 0);
+ assert(std::as_const(ov).size() == 0);
+ }
+ {
+ // Test a non-empty view.
+ int a[] = {1};
+ auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));
+ assert(ov.size() == 1);
+ assert(std::as_const(ov).size() == 1);
+ }
+ {
+ // Test a non-view.
+ std::array<int, 2> a = {1, 2};
+ auto ov = std::ranges::owning_view(std::move(a));
+ assert(ov.size() == 2);
+ assert(std::as_const(ov).size() == 2);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp
index 5f7fd83f1611e..852effb8d1bfd 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp
@@ -39,22 +39,29 @@ void testCTAD() {
View v;
Range r;
BorrowedRange br;
+
static_assert(std::same_as<
decltype(std::ranges::common_view(v)),
std::ranges::common_view<View>
>);
+ static_assert(std::same_as<
+ decltype(std::ranges::common_view(std::move(v))),
+ std::ranges::common_view<View>
+ >);
static_assert(std::same_as<
decltype(std::ranges::common_view(r)),
std::ranges::common_view<std::ranges::ref_view<Range>>
>);
- // std::ranges::common_view(std::move(r)) invalid. RValue range must be borrowed.
+ static_assert(std::same_as<
+ decltype(std::ranges::common_view(std::move(r))),
+ std::ranges::common_view<std::ranges::owning_view<Range>>
+ >);
static_assert(std::same_as<
decltype(std::ranges::common_view(br)),
std::ranges::common_view<std::ranges::ref_view<BorrowedRange>>
>);
static_assert(std::same_as<
decltype(std::ranges::common_view(std::move(br))),
- std::ranges::common_view<std::ranges::subrange<
- int *, sentinel_wrapper<int *>, std::ranges::subrange_kind::unsized>>
+ std::ranges::common_view<std::ranges::owning_view<BorrowedRange>>
>);
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp
index 84575c9c18977..98e9887fa73d9 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp
@@ -11,22 +11,56 @@
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// template<class R>
-// drop_view(R&&, range_
diff erence_t<R>) -> drop_view<views::all_t<R>>;
+// drop_view(R&&, range_
diff erence_t<R>) -> drop_view<views::all_t<R>>;
#include <ranges>
+#include <cassert>
+#include <concepts>
-#include "test_macros.h"
-#include "types.h"
+struct View : std::ranges::view_base {
+ int *begin() const;
+ int *end() const;
+};
-namespace ranges = std::ranges;
+struct Range {
+ int *begin() const;
+ int *end() const;
+};
-static_assert(std::same_as<decltype(ranges::drop_view(MoveOnlyView(), 0)), ranges::drop_view<MoveOnlyView>>);
-static_assert(std::same_as<decltype(ranges::drop_view(CopyableView(), 0)), ranges::drop_view<CopyableView>>);
-static_assert(std::same_as<decltype(ranges::drop_view(ForwardView(), 0)), ranges::drop_view<ForwardView>>);
-static_assert(std::same_as<decltype(ranges::drop_view(InputView(), 0)), ranges::drop_view<InputView>>);
+struct BorrowedRange {
+ int *begin() const;
+ int *end() const;
+};
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
-static_assert(std::same_as<decltype(ranges::drop_view(std::declval<ForwardRange&>(), 0)),
- ranges::drop_view<ranges::ref_view<ForwardRange>>>);
+void testCTAD() {
+ View v;
+ Range r;
+ BorrowedRange br;
-static_assert(std::same_as<decltype(ranges::drop_view(BorrowableRange(), 0)),
- ranges::drop_view<ranges::subrange<int*>>>);
+ static_assert(std::same_as<
+ decltype(std::ranges::drop_view(v, 0)),
+ std::ranges::drop_view<View>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::drop_view(std::move(v), 0)),
+ std::ranges::drop_view<View>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::drop_view(r, 0)),
+ std::ranges::drop_view<std::ranges::ref_view<Range>>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::drop_view(std::move(r), 0)),
+ std::ranges::drop_view<std::ranges::owning_view<Range>>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::drop_view(br, 0)),
+ std::ranges::drop_view<std::ranges::ref_view<BorrowedRange>>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::drop_view(std::move(br), 0)),
+ std::ranges::drop_view<std::ranges::owning_view<BorrowedRange>>
+ >);
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
index a81fa03e15c21..f0dd9abc33723 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
@@ -15,58 +15,55 @@
#include <ranges>
-#include "test_iterators.h"
+struct Child {
+ int *begin() const;
+ int *end() const;
+};
-template<class T>
struct View : std::ranges::view_base {
- // All friends here are defined to prevent GCC warnings.
- friend T* begin(View&) { return nullptr; }
- friend T* begin(View const&) { return nullptr; }
- friend sentinel_wrapper<T*> end(View&) { return sentinel_wrapper<T*>(nullptr); }
- friend sentinel_wrapper<T*> end(View const&) { return sentinel_wrapper<T*>(nullptr); }
+ Child *begin() const;
+ Child *end() const;
};
-template<class T>
struct Range {
- friend T* begin(Range&) { return nullptr; }
- friend T* begin(Range const&) { return nullptr; }
- friend sentinel_wrapper<T*> end(Range&) { return sentinel_wrapper<T*>(nullptr); }
- friend sentinel_wrapper<T*> end(Range const&) { return sentinel_wrapper<T*>(nullptr); }
+ Child *begin() const;
+ Child *end() const;
};
-template<class T>
struct BorrowedRange {
- friend T* begin(BorrowedRange&) { return nullptr; }
- friend T* begin(BorrowedRange const&) { return nullptr; }
- friend sentinel_wrapper<T*> end(BorrowedRange&) { return sentinel_wrapper<T*>(nullptr); }
- friend sentinel_wrapper<T*> end(BorrowedRange const&) { return sentinel_wrapper<T*>(nullptr); }
+ Child *begin() const;
+ Child *end() const;
};
-
template<>
-inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange<BorrowedRange<int>>> = true;
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
void testCTAD() {
- View<View<int>> v;
- Range<Range<int>> r;
- BorrowedRange<BorrowedRange<int>> br;
+ View v;
+ Range r;
+ BorrowedRange br;
static_assert(std::same_as<
decltype(std::ranges::join_view(v)),
- std::ranges::join_view<View<View<int>>>
+ std::ranges::join_view<View>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::join_view(std::move(v))),
+ std::ranges::join_view<View>
>);
static_assert(std::same_as<
decltype(std::ranges::join_view(r)),
- std::ranges::join_view<std::ranges::ref_view<Range<Range<int>>>>
+ std::ranges::join_view<std::ranges::ref_view<Range>>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::join_view(std::move(r))),
+ std::ranges::join_view<std::ranges::owning_view<Range>>
>);
- // std::ranges::join_view(std::move(r)) invalid. RValue range must be borrowed.
static_assert(std::same_as<
decltype(std::ranges::join_view(br)),
- std::ranges::join_view<std::ranges::ref_view<BorrowedRange<BorrowedRange<int>>>>
+ std::ranges::join_view<std::ranges::ref_view<BorrowedRange>>
>);
static_assert(std::same_as<
decltype(std::ranges::join_view(std::move(br))),
- std::ranges::join_view<std::ranges::subrange<BorrowedRange<int> *,
- sentinel_wrapper<BorrowedRange<int> *>,
- std::ranges::subrange_kind::unsized>>
+ std::ranges::join_view<std::ranges::owning_view<BorrowedRange>>
>);
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp
new file mode 100644
index 0000000000000..ea0caf474fa32
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// template<class R>
+// reverse_view(R&&) -> reverse_view<views::all_t<R>>;
+
+#include <ranges>
+
+#include <concepts>
+#include <utility>
+
+#include "test_iterators.h"
+
+struct View : std::ranges::view_base {
+ int *begin() const;
+ int *end() const;
+};
+
+struct Range {
+ int *begin() const;
+ int *end() const;
+};
+
+struct BorrowedRange {
+ int *begin() const;
+ int *end() const;
+};
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
+
+void testCTAD() {
+ View v;
+ Range r;
+ BorrowedRange br;
+
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(v)),
+ std::ranges::reverse_view<View>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(std::move(v))),
+ std::ranges::reverse_view<View>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(r)),
+ std::ranges::reverse_view<std::ranges::ref_view<Range>>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(std::move(r))),
+ std::ranges::reverse_view<std::ranges::owning_view<Range>>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(br)),
+ std::ranges::reverse_view<std::ranges::ref_view<BorrowedRange>>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(std::move(br))),
+ std::ranges::reverse_view<std::ranges::owning_view<BorrowedRange>>
+ >);
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp
deleted file mode 100644
index bd02bf1a1d73c..0000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: libcpp-no-concepts
-// UNSUPPORTED: libcpp-has-no-incomplete-ranges
-
-// template<class R>
-// reverse_view(R&&) -> reverse_view<views::all_t<R>>;
-
-#include <ranges>
-
-#include <concepts>
-#include <utility>
-
-#include "test_iterators.h"
-
-struct View : std::ranges::view_base {
- friend int* begin(View&) { return nullptr; }
- friend int* begin(View const&) { return nullptr; }
- friend sentinel_wrapper<int*> end(View&) { return sentinel_wrapper<int*>(nullptr); }
- friend sentinel_wrapper<int*> end(View const&) { return sentinel_wrapper<int*>(nullptr); }
-};
-
-struct Range {
- friend int* begin(Range&) { return nullptr; }
- friend int* begin(Range const&) { return nullptr; }
- friend sentinel_wrapper<int*> end(Range&) { return sentinel_wrapper<int*>(nullptr); }
- friend sentinel_wrapper<int*> end(Range const&) { return sentinel_wrapper<int*>(nullptr); }
-};
-
-struct BorrowedRange {
- friend int* begin(BorrowedRange&) { return nullptr; }
- friend int* begin(BorrowedRange const&) { return nullptr; }
- friend sentinel_wrapper<int*> end(BorrowedRange&) { return sentinel_wrapper<int*>(nullptr); }
- friend sentinel_wrapper<int*> end(BorrowedRange const&) { return sentinel_wrapper<int*>(nullptr); }
-};
-
-template<>
-inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
-
-int main(int, char**) {
- View v;
- Range r;
- BorrowedRange br;
-
- {
- std::same_as<std::ranges::reverse_view<View>> auto x = std::ranges::reverse_view(v);
- (void)x;
- }
- {
- std::same_as<std::ranges::reverse_view<std::ranges::ref_view<Range>>> auto x = std::ranges::reverse_view(r);
- (void)x;
- // std::ranges::reverse_view(std::move(r)) is invalid. RValue range must be borrowed.
- }
- {
- std::same_as<std::ranges::reverse_view<std::ranges::ref_view<BorrowedRange>>> auto x = std::ranges::reverse_view(br);
- (void)x;
- }
- {
- using Subrange = std::ranges::subrange<int *, sentinel_wrapper<int *>, std::ranges::subrange_kind::unsized>;
- std::same_as<std::ranges::reverse_view<Subrange>> auto x = std::ranges::reverse_view(std::move(br));
- (void)x;
- }
-
- return 0;
-}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp
index bf326895758c7..419fad396caaa 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp
@@ -17,29 +17,20 @@
#include <cassert>
#include <concepts>
-#include "test_iterators.h"
-
struct View : std::ranges::view_base {
- friend int* begin(View&);
- friend int* begin(View const&);
- friend sentinel_wrapper<int*> end(View&);
- friend sentinel_wrapper<int*> end(View const&);
+ int *begin() const;
+ int *end() const;
};
struct Range {
- friend int* begin(Range&);
- friend int* begin(Range const&);
- friend sentinel_wrapper<int*> end(Range&);
- friend sentinel_wrapper<int*> end(Range const&);
+ int *begin() const;
+ int *end() const;
};
struct BorrowedRange {
- friend int* begin(BorrowedRange&);
- friend int* begin(BorrowedRange const&);
- friend sentinel_wrapper<int*> end(BorrowedRange&);
- friend sentinel_wrapper<int*> end(BorrowedRange const&);
+ int *begin() const;
+ int *end() const;
};
-
template<>
inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
@@ -47,22 +38,29 @@ void testCTAD() {
View v;
Range r;
BorrowedRange br;
+
static_assert(std::same_as<
decltype(std::ranges::take_view(v, 0)),
std::ranges::take_view<View>
>);
+ static_assert(std::same_as<
+ decltype(std::ranges::take_view(std::move(v), 0)),
+ std::ranges::take_view<View>
+ >);
static_assert(std::same_as<
decltype(std::ranges::take_view(r, 0)),
std::ranges::take_view<std::ranges::ref_view<Range>>
>);
- // std::ranges::take_view(std::move(r), 0) invalid. RValue range must be borrowed.
+ static_assert(std::same_as<
+ decltype(std::ranges::take_view(std::move(r), 0)),
+ std::ranges::take_view<std::ranges::owning_view<Range>>
+ >);
static_assert(std::same_as<
decltype(std::ranges::take_view(br, 0)),
std::ranges::take_view<std::ranges::ref_view<BorrowedRange>>
>);
static_assert(std::same_as<
decltype(std::ranges::take_view(std::move(br), 0)),
- std::ranges::take_view<std::ranges::subrange<
- int *, sentinel_wrapper<int *>, std::ranges::subrange_kind::unsized>>
+ std::ranges::take_view<std::ranges::owning_view<BorrowedRange>>
>);
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp
index c07c79452d956..086dc2fb471ae 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp
@@ -10,17 +10,62 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
-// CTAD tests.
+// template<class R, class F>
+// transform_view(R&&, F) -> transform_view<views::all_t<R>, F>;
#include <ranges>
+#include <cassert>
#include <concepts>
-#include "test_macros.h"
-#include "types.h"
+struct PlusOne {
+ int operator()(int x) const;
+};
-static_assert(std::same_as<decltype(std::ranges::transform_view(InputView(), PlusOne())),
- std::ranges::transform_view<InputView, PlusOne>>);
-static_assert(std::same_as<decltype(std::ranges::transform_view(std::declval<ForwardRange&>(), PlusOne())),
- std::ranges::transform_view<std::ranges::ref_view<ForwardRange>, PlusOne>>);
-static_assert(std::same_as<decltype(std::ranges::transform_view(BorrowableRange(), PlusOne())),
- std::ranges::transform_view<std::ranges::subrange<int*>, PlusOne>>);
+struct View : std::ranges::view_base {
+ int *begin() const;
+ int *end() const;
+};
+
+struct Range {
+ int *begin() const;
+ int *end() const;
+};
+
+struct BorrowedRange {
+ int *begin() const;
+ int *end() const;
+};
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
+
+void testCTAD() {
+ View v;
+ Range r;
+ BorrowedRange br;
+ PlusOne f;
+
+ static_assert(std::same_as<
+ decltype(std::ranges::transform_view(v, f)),
+ std::ranges::transform_view<View, PlusOne>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::transform_view(std::move(v), f)),
+ std::ranges::transform_view<View, PlusOne>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::transform_view(r, f)),
+ std::ranges::transform_view<std::ranges::ref_view<Range>, PlusOne>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::transform_view(std::move(r), f)),
+ std::ranges::transform_view<std::ranges::owning_view<Range>, PlusOne>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::transform_view(br, f)),
+ std::ranges::transform_view<std::ranges::ref_view<BorrowedRange>, PlusOne>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::transform_view(std::move(br), f)),
+ std::ranges::transform_view<std::ranges::owning_view<BorrowedRange>, PlusOne>
+ >);
+}
diff --git a/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp
index bd16cea6fd1e4..e0d1c6511d402 100644
--- a/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp
@@ -23,50 +23,53 @@
// range<T>
// view<remove_cvref_t<T>>
// constructible_from<remove_cvref_t<T>, T>
-// borrowed_range<T>
+// lvalue_reference_t<T> || movable<remove_reference_t<T>>
+// is-initializer-list<T>
//
// We test all the relevant combinations of satisfying/not satisfying those constraints.
-// viewable_range<T> is not satisfied for (range=false, view=*, constructible_from=*, borrowed_range=*)
+// viewable_range<T> is not satisfied for (range=false, view=*, constructible_from=*, lvalue-or-movable=*)
struct T1 { };
static_assert(!std::ranges::range<T1>);
static_assert(!std::ranges::viewable_range<T1>);
static_assert(!std::ranges::viewable_range<T1&>);
+static_assert(!std::ranges::viewable_range<T1&&>);
static_assert(!std::ranges::viewable_range<T1 const>);
static_assert(!std::ranges::viewable_range<T1 const&>);
+static_assert(!std::ranges::viewable_range<T1 const&&>);
-// viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=true)
+// viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=true)
struct T2 : test_range<cpp20_input_iterator>, std::ranges::view_base {
T2(T2 const&) = default;
};
-template<> constexpr bool std::ranges::enable_borrowed_range<T2> = true;
static_assert(std::ranges::range<T2>);
static_assert(std::ranges::view<T2>);
static_assert(std::constructible_from<T2, T2>);
-static_assert(std::ranges::borrowed_range<T2>);
static_assert(std::ranges::viewable_range<T2>);
static_assert(std::ranges::viewable_range<T2&>);
+static_assert(std::ranges::viewable_range<T2&&>);
static_assert(std::ranges::viewable_range<T2 const>);
static_assert(std::ranges::viewable_range<T2 const&>);
+static_assert(std::ranges::viewable_range<T2 const&&>);
-// viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=false)
+// viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=false)
struct T3 : test_range<cpp20_input_iterator>, std::ranges::view_base {
T3(T3 const&) = default;
};
-template<> constexpr bool std::ranges::enable_borrowed_range<T3> = false;
static_assert(std::ranges::range<T3>);
static_assert(std::ranges::view<T3>);
static_assert(std::constructible_from<T3, T3>);
-static_assert(!std::ranges::borrowed_range<T3>);
static_assert(std::ranges::viewable_range<T3>);
static_assert(std::ranges::viewable_range<T3&>);
+static_assert(std::ranges::viewable_range<T3&&>);
static_assert(std::ranges::viewable_range<T3 const>);
static_assert(std::ranges::viewable_range<T3 const&>);
+static_assert(std::ranges::viewable_range<T3 const&&>);
-// viewable_range<T> is not satisfied for (range=true, view=true, constructible_from=false, borrowed_range=true)
+// viewable_range<T> is not satisfied for (range=true, view=true, constructible_from=false, lvalue-or-movable=true)
struct T4 : test_range<cpp20_input_iterator>, std::ranges::view_base {
T4(T4 const&) = delete;
T4(T4&&) = default; // necessary to model view
@@ -75,53 +78,83 @@ struct T4 : test_range<cpp20_input_iterator>, std::ranges::view_base {
static_assert(std::ranges::range<T4 const&>);
static_assert(std::ranges::view<std::remove_cvref_t<T4 const&>>);
static_assert(!std::constructible_from<std::remove_cvref_t<T4 const&>, T4 const&>);
-static_assert(std::ranges::borrowed_range<T4 const&>);
static_assert(!std::ranges::viewable_range<T4 const&>);
-// A type that satisfies (range=true, view=true, constructible_from=false, borrowed_range=false) can't be formed
+// A type that satisfies (range=true, view=true, constructible_from=false, lvalue-or-movable=false) can't be formed,
+// because views are movable by definition
-// viewable_range<T> is satisfied for (range=true, view=false, constructible_from=true, borrowed_range=true)
+// viewable_range<T> is satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=true)...
struct T5 : test_range<cpp20_input_iterator> { };
-template<> constexpr bool std::ranges::enable_borrowed_range<T5> = true;
-static_assert(std::ranges::range<T5>);
+static_assert( std::ranges::range<T5>);
static_assert(!std::ranges::view<T5>);
-static_assert(std::constructible_from<T5, T5>);
-static_assert(std::ranges::borrowed_range<T5>);
-
-static_assert(std::ranges::viewable_range<T5>);
-
-// viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=true, borrowed_range=false)
-struct T6 : test_range<cpp20_input_iterator> { };
-template<> constexpr bool std::ranges::enable_borrowed_range<T6> = false;
-static_assert(std::ranges::range<T6>);
+static_assert( std::constructible_from<T5, T5>);
+static_assert( std::movable<T5>);
+static_assert(!std::movable<const T5>);
+
+static_assert( std::ranges::viewable_range<T5>); // movable
+static_assert( std::ranges::viewable_range<T5&>); // movable
+static_assert( std::ranges::viewable_range<T5&&>); // movable
+static_assert(!std::ranges::viewable_range<const T5>);
+static_assert( std::ranges::viewable_range<const T5&>); // lvalue
+static_assert(!std::ranges::viewable_range<const T5&&>);
+
+// ...but not if the (non-view, lvalue-or-movable) range is an initializer_list.
+static_assert( std::ranges::range<std::initializer_list<int>>);
+static_assert(!std::ranges::view<std::initializer_list<int>>);
+static_assert( std::constructible_from<std::initializer_list<int>, std::initializer_list<int>>);
+static_assert( std::movable<std::initializer_list<int>>);
+
+static_assert(!std::ranges::viewable_range<std::initializer_list<int>>);
+static_assert( std::ranges::viewable_range<std::initializer_list<int>&>);
+static_assert(!std::ranges::viewable_range<std::initializer_list<int>&&>);
+static_assert(!std::ranges::viewable_range<std::initializer_list<int> const>);
+static_assert( std::ranges::viewable_range<std::initializer_list<int> const&>);
+static_assert(!std::ranges::viewable_range<std::initializer_list<int> const&&>);
+
+// viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=false)
+struct T6 : test_range<cpp20_input_iterator> { T6(T6&&); T6& operator=(T6&&) = delete; };
+static_assert( std::ranges::range<T6>);
static_assert(!std::ranges::view<T6>);
-static_assert(std::constructible_from<T6, T6>);
-static_assert(!std::ranges::borrowed_range<T6>);
+static_assert( std::constructible_from<T6, T6>);
+static_assert(!std::movable<T6>);
static_assert(!std::ranges::viewable_range<T6>);
+static_assert( std::ranges::viewable_range<T6&>); // lvalue
+static_assert(!std::ranges::viewable_range<T6&&>);
+static_assert(!std::ranges::viewable_range<const T6>);
+static_assert( std::ranges::viewable_range<const T6&>); // lvalue
+static_assert(!std::ranges::viewable_range<const T6&&>);
-// viewable_range<T> is satisfied for (range=true, view=false, constructible_from=false, borrowed_range=true)
+// viewable_range<T> is satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=true)
struct T7 : test_range<cpp20_input_iterator> {
T7(T7 const&) = delete;
};
static_assert(std::ranges::range<T7&>);
static_assert(!std::ranges::view<std::remove_cvref_t<T7&>>);
static_assert(!std::constructible_from<std::remove_cvref_t<T7&>, T7&>);
-static_assert(std::ranges::borrowed_range<T7&>);
-static_assert(std::ranges::viewable_range<T7&>);
+static_assert(!std::ranges::viewable_range<T7>);
+static_assert( std::ranges::viewable_range<T7&>);
+static_assert(!std::ranges::viewable_range<T7&&>);
+static_assert(!std::ranges::viewable_range<const T7>);
+static_assert( std::ranges::viewable_range<const T7&>);
+static_assert(!std::ranges::viewable_range<const T7&&>);
-// A type that satisfies (range=true, view=false, constructible_from=false, borrowed_range=false) can't be formed
+// viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=false)
struct T8 : test_range<cpp20_input_iterator> {
T8(T8 const&) = delete;
};
static_assert(std::ranges::range<T8>);
static_assert(!std::ranges::view<T8>);
static_assert(!std::constructible_from<T8, T8>);
-static_assert(!std::ranges::borrowed_range<T8>);
static_assert(!std::ranges::viewable_range<T8>);
+static_assert( std::ranges::viewable_range<T8&>);
+static_assert(!std::ranges::viewable_range<T8&&>);
+static_assert(!std::ranges::viewable_range<const T8>);
+static_assert( std::ranges::viewable_range<const T8&>);
+static_assert(!std::ranges::viewable_range<const T8&&>);
// Test with a few degenerate types
static_assert(!std::ranges::viewable_range<void>);
@@ -129,5 +162,7 @@ static_assert(!std::ranges::viewable_range<int>);
static_assert(!std::ranges::viewable_range<int (*)(char)>);
static_assert(!std::ranges::viewable_range<int[]>);
static_assert(!std::ranges::viewable_range<int[10]>);
-static_assert(!std::ranges::viewable_range<int(&)[]>); // unbounded array is not a range
-static_assert( std::ranges::viewable_range<int(&)[10]>);
+static_assert(!std::ranges::viewable_range<int(&)[]>); // not a range
+static_assert( std::ranges::viewable_range<int(&)[10]>); // OK, lvalue
+static_assert(!std::ranges::viewable_range<int(&&)[]>);
+static_assert(!std::ranges::viewable_range<int(&&)[10]>);
diff --git a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
index ec1b9b205fd24..3fdb29ee112d0 100644
--- a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
@@ -26,7 +26,7 @@ static_assert(std::ranges::contiguous_range<std::cmatch>);
static_assert(!std::ranges::view<std::cmatch>);
static_assert(std::ranges::sized_range<std::cmatch>);
static_assert(!std::ranges::borrowed_range<std::cmatch>);
-static_assert(!std::ranges::viewable_range<std::cmatch>);
+static_assert(std::ranges::viewable_range<std::cmatch>);
static_assert(std::same_as<std::ranges::iterator_t<std::cmatch const>, std::cmatch::const_iterator>);
static_assert(std::ranges::common_range<std::cmatch const>);
diff --git a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
index 0e34ded705f66..ad018c02f3f84 100644
--- a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
@@ -26,7 +26,7 @@ static_assert(std::ranges::contiguous_range<std::string>);
static_assert(!std::ranges::view<std::string>);
static_assert(std::ranges::sized_range<std::string>);
static_assert(!std::ranges::borrowed_range<std::string>);
-static_assert(!std::ranges::viewable_range<std::string>);
+static_assert(std::ranges::viewable_range<std::string>);
static_assert(std::same_as<std::ranges::iterator_t<std::string const>, std::string::const_iterator>);
static_assert(std::ranges::common_range<std::string const>);
More information about the libcxx-commits
mailing list