[libcxx-commits] [libcxx] [libcxx] P2278R4: implement `{basic_, }const_iterator`, and have `cbegin` et. al. return it (PR #99915)
nicole mazzuca via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Aug 7 12:34:37 PDT 2024
https://github.com/strega-nil updated https://github.com/llvm/llvm-project/pull/99915
>From e58981c3b068625383c96e813c0f6cf6653bab0d Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Mon, 22 Jul 2024 15:39:27 +0200
Subject: [PATCH 01/16] [libcxx] P2278R4: const_iterator and c{begin,end}
Implements `basic_const_iterator` and the const accessors.
Does not implement `const_view`
Does not implement changes to `span` and friends.
---
libcxx/docs/Status/Cxx23Papers.csv | 2 +-
libcxx/include/CMakeLists.txt | 2 +
libcxx/include/__iterator/const_iterator.h | 328 +++++++++++++++++++++
libcxx/include/__ranges/access.h | 55 ----
libcxx/include/__ranges/concepts.h | 14 +
libcxx/include/__ranges/const_access.h | 202 +++++++++++++
libcxx/include/__ranges/rbegin.h | 28 --
libcxx/include/__ranges/rend.h | 27 --
libcxx/include/iterator | 29 ++
libcxx/include/ranges | 8 +
10 files changed, 584 insertions(+), 111 deletions(-)
create mode 100644 libcxx/include/__iterator/const_iterator.h
create mode 100644 libcxx/include/__ranges/const_access.h
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index f8970320ce1fa..2d294e8501e5b 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -61,7 +61,7 @@
"`P1899R3 <https://wg21.link/P1899R3>`__","LWG","``stride_view``","July 2022","","","|ranges|"
"`P2093R14 <https://wg21.link/P2093R14>`__","LWG","Formatted output","July 2022","|Complete|","18.0","|format|"
"`P2165R4 <https://wg21.link/P2165R4>`__","LWG","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","July 2022","",""
-"`P2278R4 <https://wg21.link/P2278R4>`__","LWG","``cbegin`` should always return a constant iterator","July 2022","","","|ranges|"
+"`P2278R4 <https://wg21.link/P2278R4>`__","LWG","``cbegin`` should always return a constant iterator","July 2022","In Progress","","|ranges|"
"`P2286R8 <https://wg21.link/P2286R8>`__","LWG","Formatting Ranges","July 2022","|Complete|","16.0","|format| |ranges|"
"`P2291R3 <https://wg21.link/P2291R3>`__","LWG","Add Constexpr Modifiers to Functions ``to_chars`` and ``from_chars`` for Integral Types in ``<charconv>`` Header","July 2022","|Complete|","16.0"
"`P2302R4 <https://wg21.link/P2302R4>`__","LWG","``std::ranges::contains``","July 2022","|Complete|","19.0","|ranges|"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 32579272858a8..577b7975f3eb2 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -444,6 +444,7 @@ set(files
__iterator/bounded_iter.h
__iterator/common_iterator.h
__iterator/concepts.h
+ __iterator/const_iterator.h
__iterator/counted_iterator.h
__iterator/cpp17_iterator_concepts.h
__iterator/data.h
@@ -639,6 +640,7 @@ set(files
__ranges/chunk_by_view.h
__ranges/common_view.h
__ranges/concepts.h
+ __ranges/const_access.h
__ranges/container_compatible_range.h
__ranges/counted.h
__ranges/dangling.h
diff --git a/libcxx/include/__iterator/const_iterator.h b/libcxx/include/__iterator/const_iterator.h
new file mode 100644
index 0000000000000..7549a98fe3ecc
--- /dev/null
+++ b/libcxx/include/__iterator/const_iterator.h
@@ -0,0 +1,328 @@
+// -*- 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___ITERATOR_CONST_ITERATOR_H
+#define _LIBCPP___ITERATOR_CONST_ITERATOR_H
+
+#include <__compare/three_way_comparable.h>
+#include <__concepts/common_with.h>
+#include <__concepts/different_from.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__type_traits/common_reference.h>
+#include <__type_traits/common_type.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/is_specialization.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+template <indirectly_readable _Iter>
+using iter_const_reference_t = common_reference_t<const iter_value_t<_Iter>&&, iter_reference_t<_Iter>>;
+
+template <class _Iter>
+concept __constant_iterator = input_iterator<_Iter> && same_as<iter_const_reference_t<_Iter>, iter_reference_t<_Iter>>;
+
+template <input_iterator _Iter>
+class basic_const_iterator;
+
+template <input_iterator _Iter>
+using const_iterator = conditional_t<__constant_iterator<_Iter>, _Iter, basic_const_iterator<_Iter>>;
+template <semiregular _Sent>
+using const_sentinel = conditional_t<input_iterator<_Sent>, const_iterator<_Sent>, _Sent>;
+
+template <class _Iter>
+concept __not_a_const_iterator = !__is_specialization_v<_Iter, basic_const_iterator>;
+
+template <indirectly_readable _Iter>
+using __iter_const_rvalue_reference_t = common_reference_t<const iter_value_t<_Iter>&&, iter_rvalue_reference_t<_Iter>>;
+
+template <class _Iter>
+struct __basic_const_iterator_concept {
+ // clang-format off
+ using iterator_concept =
+ conditional_t<contiguous_iterator<_Iter>,
+ contiguous_iterator_tag,
+ conditional_t<random_access_iterator<_Iter>,
+ random_access_iterator_tag,
+ conditional_t<bidirectional_iterator<_Iter>,
+ bidirectional_iterator_tag,
+ conditional_t<forward_iterator<_Iter>,
+ forward_iterator_tag,
+ // else
+ input_iterator_tag>>>>;
+ // clang-format on
+};
+
+template <class _Iter>
+struct __basic_const_iterator_category : __basic_const_iterator_concept<_Iter> {};
+template <forward_iterator _Iter>
+struct __basic_const_iterator_category<_Iter> : __basic_const_iterator_concept<_Iter> {
+ using iterator_category = __basic_const_iterator_concept<_Iter>::iterator_concept;
+};
+
+template <input_iterator _Iter>
+class _LIBCPP_TEMPLATE_VIS basic_const_iterator : __basic_const_iterator_category<_Iter> {
+ _Iter __current = _Iter();
+
+ using __reference = iter_const_reference_t<_Iter>;
+ using __rvalue_reference = __iter_const_rvalue_reference_t<_Iter>;
+
+public:
+ using value_type = iter_value_t<_Iter>;
+ using difference_type = iter_difference_t<_Iter>;
+
+ _LIBCPP_HIDE_FROM_ABI basic_const_iterator()
+ requires default_initializable<_Iter>
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator(_Iter __cur) : __current(std::move(__cur)) {}
+ template <convertible_to<_Iter> _Type>
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator(basic_const_iterator<_Type> __cur)
+ : __current(std::move(__cur.__current)) {}
+ template <__different_from<basic_const_iterator> _Type>
+ requires convertible_to<_Type, _Iter>
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator(_Type&& __cur) : __current(std::forward<_Type>(__cur)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const& noexcept { return __current; }
+ _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return std::move(__current); }
+
+ constexpr __reference operator*() const { return static_cast<__reference>(*__current); }
+ _LIBCPP_HIDE_FROM_ABI constexpr const auto* operator->() const
+ requires is_lvalue_reference_v<iter_reference_t<_Iter>> &&
+ same_as<remove_cvref_t<iter_reference_t<_Iter>>, value_type>
+ {
+ if constexpr (contiguous_iterator<_Iter>) {
+ return std::to_address(__current);
+ } else {
+ return std::addressof(*__current);
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator& operator++() {
+ ++__current;
+ return *this;
+ }
+ constexpr void operator++(int) { ++__current; }
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator operator++(int)
+ requires forward_iterator<_Iter>
+ {
+ auto __tmp = *this;
+ ++__current;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator& operator--()
+ requires bidirectional_iterator<_Iter>
+ {
+ --__current;
+ return *this;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator operator--(int)
+ requires bidirectional_iterator<_Iter>
+ {
+ auto __tmp = *this;
+ --__current;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator& operator+=(difference_type __n)
+ requires random_access_iterator<_Iter>
+ {
+ __current += __n;
+ return *this;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator& operator-=(difference_type __n)
+ requires random_access_iterator<_Iter>
+ {
+ __current -= __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __reference operator[](difference_type __n) const
+ requires random_access_iterator<_Iter>
+ {
+ return static_cast<__reference>(__current[__n]);
+ }
+
+ template <sentinel_for<_Iter> _Sent>
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Sent& __sent) const {
+ return __current == __sent;
+ }
+
+ template <__not_a_const_iterator _ConstIt>
+ requires __constant_iterator<_ConstIt> && convertible_to<_Iter const&, _ConstIt>
+ _LIBCPP_HIDE_FROM_ABI constexpr operator _ConstIt() const& {
+ return __current;
+ }
+ template <__not_a_const_iterator _ConstIt>
+ requires __constant_iterator<_ConstIt> && convertible_to<_Iter, _ConstIt>
+ _LIBCPP_HIDE_FROM_ABI constexpr operator _ConstIt() && {
+ return std::move(__current);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const basic_const_iterator& __rhs) const
+ requires random_access_iterator<_Iter>
+ {
+ return __current < __rhs.__current;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const basic_const_iterator& __rhs) const
+ requires random_access_iterator<_Iter>
+ {
+ return __current > __rhs.__current;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const basic_const_iterator& __rhs) const
+ requires random_access_iterator<_Iter>
+ {
+ return __current <= __rhs.__current;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const basic_const_iterator& __rhs) const
+ requires random_access_iterator<_Iter>
+ {
+ return __current >= __rhs.__current;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const basic_const_iterator& __rhs) const
+ requires random_access_iterator<_Iter> && three_way_comparable<_Iter>
+ {
+ return __current <=> __rhs.__current;
+ }
+
+ template <__different_from<basic_const_iterator> _Iter2>
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Iter2& __rhs) const
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
+ {
+ return __current < __rhs.__current;
+ }
+ template <__different_from<basic_const_iterator> _Iter2>
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Iter2& __rhs) const
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
+ {
+ return __current > __rhs.__current;
+ }
+ template <__different_from<basic_const_iterator> _Iter2>
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Iter2& __rhs) const
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
+ {
+ return __current <= __rhs.__current;
+ }
+ template <__different_from<basic_const_iterator> _Iter2>
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Iter2& __rhs) const
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
+ {
+ return __current >= __rhs.__current;
+ }
+ template <__different_from<basic_const_iterator> _Iter2>
+ _LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const _Iter2& __rhs) const
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> &&
+ three_way_comparable_with<_Iter, _Iter2>
+ {
+ return __current <=> __rhs.__current;
+ }
+
+ template <__not_a_const_iterator _Iter2>
+ friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Iter2& __lhs, const basic_const_iterator& __rhs)
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
+ {
+ return __lhs < __rhs.__current;
+ }
+ template <__not_a_const_iterator _Iter2>
+ friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Iter2& __lhs, const basic_const_iterator& __rhs)
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
+ {
+ return __lhs > __rhs.__current;
+ }
+ template <__not_a_const_iterator _Iter2>
+ friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Iter2& __lhs, const basic_const_iterator& __rhs)
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
+ {
+ return __lhs <= __rhs.__current;
+ }
+ template <__not_a_const_iterator _Iter2>
+ friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Iter2& __lhs, const basic_const_iterator& __rhs)
+ requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
+ {
+ return __lhs >= __rhs.__current;
+ }
+
+ friend _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator
+ operator+(const basic_const_iterator& __it, difference_type __n)
+ requires random_access_iterator<_Iter>
+ {
+ return basic_const_iterator(__it.__current + __n);
+ }
+ friend _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator
+ operator+(difference_type __n, const basic_const_iterator& __it)
+ requires random_access_iterator<_Iter>
+ {
+ return basic_const_iterator(__it.__current + __n);
+ }
+
+ friend _LIBCPP_HIDE_FROM_ABI constexpr basic_const_iterator
+ operator-(const basic_const_iterator& __it, difference_type __n)
+ requires random_access_iterator<_Iter>
+ {
+ return basic_const_iterator(__it.__current - __n);
+ }
+ template <sized_sentinel_for<_Iter> _Sent>
+ _LIBCPP_HIDE_FROM_ABI constexpr difference_type operator-(const _Sent& __rhs) const {
+ return __current - __rhs;
+ }
+ template <__not_a_const_iterator _Sent>
+ requires sized_sentinel_for<_Sent, _Iter>
+ friend _LIBCPP_HIDE_FROM_ABI constexpr difference_type
+ operator-(const _Sent& __lhs, const basic_const_iterator& __rhs) {
+ return __lhs - __rhs;
+ }
+
+ friend _LIBCPP_HIDE_FROM_ABI constexpr __rvalue_reference iter_move(const basic_const_iterator& __it) noexcept(
+ noexcept(static_cast<__rvalue_reference>(ranges::iter_move(__it.current_)))) {
+ return static_cast<__rvalue_reference>(ranges::iter_move(__it.current_));
+ }
+};
+
+template <class _Type1, common_with<_Type1> _Type2>
+ requires input_iterator<common_type_t<_Type1, _Type2>>
+struct common_type<basic_const_iterator<_Type1>, _Type2> {
+ using type = basic_const_iterator<common_type_t<_Type1, _Type2>>;
+};
+template <class _Type1, common_with<_Type1> _Type2>
+ requires input_iterator<common_type_t<_Type1, _Type2>>
+struct common_type<_Type2, basic_const_iterator<_Type1>> {
+ using type = basic_const_iterator<common_type_t<_Type1, _Type2>>;
+};
+template <class _Type1, common_with<_Type1> _Type2>
+ requires input_iterator<common_type_t<_Type1, _Type2>>
+struct common_type<basic_const_iterator<_Type1>, basic_const_iterator<_Type2>> {
+ using type = basic_const_iterator<common_type_t<_Type1, _Type2>>;
+};
+
+template <input_iterator _Iter>
+_LIBCPP_HIDE_FROM_ABI constexpr const_iterator<_Iter> make_const_iterator(_Iter __it) {
+ return __it;
+}
+template <semiregular _Sent>
+_LIBCPP_HIDE_FROM_ABI constexpr const_sentinel<_Sent> make_const_sentinel(_Sent __sent) {
+ return __sent;
+}
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ITERATOR_CONST_ITERATOR_H
diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h
index c0a40c5e10178..7955b3b2166dc 100644
--- a/libcxx/include/__ranges/access.h
+++ b/libcxx/include/__ranges/access.h
@@ -148,61 +148,6 @@ inline constexpr auto end = __end::__fn{};
} // namespace __cpo
} // namespace ranges
-// [range.access.cbegin]
-
-namespace ranges {
-namespace __cbegin {
-struct __fn {
- template <class _Tp>
- requires is_lvalue_reference_v<_Tp&&>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
- noexcept(noexcept(ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t))))
- -> decltype(ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t))) {
- return ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t));
- }
-
- template <class _Tp>
- requires is_rvalue_reference_v<_Tp&&>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
- noexcept(noexcept(ranges::begin(static_cast<const _Tp&&>(__t))))
- -> decltype(ranges::begin(static_cast<const _Tp&&>(__t))) {
- return ranges::begin(static_cast<const _Tp&&>(__t));
- }
-};
-} // namespace __cbegin
-
-inline namespace __cpo {
-inline constexpr auto cbegin = __cbegin::__fn{};
-} // namespace __cpo
-} // namespace ranges
-
-// [range.access.cend]
-
-namespace ranges {
-namespace __cend {
-struct __fn {
- template <class _Tp>
- requires is_lvalue_reference_v<_Tp&&>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
- noexcept(noexcept(ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t))))
- -> decltype(ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t))) {
- return ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t));
- }
-
- template <class _Tp>
- requires is_rvalue_reference_v<_Tp&&>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept(
- noexcept(ranges::end(static_cast<const _Tp&&>(__t)))) -> decltype(ranges::end(static_cast<const _Tp&&>(__t))) {
- return ranges::end(static_cast<const _Tp&&>(__t));
- }
-};
-} // namespace __cend
-
-inline namespace __cpo {
-inline constexpr auto cend = __cend::__fn{};
-} // namespace __cpo
-} // namespace ranges
-
#endif // _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index 674a3f359ff99..19264d4ac76c3 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -15,6 +15,7 @@
#include <__concepts/same_as.h>
#include <__config>
#include <__iterator/concepts.h>
+#include <__iterator/const_iterator.h>
#include <__iterator/incrementable_traits.h>
#include <__iterator/iter_move.h>
#include <__iterator/iterator_traits.h>
@@ -61,6 +62,11 @@ concept borrowed_range =
template <range _Rp>
using sentinel_t = decltype(ranges::end(std::declval<_Rp&>()));
+# if _LIBCPP_STD_VER >= 23
+template <range _Rp>
+using const_iterator_t = const_iterator<iterator_t<_Rp>>;
+# endif // _LIBCPP_STD_VER >= 23
+
template <range _Rp>
using range_difference_t = iter_difference_t<iterator_t<_Rp>>;
@@ -70,6 +76,9 @@ using range_value_t = iter_value_t<iterator_t<_Rp>>;
template <range _Rp>
using range_reference_t = iter_reference_t<iterator_t<_Rp>>;
+template <range _Rp>
+using range_const_reference_t = iter_const_reference_t<iterator_t<_Rp>>;
+
template <range _Rp>
using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<_Rp>>;
@@ -133,6 +142,11 @@ concept viewable_range =
(is_lvalue_reference_v<_Tp> ||
(movable<remove_reference_t<_Tp>> && !__is_std_initializer_list<remove_cvref_t<_Tp>>))));
+# if _LIBCPP_STD_VER >= 23
+template <class _Tp>
+concept constant_range = input_range<_Tp> && __constant_iterator<iterator_t<_Tp>>;
+# endif // _LIBCPP_STD_VER >= 23
+
} // namespace ranges
#endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__ranges/const_access.h b/libcxx/include/__ranges/const_access.h
new file mode 100644
index 0000000000000..4bc14e0049b71
--- /dev/null
+++ b/libcxx/include/__ranges/const_access.h
@@ -0,0 +1,202 @@
+// -*- 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_CONST_ACCESS_H
+#define _LIBCPP___RANGES_CONST_ACCESS_H
+
+#include <__iterator/const_iterator.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/rbegin.h>
+#include <__ranges/rend.h>
+#include <__type_traits/is_reference.h>
+#include <__type_traits/remove_reference.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 20
+
+// [range.const]
+# if _LIBCPP_STD_VER >= 23
+namespace ranges {
+template <input_range _Rp>
+constexpr auto& __possibly_const_range(_Rp& __rng) {
+ if constexpr (constant_range<const _Rp> && !constant_range<_Rp>) {
+ return const_cast<const _Rp&>(__rng);
+ } else {
+ return __rng;
+ }
+}
+} // namespace ranges
+# endif // _LIBCPP_STD_VER >= 23
+
+// [range.access.cbegin]
+namespace ranges {
+
+template <class _Type>
+concept __const_accessible_range = (!is_rvalue_reference_v<_Type&&> || enable_borrowed_range<remove_cv_t<_Type>>);
+
+namespace __cbegin {
+struct __fn {
+# if _LIBCPP_STD_VER >= 23
+ template <class _Rng>
+ using _UType = decltype(ranges::begin(ranges::__possibly_const_range(std::declval<_Rng>())));
+
+ template <__const_accessible_range _Rng>
+ auto operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>(
+ ranges::begin(ranges::__possibly_const_range(std::declval<_Rng>()))))) -> const_iterator<_UType<_Rng>> {
+ return const_iterator<_UType<_Rng>>(ranges::begin(ranges::__possibly_const_range(__rng)));
+ }
+# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 vvv
+ template <class _Tp>
+ requires is_lvalue_reference_v<_Tp&&>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
+ noexcept(noexcept(ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t))))
+ -> decltype(ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t))) {
+ return ranges::begin(static_cast<const remove_reference_t<_Tp>&>(__t));
+ }
+
+ template <class _Tp>
+ requires is_rvalue_reference_v<_Tp&&>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
+ noexcept(noexcept(ranges::begin(static_cast<const _Tp&&>(__t))))
+ -> decltype(ranges::begin(static_cast<const _Tp&&>(__t))) {
+ return ranges::begin(static_cast<const _Tp&&>(__t));
+ }
+# endif // ^^^ _LIBCPP_STD_VER < 23
+};
+} // namespace __cbegin
+
+inline namespace __cpo {
+inline constexpr auto cbegin = __cbegin::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+// [range.access.cend]
+namespace ranges {
+namespace __cend {
+struct __fn {
+# if _LIBCPP_STD_VER >= 23
+ template <class _Rng>
+ using _UType = decltype(ranges::end(ranges::__possibly_const_range(std::declval<_Rng>())));
+
+ template <__const_accessible_range _Rng>
+ auto operator()(_Rng&& __rng) noexcept(noexcept(const_sentinel<_UType<_Rng>>(
+ ranges::end(ranges::__possibly_const_range(__rng))))) -> const_sentinel<_UType<_Rng>> {
+ return const_sentinel<_UType<_Rng>>(ranges::end(ranges::__possibly_const_range(__rng)));
+ }
+# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 vvv
+ template <class _Tp>
+ requires is_lvalue_reference_v<_Tp&&>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
+ noexcept(noexcept(ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t))))
+ -> decltype(ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t))) {
+ return ranges::end(static_cast<const remove_reference_t<_Tp>&>(__t));
+ }
+
+ template <class _Tp>
+ requires is_rvalue_reference_v<_Tp&&>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept(
+ noexcept(ranges::end(static_cast<const _Tp&&>(__t)))) -> decltype(ranges::end(static_cast<const _Tp&&>(__t))) {
+ return ranges::end(static_cast<const _Tp&&>(__t));
+ }
+# endif
+};
+} // namespace __cend
+
+inline namespace __cpo {
+inline constexpr auto cend = __cend::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+// [range.access.crbegin]
+namespace ranges {
+namespace __crbegin {
+struct __fn {
+# if _LIBCPP_STD_VER >= 23
+ template <class _Rng>
+ using _UType = decltype(ranges::rbegin(ranges::__possibly_const_range(std::declval<_Rng>())));
+
+ template <__const_accessible_range _Rng>
+ auto operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>(
+ ranges::rbegin(ranges::__possibly_const_range(__rng))))) -> const_iterator<_UType<_Rng>> {
+ return const_iterator<_UType<_Rng>>(ranges::rbegin(ranges::__possibly_const_range(__rng)));
+ }
+# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23
+ template <class _Tp>
+ requires is_lvalue_reference_v<_Tp&&>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
+ noexcept(noexcept(ranges::rbegin(static_cast<const remove_reference_t<_Tp>&>(__t))))
+ -> decltype(ranges::rbegin(static_cast<const remove_reference_t<_Tp>&>(__t))) {
+ return ranges::rbegin(static_cast<const remove_reference_t<_Tp>&>(__t));
+ }
+
+ template <class _Tp>
+ requires is_rvalue_reference_v<_Tp&&>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
+ noexcept(noexcept(ranges::rbegin(static_cast<const _Tp&&>(__t))))
+ -> decltype(ranges::rbegin(static_cast<const _Tp&&>(__t))) {
+ return ranges::rbegin(static_cast<const _Tp&&>(__t));
+ }
+# endif // ^^^ _LIBCPP_STD_VER < 23
+};
+} // namespace __crbegin
+
+inline namespace __cpo {
+inline constexpr auto crbegin = __crbegin::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+// [range.access.crend]
+namespace ranges {
+namespace __crend {
+struct __fn {
+# if _LIBCPP_STD_VER >= 23
+ template <class _Rng>
+ using _UType = decltype(ranges::rend(ranges::__possibly_const_range(std::declval<_Rng>())));
+
+ template <__const_accessible_range _Rng>
+ auto operator()(_Rng&& __rng) noexcept(noexcept(const_sentinel<_UType<_Rng>>(
+ ranges::rend(ranges::__possibly_const_range(__rng))))) -> const_sentinel<_UType<_Rng>> {
+ return const_sentinel<_UType<_Rng>>(ranges::rend(ranges::__possibly_const_range(__rng)));
+ }
+# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 vvv
+ template <class _Tp>
+ requires is_lvalue_reference_v<_Tp&&>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
+ noexcept(noexcept(ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t))))
+ -> decltype(ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t))) {
+ return ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t));
+ }
+
+ template <class _Tp>
+ requires is_rvalue_reference_v<_Tp&&>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept(
+ noexcept(ranges::rend(static_cast<const _Tp&&>(__t)))) -> decltype(ranges::rend(static_cast<const _Tp&&>(__t))) {
+ return ranges::rend(static_cast<const _Tp&&>(__t));
+ }
+# endif // ^^^ _LIBCPP_STD_VER < 23
+};
+} // namespace __crend
+
+inline namespace __cpo {
+inline constexpr auto crend = __crend::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 20
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___RANGES_CONST_ACCESS_H
diff --git a/libcxx/include/__ranges/rbegin.h b/libcxx/include/__ranges/rbegin.h
index 12e739e1a2b85..a6f7e2d9f1aea 100644
--- a/libcxx/include/__ranges/rbegin.h
+++ b/libcxx/include/__ranges/rbegin.h
@@ -85,34 +85,6 @@ inline constexpr auto rbegin = __rbegin::__fn{};
} // namespace __cpo
} // namespace ranges
-// [range.access.crbegin]
-
-namespace ranges {
-namespace __crbegin {
-struct __fn {
- template <class _Tp>
- requires is_lvalue_reference_v<_Tp&&>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
- noexcept(noexcept(ranges::rbegin(static_cast<const remove_reference_t<_Tp>&>(__t))))
- -> decltype(ranges::rbegin(static_cast<const remove_reference_t<_Tp>&>(__t))) {
- return ranges::rbegin(static_cast<const remove_reference_t<_Tp>&>(__t));
- }
-
- template <class _Tp>
- requires is_rvalue_reference_v<_Tp&&>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
- noexcept(noexcept(ranges::rbegin(static_cast<const _Tp&&>(__t))))
- -> decltype(ranges::rbegin(static_cast<const _Tp&&>(__t))) {
- return ranges::rbegin(static_cast<const _Tp&&>(__t));
- }
-};
-} // namespace __crbegin
-
-inline namespace __cpo {
-inline constexpr auto crbegin = __crbegin::__fn{};
-} // namespace __cpo
-} // namespace ranges
-
#endif // _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__ranges/rend.h b/libcxx/include/__ranges/rend.h
index 02b4c5999a7eb..5171cc6cf3434 100644
--- a/libcxx/include/__ranges/rend.h
+++ b/libcxx/include/__ranges/rend.h
@@ -89,33 +89,6 @@ inline constexpr auto rend = __rend::__fn{};
} // namespace __cpo
} // namespace ranges
-// [range.access.crend]
-
-namespace ranges {
-namespace __crend {
-struct __fn {
- template <class _Tp>
- requires is_lvalue_reference_v<_Tp&&>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
- noexcept(noexcept(ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t))))
- -> decltype(ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t))) {
- return ranges::rend(static_cast<const remove_reference_t<_Tp>&>(__t));
- }
-
- template <class _Tp>
- requires is_rvalue_reference_v<_Tp&&>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept(
- noexcept(ranges::rend(static_cast<const _Tp&&>(__t)))) -> decltype(ranges::rend(static_cast<const _Tp&&>(__t))) {
- return ranges::rend(static_cast<const _Tp&&>(__t));
- }
-};
-} // namespace __crend
-
-inline namespace __cpo {
-inline constexpr auto crend = __crend::__fn{};
-} // namespace __cpo
-} // namespace ranges
-
#endif // _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
index fca75f0a19ed1..9a0c618f860cf 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -383,6 +383,31 @@ insert_iterator<Container> inserter(Container& x, typename Container::iterator i
template <class Container>
constexpr insert_iterator<Container> inserter(Container& x, ranges::iterator_t<Container> i); // since C++20
+template<indirectly_readable I>
+using iter_const_reference_t = see below; // since C++23
+template<input_iterator I>
+using const_iterator = see below; // since C++23
+template<semiregular S>
+using const_sentinel = see below; // since C++23
+
+template<input_iterator Iterator>
+class basic_const_iterator; // since C++23
+
+template<class T, common_with<T> U>
+ requires input_iterator<common_type_t<T, U>>
+struct common_type<basic_const_iterator<T>, U>; // since C++23
+template<class T, common_with<T> U>
+ requires input_iterator<common_type_t<T, U>>
+struct common_type<U, basic_const_iterator<T>>; // since C++23
+template<class T, common_with<T> U>
+ requires input_iterator<common_type_t<T, U>>
+struct common_type<basic_const_iterator<T>, basic_const_iterator<U>>; // since C++23
+
+template<input_iterator I>
+constexpr const_iterator<I> make_const_iterator(I it); // since C++23
+template<semiregular S>
+constexpr const_sentinel<S> make_const_sentinel(S s); // since C++23
+
template <class Iterator>
class move_iterator {
public:
@@ -726,6 +751,10 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
# include <__iterator/unreachable_sentinel.h>
#endif
+#if _LIBCPP_STD_VER >= 23
+# include <__iterator/const_iterator.h>
+#endif
+
#include <version>
// standard-mandated includes
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index fa35874265de6..7961862085023 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -39,6 +39,8 @@ namespace std::ranges {
using iterator_t = decltype(ranges::begin(declval<T&>()));
template<range R>
using sentinel_t = decltype(ranges::end(declval<R&>()));
+ template<range R>
+ using const_iterator_t = decltype(ranges::end(declval<R&>())); // since C++23
template<range R>
using range_difference_t = iter_difference_t<iterator_t<R>>;
template<sized_range R>
@@ -47,6 +49,8 @@ namespace std::ranges {
using range_value_t = iter_value_t<iterator_t<R>>;
template<range R>
using range_reference_t = iter_reference_t<iterator_t<R>>;
+ template<range R>
+ using range_const_reference_t = decltype(ranges::end(declval<R&>())); // since C++23
template<range R>
using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<R>>;
template <range R>
@@ -93,6 +97,9 @@ namespace std::ranges {
template<class T>
concept viewable_range = see below;
+ template<class T>
+ concept constant_range = see below;
+
// [range.adaptor.object], range adaptor objects
template<class D>
requires is_class_v<D> && same_as<D, remove_cv_t<D>>
@@ -387,6 +394,7 @@ namespace std {
# include <__ranges/all.h>
# include <__ranges/common_view.h>
# include <__ranges/concepts.h>
+# include <__ranges/const_access.h>
# include <__ranges/counted.h>
# include <__ranges/dangling.h>
# include <__ranges/data.h>
>From 3b3c56d282a8d797118e5ec0157447404eef8dfd Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Wed, 24 Jul 2024 10:33:46 +0200
Subject: [PATCH 02/16] [wip] start working on testing
---
libcxx/include/__iterator/const_iterator.h | 12 +
libcxx/include/__ranges/const_access.h | 12 +-
libcxx/include/module.modulemap | 2 +
libcxx/modules/std/iterator.inc | 15 +-
.../std/ranges/range.access/begin.pass.cpp | 2 +-
.../test/std/ranges/range.access/end.pass.cpp | 2 +-
.../std/ranges/range.access/rbegin.pass.cpp | 233 +++++++++++-------
.../std/ranges/range.access/rend.pass.cpp | 195 ++++++++++-----
8 files changed, 309 insertions(+), 164 deletions(-)
diff --git a/libcxx/include/__iterator/const_iterator.h b/libcxx/include/__iterator/const_iterator.h
index 7549a98fe3ecc..4ad37345cd887 100644
--- a/libcxx/include/__iterator/const_iterator.h
+++ b/libcxx/include/__iterator/const_iterator.h
@@ -12,13 +12,25 @@
#include <__compare/three_way_comparable.h>
#include <__concepts/common_with.h>
+#include <__concepts/convertible_to.h>
#include <__concepts/different_from.h>
+#include <__concepts/same_as.h>
+#include <__concepts/semiregular.h>
+#include <__concepts/totally_ordered.h>
#include <__iterator/concepts.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/iter_move.h>
#include <__iterator/iterator_traits.h>
+#include <__memory/addressof.h>
+#include <__memory/pointer_traits.h>
#include <__type_traits/common_reference.h>
#include <__type_traits/common_type.h>
+#include <__type_traits/conditional.h>
#include <__type_traits/integral_constant.h>
+#include <__type_traits/is_reference.h>
#include <__type_traits/is_specialization.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
diff --git a/libcxx/include/__ranges/const_access.h b/libcxx/include/__ranges/const_access.h
index 4bc14e0049b71..270bf7b2f1675 100644
--- a/libcxx/include/__ranges/const_access.h
+++ b/libcxx/include/__ranges/const_access.h
@@ -54,7 +54,8 @@ struct __fn {
using _UType = decltype(ranges::begin(ranges::__possibly_const_range(std::declval<_Rng>())));
template <__const_accessible_range _Rng>
- auto operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>(
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
+ operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>(
ranges::begin(ranges::__possibly_const_range(std::declval<_Rng>()))))) -> const_iterator<_UType<_Rng>> {
return const_iterator<_UType<_Rng>>(ranges::begin(ranges::__possibly_const_range(__rng)));
}
@@ -92,7 +93,8 @@ struct __fn {
using _UType = decltype(ranges::end(ranges::__possibly_const_range(std::declval<_Rng>())));
template <__const_accessible_range _Rng>
- auto operator()(_Rng&& __rng) noexcept(noexcept(const_sentinel<_UType<_Rng>>(
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
+ operator()(_Rng&& __rng) noexcept(noexcept(const_sentinel<_UType<_Rng>>(
ranges::end(ranges::__possibly_const_range(__rng))))) -> const_sentinel<_UType<_Rng>> {
return const_sentinel<_UType<_Rng>>(ranges::end(ranges::__possibly_const_range(__rng)));
}
@@ -129,7 +131,8 @@ struct __fn {
using _UType = decltype(ranges::rbegin(ranges::__possibly_const_range(std::declval<_Rng>())));
template <__const_accessible_range _Rng>
- auto operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>(
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
+ operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>(
ranges::rbegin(ranges::__possibly_const_range(__rng))))) -> const_iterator<_UType<_Rng>> {
return const_iterator<_UType<_Rng>>(ranges::rbegin(ranges::__possibly_const_range(__rng)));
}
@@ -167,7 +170,8 @@ struct __fn {
using _UType = decltype(ranges::rend(ranges::__possibly_const_range(std::declval<_Rng>())));
template <__const_accessible_range _Rng>
- auto operator()(_Rng&& __rng) noexcept(noexcept(const_sentinel<_UType<_Rng>>(
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
+ operator()(_Rng&& __rng) noexcept(noexcept(const_sentinel<_UType<_Rng>>(
ranges::rend(ranges::__possibly_const_range(__rng))))) -> const_sentinel<_UType<_Rng>> {
return const_sentinel<_UType<_Rng>>(ranges::rend(ranges::__possibly_const_range(__rng)));
}
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 13d0dce34d97e..9a690aa41ef4a 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1401,6 +1401,7 @@ module std_private_iterator_concepts [system] {
export std_private_type_traits_is_reference
export std_private_type_traits_remove_cvref
}
+module std_private_iterator_const_iterator [system] { header "__iterator/const_iterator.h" }
module std_private_iterator_counted_iterator [system] { header "__iterator/counted_iterator.h" }
module std_private_iterator_cpp17_iterator_concepts [system] { header "__iterator/cpp17_iterator_concepts.h" }
module std_private_iterator_data [system] { header "__iterator/data.h" }
@@ -1702,6 +1703,7 @@ module std_private_ranges_all [system] {
module std_private_ranges_as_rvalue_view [system] { header "__ranges/as_rvalue_view.h" }
module std_private_ranges_chunk_by_view [system] { header "__ranges/chunk_by_view.h" }
module std_private_ranges_common_view [system] { header "__ranges/common_view.h" }
+module std_private_ranges_const_access [system] { header "__iterator/const_access.h" }
module std_private_ranges_concepts [system] {
header "__ranges/concepts.h"
export std_private_iterator_concepts
diff --git a/libcxx/modules/std/iterator.inc b/libcxx/modules/std/iterator.inc
index 10c63d74e6e05..5278ceaf2785b 100644
--- a/libcxx/modules/std/iterator.inc
+++ b/libcxx/modules/std/iterator.inc
@@ -182,18 +182,21 @@ export namespace std {
using std::insert_iterator;
using std::inserter;
+#if _LIBCPP_STD_VER >= 23
// [const.iterators], constant iterators and sentinels
// [const.iterators.alias], alias templates
- // using std::const_iterator;
- // using std::const_sentinel;
- // using std::iter_const_reference_t;
+ using std::const_iterator;
+ using std::const_sentinel;
+ using std::iter_const_reference_t;
// [const.iterators.iterator], class template basic_const_iterator
- // using std::basic_const_iterator;
+ using std::basic_const_iterator;
- // using std::common_type;
+ using std::common_type;
- // using std::make_const_iterator;
+ using std::make_const_iterator;
+ using std::make_const_sentinel;
+#endif
// [move.iterators], move iterators and sentinels
using std::move_iterator;
diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp
index 5ca3d59abb140..077d17c085b99 100644
--- a/libcxx/test/std/ranges/range.access/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// std::ranges::begin
-// std::ranges::cbegin
+// std::ranges::cbegin // until C++23
#include <ranges>
diff --git a/libcxx/test/std/ranges/range.access/end.pass.cpp b/libcxx/test/std/ranges/range.access/end.pass.cpp
index 3e465b357e985..19534d0341857 100644
--- a/libcxx/test/std/ranges/range.access/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/end.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// std::ranges::end
-// std::ranges::cend
+// std::ranges::cend // until C++23
#include <ranges>
diff --git a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
index 3997f38efd029..d34ee9f2da0a7 100644
--- a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// std::ranges::rbegin
-// std::ranges::crbegin
+// std::ranges::crbegin // until C++23
#include <ranges>
@@ -19,7 +19,9 @@
#include "test_iterators.h"
using RangeRBeginT = decltype(std::ranges::rbegin);
+#if _LIBCPP_STD_VER <= 23
using RangeCRBeginT = decltype(std::ranges::crbegin);
+#endif // _LIBCPP_STD_VER <= 23
static int globalBuff[8];
@@ -27,34 +29,42 @@ static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeRBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeRBeginT, int (&)[]>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCRBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&)[]>);
+#endif // _LIBCPP_STD_VER <= 23
struct Incomplete;
static_assert(!std::is_invocable_v<RangeRBeginT, Incomplete(&&)[]>);
-static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete(&&)[]>);
-static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[]>);
-static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[]>);
-
+static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeRBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete(&&)[10]>);
+
+#if _LIBCPP_STD_VER <= 23
+static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[10]>);
+#endif // _LIBCPP_STD_VER <= 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[]>);
+#if _LIBCPP_STD_VER <= 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[]>);
+#endif // _LIBCPP_STD_VER <= 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[10]>);
+#if _LIBCPP_STD_VER <= 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[10]>);
+#endif // _LIBCPP_STD_VER <= 23
struct RBeginMember {
int x;
@@ -66,45 +76,48 @@ static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember &>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember &&>);
static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember const&>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember const&&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember &>);
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember &&>);
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember const&>);
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember const&&>);
+#endif // _LIBCPP_STD_VER <= 23
constexpr bool testReturnTypes() {
- {
- int *x[2];
- ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int**>);
- ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<int* const*>);
- }
- {
- int x[2][2];
- ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int(*)[2]>);
- ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<const int(*)[2]>);
- }
- {
- struct Different {
- char*& rbegin();
- short*& rbegin() const;
- } x;
- ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), char*);
- ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), short*);
- }
+ int* a[2];
+ int b[2][2];
+ struct Different {
+ char*& rbegin();
+ short*& rbegin() const;
+ } c;
+
+ ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int**>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int(*)[2]>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), char*);
+
+#if _LIBCPP_STD_VER <= 23
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<int* const*>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<const int(*)[2]>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), short*);
+#endif // _LIBCPP_STD_VER <= 23
+
return true;
}
constexpr bool testArray() {
int a[2];
- assert(std::ranges::rbegin(a).base() == a + 2);
- assert(std::ranges::crbegin(a).base() == a + 2);
-
int b[2][2];
- assert(std::ranges::rbegin(b).base() == b + 2);
- assert(std::ranges::crbegin(b).base() == b + 2);
-
RBeginMember c[2];
+
+ assert(std::ranges::rbegin(a).base() == a + 2);
+ assert(std::ranges::rbegin(b).base() == b + 2);
assert(std::ranges::rbegin(c).base() == c + 2);
+
+#if _LIBCPP_STD_VER <= 23
+ assert(std::ranges::crbegin(a).base() == a + 2);
+ assert(std::ranges::crbegin(b).base() == b + 2);
assert(std::ranges::crbegin(c).base() == c + 2);
+#endif // _LIBCPP_STD_VER <= 23
return true;
}
@@ -131,8 +144,10 @@ struct NonConstRBeginMember {
};
static_assert( std::is_invocable_v<RangeRBeginT, NonConstRBeginMember &>);
static_assert(!std::is_invocable_v<RangeRBeginT, NonConstRBeginMember const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember &>);
static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct EnabledBorrowingRBeginMember {
constexpr int *rbegin() const { return globalBuff; }
@@ -154,28 +169,28 @@ struct EmptyPtrRBeginMember {
constexpr bool testRBeginMember() {
RBeginMember a;
+ NonConstRBeginMember b;
+ EnabledBorrowingRBeginMember c;
+ RBeginMemberFunction d;
+ EmptyPtrRBeginMember e;
+
assert(std::ranges::rbegin(a) == &a.x);
- assert(std::ranges::crbegin(a) == &a.x);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember&&>);
- static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember&&>);
-
- NonConstRBeginMember b;
assert(std::ranges::rbegin(b) == &b.x);
- static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember&>);
-
- EnabledBorrowingRBeginMember c;
assert(std::ranges::rbegin(c) == globalBuff);
- assert(std::ranges::crbegin(c) == globalBuff);
assert(std::ranges::rbegin(std::move(c)) == globalBuff);
- assert(std::ranges::crbegin(std::move(c)) == globalBuff);
-
- RBeginMemberFunction d;
assert(std::ranges::rbegin(d) == &d.x);
- assert(std::ranges::crbegin(d) == &d.x);
-
- EmptyPtrRBeginMember e;
assert(std::ranges::rbegin(e) == &e.x);
+
+#if _LIBCPP_STD_VER <= 23
+ assert(std::ranges::crbegin(a) == &a.x);
+ static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember&&>);
+ static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember&>);
+ assert(std::ranges::crbegin(c) == globalBuff);
+ assert(std::ranges::crbegin(std::move(c)) == globalBuff);
+ assert(std::ranges::crbegin(d) == &d.x);
assert(std::ranges::crbegin(e) == &e.x);
+#endif // _LIBCPP_STD_VER <= 23
return true;
}
@@ -189,8 +204,10 @@ static_assert( std::is_invocable_v<RangeRBeginT, RBeginFunction const&>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunction &&>);
static_assert(
std::is_invocable_v<RangeRBeginT, RBeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction const&>);
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction &>);
+#endif // _LIBCPP_STD_VER <= 23
struct RBeginFunctionReturnsInt {
friend int rbegin(RBeginFunctionReturnsInt const&);
@@ -214,10 +231,12 @@ struct RBeginFunctionReturnsPtrConvertible {
};
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsPtrConvertible const&>);
+#if _LIBCPP_STD_VER <= 23
struct RBeginFunctionByValue {
friend constexpr int *rbegin(RBeginFunctionByValue) { return globalBuff + 1; }
};
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginFunctionByValue>);
+#endif // _LIBCPP_STD_VER <= 23
struct RBeginFunctionEnabledBorrowing {
friend constexpr int *rbegin(RBeginFunctionEnabledBorrowing) { return globalBuff + 2; }
@@ -247,45 +266,44 @@ struct RBeginFunctionWithPrivateBeginMember {
constexpr bool testRBeginFunction() {
RBeginFunction a{};
const RBeginFunction aa{};
- assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::crbegin(a) == &a.x);
- assert(std::ranges::rbegin(aa) == &aa.x);
- assert(std::ranges::crbegin(aa) == &aa.x);
-
RBeginFunctionByValue b{};
const RBeginFunctionByValue bb{};
- assert(std::ranges::rbegin(b) == globalBuff + 1);
- assert(std::ranges::crbegin(b) == globalBuff + 1);
- assert(std::ranges::rbegin(bb) == globalBuff + 1);
- assert(std::ranges::crbegin(bb) == globalBuff + 1);
-
RBeginFunctionEnabledBorrowing c{};
const RBeginFunctionEnabledBorrowing cc{};
- assert(std::ranges::rbegin(std::move(c)) == globalBuff + 2);
- assert(std::ranges::crbegin(std::move(c)) == globalBuff + 2);
- assert(std::ranges::rbegin(std::move(cc)) == globalBuff + 2);
- assert(std::ranges::crbegin(std::move(cc)) == globalBuff + 2);
-
RBeginFunctionReturnsEmptyPtr d{};
const RBeginFunctionReturnsEmptyPtr dd{};
- assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::crbegin(d) == &d.x);
- assert(std::ranges::rbegin(dd) == &dd.x);
- assert(std::ranges::crbegin(dd) == &dd.x);
-
RBeginFunctionWithDataMember e{};
const RBeginFunctionWithDataMember ee{};
+ RBeginFunctionWithPrivateBeginMember f{};
+ const RBeginFunctionWithPrivateBeginMember ff{};
+
+ assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::rbegin(aa) == &aa.x);
+ assert(std::ranges::rbegin(b) == globalBuff + 1);
+ assert(std::ranges::rbegin(bb) == globalBuff + 1);
+ assert(std::ranges::rbegin(std::move(c)) == globalBuff + 2);
+ assert(std::ranges::rbegin(std::move(cc)) == globalBuff + 2);
+ assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::rbegin(dd) == &dd.x);
assert(std::ranges::rbegin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::rbegin(ee) == &ee.x);
+ assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::rbegin(ff) == &ff.y);
+
+#if _LIBCPP_STD_VER <= 23
+ assert(std::ranges::crbegin(a) == &a.x);
+ assert(std::ranges::crbegin(aa) == &aa.x);
+ assert(std::ranges::crbegin(b) == globalBuff + 1);
+ assert(std::ranges::crbegin(bb) == globalBuff + 1);
+ assert(std::ranges::crbegin(std::move(c)) == globalBuff + 2);
+ assert(std::ranges::crbegin(std::move(cc)) == globalBuff + 2);
+ assert(std::ranges::crbegin(d) == &d.x);
+ assert(std::ranges::crbegin(dd) == &dd.x);
assert(std::ranges::crbegin(e) == &e.x);
assert(std::ranges::crbegin(ee) == &ee.x);
-
- RBeginFunctionWithPrivateBeginMember f{};
- const RBeginFunctionWithPrivateBeginMember ff{};
- assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crbegin(f) == &f.y);
- assert(std::ranges::rbegin(ff) == &ff.y);
assert(std::ranges::crbegin(ff) == &ff.y);
+#endif // _LIBCPP_STD_VER <= 23
return true;
}
@@ -301,7 +319,9 @@ struct MemberBeginEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginEnd const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginEnd {
int b, e;
@@ -319,7 +339,9 @@ struct FunctionBeginEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginEnd const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberBeginFunctionEnd {
int b, e;
@@ -335,7 +357,9 @@ struct MemberBeginFunctionEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginFunctionEnd const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginMemberEnd {
int b, e;
@@ -351,59 +375,77 @@ struct FunctionBeginMemberEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginMemberEnd const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberBeginEndDifferentTypes {
bidirectional_iterator<int*> begin();
bidirectional_iterator<const int*> end();
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndDifferentTypes&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndDifferentTypes&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginEndDifferentTypes {
friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);
friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndDifferentTypes&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndDifferentTypes&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberBeginEndForwardIterators {
forward_iterator<int*> begin();
forward_iterator<int*> end();
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndForwardIterators&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndForwardIterators&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginEndForwardIterators {
friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);
friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndForwardIterators&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndForwardIterators&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberBeginOnly {
bidirectional_iterator<int*> begin() const;
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginOnly&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginOnly&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginOnly {
friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginOnly&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginOnly&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberEndOnly {
bidirectional_iterator<int*> end() const;
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberEndOnly&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberEndOnly&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionEndOnly {
friend bidirectional_iterator<int*> end(FunctionEndOnly&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionEndOnly&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionEndOnly&>);
+#endif // _LIBCPP_STD_VER <= 23
// Make sure there is no clash between the following cases:
// - the case that handles classes defining member `rbegin` and `rend` functions;
@@ -414,93 +456,112 @@ struct MemberBeginAndRBegin {
int* rbegin() const;
int* rend() const;
};
-static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginAndRBegin&>);
-static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginAndRBegin&>);
+static_assert(std::is_invocable_v<RangeRBeginT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeRBeginT, MemberBeginAndRBegin&>, int*>);
+#if _LIBCPP_STD_VER <= 23
+static_assert(std::is_invocable_v<RangeCRBeginT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeCRBeginT, MemberBeginAndRBegin&>, int*>);
+#endif // _LIBCPP_STD_VER <= 23
constexpr bool testBeginEnd() {
MemberBeginEnd a{};
const MemberBeginEnd aa{};
- assert(base(std::ranges::rbegin(a).base()) == &a.e);
- assert(base(std::ranges::crbegin(a).base()) == &a.ce);
- assert(base(std::ranges::rbegin(aa).base()) == &aa.ce);
- assert(base(std::ranges::crbegin(aa).base()) == &aa.ce);
-
FunctionBeginEnd b{};
const FunctionBeginEnd bb{};
- assert(base(std::ranges::rbegin(b).base()) == &b.e);
- assert(base(std::ranges::crbegin(b).base()) == &b.ce);
- assert(base(std::ranges::rbegin(bb).base()) == &bb.ce);
- assert(base(std::ranges::crbegin(bb).base()) == &bb.ce);
-
MemberBeginFunctionEnd c{};
const MemberBeginFunctionEnd cc{};
- assert(base(std::ranges::rbegin(c).base()) == &c.e);
- assert(base(std::ranges::crbegin(c).base()) == &c.ce);
- assert(base(std::ranges::rbegin(cc).base()) == &cc.ce);
- assert(base(std::ranges::crbegin(cc).base()) == &cc.ce);
-
FunctionBeginMemberEnd d{};
const FunctionBeginMemberEnd dd{};
+
+ assert(base(std::ranges::rbegin(a).base()) == &a.e);
+ assert(base(std::ranges::rbegin(aa).base()) == &aa.ce);
+ assert(base(std::ranges::rbegin(b).base()) == &b.e);
+ assert(base(std::ranges::rbegin(bb).base()) == &bb.ce);
+ assert(base(std::ranges::rbegin(c).base()) == &c.e);
+ assert(base(std::ranges::rbegin(cc).base()) == &cc.ce);
assert(base(std::ranges::rbegin(d).base()) == &d.e);
- assert(base(std::ranges::crbegin(d).base()) == &d.ce);
assert(base(std::ranges::rbegin(dd).base()) == &dd.ce);
+
+#if _LIBCPP_STD_VER <= 23
+ assert(base(std::ranges::crbegin(a).base()) == &a.ce);
+ assert(base(std::ranges::crbegin(aa).base()) == &aa.ce);
+ assert(base(std::ranges::crbegin(b).base()) == &b.ce);
+ assert(base(std::ranges::crbegin(bb).base()) == &bb.ce);
+ assert(base(std::ranges::crbegin(c).base()) == &c.ce);
+ assert(base(std::ranges::crbegin(cc).base()) == &cc.ce);
+ assert(base(std::ranges::crbegin(d).base()) == &d.ce);
assert(base(std::ranges::crbegin(dd).base()) == &dd.ce);
+#endif // _LIBCPP_STD_VER <= 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::rbegin(std::declval<int (&)[10]>()));
+#if _LIBCPP_STD_VER <= 23
ASSERT_NOEXCEPT(std::ranges::crbegin(std::declval<int (&)[10]>()));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowMemberRBegin {
ThrowingIterator<int> rbegin() const noexcept; // auto(t.rbegin()) doesn't throw
} ntmb;
static_assert(noexcept(std::ranges::rbegin(ntmb)));
+#if _LIBCPP_STD_VER <= 23
static_assert(noexcept(std::ranges::crbegin(ntmb)));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowADLRBegin {
friend ThrowingIterator<int> rbegin(NoThrowADLRBegin&) noexcept; // auto(rbegin(t)) doesn't throw
friend ThrowingIterator<int> rbegin(const NoThrowADLRBegin&) noexcept;
} ntab;
static_assert(noexcept(std::ranges::rbegin(ntab)));
+#if _LIBCPP_STD_VER <= 23
static_assert(noexcept(std::ranges::crbegin(ntab)));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowMemberRBeginReturnsRef {
ThrowingIterator<int>& rbegin() const noexcept; // auto(t.rbegin()) may throw
} ntmbrr;
static_assert(!noexcept(std::ranges::rbegin(ntmbrr)));
+#if _LIBCPP_STD_VER <= 23
static_assert(!noexcept(std::ranges::crbegin(ntmbrr)));
+#endif // _LIBCPP_STD_VER <= 23
struct RBeginReturnsArrayRef {
auto rbegin() const noexcept -> int(&)[10];
} brar;
static_assert(noexcept(std::ranges::rbegin(brar)));
+#if _LIBCPP_STD_VER <= 23
static_assert(noexcept(std::ranges::crbegin(brar)));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowBeginThrowingEnd {
int* begin() const noexcept;
int* end() const;
} ntbte;
static_assert(!noexcept(std::ranges::rbegin(ntbte)));
+#if _LIBCPP_STD_VER <= 23
static_assert(!noexcept(std::ranges::crbegin(ntbte)));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowEndThrowingBegin {
int* begin() const;
int* end() const noexcept;
} ntetb;
static_assert(noexcept(std::ranges::rbegin(ntetb)));
+#if _LIBCPP_STD_VER <= 23
static_assert(noexcept(std::ranges::crbegin(ntetb)));
+#endif // _LIBCPP_STD_VER <= 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*&>);
+#endif // _LIBCPP_STD_VER <= 23
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/rend.pass.cpp b/libcxx/test/std/ranges/range.access/rend.pass.cpp
index f5f59edf19393..55c2e084d25c3 100644
--- a/libcxx/test/std/ranges/range.access/rend.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rend.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// std::ranges::rend
-// std::ranges::crend
+// std::ranges::crend // before C++23
#include <ranges>
@@ -19,7 +19,9 @@
#include "test_iterators.h"
using RangeREndT = decltype(std::ranges::rend);
+#if _LIBCPP_STD_VER <= 23
using RangeCREndT = decltype(std::ranges::crend);
+#endif // _LIBCPP_STD_VER <= 23
static int globalBuff[8];
@@ -27,16 +29,20 @@ static_assert(!std::is_invocable_v<RangeREndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeREndT, int (&)[10]>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCREndT, int (&)[10]>);
+#endif // _LIBCPP_STD_VER <= 23
struct Incomplete;
static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[42]>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[42]>);
+#endif // _LIBCPP_STD_VER <= 23
struct REndMember {
int x;
@@ -49,22 +55,28 @@ static_assert( std::is_invocable_v<RangeREndT, REndMember&>);
static_assert(!std::is_invocable_v<RangeREndT, REndMember &&>);
static_assert( std::is_invocable_v<RangeREndT, REndMember const&>);
static_assert(!std::is_invocable_v<RangeREndT, REndMember const&&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCREndT, REndMember &>);
static_assert(!std::is_invocable_v<RangeCREndT, REndMember &&>);
static_assert( std::is_invocable_v<RangeCREndT, REndMember const&>);
static_assert(!std::is_invocable_v<RangeCREndT, REndMember const&&>);
+#endif // _LIBCPP_STD_VER <= 23
constexpr bool testReturnTypes() {
{
int *x[2];
ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator<int**>);
+#if _LIBCPP_STD_VER <= 23
ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator<int* const*>);
+#endif // _LIBCPP_STD_VER <= 23
}
{
int x[2][2];
ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator<int(*)[2]>);
+#if _LIBCPP_STD_VER <= 23
ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator<const int(*)[2]>);
+#endif // _LIBCPP_STD_VER <= 23
}
{
@@ -75,7 +87,9 @@ constexpr bool testReturnTypes() {
sentinel_wrapper<short*>& rend() const;
} x;
ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), sentinel_wrapper<char*>);
+#if _LIBCPP_STD_VER <= 23
ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), sentinel_wrapper<short*>);
+#endif // _LIBCPP_STD_VER <= 23
}
return true;
@@ -83,17 +97,19 @@ constexpr bool testReturnTypes() {
constexpr bool testArray() {
int a[2];
- assert(std::ranges::rend(a).base() == a);
- assert(std::ranges::crend(a).base() == a);
-
int b[2][2];
- assert(std::ranges::rend(b).base() == b);
- assert(std::ranges::crend(b).base() == b);
-
REndMember c[2];
+
+ assert(std::ranges::rend(a).base() == a);
+ assert(std::ranges::rend(b).base() == b);
assert(std::ranges::rend(c).base() == c);
- assert(std::ranges::crend(c).base() == c);
+#if _LIBCPP_STD_VER <= 23
+ assert(std::ranges::crend(b).base() == b);
+ assert(std::ranges::crend(a).base() == a);
+ assert(std::ranges::crend(c).base() == c);
+#endif // _LIBCPP_STD_VER <= 23 \
+ //
return true;
}
@@ -130,8 +146,10 @@ struct NonConstREndMember {
};
static_assert( std::is_invocable_v<RangeREndT, NonConstREndMember &>);
static_assert(!std::is_invocable_v<RangeREndT, NonConstREndMember const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember &>);
static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct EnabledBorrowingREndMember {
constexpr int* rbegin() const { return nullptr; }
@@ -163,24 +181,24 @@ struct EmptyPtrREndMember {
constexpr bool testREndMember() {
REndMember a;
- assert(std::ranges::rend(a) == &a.x);
- assert(std::ranges::crend(a) == &a.x);
-
NonConstREndMember b;
- assert(std::ranges::rend(b) == &b.x);
- static_assert(!std::is_invocable_v<RangeCREndT, decltype((b))>);
-
EnabledBorrowingREndMember c;
- assert(std::ranges::rend(std::move(c)) == &globalBuff[0]);
- assert(std::ranges::crend(std::move(c)) == &globalBuff[0]);
-
REndMemberFunction d;
- assert(std::ranges::rend(d) == &d.x);
- assert(std::ranges::crend(d) == &d.x);
-
EmptyPtrREndMember e;
+
+ assert(std::ranges::rend(a) == &a.x);
+ assert(std::ranges::rend(b) == &b.x);
+ assert(std::ranges::rend(std::move(c)) == &globalBuff[0]);
+ assert(std::ranges::rend(d) == &d.x);
assert(std::ranges::rend(e) == &e.x);
+
+#if _LIBCPP_STD_VER <= 23
+ assert(std::ranges::crend(a) == &a.x);
+ static_assert(!std::is_invocable_v<RangeCREndT, decltype((b))>);
+ assert(std::ranges::crend(std::move(c)) == &globalBuff[0]);
+ assert(std::ranges::crend(d) == &d.x);
assert(std::ranges::crend(e) == &e.x);
+#endif // _LIBCPP_STD_VER <= 23
return true;
}
@@ -197,8 +215,10 @@ static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
static_assert( std::is_invocable_v<RangeREndT, REndFunction const&>);
static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
static_assert(std::is_invocable_v<RangeREndT, REndFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCREndT, REndFunction const&>);
static_assert( std::is_invocable_v<RangeCREndT, REndFunction &>);
+#endif // _LIBCPP_STD_VER <= 23
struct REndFunctionReturnsInt {
friend constexpr int rbegin(REndFunctionReturnsInt const&);
@@ -233,7 +253,9 @@ struct REndFunctionByValue {
friend constexpr int* rbegin(REndFunctionByValue) { return nullptr; }
friend constexpr int* rend(REndFunctionByValue) { return &globalBuff[1]; }
};
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, REndFunctionByValue>);
+#endif // _LIBCPP_STD_VER <= 23
struct REndFunctionEnabledBorrowing {
friend constexpr int* rbegin(REndFunctionEnabledBorrowing) { return nullptr; }
@@ -269,47 +291,45 @@ struct RBeginMemberEndFunction {
constexpr bool testREndFunction() {
const REndFunction a{};
- assert(std::ranges::rend(a) == &a.x);
- assert(std::ranges::crend(a) == &a.x);
REndFunction aa{};
- assert(std::ranges::rend(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::crend(aa) == &aa.x);
-
REndFunctionByValue b;
- assert(std::ranges::rend(b) == &globalBuff[1]);
- assert(std::ranges::crend(b) == &globalBuff[1]);
-
REndFunctionEnabledBorrowing c;
- assert(std::ranges::rend(std::move(c)) == &globalBuff[2]);
- assert(std::ranges::crend(std::move(c)) == &globalBuff[2]);
-
const REndFunctionReturnsEmptyPtr d{};
- assert(std::ranges::rend(d) == &d.x);
- assert(std::ranges::crend(d) == &d.x);
REndFunctionReturnsEmptyPtr dd{};
- assert(std::ranges::rend(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::crend(dd) == &dd.x);
-
const REndFunctionWithDataMember e{};
- assert(std::ranges::rend(e) == &e.x);
- assert(std::ranges::crend(e) == &e.x);
REndFunctionWithDataMember ee{};
- assert(std::ranges::rend(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::crend(ee) == &ee.x);
-
const REndFunctionWithPrivateEndMember f{};
- assert(std::ranges::rend(f) == &f.y);
- assert(std::ranges::crend(f) == &f.y);
REndFunctionWithPrivateEndMember ff{};
- assert(std::ranges::rend(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::crend(ff) == &ff.y);
-
const RBeginMemberEndFunction g{};
- assert(std::ranges::rend(g) == &g.x);
- assert(std::ranges::crend(g) == &g.x);
RBeginMemberEndFunction gg{};
+
+ assert(std::ranges::rend(a) == &a.x);
+ assert(std::ranges::rend(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::rend(b) == &globalBuff[1]);
+ assert(std::ranges::rend(std::move(c)) == &globalBuff[2]);
+ assert(std::ranges::rend(d) == &d.x);
+ assert(std::ranges::rend(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::rend(e) == &e.x);
+ assert(std::ranges::rend(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::rend(f) == &f.y);
+ assert(std::ranges::rend(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::rend(g) == &g.x);
assert(std::ranges::rend(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+
+#if _LIBCPP_STD_VER <= 23
+ assert(std::ranges::crend(a) == &a.x);
+ assert(std::ranges::crend(aa) == &aa.x);
+ assert(std::ranges::crend(b) == &globalBuff[1]);
+ assert(std::ranges::crend(std::move(c)) == &globalBuff[2]);
+ assert(std::ranges::crend(d) == &d.x);
+ assert(std::ranges::crend(dd) == &dd.x);
+ assert(std::ranges::crend(e) == &e.x);
+ assert(std::ranges::crend(ee) == &ee.x);
+ assert(std::ranges::crend(f) == &f.y);
+ assert(std::ranges::crend(ff) == &ff.y);
+ assert(std::ranges::crend(g) == &g.x);
assert(std::ranges::crend(gg) == &gg.x);
+#endif // _LIBCPP_STD_VER <= 23
return true;
}
@@ -325,7 +345,9 @@ struct MemberBeginEnd {
};
static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd&>);
static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCREndT, MemberBeginEnd const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginEnd {
int b, e;
@@ -343,7 +365,9 @@ struct FunctionBeginEnd {
};
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd&>);
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginEnd const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberBeginFunctionEnd {
int b, e;
@@ -359,7 +383,9 @@ struct MemberBeginFunctionEnd {
};
static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd&>);
static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCREndT, MemberBeginFunctionEnd const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginMemberEnd {
int b, e;
@@ -375,59 +401,77 @@ struct FunctionBeginMemberEnd {
};
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd&>);
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd const&>);
+#if _LIBCPP_STD_VER <= 23
static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginMemberEnd const&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberBeginEndDifferentTypes {
bidirectional_iterator<int*> begin();
bidirectional_iterator<const int*> end();
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndDifferentTypes&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndDifferentTypes&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginEndDifferentTypes {
friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);
friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndDifferentTypes&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndDifferentTypes&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberBeginEndForwardIterators {
forward_iterator<int*> begin();
forward_iterator<int*> end();
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndForwardIterators&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndForwardIterators&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginEndForwardIterators {
friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);
friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndForwardIterators&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndForwardIterators&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberBeginOnly {
bidirectional_iterator<int*> begin() const;
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginOnly&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginOnly&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionBeginOnly {
friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginOnly&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginOnly&>);
+#endif // _LIBCPP_STD_VER <= 23
struct MemberEndOnly {
bidirectional_iterator<int*> end() const;
};
static_assert(!std::is_invocable_v<RangeREndT, MemberEndOnly&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberEndOnly&>);
+#endif // _LIBCPP_STD_VER <= 23
struct FunctionEndOnly {
friend bidirectional_iterator<int*> end(FunctionEndOnly&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionEndOnly&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionEndOnly&>);
+#endif // _LIBCPP_STD_VER <= 23
// Make sure there is no clash between the following cases:
// - the case that handles classes defining member `rbegin` and `rend` functions;
@@ -438,53 +482,60 @@ struct MemberBeginAndRBegin {
int* rbegin() const;
int* rend() const;
};
-static_assert( std::is_invocable_v<RangeREndT, MemberBeginAndRBegin&>);
-static_assert( std::is_invocable_v<RangeCREndT, MemberBeginAndRBegin&>);
+static_assert(std::is_invocable_v<RangeREndT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeREndT, MemberBeginAndRBegin&>, int*>);
+#if _LIBCPP_STD_VER <= 23
+static_assert(std::is_invocable_v<RangeCREndT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeCREndT, MemberBeginAndRBegin&>, int*>);
+#endif // _LIBCPP_STD_VER <= 23
constexpr bool testBeginEnd() {
MemberBeginEnd a{};
const MemberBeginEnd aa{};
- assert(base(std::ranges::rend(a).base()) == &a.b);
- assert(base(std::ranges::crend(a).base()) == &a.cb);
- assert(base(std::ranges::rend(aa).base()) == &aa.cb);
- assert(base(std::ranges::crend(aa).base()) == &aa.cb);
-
FunctionBeginEnd b{};
const FunctionBeginEnd bb{};
- assert(base(std::ranges::rend(b).base()) == &b.b);
- assert(base(std::ranges::crend(b).base()) == &b.cb);
- assert(base(std::ranges::rend(bb).base()) == &bb.cb);
- assert(base(std::ranges::crend(bb).base()) == &bb.cb);
-
MemberBeginFunctionEnd c{};
const MemberBeginFunctionEnd cc{};
- assert(base(std::ranges::rend(c).base()) == &c.b);
- assert(base(std::ranges::crend(c).base()) == &c.cb);
- assert(base(std::ranges::rend(cc).base()) == &cc.cb);
- assert(base(std::ranges::crend(cc).base()) == &cc.cb);
-
FunctionBeginMemberEnd d{};
const FunctionBeginMemberEnd dd{};
+
+ assert(base(std::ranges::rend(a).base()) == &a.b);
+ assert(base(std::ranges::rend(aa).base()) == &aa.cb);
+ assert(base(std::ranges::rend(b).base()) == &b.b);
+ assert(base(std::ranges::rend(bb).base()) == &bb.cb);
+ assert(base(std::ranges::rend(c).base()) == &c.b);
+ assert(base(std::ranges::rend(cc).base()) == &cc.cb);
assert(base(std::ranges::rend(d).base()) == &d.b);
- assert(base(std::ranges::crend(d).base()) == &d.cb);
assert(base(std::ranges::rend(dd).base()) == &dd.cb);
+
+#if _LIBCPP_STD_VER <= 23
+ assert(base(std::ranges::crend(a).base()) == &a.cb);
+ assert(base(std::ranges::crend(aa).base()) == &aa.cb);
+ assert(base(std::ranges::crend(b).base()) == &b.cb);
+ assert(base(std::ranges::crend(bb).base()) == &bb.cb);
+ assert(base(std::ranges::crend(c).base()) == &c.cb);
+ assert(base(std::ranges::crend(cc).base()) == &cc.cb);
+ assert(base(std::ranges::crend(d).base()) == &d.cb);
assert(base(std::ranges::crend(dd).base()) == &dd.cb);
+#endif // _LIBCPP_STD_VER <= 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::rend(std::declval<int (&)[10]>()));
+#if _LIBCPP_STD_VER <= 23
ASSERT_NOEXCEPT(std::ranges::crend(std::declval<int (&)[10]>()));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowMemberREnd {
ThrowingIterator<int> rbegin() const;
ThrowingIterator<int> rend() const noexcept; // auto(t.rend()) doesn't throw
} ntmre;
static_assert(noexcept(std::ranges::rend(ntmre)));
+#if _LIBCPP_STD_VER <= 23
static_assert(noexcept(std::ranges::crend(ntmre)));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowADLREnd {
ThrowingIterator<int> rbegin() const;
@@ -492,43 +543,55 @@ struct NoThrowADLREnd {
friend ThrowingIterator<int> rend(const NoThrowADLREnd&) noexcept;
} ntare;
static_assert(noexcept(std::ranges::rend(ntare)));
+#if _LIBCPP_STD_VER <= 23
static_assert(noexcept(std::ranges::crend(ntare)));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowMemberREndReturnsRef {
ThrowingIterator<int> rbegin() const;
ThrowingIterator<int>& rend() const noexcept; // auto(t.rend()) may throw
} ntmrerr;
static_assert(!noexcept(std::ranges::rend(ntmrerr)));
+#if _LIBCPP_STD_VER <= 23
static_assert(!noexcept(std::ranges::crend(ntmrerr)));
+#endif // _LIBCPP_STD_VER <= 23
struct REndReturnsArrayRef {
auto rbegin() const noexcept -> int(&)[10];
auto rend() const noexcept -> int(&)[10];
} rerar;
static_assert(noexcept(std::ranges::rend(rerar)));
+#if _LIBCPP_STD_VER <= 23
static_assert(noexcept(std::ranges::crend(rerar)));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowBeginThrowingEnd {
int* begin() const noexcept;
int* end() const;
} ntbte;
static_assert(noexcept(std::ranges::rend(ntbte)));
+#if _LIBCPP_STD_VER <= 23
static_assert(noexcept(std::ranges::crend(ntbte)));
+#endif // _LIBCPP_STD_VER <= 23
struct NoThrowEndThrowingBegin {
int* begin() const;
int* end() const noexcept;
} ntetb;
static_assert(!noexcept(std::ranges::rend(ntetb)));
+#if _LIBCPP_STD_VER <= 23
static_assert(!noexcept(std::ranges::crend(ntetb)));
+#endif // _LIBCPP_STD_VER <= 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*&>);
+#if _LIBCPP_STD_VER <= 23
static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*&>);
+#endif // _LIBCPP_STD_VER <= 23
int main(int, char**) {
static_assert(testReturnTypes());
>From 9fae0d6d940986bfecdf0edd0c6ba1ce79cbbc8c Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Wed, 24 Jul 2024 18:46:33 +0200
Subject: [PATCH 03/16] fix all the failing tests
still need to add tests of my own, but now ready to be reviewed at least
---
libcxx/include/__ranges/const_access.h | 2 +
libcxx/include/module.modulemap | 2 +-
.../std/ranges/range.access/begin.pass.cpp | 158 +++++++++-------
.../test/std/ranges/range.access/end.pass.cpp | 157 +++++++++-------
.../std/ranges/range.access/rbegin.pass.cpp | 152 +++++++--------
.../std/ranges/range.access/rend.pass.cpp | 174 +++++++++---------
6 files changed, 347 insertions(+), 298 deletions(-)
diff --git a/libcxx/include/__ranges/const_access.h b/libcxx/include/__ranges/const_access.h
index 270bf7b2f1675..df2811839bc46 100644
--- a/libcxx/include/__ranges/const_access.h
+++ b/libcxx/include/__ranges/const_access.h
@@ -17,7 +17,9 @@
#include <__ranges/rbegin.h>
#include <__ranges/rend.h>
#include <__type_traits/is_reference.h>
+#include <__type_traits/remove_cv.h>
#include <__type_traits/remove_reference.h>
+#include <__utility/declval.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 9a690aa41ef4a..852c5b8c9fab5 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1703,7 +1703,7 @@ module std_private_ranges_all [system] {
module std_private_ranges_as_rvalue_view [system] { header "__ranges/as_rvalue_view.h" }
module std_private_ranges_chunk_by_view [system] { header "__ranges/chunk_by_view.h" }
module std_private_ranges_common_view [system] { header "__ranges/common_view.h" }
-module std_private_ranges_const_access [system] { header "__iterator/const_access.h" }
+module std_private_ranges_const_access [system] { header "__ranges/const_access.h" }
module std_private_ranges_concepts [system] {
header "__ranges/concepts.h"
export std_private_iterator_concepts
diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp
index 077d17c085b99..b0097dff17103 100644
--- a/libcxx/test/std/ranges/range.access/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp
@@ -19,7 +19,9 @@
#include "test_iterators.h"
using RangeBeginT = decltype(std::ranges::begin);
+#if _LIBCPP_STD_VER < 23
using RangeCBeginT = decltype(std::ranges::cbegin);
+#endif // _LIBCPP_STD_VER < 23
static int globalBuff[8];
@@ -27,33 +29,43 @@ 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 (&)[]>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[]>);
static_assert( std::is_invocable_v<RangeCBeginT, int (&)[]>);
+#endif // _LIBCPP_STD_VER < 23
struct Incomplete;
static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[]>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[]>);
+#endif // _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[10]>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[10]>);
+#endif // _LIBCPP_STD_VER < 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[]>);
+#if _LIBCPP_STD_VER < 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[]>);
+#endif // _LIBCPP_STD_VER < 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[10]>);
+#if _LIBCPP_STD_VER < 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[10]>);
+#endif // _LIBCPP_STD_VER < 23
struct BeginMember {
int x;
@@ -65,45 +77,48 @@ static_assert( std::is_invocable_v<RangeBeginT, BeginMember &>);
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 const&&>);
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCBeginT, BeginMember &>);
static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember &&>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginMember const&>);
static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember const&&>);
+#endif // _LIBCPP_STD_VER < 23
constexpr bool testReturnTypes() {
- {
- int *x[2];
- ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int**);
- ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), int* const*);
- }
- {
- int x[2][2];
- ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int(*)[2]);
- ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), const int(*)[2]);
- }
- {
- struct Different {
- char*& begin();
- short*& begin() const;
- } x;
- ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), char*);
- ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), short*);
- }
+ int* a[2];
+ int b[2][2];
+ struct Different {
+ char*& begin();
+ short*& begin() const;
+ } c;
+
+ ASSERT_SAME_TYPE(decltype(std::ranges::begin(a)), int**);
+ ASSERT_SAME_TYPE(decltype(std::ranges::begin(b)), int(*)[2]);
+ ASSERT_SAME_TYPE(decltype(std::ranges::begin(c)), char*);
+
+#if _LIBCPP_STD_VER < 23
+ ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(a)), int* const*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(b)), const int(*)[2]);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(c)), short*);
+#endif // _LIBCPP_STD_VER < 23
+
return true;
}
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(a) == a);
+ assert(std::ranges::begin(b) == b);
assert(std::ranges::begin(c) == c);
+
+#if _LIBCPP_STD_VER < 23
+ assert(std::ranges::cbegin(a) == a);
+ assert(std::ranges::cbegin(b) == b);
assert(std::ranges::cbegin(c) == c);
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -136,8 +151,10 @@ struct NonConstBeginMember {
};
static_assert( std::is_invocable_v<RangeBeginT, NonConstBeginMember &>);
static_assert(!std::is_invocable_v<RangeBeginT, NonConstBeginMember const&>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember &>);
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember const&>);
+#endif // _LIBCPP_STD_VER < 23
struct EnabledBorrowingBeginMember {
constexpr int *begin() const { return &globalBuff[0]; }
@@ -159,28 +176,28 @@ struct EmptyPtrBeginMember {
constexpr bool testBeginMember() {
BeginMember a;
+ NonConstBeginMember b;
+ EnabledBorrowingBeginMember c;
+ BeginMemberFunction d;
+ EmptyPtrBeginMember e;
+
assert(std::ranges::begin(a) == &a.x);
- assert(std::ranges::cbegin(a) == &a.x);
static_assert(!std::is_invocable_v<RangeBeginT, BeginMember&&>);
- static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember&&>);
-
- NonConstBeginMember b;
assert(std::ranges::begin(b) == &b.x);
- static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember&>);
-
- EnabledBorrowingBeginMember c;
assert(std::ranges::begin(c) == &globalBuff[0]);
- assert(std::ranges::cbegin(c) == &globalBuff[0]);
assert(std::ranges::begin(std::move(c)) == &globalBuff[0]);
- assert(std::ranges::cbegin(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);
+
+#if _LIBCPP_STD_VER < 23
+ assert(std::ranges::cbegin(a) == &a.x);
+ static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember&&>);
+ static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember&>);
+ assert(std::ranges::cbegin(c) == &globalBuff[0]);
+ assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]);
+ assert(std::ranges::cbegin(d) == &d.x);
assert(std::ranges::cbegin(e) == &e.x);
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -193,8 +210,10 @@ struct BeginFunction {
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&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
+#endif // _LIBCPP_STD_VER < 23
struct BeginFunctionReturnsInt {
friend int begin(BeginFunctionReturnsInt const&);
@@ -215,7 +234,9 @@ static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsPtrConvertib
struct BeginFunctionByValue {
friend constexpr int *begin(BeginFunctionByValue) { return &globalBuff[1]; }
};
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, BeginFunctionByValue>);
+#endif // _LIBCPP_STD_VER < 23
struct BeginFunctionEnabledBorrowing {
friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; }
@@ -245,85 +266,96 @@ struct BeginFunctionWithPrivateBeginMember {
constexpr bool testBeginFunction() {
BeginFunction a{};
const BeginFunction aa{};
- assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::cbegin(a) == &a.x);
- assert(std::ranges::begin(aa) == &aa.x);
- assert(std::ranges::cbegin(aa) == &aa.x);
-
BeginFunctionByValue b{};
const BeginFunctionByValue bb{};
- assert(std::ranges::begin(b) == &globalBuff[1]);
- assert(std::ranges::cbegin(b) == &globalBuff[1]);
- assert(std::ranges::begin(bb) == &globalBuff[1]);
- assert(std::ranges::cbegin(bb) == &globalBuff[1]);
-
BeginFunctionEnabledBorrowing c{};
const BeginFunctionEnabledBorrowing cc{};
- assert(std::ranges::begin(std::move(c)) == &globalBuff[2]);
- assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]);
- assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]);
- assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]);
-
BeginFunctionReturnsEmptyPtr d{};
const BeginFunctionReturnsEmptyPtr dd{};
- assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::cbegin(d) == &d.x);
- assert(std::ranges::begin(dd) == &dd.x);
- assert(std::ranges::cbegin(dd) == &dd.x);
-
BeginFunctionWithDataMember e{};
const BeginFunctionWithDataMember ee{};
+ BeginFunctionWithPrivateBeginMember f{};
+ const BeginFunctionWithPrivateBeginMember ff{};
+
+ assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::begin(aa) == &aa.x);
+ assert(std::ranges::begin(b) == &globalBuff[1]);
+ assert(std::ranges::begin(bb) == &globalBuff[1]);
+ assert(std::ranges::begin(std::move(c)) == &globalBuff[2]);
+ assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]);
+ assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::begin(dd) == &dd.x);
assert(std::ranges::begin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::begin(ee) == &ee.x);
+ assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::begin(ff) == &ff.y);
+
+#if _LIBCPP_STD_VER < 23
+ assert(std::ranges::cbegin(a) == &a.x);
+ assert(std::ranges::cbegin(aa) == &aa.x);
+ assert(std::ranges::cbegin(b) == &globalBuff[1]);
+ assert(std::ranges::cbegin(bb) == &globalBuff[1]);
+ assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]);
+ assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]);
+ assert(std::ranges::cbegin(d) == &d.x);
+ assert(std::ranges::cbegin(dd) == &dd.x);
assert(std::ranges::cbegin(e) == &e.x);
assert(std::ranges::cbegin(ee) == &ee.x);
-
- BeginFunctionWithPrivateBeginMember f{};
- const BeginFunctionWithPrivateBeginMember ff{};
- assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cbegin(f) == &f.y);
- assert(std::ranges::begin(ff) == &ff.y);
assert(std::ranges::cbegin(ff) == &ff.y);
+#endif // _LIBCPP_STD_VER < 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
+#if _LIBCPP_STD_VER < 23
ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval<int (&)[10]>()));
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowMemberBegin {
ThrowingIterator<int> begin() const noexcept; // auto(t.begin()) doesn't throw
} ntmb;
static_assert(noexcept(std::ranges::begin(ntmb)));
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::cbegin(ntmb)));
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowADLBegin {
friend ThrowingIterator<int> begin(NoThrowADLBegin&) noexcept; // auto(begin(t)) doesn't throw
friend ThrowingIterator<int> begin(const NoThrowADLBegin&) noexcept;
} ntab;
static_assert(noexcept(std::ranges::begin(ntab)));
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::cbegin(ntab)));
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowMemberBeginReturnsRef {
ThrowingIterator<int>& begin() const noexcept; // auto(t.begin()) may throw
} ntmbrr;
static_assert(!noexcept(std::ranges::begin(ntmbrr)));
+#if _LIBCPP_STD_VER < 23
static_assert(!noexcept(std::ranges::cbegin(ntmbrr)));
+#endif // _LIBCPP_STD_VER < 23
struct BeginReturnsArrayRef {
auto begin() const noexcept -> int(&)[10];
} brar;
static_assert(noexcept(std::ranges::begin(brar)));
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::cbegin(brar)));
+#endif // _LIBCPP_STD_VER < 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*&>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*&>);
+#endif // _LIBCPP_STD_VER < 23
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/end.pass.cpp b/libcxx/test/std/ranges/range.access/end.pass.cpp
index 19534d0341857..ffbc5ba3d16e4 100644
--- a/libcxx/test/std/ranges/range.access/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/end.pass.cpp
@@ -19,7 +19,9 @@
#include "test_iterators.h"
using RangeEndT = decltype(std::ranges::end);
+#if _LIBCPP_STD_VER < 23
using RangeCEndT = decltype(std::ranges::cend);
+#endif // _LIBCPP_STD_VER < 23
static int globalBuff[8];
@@ -27,16 +29,20 @@ 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]>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCEndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCEndT, int (&)[10]>);
+#endif // _LIBCPP_STD_VER < 23
struct Incomplete;
static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[42]>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[42]>);
+#endif // _LIBCPP_STD_VER < 23
struct EndMember {
int x;
@@ -49,47 +55,50 @@ static_assert( std::is_invocable_v<RangeEndT, EndMember &>);
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 const&&>);
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCEndT, EndMember &>);
static_assert(!std::is_invocable_v<RangeCEndT, EndMember &&>);
static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>);
static_assert(!std::is_invocable_v<RangeCEndT, EndMember const&&>);
+#endif // _LIBCPP_STD_VER < 23
constexpr bool testReturnTypes() {
- {
- int *x[2];
- ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int**);
- ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), int* const*);
- }
- {
- int x[2][2];
- ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int(*)[2]);
- ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), const int(*)[2]);
- }
- {
- struct Different {
- char *begin();
- sentinel_wrapper<char*>& end();
- short *begin() const;
- sentinel_wrapper<short*>& end() const;
- } x;
- ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), sentinel_wrapper<char*>);
- ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), sentinel_wrapper<short*>);
- }
+ int* a[2];
+ int b[2][2];
+ struct Different {
+ char* begin();
+ sentinel_wrapper<char*>& end();
+ short* begin() const;
+ sentinel_wrapper<short*>& end() const;
+ } c;
+
+ ASSERT_SAME_TYPE(decltype(std::ranges::end(a)), int**);
+ ASSERT_SAME_TYPE(decltype(std::ranges::end(b)), int(*)[2]);
+ ASSERT_SAME_TYPE(decltype(std::ranges::end(c)), sentinel_wrapper<char*>);
+
+#if _LIBCPP_STD_VER < 23
+ ASSERT_SAME_TYPE(decltype(std::ranges::cend(a)), int* const*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cend(b)), const int(*)[2]);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cend(c)), sentinel_wrapper<short*>);
+#endif // _LIBCPP_STD_VER < 23
+
return true;
}
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(a) == a + 2);
+ assert(std::ranges::end(b) == b + 2);
assert(std::ranges::end(c) == c + 2);
+
+#if _LIBCPP_STD_VER < 23
+ assert(std::ranges::cend(a) == a + 2);
+ assert(std::ranges::cend(b) == b + 2);
assert(std::ranges::cend(c) == c + 2);
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -127,8 +136,10 @@ struct NonConstEndMember {
};
static_assert( std::is_invocable_v<RangeEndT, NonConstEndMember &>);
static_assert(!std::is_invocable_v<RangeEndT, NonConstEndMember const&>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>);
static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>);
+#endif // _LIBCPP_STD_VER < 23
struct EnabledBorrowingEndMember {
constexpr int *begin() const { return nullptr; }
@@ -160,24 +171,24 @@ struct EmptyPtrEndMember {
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);
- static_assert(!std::is_invocable_v<RangeCEndT, decltype((b))>);
-
EnabledBorrowingEndMember c;
- assert(std::ranges::end(std::move(c)) == &globalBuff[0]);
- assert(std::ranges::cend(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(a) == &a.x);
+ assert(std::ranges::end(b) == &b.x);
+ assert(std::ranges::end(std::move(c)) == &globalBuff[0]);
+ assert(std::ranges::end(d) == &d.x);
assert(std::ranges::end(e) == &e.x);
+
+#if _LIBCPP_STD_VER < 23
+ assert(std::ranges::cend(a) == &a.x);
+ static_assert(!std::is_invocable_v<RangeCEndT, decltype((b))>);
+ assert(std::ranges::cend(std::move(c)) == &globalBuff[0]);
+ assert(std::ranges::cend(d) == &d.x);
assert(std::ranges::cend(e) == &e.x);
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -194,8 +205,10 @@ 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&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
+#endif // _LIBCPP_STD_VER < 23
struct EndFunctionReturnsInt {
friend constexpr int begin(EndFunctionReturnsInt const&);
@@ -230,7 +243,9 @@ struct EndFunctionByValue {
friend constexpr int *begin(EndFunctionByValue) { return nullptr; }
friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; }
};
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, EndFunctionByValue>);
+#endif // _LIBCPP_STD_VER < 23
struct EndFunctionEnabledBorrowing {
friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; }
@@ -268,61 +283,63 @@ struct BeginMemberEndFunction {
constexpr bool testEndFunction() {
const EndFunction a{};
- assert(std::ranges::end(a) == &a.x);
- assert(std::ranges::cend(a) == &a.x);
EndFunction aa{};
- assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- 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]);
- assert(std::ranges::cend(std::move(c)) == &globalBuff[2]);
-
const EndFunctionReturnsEmptyPtr d{};
- assert(std::ranges::end(d) == &d.x);
- assert(std::ranges::cend(d) == &d.x);
EndFunctionReturnsEmptyPtr dd{};
- assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::cend(dd) == &dd.x);
-
const EndFunctionWithDataMember e{};
- assert(std::ranges::end(e) == &e.x);
- assert(std::ranges::cend(e) == &e.x);
EndFunctionWithDataMember ee{};
- assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::cend(ee) == &ee.x);
-
const EndFunctionWithPrivateEndMember f{};
- assert(std::ranges::end(f) == &f.y);
- assert(std::ranges::cend(f) == &f.y);
EndFunctionWithPrivateEndMember ff{};
- assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
- assert(std::ranges::cend(ff) == &ff.y);
-
const BeginMemberEndFunction g{};
- assert(std::ranges::end(g) == &g.x);
- assert(std::ranges::cend(g) == &g.x);
BeginMemberEndFunction gg{};
+
+ assert(std::ranges::end(a) == &a.x);
+ assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::end(b) == &globalBuff[1]);
+ assert(std::ranges::end(std::move(c)) == &globalBuff[2]);
+ assert(std::ranges::end(d) == &d.x);
+ assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::end(e) == &e.x);
+ assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::end(f) == &f.y);
+ assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+ assert(std::ranges::end(g) == &g.x);
assert(std::ranges::end(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
+
+#if _LIBCPP_STD_VER < 23
+ assert(std::ranges::cend(a) == &a.x);
+ assert(std::ranges::cend(aa) == &aa.x);
+ assert(std::ranges::cend(b) == &globalBuff[1]);
+ assert(std::ranges::cend(std::move(c)) == &globalBuff[2]);
+ assert(std::ranges::cend(d) == &d.x);
+ assert(std::ranges::cend(dd) == &dd.x);
+ assert(std::ranges::cend(e) == &e.x);
+ assert(std::ranges::cend(ee) == &ee.x);
+ assert(std::ranges::cend(f) == &f.y);
+ assert(std::ranges::cend(ff) == &ff.y);
+ assert(std::ranges::cend(g) == &g.x);
assert(std::ranges::cend(gg) == &gg.x);
+#endif // _LIBCPP_STD_VER < 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::end(std::declval<int (&)[10]>()));
+#if _LIBCPP_STD_VER < 23
ASSERT_NOEXCEPT(std::ranges::cend(std::declval<int (&)[10]>()));
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowMemberEnd {
ThrowingIterator<int> begin() const;
ThrowingIterator<int> end() const noexcept; // auto(t.end()) doesn't throw
} ntme;
static_assert(noexcept(std::ranges::end(ntme)));
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::cend(ntme)));
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowADLEnd {
ThrowingIterator<int> begin() const;
@@ -330,29 +347,37 @@ struct NoThrowADLEnd {
friend ThrowingIterator<int> end(const NoThrowADLEnd&) noexcept;
} ntae;
static_assert(noexcept(std::ranges::end(ntae)));
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::cend(ntae)));
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowMemberEndReturnsRef {
ThrowingIterator<int> begin() const;
ThrowingIterator<int>& end() const noexcept; // auto(t.end()) may throw
} ntmerr;
static_assert(!noexcept(std::ranges::end(ntmerr)));
+#if _LIBCPP_STD_VER < 23
static_assert(!noexcept(std::ranges::cend(ntmerr)));
+#endif // _LIBCPP_STD_VER < 23
struct EndReturnsArrayRef {
auto begin() const noexcept -> int(&)[10];
auto end() const noexcept -> int(&)[10];
} erar;
static_assert(noexcept(std::ranges::end(erar)));
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::cend(erar)));
+#endif // _LIBCPP_STD_VER < 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*&>);
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>);
+#endif // _LIBCPP_STD_VER < 23
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
index d34ee9f2da0a7..a168889d5fa20 100644
--- a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
@@ -19,9 +19,9 @@
#include "test_iterators.h"
using RangeRBeginT = decltype(std::ranges::rbegin);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
using RangeCRBeginT = decltype(std::ranges::crbegin);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
static int globalBuff[8];
@@ -29,12 +29,12 @@ static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeRBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeRBeginT, int (&)[]>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCRBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&)[]>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct Incomplete;
@@ -43,28 +43,28 @@ static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeRBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete(&&)[10]>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[10]>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[]>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[]>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[10]>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[10]>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct RBeginMember {
int x;
@@ -76,12 +76,12 @@ static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember &>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember &&>);
static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember const&>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember const&&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember &>);
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember &&>);
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember const&>);
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember const&&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
constexpr bool testReturnTypes() {
int* a[2];
@@ -91,15 +91,15 @@ constexpr bool testReturnTypes() {
short*& rbegin() const;
} c;
- ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int**>);
- ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int(*)[2]>);
- ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), char*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(a)), std::reverse_iterator<int**>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(b)), std::reverse_iterator<int(*)[2]>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(c)), char*);
-#if _LIBCPP_STD_VER <= 23
- ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<int* const*>);
- ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<const int(*)[2]>);
- ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), short*);
-#endif // _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(a)), std::reverse_iterator<int* const*>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(b)), std::reverse_iterator<const int(*)[2]>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(c)), short*);
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -113,11 +113,11 @@ constexpr bool testArray() {
assert(std::ranges::rbegin(b).base() == b + 2);
assert(std::ranges::rbegin(c).base() == c + 2);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
assert(std::ranges::crbegin(a).base() == a + 2);
assert(std::ranges::crbegin(b).base() == b + 2);
assert(std::ranges::crbegin(c).base() == c + 2);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -144,10 +144,10 @@ struct NonConstRBeginMember {
};
static_assert( std::is_invocable_v<RangeRBeginT, NonConstRBeginMember &>);
static_assert(!std::is_invocable_v<RangeRBeginT, NonConstRBeginMember const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember &>);
static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct EnabledBorrowingRBeginMember {
constexpr int *rbegin() const { return globalBuff; }
@@ -182,7 +182,7 @@ constexpr bool testRBeginMember() {
assert(std::ranges::rbegin(d) == &d.x);
assert(std::ranges::rbegin(e) == &e.x);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
assert(std::ranges::crbegin(a) == &a.x);
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember&&>);
static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember&>);
@@ -190,7 +190,7 @@ constexpr bool testRBeginMember() {
assert(std::ranges::crbegin(std::move(c)) == globalBuff);
assert(std::ranges::crbegin(d) == &d.x);
assert(std::ranges::crbegin(e) == &e.x);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -204,10 +204,10 @@ static_assert( std::is_invocable_v<RangeRBeginT, RBeginFunction const&>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunction &&>);
static_assert(
std::is_invocable_v<RangeRBeginT, RBeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction const&>);
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction &>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct RBeginFunctionReturnsInt {
friend int rbegin(RBeginFunctionReturnsInt const&);
@@ -231,12 +231,12 @@ struct RBeginFunctionReturnsPtrConvertible {
};
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsPtrConvertible const&>);
-#if _LIBCPP_STD_VER <= 23
struct RBeginFunctionByValue {
friend constexpr int *rbegin(RBeginFunctionByValue) { return globalBuff + 1; }
};
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginFunctionByValue>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct RBeginFunctionEnabledBorrowing {
friend constexpr int *rbegin(RBeginFunctionEnabledBorrowing) { return globalBuff + 2; }
@@ -290,7 +290,7 @@ constexpr bool testRBeginFunction() {
assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::rbegin(ff) == &ff.y);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
assert(std::ranges::crbegin(a) == &a.x);
assert(std::ranges::crbegin(aa) == &aa.x);
assert(std::ranges::crbegin(b) == globalBuff + 1);
@@ -303,7 +303,7 @@ constexpr bool testRBeginFunction() {
assert(std::ranges::crbegin(ee) == &ee.x);
assert(std::ranges::crbegin(f) == &f.y);
assert(std::ranges::crbegin(ff) == &ff.y);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -319,9 +319,9 @@ struct MemberBeginEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginEnd const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginEnd {
int b, e;
@@ -339,9 +339,9 @@ struct FunctionBeginEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginEnd const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberBeginFunctionEnd {
int b, e;
@@ -357,9 +357,9 @@ struct MemberBeginFunctionEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginFunctionEnd const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginMemberEnd {
int b, e;
@@ -375,77 +375,77 @@ struct FunctionBeginMemberEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginMemberEnd const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberBeginEndDifferentTypes {
bidirectional_iterator<int*> begin();
bidirectional_iterator<const int*> end();
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndDifferentTypes&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndDifferentTypes&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginEndDifferentTypes {
friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);
friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndDifferentTypes&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndDifferentTypes&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberBeginEndForwardIterators {
forward_iterator<int*> begin();
forward_iterator<int*> end();
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndForwardIterators&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndForwardIterators&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginEndForwardIterators {
friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);
friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndForwardIterators&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndForwardIterators&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberBeginOnly {
bidirectional_iterator<int*> begin() const;
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginOnly&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginOnly&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginOnly {
friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginOnly&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginOnly&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberEndOnly {
bidirectional_iterator<int*> end() const;
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberEndOnly&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberEndOnly&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionEndOnly {
friend bidirectional_iterator<int*> end(FunctionEndOnly&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionEndOnly&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionEndOnly&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
// Make sure there is no clash between the following cases:
// - the case that handles classes defining member `rbegin` and `rend` functions;
@@ -458,10 +458,10 @@ struct MemberBeginAndRBegin {
};
static_assert(std::is_invocable_v<RangeRBeginT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeRBeginT, MemberBeginAndRBegin&>, int*>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(std::is_invocable_v<RangeCRBeginT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeCRBeginT, MemberBeginAndRBegin&>, int*>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
constexpr bool testBeginEnd() {
MemberBeginEnd a{};
@@ -482,7 +482,7 @@ constexpr bool testBeginEnd() {
assert(base(std::ranges::rbegin(d).base()) == &d.e);
assert(base(std::ranges::rbegin(dd).base()) == &dd.ce);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
assert(base(std::ranges::crbegin(a).base()) == &a.ce);
assert(base(std::ranges::crbegin(aa).base()) == &aa.ce);
assert(base(std::ranges::crbegin(b).base()) == &b.ce);
@@ -491,77 +491,77 @@ constexpr bool testBeginEnd() {
assert(base(std::ranges::crbegin(cc).base()) == &cc.ce);
assert(base(std::ranges::crbegin(d).base()) == &d.ce);
assert(base(std::ranges::crbegin(dd).base()) == &dd.ce);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::rbegin(std::declval<int (&)[10]>()));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
ASSERT_NOEXCEPT(std::ranges::crbegin(std::declval<int (&)[10]>()));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowMemberRBegin {
ThrowingIterator<int> rbegin() const noexcept; // auto(t.rbegin()) doesn't throw
} ntmb;
static_assert(noexcept(std::ranges::rbegin(ntmb)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::crbegin(ntmb)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowADLRBegin {
friend ThrowingIterator<int> rbegin(NoThrowADLRBegin&) noexcept; // auto(rbegin(t)) doesn't throw
friend ThrowingIterator<int> rbegin(const NoThrowADLRBegin&) noexcept;
} ntab;
static_assert(noexcept(std::ranges::rbegin(ntab)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::crbegin(ntab)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowMemberRBeginReturnsRef {
ThrowingIterator<int>& rbegin() const noexcept; // auto(t.rbegin()) may throw
} ntmbrr;
static_assert(!noexcept(std::ranges::rbegin(ntmbrr)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!noexcept(std::ranges::crbegin(ntmbrr)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct RBeginReturnsArrayRef {
auto rbegin() const noexcept -> int(&)[10];
} brar;
static_assert(noexcept(std::ranges::rbegin(brar)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::crbegin(brar)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowBeginThrowingEnd {
int* begin() const noexcept;
int* end() const;
} ntbte;
static_assert(!noexcept(std::ranges::rbegin(ntbte)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!noexcept(std::ranges::crbegin(ntbte)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowEndThrowingBegin {
int* begin() const;
int* end() const noexcept;
} ntetb;
static_assert(noexcept(std::ranges::rbegin(ntetb)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::crbegin(ntetb)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/rend.pass.cpp b/libcxx/test/std/ranges/range.access/rend.pass.cpp
index 55c2e084d25c3..6029d7f960d88 100644
--- a/libcxx/test/std/ranges/range.access/rend.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rend.pass.cpp
@@ -19,9 +19,9 @@
#include "test_iterators.h"
using RangeREndT = decltype(std::ranges::rend);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
using RangeCREndT = decltype(std::ranges::crend);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
static int globalBuff[8];
@@ -29,20 +29,20 @@ static_assert(!std::is_invocable_v<RangeREndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeREndT, int (&)[10]>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCREndT, int (&)[10]>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct Incomplete;
static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[42]>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[42]>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct REndMember {
int x;
@@ -55,42 +55,32 @@ static_assert( std::is_invocable_v<RangeREndT, REndMember&>);
static_assert(!std::is_invocable_v<RangeREndT, REndMember &&>);
static_assert( std::is_invocable_v<RangeREndT, REndMember const&>);
static_assert(!std::is_invocable_v<RangeREndT, REndMember const&&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, REndMember &>);
static_assert(!std::is_invocable_v<RangeCREndT, REndMember &&>);
static_assert( std::is_invocable_v<RangeCREndT, REndMember const&>);
static_assert(!std::is_invocable_v<RangeCREndT, REndMember const&&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
constexpr bool testReturnTypes() {
- {
- int *x[2];
- ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator<int**>);
-#if _LIBCPP_STD_VER <= 23
- ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator<int* const*>);
-#endif // _LIBCPP_STD_VER <= 23
- }
-
- {
- int x[2][2];
- ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator<int(*)[2]>);
-#if _LIBCPP_STD_VER <= 23
- ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator<const int(*)[2]>);
-#endif // _LIBCPP_STD_VER <= 23
- }
-
- {
- struct Different {
- char* rbegin();
- sentinel_wrapper<char*>& rend();
- short* rbegin() const;
- sentinel_wrapper<short*>& rend() const;
- } x;
- ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), sentinel_wrapper<char*>);
-#if _LIBCPP_STD_VER <= 23
- ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), sentinel_wrapper<short*>);
-#endif // _LIBCPP_STD_VER <= 23
- }
+ int* a[2];
+ int b[2][2];
+ struct Different {
+ char* rbegin();
+ sentinel_wrapper<char*>& rend();
+ short* rbegin() const;
+ sentinel_wrapper<short*>& rend() const;
+ } c;
+
+ ASSERT_SAME_TYPE(decltype(std::ranges::rend(a)), std::reverse_iterator<int**>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::rend(b)), std::reverse_iterator<int(*)[2]>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::rend(c)), sentinel_wrapper<char*>);
+
+#if _LIBCPP_STD_VER < 23
+ ASSERT_SAME_TYPE(decltype(std::ranges::crend(a)), std::reverse_iterator<int* const*>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crend(b)), std::reverse_iterator<const int(*)[2]>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crend(c)), sentinel_wrapper<short*>);
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -104,11 +94,11 @@ constexpr bool testArray() {
assert(std::ranges::rend(b).base() == b);
assert(std::ranges::rend(c).base() == c);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
assert(std::ranges::crend(b).base() == b);
assert(std::ranges::crend(a).base() == a);
assert(std::ranges::crend(c).base() == c);
-#endif // _LIBCPP_STD_VER <= 23 \
+#endif // _LIBCPP_STD_VER < 23 \
//
return true;
}
@@ -146,10 +136,10 @@ struct NonConstREndMember {
};
static_assert( std::is_invocable_v<RangeREndT, NonConstREndMember &>);
static_assert(!std::is_invocable_v<RangeREndT, NonConstREndMember const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember &>);
static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct EnabledBorrowingREndMember {
constexpr int* rbegin() const { return nullptr; }
@@ -192,13 +182,13 @@ constexpr bool testREndMember() {
assert(std::ranges::rend(d) == &d.x);
assert(std::ranges::rend(e) == &e.x);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
assert(std::ranges::crend(a) == &a.x);
static_assert(!std::is_invocable_v<RangeCREndT, decltype((b))>);
assert(std::ranges::crend(std::move(c)) == &globalBuff[0]);
assert(std::ranges::crend(d) == &d.x);
assert(std::ranges::crend(e) == &e.x);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -215,10 +205,10 @@ static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
static_assert( std::is_invocable_v<RangeREndT, REndFunction const&>);
static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
static_assert(std::is_invocable_v<RangeREndT, REndFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, REndFunction const&>);
static_assert( std::is_invocable_v<RangeCREndT, REndFunction &>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct REndFunctionReturnsInt {
friend constexpr int rbegin(REndFunctionReturnsInt const&);
@@ -253,9 +243,9 @@ struct REndFunctionByValue {
friend constexpr int* rbegin(REndFunctionByValue) { return nullptr; }
friend constexpr int* rend(REndFunctionByValue) { return &globalBuff[1]; }
};
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, REndFunctionByValue>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct REndFunctionEnabledBorrowing {
friend constexpr int* rbegin(REndFunctionEnabledBorrowing) { return nullptr; }
@@ -316,7 +306,7 @@ constexpr bool testREndFunction() {
assert(std::ranges::rend(g) == &g.x);
assert(std::ranges::rend(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
assert(std::ranges::crend(a) == &a.x);
assert(std::ranges::crend(aa) == &aa.x);
assert(std::ranges::crend(b) == &globalBuff[1]);
@@ -329,7 +319,7 @@ constexpr bool testREndFunction() {
assert(std::ranges::crend(ff) == &ff.y);
assert(std::ranges::crend(g) == &g.x);
assert(std::ranges::crend(gg) == &gg.x);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
return true;
}
@@ -345,9 +335,9 @@ struct MemberBeginEnd {
};
static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd&>);
static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, MemberBeginEnd const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginEnd {
int b, e;
@@ -365,9 +355,9 @@ struct FunctionBeginEnd {
};
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd&>);
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginEnd const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberBeginFunctionEnd {
int b, e;
@@ -383,9 +373,9 @@ struct MemberBeginFunctionEnd {
};
static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd&>);
static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, MemberBeginFunctionEnd const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginMemberEnd {
int b, e;
@@ -401,77 +391,77 @@ struct FunctionBeginMemberEnd {
};
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd&>);
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd const&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginMemberEnd const&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberBeginEndDifferentTypes {
bidirectional_iterator<int*> begin();
bidirectional_iterator<const int*> end();
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndDifferentTypes&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndDifferentTypes&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginEndDifferentTypes {
friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);
friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndDifferentTypes&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndDifferentTypes&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberBeginEndForwardIterators {
forward_iterator<int*> begin();
forward_iterator<int*> end();
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndForwardIterators&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndForwardIterators&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginEndForwardIterators {
friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);
friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndForwardIterators&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndForwardIterators&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberBeginOnly {
bidirectional_iterator<int*> begin() const;
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginOnly&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginOnly&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionBeginOnly {
friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginOnly&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginOnly&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct MemberEndOnly {
bidirectional_iterator<int*> end() const;
};
static_assert(!std::is_invocable_v<RangeREndT, MemberEndOnly&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberEndOnly&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct FunctionEndOnly {
friend bidirectional_iterator<int*> end(FunctionEndOnly&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionEndOnly&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionEndOnly&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
// Make sure there is no clash between the following cases:
// - the case that handles classes defining member `rbegin` and `rend` functions;
@@ -484,10 +474,10 @@ struct MemberBeginAndRBegin {
};
static_assert(std::is_invocable_v<RangeREndT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeREndT, MemberBeginAndRBegin&>, int*>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(std::is_invocable_v<RangeCREndT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeCREndT, MemberBeginAndRBegin&>, int*>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
constexpr bool testBeginEnd() {
MemberBeginEnd a{};
@@ -508,7 +498,7 @@ constexpr bool testBeginEnd() {
assert(base(std::ranges::rend(d).base()) == &d.b);
assert(base(std::ranges::rend(dd).base()) == &dd.cb);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
assert(base(std::ranges::crend(a).base()) == &a.cb);
assert(base(std::ranges::crend(aa).base()) == &aa.cb);
assert(base(std::ranges::crend(b).base()) == &b.cb);
@@ -517,25 +507,25 @@ constexpr bool testBeginEnd() {
assert(base(std::ranges::crend(cc).base()) == &cc.cb);
assert(base(std::ranges::crend(d).base()) == &d.cb);
assert(base(std::ranges::crend(dd).base()) == &dd.cb);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::rend(std::declval<int (&)[10]>()));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
ASSERT_NOEXCEPT(std::ranges::crend(std::declval<int (&)[10]>()));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowMemberREnd {
ThrowingIterator<int> rbegin() const;
ThrowingIterator<int> rend() const noexcept; // auto(t.rend()) doesn't throw
} ntmre;
static_assert(noexcept(std::ranges::rend(ntmre)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::crend(ntmre)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowADLREnd {
ThrowingIterator<int> rbegin() const;
@@ -543,55 +533,55 @@ struct NoThrowADLREnd {
friend ThrowingIterator<int> rend(const NoThrowADLREnd&) noexcept;
} ntare;
static_assert(noexcept(std::ranges::rend(ntare)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::crend(ntare)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowMemberREndReturnsRef {
ThrowingIterator<int> rbegin() const;
ThrowingIterator<int>& rend() const noexcept; // auto(t.rend()) may throw
} ntmrerr;
static_assert(!noexcept(std::ranges::rend(ntmrerr)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!noexcept(std::ranges::crend(ntmrerr)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct REndReturnsArrayRef {
auto rbegin() const noexcept -> int(&)[10];
auto rend() const noexcept -> int(&)[10];
} rerar;
static_assert(noexcept(std::ranges::rend(rerar)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::crend(rerar)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowBeginThrowingEnd {
int* begin() const noexcept;
int* end() const;
} ntbte;
static_assert(noexcept(std::ranges::rend(ntbte)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(noexcept(std::ranges::crend(ntbte)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
struct NoThrowEndThrowingBegin {
int* begin() const;
int* end() const noexcept;
} ntetb;
static_assert(!noexcept(std::ranges::rend(ntetb)));
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!noexcept(std::ranges::crend(ntetb)));
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*&>);
-#if _LIBCPP_STD_VER <= 23
+#if _LIBCPP_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*&>);
-#endif // _LIBCPP_STD_VER <= 23
+#endif // _LIBCPP_STD_VER < 23
int main(int, char**) {
static_assert(testReturnTypes());
>From 9ae919448814ba87987bcff3fdb4a6460e1946c3 Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Wed, 24 Jul 2024 21:04:09 +0200
Subject: [PATCH 04/16] Finish off the docs
additionally minor fix to formatting
still need to test...
---
libcxx/docs/Status/Cxx2c.rst | 2 ++
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
libcxx/test/std/ranges/range.access/rend.pass.cpp | 4 ++--
libcxx/utils/generate_feature_test_macro_components.py | 3 +--
4 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/libcxx/docs/Status/Cxx2c.rst b/libcxx/docs/Status/Cxx2c.rst
index 1b8d96588c3cb..9514daf5464e7 100644
--- a/libcxx/docs/Status/Cxx2c.rst
+++ b/libcxx/docs/Status/Cxx2c.rst
@@ -44,6 +44,8 @@ Paper Status
.. [#note-P2944R3] Implemented comparisons for ``reference_wrapper`` only.
.. [#note-P2422R1] Libc++ keeps the ``nodiscard`` attributes as a conforming extension.
.. [#note-P2997R1] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
+ .. [#note-P2836R1] This paper is applies as DR against C++23 (MSVC STL and libstdc++ have done the same);
+ it is marked in progress as the feature macro is not yet defined and therefore has not been updated.
.. _issues-status-cxx2c:
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 130e4ef894f29..24270fbc8c04f 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -42,7 +42,7 @@
"`P2819R2 <https://wg21.link/P2819R2>`__","LWG","Add tuple protocol to complex","Kona November 2023","|Complete|","19.0",""
"`P2937R0 <https://wg21.link/P2937R0>`__","LWG","Freestanding: Remove ``strtok``","Kona November 2023","","",""
"`P2833R2 <https://wg21.link/P2833R2>`__","LWG","Freestanding Library: inout expected span","Kona November 2023","","",""
-"`P2836R1 <https://wg21.link/P2836R1>`__","LWG","``std::basic_const_iterator`` should follow its underlying type's convertibility","Kona November 2023","","","|DR|"
+"`P2836R1 <https://wg21.link/P2836R1>`__","LWG","``std::basic_const_iterator`` should follow its underlying type's convertibility","Kona November 2023","|In progress| [#note-P2836R1]","","|DR|"
"`P2264R7 <https://wg21.link/P2264R7>`__","LWG","Make ``assert()`` macro user friendly for C and C++","Kona November 2023","","",""
"`P1673R13 <https://wg21.link/P1673R13>`__","LWG","A free function linear algebra interface based on the BLAS","Kona November 2023","","",""
"","","","","","",""
diff --git a/libcxx/test/std/ranges/range.access/rend.pass.cpp b/libcxx/test/std/ranges/range.access/rend.pass.cpp
index 6029d7f960d88..1108109009dfc 100644
--- a/libcxx/test/std/ranges/range.access/rend.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rend.pass.cpp
@@ -98,8 +98,8 @@ constexpr bool testArray() {
assert(std::ranges::crend(b).base() == b);
assert(std::ranges::crend(a).base() == a);
assert(std::ranges::crend(c).base() == c);
-#endif // _LIBCPP_STD_VER < 23 \
- //
+#endif // _LIBCPP_STD_VER < 23
+
return true;
}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index a351112471295..2fdfbf8a0de95 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1000,8 +1000,7 @@ def add_version_header(tc):
{
"name": "__cpp_lib_ranges_as_const",
"values": {
- "c++23": 202207 # P2278R4 cbegin should always return a constant iterator
- # 202311 # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility
+ "c++23": 202311 # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility
},
"headers": ["ranges"],
"unimplemented": True,
>From 863f4802c648b967135c43199f3e4fe25c744aae Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Sat, 27 Jul 2024 11:00:17 +0200
Subject: [PATCH 05/16] run the generate script
---
libcxx/include/version | 4 ++--
.../ranges.version.compile.pass.cpp | 10 +++++-----
.../version.version.compile.pass.cpp | 10 +++++-----
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/libcxx/include/version b/libcxx/include/version
index 40548098a92d6..5535815a8423c 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -184,7 +184,7 @@ __cpp_lib_print 202207L <ostream> <print
__cpp_lib_quoted_string_io 201304L <iomanip>
__cpp_lib_ranges 202207L <algorithm> <functional> <iterator>
<memory> <ranges>
-__cpp_lib_ranges_as_const 202207L <ranges>
+__cpp_lib_ranges_as_const 202311L <ranges>
__cpp_lib_ranges_as_rvalue 202207L <ranges>
__cpp_lib_ranges_chunk 202202L <ranges>
__cpp_lib_ranges_chunk_by 202202L <ranges>
@@ -480,7 +480,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_optional 202110L
# define __cpp_lib_out_ptr 202106L
# define __cpp_lib_print 202207L
-// # define __cpp_lib_ranges_as_const 202207L
+// # define __cpp_lib_ranges_as_const 202311L
# define __cpp_lib_ranges_as_rvalue 202207L
// # define __cpp_lib_ranges_chunk 202202L
# define __cpp_lib_ranges_chunk_by 202202L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
index 30feacd796d8e..379f67365e95d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
@@ -18,7 +18,7 @@
/* Constant Value
__cpp_lib_default_template_type_for_algorithm_values 202403L [C++26]
__cpp_lib_ranges 202207L [C++20]
- __cpp_lib_ranges_as_const 202207L [C++23]
+ __cpp_lib_ranges_as_const 202311L [C++23]
__cpp_lib_ranges_as_rvalue 202207L [C++23]
__cpp_lib_ranges_chunk 202202L [C++23]
__cpp_lib_ranges_chunk_by 202202L [C++23]
@@ -253,8 +253,8 @@
# ifndef __cpp_lib_ranges_as_const
# error "__cpp_lib_ranges_as_const should be defined in c++23"
# endif
-# if __cpp_lib_ranges_as_const != 202207L
-# error "__cpp_lib_ranges_as_const should have the value 202207L in c++23"
+# if __cpp_lib_ranges_as_const != 202311L
+# error "__cpp_lib_ranges_as_const should have the value 202311L in c++23"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_ranges_as_const
@@ -372,8 +372,8 @@
# ifndef __cpp_lib_ranges_as_const
# error "__cpp_lib_ranges_as_const should be defined in c++26"
# endif
-# if __cpp_lib_ranges_as_const != 202207L
-# error "__cpp_lib_ranges_as_const should have the value 202207L in c++26"
+# if __cpp_lib_ranges_as_const != 202311L
+# error "__cpp_lib_ranges_as_const should have the value 202311L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_ranges_as_const
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index f26e7dc4b4c63..2c4ead61bb631 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -167,7 +167,7 @@
__cpp_lib_print 202207L [C++23]
__cpp_lib_quoted_string_io 201304L [C++14]
__cpp_lib_ranges 202207L [C++20]
- __cpp_lib_ranges_as_const 202207L [C++23]
+ __cpp_lib_ranges_as_const 202311L [C++23]
__cpp_lib_ranges_as_rvalue 202207L [C++23]
__cpp_lib_ranges_chunk 202202L [C++23]
__cpp_lib_ranges_chunk_by 202202L [C++23]
@@ -5627,8 +5627,8 @@
# ifndef __cpp_lib_ranges_as_const
# error "__cpp_lib_ranges_as_const should be defined in c++23"
# endif
-# if __cpp_lib_ranges_as_const != 202207L
-# error "__cpp_lib_ranges_as_const should have the value 202207L in c++23"
+# if __cpp_lib_ranges_as_const != 202311L
+# error "__cpp_lib_ranges_as_const should have the value 202311L in c++23"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_ranges_as_const
@@ -7478,8 +7478,8 @@
# ifndef __cpp_lib_ranges_as_const
# error "__cpp_lib_ranges_as_const should be defined in c++26"
# endif
-# if __cpp_lib_ranges_as_const != 202207L
-# error "__cpp_lib_ranges_as_const should have the value 202207L in c++26"
+# if __cpp_lib_ranges_as_const != 202311L
+# error "__cpp_lib_ranges_as_const should have the value 202311L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_ranges_as_const
>From 691585a433462d0e9ae21abe6fb58cdd2cc2db8d Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Sat, 27 Jul 2024 17:26:23 +0200
Subject: [PATCH 06/16] wip
---
libcxx/include/__ranges/concepts.h | 2 ++
libcxx/include/ranges | 6 ++++--
libcxx/modules/std/ranges.inc | 14 ++++++++++----
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index 19264d4ac76c3..bc55c25239553 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -76,8 +76,10 @@ using range_value_t = iter_value_t<iterator_t<_Rp>>;
template <range _Rp>
using range_reference_t = iter_reference_t<iterator_t<_Rp>>;
+# if _LIBCPP_STD_VER >= 23
template <range _Rp>
using range_const_reference_t = iter_const_reference_t<iterator_t<_Rp>>;
+# endif
template <range _Rp>
using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<_Rp>>;
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 7961862085023..03e5da4b58908 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -40,7 +40,9 @@ namespace std::ranges {
template<range R>
using sentinel_t = decltype(ranges::end(declval<R&>()));
template<range R>
- using const_iterator_t = decltype(ranges::end(declval<R&>())); // since C++23
+ using const_iterator_t = const_iterator<iterator_t<R>>; // since C++23
+ template<range R>
+ using const_sentinel_t = const_sentinel<sentinel_t<R>>; // since C++23
template<range R>
using range_difference_t = iter_difference_t<iterator_t<R>>;
template<sized_range R>
@@ -50,7 +52,7 @@ namespace std::ranges {
template<range R>
using range_reference_t = iter_reference_t<iterator_t<R>>;
template<range R>
- using range_const_reference_t = decltype(ranges::end(declval<R&>())); // since C++23
+ using range_const_reference_t = iter_const_reference_t<iterator_t<R>>; // since C++23
template<range R>
using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<R>>;
template <range R>
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index f71efe948ede1..e111d818a3ae0 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -34,10 +34,14 @@ export namespace std {
using std::ranges::borrowed_range;
- // using std::ranges::const_iterator_t;
- // using std::ranges::const_sentinel_t;
+#if _LIBCPP_STD_VER >= 23
+ using std::ranges::const_iterator_t;
+ using std::ranges::const_sentinel_t;
+#endif
using std::ranges::iterator_t;
- // using std::ranges::range_const_reference_t;
+#if _LIBCPP_STD_VER >= 23
+ using std::ranges::range_const_reference_t;
+#endif
using std::ranges::range_common_reference_t;
using std::ranges::range_difference_t;
using std::ranges::range_reference_t;
@@ -58,7 +62,9 @@ export namespace std {
// [range.refinements], other range refinements
using std::ranges::bidirectional_range;
using std::ranges::common_range;
- // using std::ranges::constant_range;
+#if _LIBCPP_STD_VER >= 23
+ using std::ranges::constant_range;
+#endif
using std::ranges::contiguous_range;
using std::ranges::forward_range;
using std::ranges::input_range;
>From e67774a55c64b8e971fec912e8a0adfbc105f380 Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Mon, 5 Aug 2024 12:11:42 +0200
Subject: [PATCH 07/16] add testing for cbegin, fix bug with rvalues
---
libcxx/include/__ranges/const_access.h | 12 +-
.../std/ranges/range.access/cbegin.pass.cpp | 204 ++++++++++++++++++
.../std/ranges/range.access/cbegin.verify.cpp | 25 +++
.../std/ranges/range.access/cend.pass.cpp | 204 ++++++++++++++++++
.../std/ranges/range.access/cend.verify.cpp | 25 +++
5 files changed, 464 insertions(+), 6 deletions(-)
create mode 100644 libcxx/test/std/ranges/range.access/cbegin.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.access/cbegin.verify.cpp
create mode 100644 libcxx/test/std/ranges/range.access/cend.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.access/cend.verify.cpp
diff --git a/libcxx/include/__ranges/const_access.h b/libcxx/include/__ranges/const_access.h
index df2811839bc46..0bdc5c6801e30 100644
--- a/libcxx/include/__ranges/const_access.h
+++ b/libcxx/include/__ranges/const_access.h
@@ -33,7 +33,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
# if _LIBCPP_STD_VER >= 23
namespace ranges {
template <input_range _Rp>
-constexpr auto& __possibly_const_range(_Rp& __rng) {
+constexpr auto& __possibly_const_range(_Rp& __rng) noexcept {
if constexpr (constant_range<const _Rp> && !constant_range<_Rp>) {
return const_cast<const _Rp&>(__rng);
} else {
@@ -53,12 +53,12 @@ namespace __cbegin {
struct __fn {
# if _LIBCPP_STD_VER >= 23
template <class _Rng>
- using _UType = decltype(ranges::begin(ranges::__possibly_const_range(std::declval<_Rng>())));
+ using _UType = decltype(ranges::begin(ranges::__possibly_const_range(std::declval<_Rng&>())));
template <__const_accessible_range _Rng>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
operator()(_Rng&& __rng) noexcept(noexcept(const_iterator<_UType<_Rng>>(
- ranges::begin(ranges::__possibly_const_range(std::declval<_Rng>()))))) -> const_iterator<_UType<_Rng>> {
+ ranges::begin(ranges::__possibly_const_range(__rng))))) -> const_iterator<_UType<_Rng>> {
return const_iterator<_UType<_Rng>>(ranges::begin(ranges::__possibly_const_range(__rng)));
}
# else // ^^^ _LIBCPP_STD_VER >= 23 / _LIBCPP_STD_VER < 23 vvv
@@ -92,7 +92,7 @@ namespace __cend {
struct __fn {
# if _LIBCPP_STD_VER >= 23
template <class _Rng>
- using _UType = decltype(ranges::end(ranges::__possibly_const_range(std::declval<_Rng>())));
+ using _UType = decltype(ranges::end(ranges::__possibly_const_range(std::declval<_Rng&>())));
template <__const_accessible_range _Rng>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
@@ -130,7 +130,7 @@ namespace __crbegin {
struct __fn {
# if _LIBCPP_STD_VER >= 23
template <class _Rng>
- using _UType = decltype(ranges::rbegin(ranges::__possibly_const_range(std::declval<_Rng>())));
+ using _UType = decltype(ranges::rbegin(ranges::__possibly_const_range(std::declval<_Rng&>())));
template <__const_accessible_range _Rng>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
@@ -169,7 +169,7 @@ namespace __crend {
struct __fn {
# if _LIBCPP_STD_VER >= 23
template <class _Rng>
- using _UType = decltype(ranges::rend(ranges::__possibly_const_range(std::declval<_Rng>())));
+ using _UType = decltype(ranges::rend(ranges::__possibly_const_range(std::declval<_Rng&>())));
template <__const_accessible_range _Rng>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
diff --git a/libcxx/test/std/ranges/range.access/cbegin.pass.cpp b/libcxx/test/std/ranges/range.access/cbegin.pass.cpp
new file mode 100644
index 0000000000000..635d9211e8392
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/cbegin.pass.cpp
@@ -0,0 +1,204 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++20
+
+// std::ranges::cbegin
+// std::ranges::crbegin
+
+#include <ranges>
+
+#include <cassert>
+#include <utility>
+#include "almost_satisfies_types.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+using RangeCBeginT = decltype(std::ranges::cbegin);
+using RangeCRBeginT = decltype(std::ranges::crbegin);
+
+static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[10]>);
+static_assert( std::is_invocable_v<RangeCBeginT, int (&)[10]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, int (&)[]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[10]>);
+static_assert( std::is_invocable_v<RangeCRBeginT, int (&)[10]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, int (&)[]>);
+
+static_assert(!std::is_invocable_v<RangeCBeginT, InputRangeNotDerivedFrom>);
+static_assert(!std::is_invocable_v<RangeCBeginT, InputRangeNotIndirectlyReadable>);
+static_assert(!std::is_invocable_v<RangeCBeginT, InputRangeNotInputOrOutputIterator>);
+static_assert(!std::is_invocable_v<RangeCBeginT, InputRangeNotSentinelSemiregular>);
+static_assert(!std::is_invocable_v<RangeCBeginT, InputRangeNotSentinelEqualityComparableWith>);
+
+static_assert(!std::is_invocable_v<RangeCRBeginT, BidirectionalRangeNotDerivedFrom>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, BidirectionalRangeNotSentinelSemiregular>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, BidirectionalRangeNotSentinelWeaklyEqualityComparableWith>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, BidirectionalRangeNotDecrementable>);
+
+struct Incomplete;
+
+static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[10]>);
+
+static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[10]>);
+
+// This case is IFNDR; we handle it SFINAE-friendly.
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[]>);
+
+// This case is IFNDR; we handle it SFINAE-friendly.
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[10]>);
+
+struct NonborrowingRange {
+ int x;
+ constexpr const int *begin() const { return &x; }
+ constexpr const int *rbegin() const { return &x; }
+ constexpr const int *end() const { return &x; }
+ constexpr const int *rend() const { return &x; }
+};
+
+// Ensure that we can't call with rvalues with borrowing disabled.
+static_assert( std::is_invocable_v<RangeCBeginT, NonborrowingRange &>);
+static_assert(!std::is_invocable_v<RangeCBeginT, NonborrowingRange &&>);
+static_assert( std::is_invocable_v<RangeCBeginT, NonborrowingRange const&>);
+static_assert(!std::is_invocable_v<RangeCBeginT, NonborrowingRange const&&>);
+static_assert( std::is_invocable_v<RangeCRBeginT, NonborrowingRange &>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, NonborrowingRange &&>);
+static_assert( std::is_invocable_v<RangeCRBeginT, NonborrowingRange const&>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, NonborrowingRange const&&>);
+
+constexpr bool testReturnTypes() {
+ int* a[2];
+ int b[2][2];
+ struct PossiblyConstRange {
+ char*& begin();
+ char*& end();
+ const short*& begin() const;
+ const short*& end() const;
+ int*& rbegin();
+ int*& rend();
+ const long*& rbegin() const;
+ const long*& rend() const;
+ } c;
+ struct AlwaysConstRange {
+ const char*& begin();
+ const char*& end();
+ const short*& begin() const;
+ const short*& end() const;
+ const int*& rbegin();
+ const int*& rend();
+ const long*& rbegin() const;
+ const long*& rend() const;
+ } d;
+ struct NeverConstRange {
+ char*& begin();
+ char*& end();
+ short*& begin() const;
+ short& end() const;
+ int*& rbegin();
+ int*& rend();
+ long*& rbegin() const;
+ long*& rend() const;
+ } e;
+
+ static_assert(!std::ranges::constant_range<PossiblyConstRange>);
+ static_assert(std::ranges::constant_range<const PossiblyConstRange>);
+ static_assert(std::ranges::constant_range<AlwaysConstRange>);
+ static_assert(std::ranges::constant_range<const AlwaysConstRange>);
+ static_assert(!std::ranges::constant_range<NeverConstRange>);
+ static_assert(!std::ranges::constant_range<const NeverConstRange>);
+
+ ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(a)), int* const*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(b)), const int(*)[2]);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(c)), const short*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(d)), const char*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(e)), std::basic_const_iterator<char*>);
+
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(a)), std::reverse_iterator<int* const*>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(b)), std::reverse_iterator<const int(*)[2]>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(c)), const long*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(d)), const int*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(e)), std::basic_const_iterator<int*>);
+
+ return true;
+}
+
+constexpr bool testArray() {
+ int a[2];
+ int b[2][2];
+ NonborrowingRange c[2];
+
+ assert(std::ranges::cbegin(a) == a);
+ assert(std::ranges::cbegin(b) == b);
+ assert(std::ranges::cbegin(c) == c);
+
+ assert(std::ranges::crbegin(a).base() == a + 2);
+ assert(std::ranges::crbegin(b).base() == b + 2);
+ assert(std::ranges::crbegin(c).base() == c + 2);
+
+ return true;
+}
+
+struct BorrowingRange {
+ int *begin() const;
+ int *end() const;
+};
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowingRange> = true;
+
+static_assert(std::is_invocable_v<RangeCBeginT, BorrowingRange>);
+static_assert(std::is_invocable_v<RangeCBeginT, const BorrowingRange>);
+static_assert(std::is_invocable_v<RangeCBeginT, BorrowingRange&>);
+static_assert(std::is_invocable_v<RangeCBeginT, const BorrowingRange&>);
+static_assert(std::is_invocable_v<RangeCRBeginT, BorrowingRange>);
+static_assert(std::is_invocable_v<RangeCRBeginT, const BorrowingRange>);
+static_assert(std::is_invocable_v<RangeCRBeginT, BorrowingRange&>);
+static_assert(std::is_invocable_v<RangeCRBeginT, const BorrowingRange&>);
+
+struct NoThrowBeginThrowingEnd {
+ const int* begin() const noexcept;
+ const int* end() const;
+} ntbte;
+static_assert(noexcept(std::ranges::cbegin(ntbte)));
+static_assert(!noexcept(std::ranges::crbegin(ntbte)));
+
+struct ThrowingBeginNoThrowEnd {
+ const int* begin() const;
+ const int* end() const noexcept;
+} tbnte;
+static_assert(!noexcept(std::ranges::cbegin(tbnte)));
+static_assert(noexcept(std::ranges::crbegin(tbnte)));
+
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
+static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*&>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*&>);
+
+int main(int, char**) {
+ static_assert(testReturnTypes());
+
+ testArray();
+ static_assert(testArray());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.access/cbegin.verify.cpp b/libcxx/test/std/ranges/range.access/cbegin.verify.cpp
new file mode 100644
index 0000000000000..18ac8ae65e338
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/cbegin.verify.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, c++20
+
+// std::ranges::cbegin
+
+#include <ranges>
+
+struct NonBorrowedRange {
+ int* begin() const;
+ int* end() const;
+};
+static_assert(!std::ranges::enable_borrowed_range<NonBorrowedRange>);
+
+// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::cbegin` is ill-formed.
+void test() {
+ std::ranges::cbegin(NonBorrowedRange());
+ // expected-error-re at -1 {{{{no matching function for call to object of type 'const (std::ranges::)?__cbegin::__fn'}}}}
+}
diff --git a/libcxx/test/std/ranges/range.access/cend.pass.cpp b/libcxx/test/std/ranges/range.access/cend.pass.cpp
new file mode 100644
index 0000000000000..366a301c8feb3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/cend.pass.cpp
@@ -0,0 +1,204 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++20
+
+// std::ranges::cend
+// std::ranges::crend
+
+#include <ranges>
+
+#include <cassert>
+#include <utility>
+#include "almost_satisfies_types.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+using RangeCEndT = decltype(std::ranges::cend);
+using RangeCREndT = decltype(std::ranges::crend);
+
+static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[10]>);
+static_assert( std::is_invocable_v<RangeCEndT, int (&)[10]>);
+static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCEndT, int (&)[]>);
+static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[10]>);
+static_assert( std::is_invocable_v<RangeCREndT, int (&)[10]>);
+static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCREndT, int (&)[]>);
+
+static_assert(!std::is_invocable_v<RangeCEndT, InputRangeNotDerivedFrom>);
+static_assert(!std::is_invocable_v<RangeCEndT, InputRangeNotIndirectlyReadable>);
+static_assert(!std::is_invocable_v<RangeCEndT, InputRangeNotInputOrOutputIterator>);
+static_assert(!std::is_invocable_v<RangeCEndT, InputRangeNotSentinelSemiregular>);
+static_assert(!std::is_invocable_v<RangeCEndT, InputRangeNotSentinelEqualityComparableWith>);
+
+static_assert(!std::is_invocable_v<RangeCREndT, BidirectionalRangeNotDerivedFrom>);
+static_assert(!std::is_invocable_v<RangeCREndT, BidirectionalRangeNotSentinelSemiregular>);
+static_assert(!std::is_invocable_v<RangeCREndT, BidirectionalRangeNotSentinelWeaklyEqualityComparableWith>);
+static_assert(!std::is_invocable_v<RangeCREndT, BidirectionalRangeNotDecrementable>);
+
+struct Incomplete;
+
+static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>);
+static_assert(!std::is_invocable_v<RangeCEndT, const Incomplete (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCEndT, const Incomplete(&&)[10]>);
+
+static_assert(!std::is_invocable_v<RangeCREndT, Incomplete (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCREndT, const Incomplete (&&)[]>);
+static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCREndT, const Incomplete(&&)[10]>);
+
+// This case is IFNDR; we handle it SFINAE-friendly.
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, const Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, const Incomplete(&)[]>);
+
+// This case is IFNDR; we handle it SFINAE-friendly.
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, const Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, const Incomplete(&)[10]>);
+
+struct NonborrowingRange {
+ int x;
+ constexpr const int *begin() const { return &x; }
+ constexpr const int *rbegin() const { return &x; }
+ constexpr const int *end() const { return &x; }
+ constexpr const int *rend() const { return &x; }
+};
+
+// Ensure that we can't call with rvalues with borrowing disabled.
+static_assert( std::is_invocable_v<RangeCEndT, NonborrowingRange &>);
+static_assert(!std::is_invocable_v<RangeCEndT, NonborrowingRange &&>);
+static_assert( std::is_invocable_v<RangeCEndT, NonborrowingRange const&>);
+static_assert(!std::is_invocable_v<RangeCEndT, NonborrowingRange const&&>);
+static_assert( std::is_invocable_v<RangeCREndT, NonborrowingRange &>);
+static_assert(!std::is_invocable_v<RangeCREndT, NonborrowingRange &&>);
+static_assert( std::is_invocable_v<RangeCREndT, NonborrowingRange const&>);
+static_assert(!std::is_invocable_v<RangeCREndT, NonborrowingRange const&&>);
+
+constexpr bool testReturnTypes() {
+ int* a[2];
+ int b[2][2];
+ struct PossiblyConstRange {
+ char*& begin();
+ char*& end();
+ const short*& begin() const;
+ const short*& end() const;
+ int*& rbegin();
+ int*& rend();
+ const long*& rbegin() const;
+ const long*& rend() const;
+ } c;
+ struct AlwaysConstRange {
+ const char*& begin();
+ const char*& end();
+ const short*& begin() const;
+ const short*& end() const;
+ const int*& rbegin();
+ const int*& rend();
+ const long*& rbegin() const;
+ const long*& rend() const;
+ } d;
+ struct NeverConstRange {
+ char*& begin();
+ char*& end();
+ short*& begin() const;
+ short& end() const;
+ int*& rbegin();
+ int*& rend();
+ long*& rbegin() const;
+ long*& rend() const;
+ } e;
+
+ static_assert(!std::ranges::constant_range<PossiblyConstRange>);
+ static_assert(std::ranges::constant_range<const PossiblyConstRange>);
+ static_assert(std::ranges::constant_range<AlwaysConstRange>);
+ static_assert(std::ranges::constant_range<const AlwaysConstRange>);
+ static_assert(!std::ranges::constant_range<NeverConstRange>);
+ static_assert(!std::ranges::constant_range<const NeverConstRange>);
+
+ ASSERT_SAME_TYPE(decltype(std::ranges::cend(a)), int* const*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cend(b)), const int(*)[2]);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cend(c)), const short*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cend(d)), const char*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::cend(e)), std::basic_const_iterator<char*>);
+
+ ASSERT_SAME_TYPE(decltype(std::ranges::crend(a)), std::reverse_iterator<int* const*>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crend(b)), std::reverse_iterator<const int(*)[2]>);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crend(c)), const long*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crend(d)), const int*);
+ ASSERT_SAME_TYPE(decltype(std::ranges::crend(e)), std::basic_const_iterator<int*>);
+
+ return true;
+}
+
+constexpr bool testArray() {
+ int a[2];
+ int b[2][2];
+ NonborrowingRange c[2];
+
+ assert(std::ranges::cend(a) == a + 2);
+ assert(std::ranges::cend(b) == b + 2);
+ assert(std::ranges::cend(c) == c + 2);
+
+ assert(std::ranges::crend(a).base() == a);
+ assert(std::ranges::crend(b).base() == b);
+ assert(std::ranges::crend(c).base() == c);
+
+ return true;
+}
+
+struct BorrowingRange {
+ int *begin() const;
+ int *end() const;
+};
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowingRange> = true;
+
+static_assert(std::is_invocable_v<RangeCEndT, BorrowingRange>);
+static_assert(std::is_invocable_v<RangeCEndT, const BorrowingRange>);
+static_assert(std::is_invocable_v<RangeCEndT, BorrowingRange&>);
+static_assert(std::is_invocable_v<RangeCEndT, const BorrowingRange&>);
+static_assert(std::is_invocable_v<RangeCREndT, BorrowingRange>);
+static_assert(std::is_invocable_v<RangeCREndT, const BorrowingRange>);
+static_assert(std::is_invocable_v<RangeCREndT, BorrowingRange&>);
+static_assert(std::is_invocable_v<RangeCREndT, const BorrowingRange&>);
+
+struct NoThrowEndThrowingEnd {
+ const int* begin() const noexcept;
+ const int* end() const;
+} ntbte;
+static_assert(!noexcept(std::ranges::cend(ntbte)));
+static_assert(noexcept(std::ranges::crend(ntbte)));
+
+struct ThrowingEndNoThrowEnd {
+ const int* begin() const;
+ const int* end() const noexcept;
+} tbnte;
+static_assert(noexcept(std::ranges::cend(tbnte)));
+static_assert(!noexcept(std::ranges::crend(tbnte)));
+
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);
+static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>);
+static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*>);
+static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*&>);
+
+int main(int, char**) {
+ static_assert(testReturnTypes());
+
+ testArray();
+ static_assert(testArray());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.access/cend.verify.cpp b/libcxx/test/std/ranges/range.access/cend.verify.cpp
new file mode 100644
index 0000000000000..e50b90b4fbd49
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/cend.verify.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, c++20
+
+// std::ranges::cend
+
+#include <ranges>
+
+struct NonBorrowedRange {
+ int* begin() const;
+ int* end() const;
+};
+static_assert(!std::ranges::enable_borrowed_range<NonBorrowedRange>);
+
+// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::cend` is ill-formed.
+void test() {
+ std::ranges::cend(NonBorrowedRange());
+ // expected-error-re at -1 {{{{no matching function for call to object of type 'const (std::ranges::)?__cend::__fn'}}}}
+}
>From df70dfbb65935eb9875313c0de73a99331eedeb5 Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Mon, 5 Aug 2024 13:33:56 +0200
Subject: [PATCH 08/16] more bugfixing, and tests for basic_const_iterator
---
libcxx/include/__iterator/const_iterator.h | 31 ++--
.../iterators/const.iterators/alias.pass.cpp | 34 +++++
.../const.iterators/iterator.pass.cpp | 141 ++++++++++++++++++
3 files changed, 196 insertions(+), 10 deletions(-)
create mode 100644 libcxx/test/std/iterators/const.iterators/alias.pass.cpp
create mode 100644 libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
diff --git a/libcxx/include/__iterator/const_iterator.h b/libcxx/include/__iterator/const_iterator.h
index 4ad37345cd887..495cba78f12b5 100644
--- a/libcxx/include/__iterator/const_iterator.h
+++ b/libcxx/include/__iterator/const_iterator.h
@@ -54,8 +54,19 @@ class basic_const_iterator;
template <input_iterator _Iter>
using const_iterator = conditional_t<__constant_iterator<_Iter>, _Iter, basic_const_iterator<_Iter>>;
+
+// This doesn't use `conditional_t` to avoid instantiating const_iterator<_Sent> when _Sent is not an input_iterator.
+template <class _Sent>
+struct __const_sentinel_impl {
+ using type = _Sent;
+};
+template <class _Sent>
+ requires input_iterator<_Sent>
+struct __const_sentinel_impl<_Sent> {
+ using type = const_iterator<_Sent>;
+};
template <semiregular _Sent>
-using const_sentinel = conditional_t<input_iterator<_Sent>, const_iterator<_Sent>, _Sent>;
+using const_sentinel = __const_sentinel_impl<_Sent>::type;
template <class _Iter>
concept __not_a_const_iterator = !__is_specialization_v<_Iter, basic_const_iterator>;
@@ -84,11 +95,11 @@ template <class _Iter>
struct __basic_const_iterator_category : __basic_const_iterator_concept<_Iter> {};
template <forward_iterator _Iter>
struct __basic_const_iterator_category<_Iter> : __basic_const_iterator_concept<_Iter> {
- using iterator_category = __basic_const_iterator_concept<_Iter>::iterator_concept;
+ using iterator_category = std::iterator_traits<_Iter>::iterator_category;
};
template <input_iterator _Iter>
-class _LIBCPP_TEMPLATE_VIS basic_const_iterator : __basic_const_iterator_category<_Iter> {
+class _LIBCPP_TEMPLATE_VIS basic_const_iterator : public __basic_const_iterator_category<_Iter> {
_Iter __current = _Iter();
using __reference = iter_const_reference_t<_Iter>;
@@ -217,32 +228,32 @@ class _LIBCPP_TEMPLATE_VIS basic_const_iterator : __basic_const_iterator_categor
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Iter2& __rhs) const
requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
{
- return __current < __rhs.__current;
+ return __current < __rhs;
}
template <__different_from<basic_const_iterator> _Iter2>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Iter2& __rhs) const
requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
{
- return __current > __rhs.__current;
+ return __current > __rhs;
}
template <__different_from<basic_const_iterator> _Iter2>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Iter2& __rhs) const
requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
{
- return __current <= __rhs.__current;
+ return __current <= __rhs;
}
template <__different_from<basic_const_iterator> _Iter2>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Iter2& __rhs) const
requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2>
{
- return __current >= __rhs.__current;
+ return __current >= __rhs;
}
template <__different_from<basic_const_iterator> _Iter2>
_LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const _Iter2& __rhs) const
requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Iter2> &&
three_way_comparable_with<_Iter, _Iter2>
{
- return __current <=> __rhs.__current;
+ return __current <=> __rhs;
}
template <__not_a_const_iterator _Iter2>
@@ -301,8 +312,8 @@ class _LIBCPP_TEMPLATE_VIS basic_const_iterator : __basic_const_iterator_categor
}
friend _LIBCPP_HIDE_FROM_ABI constexpr __rvalue_reference iter_move(const basic_const_iterator& __it) noexcept(
- noexcept(static_cast<__rvalue_reference>(ranges::iter_move(__it.current_)))) {
- return static_cast<__rvalue_reference>(ranges::iter_move(__it.current_));
+ noexcept(static_cast<__rvalue_reference>(ranges::iter_move(__it.__current)))) {
+ return static_cast<__rvalue_reference>(ranges::iter_move(__it.__current));
}
};
diff --git a/libcxx/test/std/iterators/const.iterators/alias.pass.cpp b/libcxx/test/std/iterators/const.iterators/alias.pass.cpp
new file mode 100644
index 0000000000000..461f21ab3b586
--- /dev/null
+++ b/libcxx/test/std/iterators/const.iterators/alias.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++20
+
+// std::const_iterator
+
+#include <iterator>
+#include <list>
+#include <ranges>
+#include "test_macros.h"
+
+ASSERT_SAME_TYPE(std::const_iterator<int*>, std::basic_const_iterator<int*>);
+ASSERT_SAME_TYPE(std::const_iterator<const int*>, const int*);
+ASSERT_SAME_TYPE(std::const_sentinel<int*>, std::basic_const_iterator<int*>);
+ASSERT_SAME_TYPE(std::const_sentinel<const int*>, const int*);
+ASSERT_SAME_TYPE(std::const_sentinel<std::default_sentinel_t>, std::default_sentinel_t);
+
+using list_iterator = std::list<int>::iterator;
+using list_const_iterator = std::list<int>::const_iterator;
+
+ASSERT_SAME_TYPE(std::const_iterator<list_iterator>, std::basic_const_iterator<list_iterator>);
+ASSERT_SAME_TYPE(std::const_iterator<list_const_iterator>, list_const_iterator);
+ASSERT_SAME_TYPE(std::const_sentinel<list_iterator>, std::basic_const_iterator<list_iterator>);
+ASSERT_SAME_TYPE(std::const_sentinel<list_const_iterator>, list_const_iterator);
+
+int main() {
+ return 0;
+}
diff --git a/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp b/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
new file mode 100644
index 0000000000000..344db90f0deb7
--- /dev/null
+++ b/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
@@ -0,0 +1,141 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++20
+
+// std::basic_const_iterator
+
+#include <iterator>
+#include <list>
+#include <ranges>
+#include <vector>
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "type_algorithms.h"
+
+template <class T>
+concept has_iterator_category = requires {
+ typename T::iterator_category;
+};
+
+template <class It>
+constexpr bool check_category_and_concept() {
+ using ConstIt = std::basic_const_iterator<It>;
+
+ if constexpr (std::contiguous_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::contiguous_iterator_tag);
+ static_assert(std::contiguous_iterator<ConstIt>);
+ } else if constexpr (std::random_access_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::random_access_iterator_tag);
+ static_assert(!std::contiguous_iterator<ConstIt>);
+ static_assert(std::random_access_iterator<ConstIt>);
+ } else if constexpr (std::bidirectional_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::bidirectional_iterator_tag);
+ static_assert(!std::random_access_iterator<ConstIt>);
+ static_assert(std::bidirectional_iterator<ConstIt>);
+ } else if constexpr (std::forward_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::forward_iterator_tag);
+ static_assert(!std::bidirectional_iterator<ConstIt>);
+ static_assert(std::forward_iterator<ConstIt>);
+ } else {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::input_iterator_tag);
+ static_assert(!std::forward_iterator<ConstIt>);
+ static_assert(std::input_iterator<ConstIt>);
+ }
+
+ if constexpr (std::forward_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_category, typename std::iterator_traits<It>::iterator_category);
+ } else {
+ static_assert(!has_iterator_category<ConstIt>);
+ }
+
+ return true;
+}
+
+constexpr bool test_p2836r1() {
+ auto f = [](std::vector<int>::const_iterator) {};
+
+ auto v = std::vector<int>();
+ {
+ auto i1 = std::ranges::cbegin(v);
+ f(i1);
+ }
+
+ auto t = v | std::views::take_while([](int const x) { return x < 100; });
+ {
+ auto i2 = std::ranges::cbegin(t);
+ f(i2);
+ }
+
+ return true;
+}
+
+constexpr bool test_basic_operations() {
+ struct S {
+ int x;
+ };
+ S arr[10] = {};
+ std::basic_const_iterator<S*> first = arr;
+ std::basic_const_iterator<S*> last = arr + 10;
+
+ for (auto it = first; it != last; ++it) {
+ (void)*it;
+ (void)it->x;
+ (void)iter_move(it);
+ }
+ static_assert(!std::is_invocable_v<decltype(std::ranges::iter_swap), decltype(first), decltype(first)>);
+
+ assert(++first == arr + 1);
+ assert(--first == arr);
+ assert(first++ == arr);
+ assert(first-- == arr + 1);
+
+ assert(first + 3 == arr + 3);
+ assert(last - 1 == arr + 9);
+
+ first += 3;
+ assert(first == arr + 3);
+ first -= 2;
+ assert(first == arr + 1);
+ --first;
+
+ assert(first < last);
+ assert(last > first);
+ assert(first <= last);
+ assert(last >= first);
+
+ assert(first < arr + 1);
+ assert(arr + 1 > first);
+ assert(first <= arr + 1);
+ assert(arr + 1 >= first);
+
+ assert((first <=> last) < 0);
+ assert((first <=> arr + 1) < 0);
+ assert((arr + 1 <=> first) > 0);
+
+ return true;
+}
+
+int main() {
+ types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class It>() {
+ using ConstIt = std::basic_const_iterator<It>;
+ ASSERT_SAME_TYPE(typename ConstIt::value_type, int);
+ static_assert(check_category_and_concept<It>());
+
+ ASSERT_SAME_TYPE(std::iter_reference_t<ConstIt>, const int&);
+ ASSERT_SAME_TYPE(std::iter_rvalue_reference_t<ConstIt>, const int&&);
+ });
+
+ test_p2836r1();
+ static_assert(test_p2836r1());
+
+ test_basic_operations();
+ static_assert(test_basic_operations());
+
+ return 0;
+}
>From d309c27003b2045ee3cd1e395afa1397698f408d Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Mon, 5 Aug 2024 14:20:07 +0200
Subject: [PATCH 09/16] modify view_interface and add testing
As a drive-by, fix some includes that would have been circular.
---
.../include/__algorithm/ranges_reverse_copy.h | 10 +++++++++-
libcxx/include/__iterator/reverse_iterator.h | 13 ------------
libcxx/include/__ranges/view_interface.h | 14 +++++++++++++
.../view.interface/view.interface.pass.cpp | 20 ++++++++++++++++++-
4 files changed, 42 insertions(+), 15 deletions(-)
diff --git a/libcxx/include/__algorithm/ranges_reverse_copy.h b/libcxx/include/__algorithm/ranges_reverse_copy.h
index e5ca5cf652dc4..7efb6df3a8b57 100644
--- a/libcxx/include/__algorithm/ranges_reverse_copy.h
+++ b/libcxx/include/__algorithm/ranges_reverse_copy.h
@@ -34,6 +34,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
+template <ranges::bidirectional_range _Range>
+_LIBCPP_HIDE_FROM_ABI constexpr ranges::subrange<reverse_iterator<ranges::iterator_t<_Range>>,
+ reverse_iterator<ranges::iterator_t<_Range>>>
+__reverse_range(_Range&& __range) {
+ auto __first = ranges::begin(__range);
+ return {std::make_reverse_iterator(ranges::next(__first, ranges::end(__range))), std::make_reverse_iterator(__first)};
+}
+
template <class _InIter, class _OutIter>
using reverse_copy_result = in_out_result<_InIter, _OutIter>;
@@ -49,7 +57,7 @@ struct __reverse_copy {
requires indirectly_copyable<iterator_t<_Range>, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr reverse_copy_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range, _OutIter __result) const {
- auto __ret = ranges::copy(std::__reverse_range(__range), std::move(__result));
+ auto __ret = ranges::copy(std::ranges::__reverse_range(__range), std::move(__result));
return {ranges::next(ranges::begin(__range), ranges::end(__range)), std::move(__ret.out)};
}
};
diff --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h
index 50c0f21eaa286..823203cadf7e1 100644
--- a/libcxx/include/__iterator/reverse_iterator.h
+++ b/libcxx/include/__iterator/reverse_iterator.h
@@ -27,9 +27,6 @@
#include <__iterator/readable_traits.h>
#include <__iterator/segmented_iterator.h>
#include <__memory/addressof.h>
-#include <__ranges/access.h>
-#include <__ranges/concepts.h>
-#include <__ranges/subrange.h>
#include <__type_traits/conditional.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_assignable.h>
@@ -315,16 +312,6 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator<_Ite
}
#endif
-#if _LIBCPP_STD_VER >= 20
-template <ranges::bidirectional_range _Range>
-_LIBCPP_HIDE_FROM_ABI constexpr ranges::subrange<reverse_iterator<ranges::iterator_t<_Range>>,
- reverse_iterator<ranges::iterator_t<_Range>>>
-__reverse_range(_Range&& __range) {
- auto __first = ranges::begin(__range);
- return {std::make_reverse_iterator(ranges::next(__first, ranges::end(__range))), std::make_reverse_iterator(__first)};
-}
-#endif
-
template <class _Iter, bool __b>
struct __unwrap_iter_impl<reverse_iterator<reverse_iterator<_Iter> >, __b> {
using _UnwrappedIter = decltype(__unwrap_iter_impl<_Iter>::__unwrap(std::declval<_Iter>()));
diff --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h
index 3bcfbaf3a2f9e..d8ec70dd333e5 100644
--- a/libcxx/include/__ranges/view_interface.h
+++ b/libcxx/include/__ranges/view_interface.h
@@ -20,6 +20,7 @@
#include <__memory/pointer_traits.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
+#include <__ranges/const_access.h>
#include <__ranges/empty.h>
#include <__ranges/size.h>
#include <__type_traits/is_class.h>
@@ -72,6 +73,19 @@ class view_interface {
}
}
+ constexpr auto cbegin() requires input_range<_Derived> {
+ return ranges::cbegin(__derived());
+ }
+ constexpr auto cbegin() const requires input_range<const _Derived> {
+ return ranges::cbegin(__derived());
+ }
+ constexpr auto cend() requires input_range<_Derived> {
+ return ranges::cend(__derived());
+ }
+ constexpr auto cend() const requires input_range<const _Derived> {
+ return ranges::cend(__derived());
+ }
+
template <class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool()
requires requires(_D2& __t) { ranges::empty(__t); }
diff --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
index 3f7c174d3fe48..9db012fe07e70 100644
--- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
@@ -35,8 +35,15 @@ using InputIter = cpp20_input_iterator<const int*>;
struct InputRange : std::ranges::view_interface<InputRange> {
int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+
constexpr InputIter begin() const { return InputIter(buff); }
- constexpr InputIter end() const { return InputIter(buff + 8); }
+ constexpr sentinel_wrapper<InputIter> end() const { return sentinel_wrapper(InputIter(buff + 8)); }
+};
+
+struct NonConstInputRange : std::ranges::view_interface<NonConstInputRange> {
+ int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+ constexpr InputIter begin() { return InputIter(buff); }
+ constexpr sentinel_wrapper<InputIter> end() { return sentinel_wrapper(InputIter(buff + 8)); }
};
struct SizedInputRange : std::ranges::view_interface<SizedInputRange> {
@@ -222,6 +229,17 @@ constexpr bool testEmpty() {
return true;
}
+template <class T>
+concept ConstAccessorsInvocable = requires (T& t) {
+ t.cbegin();
+ t.cend();
+};
+
+static_assert(ConstAccessorsInvocable<InputRange>);
+static_assert(ConstAccessorsInvocable<const InputRange>);
+static_assert(ConstAccessorsInvocable<NonConstInputRange>);
+static_assert(!ConstAccessorsInvocable<const NonConstInputRange>);
+
template<class T>
concept DataInvocable = requires (T const& obj) { obj.data(); };
>From 18300464e0daecb4cceab541260ab7b1befc54ea Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Mon, 5 Aug 2024 14:26:32 +0200
Subject: [PATCH 10/16] run a formatting pass
---
libcxx/include/__ranges/view_interface.h | 16 +-
.../iterators/const.iterators/alias.pass.cpp | 6 +-
.../const.iterators/iterator.pass.cpp | 198 +++++++++---------
.../std/ranges/range.access/cbegin.pass.cpp | 63 +++---
.../std/ranges/range.access/cend.pass.cpp | 63 +++---
.../view.interface/view.interface.pass.cpp | 2 +-
6 files changed, 179 insertions(+), 169 deletions(-)
diff --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h
index d8ec70dd333e5..2dd5029f4499f 100644
--- a/libcxx/include/__ranges/view_interface.h
+++ b/libcxx/include/__ranges/view_interface.h
@@ -73,16 +73,24 @@ class view_interface {
}
}
- constexpr auto cbegin() requires input_range<_Derived> {
+ constexpr auto cbegin()
+ requires input_range<_Derived>
+ {
return ranges::cbegin(__derived());
}
- constexpr auto cbegin() const requires input_range<const _Derived> {
+ constexpr auto cbegin() const
+ requires input_range<const _Derived>
+ {
return ranges::cbegin(__derived());
}
- constexpr auto cend() requires input_range<_Derived> {
+ constexpr auto cend()
+ requires input_range<_Derived>
+ {
return ranges::cend(__derived());
}
- constexpr auto cend() const requires input_range<const _Derived> {
+ constexpr auto cend() const
+ requires input_range<const _Derived>
+ {
return ranges::cend(__derived());
}
diff --git a/libcxx/test/std/iterators/const.iterators/alias.pass.cpp b/libcxx/test/std/iterators/const.iterators/alias.pass.cpp
index 461f21ab3b586..10c0665764cc8 100644
--- a/libcxx/test/std/iterators/const.iterators/alias.pass.cpp
+++ b/libcxx/test/std/iterators/const.iterators/alias.pass.cpp
@@ -21,7 +21,7 @@ ASSERT_SAME_TYPE(std::const_sentinel<int*>, std::basic_const_iterator<int*>);
ASSERT_SAME_TYPE(std::const_sentinel<const int*>, const int*);
ASSERT_SAME_TYPE(std::const_sentinel<std::default_sentinel_t>, std::default_sentinel_t);
-using list_iterator = std::list<int>::iterator;
+using list_iterator = std::list<int>::iterator;
using list_const_iterator = std::list<int>::const_iterator;
ASSERT_SAME_TYPE(std::const_iterator<list_iterator>, std::basic_const_iterator<list_iterator>);
@@ -29,6 +29,4 @@ ASSERT_SAME_TYPE(std::const_iterator<list_const_iterator>, list_const_iterator);
ASSERT_SAME_TYPE(std::const_sentinel<list_iterator>, std::basic_const_iterator<list_iterator>);
ASSERT_SAME_TYPE(std::const_sentinel<list_const_iterator>, list_const_iterator);
-int main() {
- return 0;
-}
+int main() { return 0; }
diff --git a/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp b/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
index 344db90f0deb7..0c35b3b93a631 100644
--- a/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
+++ b/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
@@ -19,123 +19,121 @@
#include "type_algorithms.h"
template <class T>
-concept has_iterator_category = requires {
- typename T::iterator_category;
-};
+concept has_iterator_category = requires { typename T::iterator_category; };
template <class It>
constexpr bool check_category_and_concept() {
- using ConstIt = std::basic_const_iterator<It>;
-
- if constexpr (std::contiguous_iterator<It>) {
- ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::contiguous_iterator_tag);
- static_assert(std::contiguous_iterator<ConstIt>);
- } else if constexpr (std::random_access_iterator<It>) {
- ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::random_access_iterator_tag);
- static_assert(!std::contiguous_iterator<ConstIt>);
- static_assert(std::random_access_iterator<ConstIt>);
- } else if constexpr (std::bidirectional_iterator<It>) {
- ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::bidirectional_iterator_tag);
- static_assert(!std::random_access_iterator<ConstIt>);
- static_assert(std::bidirectional_iterator<ConstIt>);
- } else if constexpr (std::forward_iterator<It>) {
- ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::forward_iterator_tag);
- static_assert(!std::bidirectional_iterator<ConstIt>);
- static_assert(std::forward_iterator<ConstIt>);
- } else {
- ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::input_iterator_tag);
- static_assert(!std::forward_iterator<ConstIt>);
- static_assert(std::input_iterator<ConstIt>);
- }
-
- if constexpr (std::forward_iterator<It>) {
- ASSERT_SAME_TYPE(typename ConstIt::iterator_category, typename std::iterator_traits<It>::iterator_category);
- } else {
- static_assert(!has_iterator_category<ConstIt>);
- }
-
- return true;
+ using ConstIt = std::basic_const_iterator<It>;
+
+ if constexpr (std::contiguous_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::contiguous_iterator_tag);
+ static_assert(std::contiguous_iterator<ConstIt>);
+ } else if constexpr (std::random_access_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::random_access_iterator_tag);
+ static_assert(!std::contiguous_iterator<ConstIt>);
+ static_assert(std::random_access_iterator<ConstIt>);
+ } else if constexpr (std::bidirectional_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::bidirectional_iterator_tag);
+ static_assert(!std::random_access_iterator<ConstIt>);
+ static_assert(std::bidirectional_iterator<ConstIt>);
+ } else if constexpr (std::forward_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::forward_iterator_tag);
+ static_assert(!std::bidirectional_iterator<ConstIt>);
+ static_assert(std::forward_iterator<ConstIt>);
+ } else {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_concept, std::input_iterator_tag);
+ static_assert(!std::forward_iterator<ConstIt>);
+ static_assert(std::input_iterator<ConstIt>);
+ }
+
+ if constexpr (std::forward_iterator<It>) {
+ ASSERT_SAME_TYPE(typename ConstIt::iterator_category, typename std::iterator_traits<It>::iterator_category);
+ } else {
+ static_assert(!has_iterator_category<ConstIt>);
+ }
+
+ return true;
}
constexpr bool test_p2836r1() {
- auto f = [](std::vector<int>::const_iterator) {};
+ auto f = [](std::vector<int>::const_iterator) {};
- auto v = std::vector<int>();
- {
- auto i1 = std::ranges::cbegin(v);
- f(i1);
- }
+ auto v = std::vector<int>();
+ {
+ auto i1 = std::ranges::cbegin(v);
+ f(i1);
+ }
- auto t = v | std::views::take_while([](int const x) { return x < 100; });
- {
- auto i2 = std::ranges::cbegin(t);
- f(i2);
- }
+ auto t = v | std::views::take_while([](int const x) { return x < 100; });
+ {
+ auto i2 = std::ranges::cbegin(t);
+ f(i2);
+ }
- return true;
+ return true;
}
constexpr bool test_basic_operations() {
- struct S {
- int x;
- };
- S arr[10] = {};
- std::basic_const_iterator<S*> first = arr;
- std::basic_const_iterator<S*> last = arr + 10;
-
- for (auto it = first; it != last; ++it) {
- (void)*it;
- (void)it->x;
- (void)iter_move(it);
- }
- static_assert(!std::is_invocable_v<decltype(std::ranges::iter_swap), decltype(first), decltype(first)>);
-
- assert(++first == arr + 1);
- assert(--first == arr);
- assert(first++ == arr);
- assert(first-- == arr + 1);
-
- assert(first + 3 == arr + 3);
- assert(last - 1 == arr + 9);
-
- first += 3;
- assert(first == arr + 3);
- first -= 2;
- assert(first == arr + 1);
- --first;
-
- assert(first < last);
- assert(last > first);
- assert(first <= last);
- assert(last >= first);
-
- assert(first < arr + 1);
- assert(arr + 1 > first);
- assert(first <= arr + 1);
- assert(arr + 1 >= first);
-
- assert((first <=> last) < 0);
- assert((first <=> arr + 1) < 0);
- assert((arr + 1 <=> first) > 0);
-
- return true;
+ struct S {
+ int x;
+ };
+ S arr[10] = {};
+ std::basic_const_iterator<S*> first = arr;
+ std::basic_const_iterator<S*> last = arr + 10;
+
+ for (auto it = first; it != last; ++it) {
+ (void)*it;
+ (void)it->x;
+ (void)iter_move(it);
+ }
+ static_assert(!std::is_invocable_v<decltype(std::ranges::iter_swap), decltype(first), decltype(first)>);
+
+ assert(++first == arr + 1);
+ assert(--first == arr);
+ assert(first++ == arr);
+ assert(first-- == arr + 1);
+
+ assert(first + 3 == arr + 3);
+ assert(last - 1 == arr + 9);
+
+ first += 3;
+ assert(first == arr + 3);
+ first -= 2;
+ assert(first == arr + 1);
+ --first;
+
+ assert(first < last);
+ assert(last > first);
+ assert(first <= last);
+ assert(last >= first);
+
+ assert(first < arr + 1);
+ assert(arr + 1 > first);
+ assert(first <= arr + 1);
+ assert(arr + 1 >= first);
+
+ assert((first <=> last) < 0);
+ assert((first <=> arr + 1) < 0);
+ assert((arr + 1 <=> first) > 0);
+
+ return true;
}
int main() {
- types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class It>() {
- using ConstIt = std::basic_const_iterator<It>;
- ASSERT_SAME_TYPE(typename ConstIt::value_type, int);
- static_assert(check_category_and_concept<It>());
+ types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class It>() {
+ using ConstIt = std::basic_const_iterator<It>;
+ ASSERT_SAME_TYPE(typename ConstIt::value_type, int);
+ static_assert(check_category_and_concept<It>());
- ASSERT_SAME_TYPE(std::iter_reference_t<ConstIt>, const int&);
- ASSERT_SAME_TYPE(std::iter_rvalue_reference_t<ConstIt>, const int&&);
- });
+ ASSERT_SAME_TYPE(std::iter_reference_t<ConstIt>, const int&);
+ ASSERT_SAME_TYPE(std::iter_rvalue_reference_t<ConstIt>, const int&&);
+ });
- test_p2836r1();
- static_assert(test_p2836r1());
+ test_p2836r1();
+ static_assert(test_p2836r1());
- test_basic_operations();
- static_assert(test_basic_operations());
+ test_basic_operations();
+ static_assert(test_basic_operations());
- return 0;
+ return 0;
}
diff --git a/libcxx/test/std/ranges/range.access/cbegin.pass.cpp b/libcxx/test/std/ranges/range.access/cbegin.pass.cpp
index 635d9211e8392..a2da7cdf3b6d3 100644
--- a/libcxx/test/std/ranges/range.access/cbegin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/cbegin.pass.cpp
@@ -19,15 +19,15 @@
#include "test_macros.h"
#include "test_iterators.h"
-using RangeCBeginT = decltype(std::ranges::cbegin);
+using RangeCBeginT = decltype(std::ranges::cbegin);
using RangeCRBeginT = decltype(std::ranges::crbegin);
static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[10]>);
-static_assert( std::is_invocable_v<RangeCBeginT, int (&)[10]>);
+static_assert(std::is_invocable_v<RangeCBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCBeginT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[10]>);
-static_assert( std::is_invocable_v<RangeCRBeginT, int (&)[10]>);
+static_assert(std::is_invocable_v<RangeCRBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&)[]>);
@@ -44,44 +44,44 @@ static_assert(!std::is_invocable_v<RangeCRBeginT, BidirectionalRangeNotDecrement
struct Incomplete;
-static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete (&&)[]>);
-static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[10]>);
-static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete (&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete (&&)[10]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete (&&)[]>);
-static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[10]>);
-static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete (&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete (&&)[10]>);
// This case is IFNDR; we handle it SFINAE-friendly.
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete (&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete (&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete (&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete (&)[]>);
// This case is IFNDR; we handle it SFINAE-friendly.
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[10]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[10]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[10]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete (&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete (&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete (&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete (&)[10]>);
struct NonborrowingRange {
int x;
- constexpr const int *begin() const { return &x; }
- constexpr const int *rbegin() const { return &x; }
- constexpr const int *end() const { return &x; }
- constexpr const int *rend() const { return &x; }
+ constexpr const int* begin() const { return &x; }
+ constexpr const int* rbegin() const { return &x; }
+ constexpr const int* end() const { return &x; }
+ constexpr const int* rend() const { return &x; }
};
// Ensure that we can't call with rvalues with borrowing disabled.
-static_assert( std::is_invocable_v<RangeCBeginT, NonborrowingRange &>);
-static_assert(!std::is_invocable_v<RangeCBeginT, NonborrowingRange &&>);
-static_assert( std::is_invocable_v<RangeCBeginT, NonborrowingRange const&>);
+static_assert(std::is_invocable_v<RangeCBeginT, NonborrowingRange&>);
+static_assert(!std::is_invocable_v<RangeCBeginT, NonborrowingRange&&>);
+static_assert(std::is_invocable_v<RangeCBeginT, NonborrowingRange const&>);
static_assert(!std::is_invocable_v<RangeCBeginT, NonborrowingRange const&&>);
-static_assert( std::is_invocable_v<RangeCRBeginT, NonborrowingRange &>);
-static_assert(!std::is_invocable_v<RangeCRBeginT, NonborrowingRange &&>);
-static_assert( std::is_invocable_v<RangeCRBeginT, NonborrowingRange const&>);
+static_assert(std::is_invocable_v<RangeCRBeginT, NonborrowingRange&>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, NonborrowingRange&&>);
+static_assert(std::is_invocable_v<RangeCRBeginT, NonborrowingRange const&>);
static_assert(!std::is_invocable_v<RangeCRBeginT, NonborrowingRange const&&>);
constexpr bool testReturnTypes() {
@@ -157,10 +157,10 @@ constexpr bool testArray() {
}
struct BorrowingRange {
- int *begin() const;
- int *end() const;
+ int* begin() const;
+ int* end() const;
};
-template<>
+template <>
inline constexpr bool std::ranges::enable_borrowed_range<BorrowingRange> = true;
static_assert(std::is_invocable_v<RangeCBeginT, BorrowingRange>);
@@ -188,7 +188,10 @@ static_assert(noexcept(std::ranges::crbegin(tbnte)));
// Test ADL-proofing.
struct Incomplete;
-template<class T> struct Holder { T t; };
+template <class T>
+struct Holder {
+ T t;
+};
static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*&>);
static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*>);
diff --git a/libcxx/test/std/ranges/range.access/cend.pass.cpp b/libcxx/test/std/ranges/range.access/cend.pass.cpp
index 366a301c8feb3..86cb8ac160eb3 100644
--- a/libcxx/test/std/ranges/range.access/cend.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/cend.pass.cpp
@@ -19,15 +19,15 @@
#include "test_macros.h"
#include "test_iterators.h"
-using RangeCEndT = decltype(std::ranges::cend);
+using RangeCEndT = decltype(std::ranges::cend);
using RangeCREndT = decltype(std::ranges::crend);
static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[10]>);
-static_assert( std::is_invocable_v<RangeCEndT, int (&)[10]>);
+static_assert(std::is_invocable_v<RangeCEndT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCEndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[10]>);
-static_assert( std::is_invocable_v<RangeCREndT, int (&)[10]>);
+static_assert(std::is_invocable_v<RangeCREndT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&)[]>);
@@ -44,44 +44,44 @@ static_assert(!std::is_invocable_v<RangeCREndT, BidirectionalRangeNotDecrementab
struct Incomplete;
-static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>);
+static_assert(!std::is_invocable_v<RangeCEndT, Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCEndT, const Incomplete (&&)[]>);
-static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[10]>);
-static_assert(!std::is_invocable_v<RangeCEndT, const Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCEndT, Incomplete (&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCEndT, const Incomplete (&&)[10]>);
static_assert(!std::is_invocable_v<RangeCREndT, Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, const Incomplete (&&)[]>);
-static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[10]>);
-static_assert(!std::is_invocable_v<RangeCREndT, const Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCREndT, Incomplete (&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCREndT, const Incomplete (&&)[10]>);
// This case is IFNDR; we handle it SFINAE-friendly.
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, Incomplete(&)[]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, const Incomplete(&)[]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, Incomplete(&)[]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, const Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, Incomplete (&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, const Incomplete (&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, Incomplete (&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, const Incomplete (&)[]>);
// This case is IFNDR; we handle it SFINAE-friendly.
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, Incomplete(&)[10]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, const Incomplete(&)[10]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, Incomplete(&)[10]>);
-LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, const Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, Incomplete (&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCEndT, const Incomplete (&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, Incomplete (&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCREndT, const Incomplete (&)[10]>);
struct NonborrowingRange {
int x;
- constexpr const int *begin() const { return &x; }
- constexpr const int *rbegin() const { return &x; }
- constexpr const int *end() const { return &x; }
- constexpr const int *rend() const { return &x; }
+ constexpr const int* begin() const { return &x; }
+ constexpr const int* rbegin() const { return &x; }
+ constexpr const int* end() const { return &x; }
+ constexpr const int* rend() const { return &x; }
};
// Ensure that we can't call with rvalues with borrowing disabled.
-static_assert( std::is_invocable_v<RangeCEndT, NonborrowingRange &>);
-static_assert(!std::is_invocable_v<RangeCEndT, NonborrowingRange &&>);
-static_assert( std::is_invocable_v<RangeCEndT, NonborrowingRange const&>);
+static_assert(std::is_invocable_v<RangeCEndT, NonborrowingRange&>);
+static_assert(!std::is_invocable_v<RangeCEndT, NonborrowingRange&&>);
+static_assert(std::is_invocable_v<RangeCEndT, NonborrowingRange const&>);
static_assert(!std::is_invocable_v<RangeCEndT, NonborrowingRange const&&>);
-static_assert( std::is_invocable_v<RangeCREndT, NonborrowingRange &>);
-static_assert(!std::is_invocable_v<RangeCREndT, NonborrowingRange &&>);
-static_assert( std::is_invocable_v<RangeCREndT, NonborrowingRange const&>);
+static_assert(std::is_invocable_v<RangeCREndT, NonborrowingRange&>);
+static_assert(!std::is_invocable_v<RangeCREndT, NonborrowingRange&&>);
+static_assert(std::is_invocable_v<RangeCREndT, NonborrowingRange const&>);
static_assert(!std::is_invocable_v<RangeCREndT, NonborrowingRange const&&>);
constexpr bool testReturnTypes() {
@@ -157,10 +157,10 @@ constexpr bool testArray() {
}
struct BorrowingRange {
- int *begin() const;
- int *end() const;
+ int* begin() const;
+ int* end() const;
};
-template<>
+template <>
inline constexpr bool std::ranges::enable_borrowed_range<BorrowingRange> = true;
static_assert(std::is_invocable_v<RangeCEndT, BorrowingRange>);
@@ -188,7 +188,10 @@ static_assert(!noexcept(std::ranges::crend(tbnte)));
// Test ADL-proofing.
struct Incomplete;
-template<class T> struct Holder { T t; };
+template <class T>
+struct Holder {
+ T t;
+};
static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>);
static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*>);
diff --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
index 9db012fe07e70..4554b5a76c753 100644
--- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
@@ -230,7 +230,7 @@ constexpr bool testEmpty() {
}
template <class T>
-concept ConstAccessorsInvocable = requires (T& t) {
+concept ConstAccessorsInvocable = requires(T& t) {
t.cbegin();
t.cend();
};
>From 8598b3cd0f3848d68a9f237526308e176f039aca Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Mon, 5 Aug 2024 15:49:06 +0200
Subject: [PATCH 11/16] how did i forget const_sentinel_t
---
libcxx/include/__ranges/concepts.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index bc55c25239553..97c2ef4978125 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -65,6 +65,8 @@ using sentinel_t = decltype(ranges::end(std::declval<_Rp&>()));
# if _LIBCPP_STD_VER >= 23
template <range _Rp>
using const_iterator_t = const_iterator<iterator_t<_Rp>>;
+template <range _Rp>
+using const_sentinel_t = const_sentinel<sentinel_t<_Rp>>;
# endif // _LIBCPP_STD_VER >= 23
template <range _Rp>
>From bca48d3432313fc9cbb6455ea02210fe8cb91fbb Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Mon, 5 Aug 2024 16:44:48 +0200
Subject: [PATCH 12/16] why... did that work on clang?
---
libcxx/test/std/iterators/const.iterators/iterator.pass.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp b/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
index 0c35b3b93a631..9163976deb8f1 100644
--- a/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
+++ b/libcxx/test/std/iterators/const.iterators/iterator.pass.cpp
@@ -89,8 +89,8 @@ constexpr bool test_basic_operations() {
static_assert(!std::is_invocable_v<decltype(std::ranges::iter_swap), decltype(first), decltype(first)>);
assert(++first == arr + 1);
- assert(--first == arr);
- assert(first++ == arr);
+ assert(--first == arr + 0);
+ assert(first++ == arr + 0);
assert(first-- == arr + 1);
assert(first + 3 == arr + 3);
>From 3d35375f565fed3f0735c5e2d04cb58d108fb78d Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Mon, 5 Aug 2024 18:06:33 +0200
Subject: [PATCH 13/16] don't check for cbegin in view_interface in < 23
drive-by: _LIBCPP_STD_VER -> TEST_STD_VER in test
---
.../std/ranges/range.access/begin.pass.cpp | 80 +++++-----
.../test/std/ranges/range.access/end.pass.cpp | 68 ++++-----
.../std/ranges/range.access/rbegin.pass.cpp | 140 +++++++++---------
.../std/ranges/range.access/rend.pass.cpp | 132 ++++++++---------
.../view.interface/view.interface.pass.cpp | 2 +
5 files changed, 212 insertions(+), 210 deletions(-)
diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp
index b0097dff17103..7f2357b319a8a 100644
--- a/libcxx/test/std/ranges/range.access/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp
@@ -19,9 +19,9 @@
#include "test_iterators.h"
using RangeBeginT = decltype(std::ranges::begin);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
using RangeCBeginT = decltype(std::ranges::cbegin);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
static int globalBuff[8];
@@ -29,43 +29,43 @@ 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 (&)[]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[]>);
static_assert( std::is_invocable_v<RangeCBeginT, int (&)[]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct Incomplete;
static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[10]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[10]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[10]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[10]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct BeginMember {
int x;
@@ -77,12 +77,12 @@ static_assert( std::is_invocable_v<RangeBeginT, BeginMember &>);
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 const&&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCBeginT, BeginMember &>);
static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember &&>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginMember const&>);
static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember const&&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
constexpr bool testReturnTypes() {
int* a[2];
@@ -96,11 +96,11 @@ constexpr bool testReturnTypes() {
ASSERT_SAME_TYPE(decltype(std::ranges::begin(b)), int(*)[2]);
ASSERT_SAME_TYPE(decltype(std::ranges::begin(c)), char*);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(a)), int* const*);
ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(b)), const int(*)[2]);
ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(c)), short*);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -114,11 +114,11 @@ constexpr bool testArray() {
assert(std::ranges::begin(b) == b);
assert(std::ranges::begin(c) == c);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::cbegin(a) == a);
assert(std::ranges::cbegin(b) == b);
assert(std::ranges::cbegin(c) == c);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -151,10 +151,10 @@ struct NonConstBeginMember {
};
static_assert( std::is_invocable_v<RangeBeginT, NonConstBeginMember &>);
static_assert(!std::is_invocable_v<RangeBeginT, NonConstBeginMember const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember &>);
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct EnabledBorrowingBeginMember {
constexpr int *begin() const { return &globalBuff[0]; }
@@ -189,7 +189,7 @@ constexpr bool testBeginMember() {
assert(std::ranges::begin(d) == &d.x);
assert(std::ranges::begin(e) == &e.x);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::cbegin(a) == &a.x);
static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember&&>);
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember&>);
@@ -197,7 +197,7 @@ constexpr bool testBeginMember() {
assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]);
assert(std::ranges::cbegin(d) == &d.x);
assert(std::ranges::cbegin(e) == &e.x);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -210,10 +210,10 @@ struct BeginFunction {
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&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct BeginFunctionReturnsInt {
friend int begin(BeginFunctionReturnsInt const&);
@@ -234,9 +234,9 @@ static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsPtrConvertib
struct BeginFunctionByValue {
friend constexpr int *begin(BeginFunctionByValue) { return &globalBuff[1]; }
};
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, BeginFunctionByValue>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct BeginFunctionEnabledBorrowing {
friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; }
@@ -290,7 +290,7 @@ constexpr bool testBeginFunction() {
assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::begin(ff) == &ff.y);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::cbegin(a) == &a.x);
assert(std::ranges::cbegin(aa) == &aa.x);
assert(std::ranges::cbegin(b) == &globalBuff[1]);
@@ -303,59 +303,59 @@ constexpr bool testBeginFunction() {
assert(std::ranges::cbegin(ee) == &ee.x);
assert(std::ranges::cbegin(f) == &f.y);
assert(std::ranges::cbegin(ff) == &ff.y);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval<int (&)[10]>()));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowMemberBegin {
ThrowingIterator<int> begin() const noexcept; // auto(t.begin()) doesn't throw
} ntmb;
static_assert(noexcept(std::ranges::begin(ntmb)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::cbegin(ntmb)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowADLBegin {
friend ThrowingIterator<int> begin(NoThrowADLBegin&) noexcept; // auto(begin(t)) doesn't throw
friend ThrowingIterator<int> begin(const NoThrowADLBegin&) noexcept;
} ntab;
static_assert(noexcept(std::ranges::begin(ntab)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::cbegin(ntab)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowMemberBeginReturnsRef {
ThrowingIterator<int>& begin() const noexcept; // auto(t.begin()) may throw
} ntmbrr;
static_assert(!noexcept(std::ranges::begin(ntmbrr)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!noexcept(std::ranges::cbegin(ntmbrr)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct BeginReturnsArrayRef {
auto begin() const noexcept -> int(&)[10];
} brar;
static_assert(noexcept(std::ranges::begin(brar)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::cbegin(brar)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/end.pass.cpp b/libcxx/test/std/ranges/range.access/end.pass.cpp
index ffbc5ba3d16e4..3197634c2d97f 100644
--- a/libcxx/test/std/ranges/range.access/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/end.pass.cpp
@@ -19,9 +19,9 @@
#include "test_iterators.h"
using RangeEndT = decltype(std::ranges::end);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
using RangeCEndT = decltype(std::ranges::cend);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
static int globalBuff[8];
@@ -29,20 +29,20 @@ 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]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCEndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCEndT, int (&)[10]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct Incomplete;
static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[42]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[42]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct EndMember {
int x;
@@ -55,12 +55,12 @@ static_assert( std::is_invocable_v<RangeEndT, EndMember &>);
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 const&&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCEndT, EndMember &>);
static_assert(!std::is_invocable_v<RangeCEndT, EndMember &&>);
static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>);
static_assert(!std::is_invocable_v<RangeCEndT, EndMember const&&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
constexpr bool testReturnTypes() {
int* a[2];
@@ -76,11 +76,11 @@ constexpr bool testReturnTypes() {
ASSERT_SAME_TYPE(decltype(std::ranges::end(b)), int(*)[2]);
ASSERT_SAME_TYPE(decltype(std::ranges::end(c)), sentinel_wrapper<char*>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
ASSERT_SAME_TYPE(decltype(std::ranges::cend(a)), int* const*);
ASSERT_SAME_TYPE(decltype(std::ranges::cend(b)), const int(*)[2]);
ASSERT_SAME_TYPE(decltype(std::ranges::cend(c)), sentinel_wrapper<short*>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -94,11 +94,11 @@ constexpr bool testArray() {
assert(std::ranges::end(b) == b + 2);
assert(std::ranges::end(c) == c + 2);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::cend(a) == a + 2);
assert(std::ranges::cend(b) == b + 2);
assert(std::ranges::cend(c) == c + 2);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -136,10 +136,10 @@ struct NonConstEndMember {
};
static_assert( std::is_invocable_v<RangeEndT, NonConstEndMember &>);
static_assert(!std::is_invocable_v<RangeEndT, NonConstEndMember const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>);
static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct EnabledBorrowingEndMember {
constexpr int *begin() const { return nullptr; }
@@ -182,13 +182,13 @@ constexpr bool testEndMember() {
assert(std::ranges::end(d) == &d.x);
assert(std::ranges::end(e) == &e.x);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::cend(a) == &a.x);
static_assert(!std::is_invocable_v<RangeCEndT, decltype((b))>);
assert(std::ranges::cend(std::move(c)) == &globalBuff[0]);
assert(std::ranges::cend(d) == &d.x);
assert(std::ranges::cend(e) == &e.x);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -205,10 +205,10 @@ 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&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct EndFunctionReturnsInt {
friend constexpr int begin(EndFunctionReturnsInt const&);
@@ -243,9 +243,9 @@ struct EndFunctionByValue {
friend constexpr int *begin(EndFunctionByValue) { return nullptr; }
friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; }
};
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, EndFunctionByValue>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct EndFunctionEnabledBorrowing {
friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; }
@@ -308,7 +308,7 @@ constexpr bool testEndFunction() {
assert(std::ranges::end(g) == &g.x);
assert(std::ranges::end(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::cend(a) == &a.x);
assert(std::ranges::cend(aa) == &aa.x);
assert(std::ranges::cend(b) == &globalBuff[1]);
@@ -321,25 +321,25 @@ constexpr bool testEndFunction() {
assert(std::ranges::cend(ff) == &ff.y);
assert(std::ranges::cend(g) == &g.x);
assert(std::ranges::cend(gg) == &gg.x);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::end(std::declval<int (&)[10]>()));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
ASSERT_NOEXCEPT(std::ranges::cend(std::declval<int (&)[10]>()));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowMemberEnd {
ThrowingIterator<int> begin() const;
ThrowingIterator<int> end() const noexcept; // auto(t.end()) doesn't throw
} ntme;
static_assert(noexcept(std::ranges::end(ntme)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::cend(ntme)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowADLEnd {
ThrowingIterator<int> begin() const;
@@ -347,37 +347,37 @@ struct NoThrowADLEnd {
friend ThrowingIterator<int> end(const NoThrowADLEnd&) noexcept;
} ntae;
static_assert(noexcept(std::ranges::end(ntae)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::cend(ntae)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowMemberEndReturnsRef {
ThrowingIterator<int> begin() const;
ThrowingIterator<int>& end() const noexcept; // auto(t.end()) may throw
} ntmerr;
static_assert(!noexcept(std::ranges::end(ntmerr)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!noexcept(std::ranges::cend(ntmerr)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct EndReturnsArrayRef {
auto begin() const noexcept -> int(&)[10];
auto end() const noexcept -> int(&)[10];
} erar;
static_assert(noexcept(std::ranges::end(erar)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::cend(erar)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
index a168889d5fa20..7919b84d2b35a 100644
--- a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
@@ -19,9 +19,9 @@
#include "test_iterators.h"
using RangeRBeginT = decltype(std::ranges::rbegin);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
using RangeCRBeginT = decltype(std::ranges::crbegin);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
static int globalBuff[8];
@@ -29,12 +29,12 @@ static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeRBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeRBeginT, int (&)[]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCRBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, int (&)[]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct Incomplete;
@@ -43,28 +43,28 @@ static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeRBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete(&&)[10]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete (&&)[]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[10]>);
static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[10]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// This case is IFNDR; we handle it SFINAE-friendly.
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[10]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[10]>);
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[10]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct RBeginMember {
int x;
@@ -76,12 +76,12 @@ static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember &>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember &&>);
static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember const&>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember const&&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember &>);
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember &&>);
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember const&>);
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember const&&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
constexpr bool testReturnTypes() {
int* a[2];
@@ -95,11 +95,11 @@ constexpr bool testReturnTypes() {
ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(b)), std::reverse_iterator<int(*)[2]>);
ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(c)), char*);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(a)), std::reverse_iterator<int* const*>);
ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(b)), std::reverse_iterator<const int(*)[2]>);
ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(c)), short*);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -113,11 +113,11 @@ constexpr bool testArray() {
assert(std::ranges::rbegin(b).base() == b + 2);
assert(std::ranges::rbegin(c).base() == c + 2);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::crbegin(a).base() == a + 2);
assert(std::ranges::crbegin(b).base() == b + 2);
assert(std::ranges::crbegin(c).base() == c + 2);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -144,10 +144,10 @@ struct NonConstRBeginMember {
};
static_assert( std::is_invocable_v<RangeRBeginT, NonConstRBeginMember &>);
static_assert(!std::is_invocable_v<RangeRBeginT, NonConstRBeginMember const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember &>);
static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct EnabledBorrowingRBeginMember {
constexpr int *rbegin() const { return globalBuff; }
@@ -182,7 +182,7 @@ constexpr bool testRBeginMember() {
assert(std::ranges::rbegin(d) == &d.x);
assert(std::ranges::rbegin(e) == &e.x);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::crbegin(a) == &a.x);
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember&&>);
static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember&>);
@@ -190,7 +190,7 @@ constexpr bool testRBeginMember() {
assert(std::ranges::crbegin(std::move(c)) == globalBuff);
assert(std::ranges::crbegin(d) == &d.x);
assert(std::ranges::crbegin(e) == &e.x);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -204,10 +204,10 @@ static_assert( std::is_invocable_v<RangeRBeginT, RBeginFunction const&>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunction &&>);
static_assert(
std::is_invocable_v<RangeRBeginT, RBeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction const&>);
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction &>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct RBeginFunctionReturnsInt {
friend int rbegin(RBeginFunctionReturnsInt const&);
@@ -234,9 +234,9 @@ static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsPtrConvert
struct RBeginFunctionByValue {
friend constexpr int *rbegin(RBeginFunctionByValue) { return globalBuff + 1; }
};
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginFunctionByValue>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct RBeginFunctionEnabledBorrowing {
friend constexpr int *rbegin(RBeginFunctionEnabledBorrowing) { return globalBuff + 2; }
@@ -290,7 +290,7 @@ constexpr bool testRBeginFunction() {
assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::rbegin(ff) == &ff.y);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::crbegin(a) == &a.x);
assert(std::ranges::crbegin(aa) == &aa.x);
assert(std::ranges::crbegin(b) == globalBuff + 1);
@@ -303,7 +303,7 @@ constexpr bool testRBeginFunction() {
assert(std::ranges::crbegin(ee) == &ee.x);
assert(std::ranges::crbegin(f) == &f.y);
assert(std::ranges::crbegin(ff) == &ff.y);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -319,9 +319,9 @@ struct MemberBeginEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginEnd const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginEnd {
int b, e;
@@ -339,9 +339,9 @@ struct FunctionBeginEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginEnd const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberBeginFunctionEnd {
int b, e;
@@ -357,9 +357,9 @@ struct MemberBeginFunctionEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginFunctionEnd const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginMemberEnd {
int b, e;
@@ -375,77 +375,77 @@ struct FunctionBeginMemberEnd {
};
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd&>);
static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginMemberEnd const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberBeginEndDifferentTypes {
bidirectional_iterator<int*> begin();
bidirectional_iterator<const int*> end();
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndDifferentTypes&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndDifferentTypes&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginEndDifferentTypes {
friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);
friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndDifferentTypes&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndDifferentTypes&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberBeginEndForwardIterators {
forward_iterator<int*> begin();
forward_iterator<int*> end();
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndForwardIterators&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndForwardIterators&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginEndForwardIterators {
friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);
friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndForwardIterators&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndForwardIterators&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberBeginOnly {
bidirectional_iterator<int*> begin() const;
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginOnly&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginOnly&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginOnly {
friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginOnly&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginOnly&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberEndOnly {
bidirectional_iterator<int*> end() const;
};
static_assert(!std::is_invocable_v<RangeRBeginT, MemberEndOnly&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, MemberEndOnly&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionEndOnly {
friend bidirectional_iterator<int*> end(FunctionEndOnly&);
};
static_assert(!std::is_invocable_v<RangeRBeginT, FunctionEndOnly&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionEndOnly&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// Make sure there is no clash between the following cases:
// - the case that handles classes defining member `rbegin` and `rend` functions;
@@ -458,10 +458,10 @@ struct MemberBeginAndRBegin {
};
static_assert(std::is_invocable_v<RangeRBeginT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeRBeginT, MemberBeginAndRBegin&>, int*>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(std::is_invocable_v<RangeCRBeginT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeCRBeginT, MemberBeginAndRBegin&>, int*>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
constexpr bool testBeginEnd() {
MemberBeginEnd a{};
@@ -482,7 +482,7 @@ constexpr bool testBeginEnd() {
assert(base(std::ranges::rbegin(d).base()) == &d.e);
assert(base(std::ranges::rbegin(dd).base()) == &dd.ce);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(base(std::ranges::crbegin(a).base()) == &a.ce);
assert(base(std::ranges::crbegin(aa).base()) == &aa.ce);
assert(base(std::ranges::crbegin(b).base()) == &b.ce);
@@ -491,77 +491,77 @@ constexpr bool testBeginEnd() {
assert(base(std::ranges::crbegin(cc).base()) == &cc.ce);
assert(base(std::ranges::crbegin(d).base()) == &d.ce);
assert(base(std::ranges::crbegin(dd).base()) == &dd.ce);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::rbegin(std::declval<int (&)[10]>()));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
ASSERT_NOEXCEPT(std::ranges::crbegin(std::declval<int (&)[10]>()));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowMemberRBegin {
ThrowingIterator<int> rbegin() const noexcept; // auto(t.rbegin()) doesn't throw
} ntmb;
static_assert(noexcept(std::ranges::rbegin(ntmb)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::crbegin(ntmb)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowADLRBegin {
friend ThrowingIterator<int> rbegin(NoThrowADLRBegin&) noexcept; // auto(rbegin(t)) doesn't throw
friend ThrowingIterator<int> rbegin(const NoThrowADLRBegin&) noexcept;
} ntab;
static_assert(noexcept(std::ranges::rbegin(ntab)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::crbegin(ntab)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowMemberRBeginReturnsRef {
ThrowingIterator<int>& rbegin() const noexcept; // auto(t.rbegin()) may throw
} ntmbrr;
static_assert(!noexcept(std::ranges::rbegin(ntmbrr)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!noexcept(std::ranges::crbegin(ntmbrr)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct RBeginReturnsArrayRef {
auto rbegin() const noexcept -> int(&)[10];
} brar;
static_assert(noexcept(std::ranges::rbegin(brar)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::crbegin(brar)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowBeginThrowingEnd {
int* begin() const noexcept;
int* end() const;
} ntbte;
static_assert(!noexcept(std::ranges::rbegin(ntbte)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!noexcept(std::ranges::crbegin(ntbte)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowEndThrowingBegin {
int* begin() const;
int* end() const noexcept;
} ntetb;
static_assert(noexcept(std::ranges::rbegin(ntetb)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::crbegin(ntetb)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/rend.pass.cpp b/libcxx/test/std/ranges/range.access/rend.pass.cpp
index 1108109009dfc..adb150461e044 100644
--- a/libcxx/test/std/ranges/range.access/rend.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rend.pass.cpp
@@ -19,9 +19,9 @@
#include "test_iterators.h"
using RangeREndT = decltype(std::ranges::rend);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
using RangeCREndT = decltype(std::ranges::crend);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
static int globalBuff[8];
@@ -29,20 +29,20 @@ static_assert(!std::is_invocable_v<RangeREndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeREndT, int (&)[10]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeCREndT, int (&)[10]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct Incomplete;
static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[42]>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[42]>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct REndMember {
int x;
@@ -55,12 +55,12 @@ static_assert( std::is_invocable_v<RangeREndT, REndMember&>);
static_assert(!std::is_invocable_v<RangeREndT, REndMember &&>);
static_assert( std::is_invocable_v<RangeREndT, REndMember const&>);
static_assert(!std::is_invocable_v<RangeREndT, REndMember const&&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, REndMember &>);
static_assert(!std::is_invocable_v<RangeCREndT, REndMember &&>);
static_assert( std::is_invocable_v<RangeCREndT, REndMember const&>);
static_assert(!std::is_invocable_v<RangeCREndT, REndMember const&&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
constexpr bool testReturnTypes() {
int* a[2];
@@ -76,11 +76,11 @@ constexpr bool testReturnTypes() {
ASSERT_SAME_TYPE(decltype(std::ranges::rend(b)), std::reverse_iterator<int(*)[2]>);
ASSERT_SAME_TYPE(decltype(std::ranges::rend(c)), sentinel_wrapper<char*>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
ASSERT_SAME_TYPE(decltype(std::ranges::crend(a)), std::reverse_iterator<int* const*>);
ASSERT_SAME_TYPE(decltype(std::ranges::crend(b)), std::reverse_iterator<const int(*)[2]>);
ASSERT_SAME_TYPE(decltype(std::ranges::crend(c)), sentinel_wrapper<short*>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -94,11 +94,11 @@ constexpr bool testArray() {
assert(std::ranges::rend(b).base() == b);
assert(std::ranges::rend(c).base() == c);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::crend(b).base() == b);
assert(std::ranges::crend(a).base() == a);
assert(std::ranges::crend(c).base() == c);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -136,10 +136,10 @@ struct NonConstREndMember {
};
static_assert( std::is_invocable_v<RangeREndT, NonConstREndMember &>);
static_assert(!std::is_invocable_v<RangeREndT, NonConstREndMember const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember &>);
static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct EnabledBorrowingREndMember {
constexpr int* rbegin() const { return nullptr; }
@@ -182,13 +182,13 @@ constexpr bool testREndMember() {
assert(std::ranges::rend(d) == &d.x);
assert(std::ranges::rend(e) == &e.x);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::crend(a) == &a.x);
static_assert(!std::is_invocable_v<RangeCREndT, decltype((b))>);
assert(std::ranges::crend(std::move(c)) == &globalBuff[0]);
assert(std::ranges::crend(d) == &d.x);
assert(std::ranges::crend(e) == &e.x);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -205,10 +205,10 @@ static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
static_assert( std::is_invocable_v<RangeREndT, REndFunction const&>);
static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
static_assert(std::is_invocable_v<RangeREndT, REndFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, REndFunction const&>);
static_assert( std::is_invocable_v<RangeCREndT, REndFunction &>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct REndFunctionReturnsInt {
friend constexpr int rbegin(REndFunctionReturnsInt const&);
@@ -243,9 +243,9 @@ struct REndFunctionByValue {
friend constexpr int* rbegin(REndFunctionByValue) { return nullptr; }
friend constexpr int* rend(REndFunctionByValue) { return &globalBuff[1]; }
};
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, REndFunctionByValue>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct REndFunctionEnabledBorrowing {
friend constexpr int* rbegin(REndFunctionEnabledBorrowing) { return nullptr; }
@@ -306,7 +306,7 @@ constexpr bool testREndFunction() {
assert(std::ranges::rend(g) == &g.x);
assert(std::ranges::rend(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(std::ranges::crend(a) == &a.x);
assert(std::ranges::crend(aa) == &aa.x);
assert(std::ranges::crend(b) == &globalBuff[1]);
@@ -319,7 +319,7 @@ constexpr bool testREndFunction() {
assert(std::ranges::crend(ff) == &ff.y);
assert(std::ranges::crend(g) == &g.x);
assert(std::ranges::crend(gg) == &gg.x);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
@@ -335,9 +335,9 @@ struct MemberBeginEnd {
};
static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd&>);
static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, MemberBeginEnd const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginEnd {
int b, e;
@@ -355,9 +355,9 @@ struct FunctionBeginEnd {
};
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd&>);
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginEnd const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberBeginFunctionEnd {
int b, e;
@@ -373,9 +373,9 @@ struct MemberBeginFunctionEnd {
};
static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd&>);
static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, MemberBeginFunctionEnd const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginMemberEnd {
int b, e;
@@ -391,77 +391,77 @@ struct FunctionBeginMemberEnd {
};
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd&>);
static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd const&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginMemberEnd const&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberBeginEndDifferentTypes {
bidirectional_iterator<int*> begin();
bidirectional_iterator<const int*> end();
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndDifferentTypes&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndDifferentTypes&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginEndDifferentTypes {
friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);
friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndDifferentTypes&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndDifferentTypes&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberBeginEndForwardIterators {
forward_iterator<int*> begin();
forward_iterator<int*> end();
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndForwardIterators&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndForwardIterators&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginEndForwardIterators {
friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);
friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndForwardIterators&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndForwardIterators&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberBeginOnly {
bidirectional_iterator<int*> begin() const;
};
static_assert(!std::is_invocable_v<RangeREndT, MemberBeginOnly&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginOnly&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionBeginOnly {
friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginOnly&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginOnly&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct MemberEndOnly {
bidirectional_iterator<int*> end() const;
};
static_assert(!std::is_invocable_v<RangeREndT, MemberEndOnly&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, MemberEndOnly&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct FunctionEndOnly {
friend bidirectional_iterator<int*> end(FunctionEndOnly&);
};
static_assert(!std::is_invocable_v<RangeREndT, FunctionEndOnly&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, FunctionEndOnly&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// Make sure there is no clash between the following cases:
// - the case that handles classes defining member `rbegin` and `rend` functions;
@@ -474,10 +474,10 @@ struct MemberBeginAndRBegin {
};
static_assert(std::is_invocable_v<RangeREndT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeREndT, MemberBeginAndRBegin&>, int*>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(std::is_invocable_v<RangeCREndT, MemberBeginAndRBegin&>);
static_assert( std::same_as<std::invoke_result_t<RangeCREndT, MemberBeginAndRBegin&>, int*>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
constexpr bool testBeginEnd() {
MemberBeginEnd a{};
@@ -498,7 +498,7 @@ constexpr bool testBeginEnd() {
assert(base(std::ranges::rend(d).base()) == &d.b);
assert(base(std::ranges::rend(dd).base()) == &dd.cb);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
assert(base(std::ranges::crend(a).base()) == &a.cb);
assert(base(std::ranges::crend(aa).base()) == &aa.cb);
assert(base(std::ranges::crend(b).base()) == &b.cb);
@@ -507,25 +507,25 @@ constexpr bool testBeginEnd() {
assert(base(std::ranges::crend(cc).base()) == &cc.cb);
assert(base(std::ranges::crend(d).base()) == &d.cb);
assert(base(std::ranges::crend(dd).base()) == &dd.cb);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
return true;
}
ASSERT_NOEXCEPT(std::ranges::rend(std::declval<int (&)[10]>()));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
ASSERT_NOEXCEPT(std::ranges::crend(std::declval<int (&)[10]>()));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowMemberREnd {
ThrowingIterator<int> rbegin() const;
ThrowingIterator<int> rend() const noexcept; // auto(t.rend()) doesn't throw
} ntmre;
static_assert(noexcept(std::ranges::rend(ntmre)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::crend(ntmre)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowADLREnd {
ThrowingIterator<int> rbegin() const;
@@ -533,55 +533,55 @@ struct NoThrowADLREnd {
friend ThrowingIterator<int> rend(const NoThrowADLREnd&) noexcept;
} ntare;
static_assert(noexcept(std::ranges::rend(ntare)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::crend(ntare)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowMemberREndReturnsRef {
ThrowingIterator<int> rbegin() const;
ThrowingIterator<int>& rend() const noexcept; // auto(t.rend()) may throw
} ntmrerr;
static_assert(!noexcept(std::ranges::rend(ntmrerr)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!noexcept(std::ranges::crend(ntmrerr)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct REndReturnsArrayRef {
auto rbegin() const noexcept -> int(&)[10];
auto rend() const noexcept -> int(&)[10];
} rerar;
static_assert(noexcept(std::ranges::rend(rerar)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::crend(rerar)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowBeginThrowingEnd {
int* begin() const noexcept;
int* end() const;
} ntbte;
static_assert(noexcept(std::ranges::rend(ntbte)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(noexcept(std::ranges::crend(ntbte)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
struct NoThrowEndThrowingBegin {
int* begin() const;
int* end() const noexcept;
} ntetb;
static_assert(!noexcept(std::ranges::rend(ntetb)));
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!noexcept(std::ranges::crend(ntetb)));
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
// Test ADL-proofing.
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*&>);
-#if _LIBCPP_STD_VER < 23
+#if TEST_STD_VER < 23
static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*&>);
-#endif // _LIBCPP_STD_VER < 23
+#endif // TEST_STD_VER < 23
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
index 4554b5a76c753..8c711cd770862 100644
--- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
@@ -229,6 +229,7 @@ constexpr bool testEmpty() {
return true;
}
+#if TEST_STD_VER >= 23
template <class T>
concept ConstAccessorsInvocable = requires(T& t) {
t.cbegin();
@@ -239,6 +240,7 @@ static_assert(ConstAccessorsInvocable<InputRange>);
static_assert(ConstAccessorsInvocable<const InputRange>);
static_assert(ConstAccessorsInvocable<NonConstInputRange>);
static_assert(!ConstAccessorsInvocable<const NonConstInputRange>);
+#endif // TEST_STD_VER >= 23
template<class T>
concept DataInvocable = requires (T const& obj) { obj.data(); };
>From a3ea4a2aed71258897fa85ea42ccb5c678c4eb15 Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Wed, 7 Aug 2024 21:18:47 +0200
Subject: [PATCH 14/16] fix LWG issue shtuff
---
libcxx/docs/Status/Cxx23Issues.csv | 10 +++++-----
libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
libcxx/include/__ranges/concepts.h | 4 ++--
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index c4c6a855cc517..78b5722915c98 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -220,7 +220,7 @@
"`LWG3762 <https://wg21.link/LWG3762>`__","``generator::iterator::operator==`` should pass by reference","November 2022","","",""
"`LWG3764 <https://wg21.link/LWG3764>`__","``reference_wrapper::operator()`` should propagate noexcept","November 2022","|Complete|","17.0",""
"`LWG3765 <https://wg21.link/LWG3765>`__","``const_sentinel`` should be constrained","November 2022","","","|ranges|"
-"`LWG3766 <https://wg21.link/LWG3766>`__","``view_interface::cbegin`` is underconstrained","November 2022","","","|ranges|"
+"`LWG3766 <https://wg21.link/LWG3766>`__","``view_interface::cbegin`` is underconstrained","November 2022","|Complete|","20.0","|ranges|"
"`LWG3770 <https://wg21.link/LWG3770>`__","``const_sentinel_t`` is missing","November 2022","","","|ranges|"
"`LWG3773 <https://wg21.link/LWG3773>`__","``views::zip_transform`` still requires ``F`` to be ``copy_constructible`` when empty pack","November 2022","","","|ranges|"
"`LWG3774 <https://wg21.link/LWG3774>`__","``<flat_set>`` should include ``<compare>``","November 2022","","","|flat_containers|"
@@ -252,7 +252,7 @@
"`LWG3664 <https://wg21.link/LWG3664>`__","`LWG 3392 <https://wg21.link/LWG3392>`__ ``broke std::ranges::distance(a, a+3)``","February 2023","","","|ranges|"
"`LWG3720 <https://wg21.link/LWG3720>`__","Restrict the valid types of ``arg-id`` for width and precision in ``std-format-spec``","February 2023","|Complete|","17.0","|format|"
"`LWG3756 <https://wg21.link/LWG3756>`__","Is the ``std::atomic_flag`` class signal-safe?","February 2023","","",""
-"`LWG3769 <https://wg21.link/LWG3769>`__","``basic_const_iterator::operator==`` causes infinite constraint recursion","February 2023","","","|spaceship|"
+"`LWG3769 <https://wg21.link/LWG3769>`__","``basic_const_iterator::operator==`` causes infinite constraint recursion","February 2023","|Complete|","20.0","|spaceship|"
"`LWG3807 <https://wg21.link/LWG3807>`__","The feature test macro for ``ranges::find_last`` should be renamed","February 2023","","","|ranges|"
"`LWG3811 <https://wg21.link/LWG3811>`__","``views::as_const`` on ``ref_view<T>`` should return ``ref_view<const T>``","February 2023","","","|ranges|"
"`LWG3820 <https://wg21.link/LWG3820>`__","``cartesian_product_view::iterator::prev`` is not quite right","February 2023","","","|ranges|"
@@ -271,7 +271,7 @@
"`LWG3849 <https://wg21.link/LWG3849>`__","``cartesian_product_view::iterator``'s default constructor is overconstrained","February 2023","","","|ranges|"
"`LWG3850 <https://wg21.link/LWG3850>`__","``views::as_const`` on ``empty_view<T>`` should return ``empty_view<const T>``","February 2023","","","|ranges|"
"`LWG3851 <https://wg21.link/LWG3851>`__","``chunk_view::inner-iterator`` missing custom ``iter_move`` and ``iter_swap``","February 2023","","","|ranges|"
-"`LWG3853 <https://wg21.link/LWG3853>`__","``basic_const_iterator<volatile int*>::operator->`` is ill-formed","February 2023","","",""
+"`LWG3853 <https://wg21.link/LWG3853>`__","``basic_const_iterator<volatile int*>::operator->`` is ill-formed","February 2023","|Complete|","20.0",""
"`LWG3857 <https://wg21.link/LWG3857>`__","``basic_string_view`` should allow explicit conversion when only traits vary","February 2023","|Complete|","17.0",""
"`LWG3860 <https://wg21.link/LWG3860>`__","``range_common_reference_t`` is missing","February 2023","|Complete|","17.0","|ranges|"
"`LWG3866 <https://wg21.link/LWG3866>`__","Bad Mandates for ``expected::transform_error`` overloads","February 2023","|Complete|","17.0",""
@@ -293,12 +293,12 @@
"`LWG3836 <https://wg21.link/LWG3836>`__","``std::expected<bool, E1>`` conversion constructor ``expected(const expected<U, G>&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","|Complete|","18.0",""
"`LWG3843 <https://wg21.link/LWG3843>`__","``std::expected<T,E>::value() &`` assumes ``E`` is copy constructible","February 2023","|Complete|","17.0",""
"`LWG3847 <https://wg21.link/LWG3847>`__","``ranges::to`` can still return views","February 2023","|Complete|","17.0","|ranges|"
-"`LWG3862 <https://wg21.link/LWG3862>`__","``basic_const_iterator``'s ``common_type`` specialization is underconstrained","February 2023","","",""
+"`LWG3862 <https://wg21.link/LWG3862>`__","``basic_const_iterator``'s ``common_type`` specialization is underconstrained","February 2023","|Complete|","20.0",""
"`LWG3865 <https://wg21.link/LWG3865>`__","Sorting a range of ``pairs``","February 2023","|Complete|","17.0","|ranges|"
"`LWG3869 <https://wg21.link/LWG3869>`__","Deprecate ``std::errc`` constants related to UNIX STREAMS","February 2023","|Complete|","19.0",""
"`LWG3870 <https://wg21.link/LWG3870>`__","Remove ``voidify``","February 2023","","",""
"`LWG3871 <https://wg21.link/LWG3871>`__","Adjust note about ``terminate``","February 2023","","",""
-"`LWG3872 <https://wg21.link/LWG3872>`__","``basic_const_iterator`` should have custom ``iter_move``","February 2023","","",""
+"`LWG3872 <https://wg21.link/LWG3872>`__","``basic_const_iterator`` should have custom ``iter_move``","February 2023","|Complete|","20.0",""
"`LWG3875 <https://wg21.link/LWG3875>`__","``std::ranges::repeat_view<T, IntegerClass>::iterator`` may be ill-formed","February 2023","|Complete|","17.0","|ranges|"
"`LWG3876 <https://wg21.link/LWG3876>`__","Default constructor of ``std::layout_XX::mapping`` misses precondition","February 2023","","",""
"`LWG3877 <https://wg21.link/LWG3877>`__","Incorrect constraints on ``const``-qualified monadic overloads for ``std::expected``","February 2023","|Complete|","17.0",""
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index a92a1fef77980..ab0f2e3a644d9 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -25,7 +25,7 @@
"`LWG3809 <https://wg21.link/LWG3809>`__","Is ``std::subtract_with_carry_engine<uint16_t>`` supposed to work","Kona November 2023","","",""
"`LWG3892 <https://wg21.link/LWG3892>`__","Incorrect formatting of nested ranges and tuples","Kona November 2023","|Complete|","17.0","|format|"
"`LWG3897 <https://wg21.link/LWG3897>`__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","|Complete|","19.0",""
-"`LWG3946 <https://wg21.link/LWG3946>`__","The definition of ``const_iterator_t`` should be reworked","Kona November 2023","","",""
+"`LWG3946 <https://wg21.link/LWG3946>`__","The definition of ``const_iterator_t`` should be reworked","Kona November 2023","|Complete|","20.0",""
"`LWG3947 <https://wg21.link/LWG3947>`__","Unexpected constraints on ``adjacent_transform_view::base()``","Kona November 2023","","","|ranges|"
"`LWG3948 <https://wg21.link/LWG3948>`__","``possibly-const-range and as-const-pointer`` should be ``noexcept``","Kona November 2023","","","|ranges|"
"`LWG3949 <https://wg21.link/LWG3949>`__","``std::atomic<bool>``'s trivial destructor dropped in C++17 spec wording","Kona November 2023","","",""
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index c63708067e3f0..87874f60b2d6d 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -42,7 +42,7 @@
"`P2819R2 <https://wg21.link/P2819R2>`__","Add tuple protocol to complex","Kona November 2023","|Complete|","19.0",""
"`P2937R0 <https://wg21.link/P2937R0>`__","Freestanding: Remove ``strtok``","Kona November 2023","","",""
"`P2833R2 <https://wg21.link/P2833R2>`__","Freestanding Library: inout expected span","Kona November 2023","","",""
-"`P2836R1 <https://wg21.link/P2836R1>`__","``std::basic_const_iterator`` should follow its underlying type's convertibility","Kona November 2023","|Complete| [#note-P2836R1]","","|DR|"
+"`P2836R1 <https://wg21.link/P2836R1>`__","``std::basic_const_iterator`` should follow its underlying type's convertibility","Kona November 2023","|Complete| [#note-P2836R1]","20.0","|DR|"
"`P2264R7 <https://wg21.link/P2264R7>`__","Make ``assert()`` macro user friendly for C and C++","Kona November 2023","","",""
"`P1673R13 <https://wg21.link/P1673R13>`__","A free function linear algebra interface based on the BLAS","Kona November 2023","","",""
"","","","","",""
diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index 97c2ef4978125..bfee6fab567e9 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -64,9 +64,9 @@ using sentinel_t = decltype(ranges::end(std::declval<_Rp&>()));
# if _LIBCPP_STD_VER >= 23
template <range _Rp>
-using const_iterator_t = const_iterator<iterator_t<_Rp>>;
+using const_iterator_t = decltype(ranges::cbegin(std::declval<_Rp&>()));
template <range _Rp>
-using const_sentinel_t = const_sentinel<sentinel_t<_Rp>>;
+using const_sentinel_t = decltype(ranges::cend(std::declval<_Rp&>()));
# endif // _LIBCPP_STD_VER >= 23
template <range _Rp>
>From 45f49b60934dfbf09175c7ceb45761e308503022 Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Wed, 7 Aug 2024 21:28:05 +0200
Subject: [PATCH 15/16] had to move const_iterator_t
---
libcxx/include/__ranges/concepts.h | 7 +------
libcxx/include/__ranges/const_access.h | 13 +++++++++++++
libcxx/include/ranges | 4 ++--
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index bfee6fab567e9..0f1c816bfc7cd 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -62,12 +62,7 @@ concept borrowed_range =
template <range _Rp>
using sentinel_t = decltype(ranges::end(std::declval<_Rp&>()));
-# if _LIBCPP_STD_VER >= 23
-template <range _Rp>
-using const_iterator_t = decltype(ranges::cbegin(std::declval<_Rp&>()));
-template <range _Rp>
-using const_sentinel_t = decltype(ranges::cend(std::declval<_Rp&>()));
-# endif // _LIBCPP_STD_VER >= 23
+// `const_iterator_t` and `const_sentinel_t` defined in <__ranges/const_access.h>
template <range _Rp>
using range_difference_t = iter_difference_t<iterator_t<_Rp>>;
diff --git a/libcxx/include/__ranges/const_access.h b/libcxx/include/__ranges/const_access.h
index 0bdc5c6801e30..8eb5cd15fea4c 100644
--- a/libcxx/include/__ranges/const_access.h
+++ b/libcxx/include/__ranges/const_access.h
@@ -86,6 +86,12 @@ inline constexpr auto cbegin = __cbegin::__fn{};
} // namespace __cpo
} // namespace ranges
+// [range.range]
+namespace ranges {
+template <class _Rp>
+using const_iterator_t = decltype(ranges::cbegin(std::declval<_Rp&>()));
+}
+
// [range.access.cend]
namespace ranges {
namespace __cend {
@@ -124,6 +130,13 @@ inline constexpr auto cend = __cend::__fn{};
} // namespace __cpo
} // namespace ranges
+// [range.range]
+namespace ranges {
+template <class _Rp>
+using const_sentinel_t = decltype(ranges::cend(std::declval<_Rp&>()));
+}
+
+
// [range.access.crbegin]
namespace ranges {
namespace __crbegin {
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 03e5da4b58908..5848308f08956 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -40,9 +40,9 @@ namespace std::ranges {
template<range R>
using sentinel_t = decltype(ranges::end(declval<R&>()));
template<range R>
- using const_iterator_t = const_iterator<iterator_t<R>>; // since C++23
+ using const_iterator_t = decltype(ranges::cbegin(declval<R&>())); // since C++23
template<range R>
- using const_sentinel_t = const_sentinel<sentinel_t<R>>; // since C++23
+ using const_sentinel_t = decltype(ranges::cend(declval<R&>())); // since C++23
template<range R>
using range_difference_t = iter_difference_t<iterator_t<R>>;
template<sized_range R>
>From 65fea36abc0df71ee51fff95cb9cf264f56e76ba Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Wed, 7 Aug 2024 21:34:18 +0200
Subject: [PATCH 16/16] format
---
libcxx/include/__ranges/const_access.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/include/__ranges/const_access.h b/libcxx/include/__ranges/const_access.h
index 8eb5cd15fea4c..f47981c8d2e2f 100644
--- a/libcxx/include/__ranges/const_access.h
+++ b/libcxx/include/__ranges/const_access.h
@@ -136,7 +136,6 @@ template <class _Rp>
using const_sentinel_t = decltype(ranges::cend(std::declval<_Rp&>()));
}
-
// [range.access.crbegin]
namespace ranges {
namespace __crbegin {
More information about the libcxx-commits
mailing list