diff --git a/stl/inc/ranges b/stl/inc/ranges index 40df5e21dba..69dccf7f418 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -33,6 +33,17 @@ namespace ranges { template inline constexpr bool _Is_initializer_list = _Is_specialization_v, initializer_list>; +#if _HAS_CXX23 + _EXPORT_STD template + using const_iterator_t = const_iterator>; + + _EXPORT_STD template + using const_sentinel_t = const_sentinel>; + + _EXPORT_STD template + using range_const_reference_t = iter_const_reference_t>; +#endif // _HAS_CXX23 + // clang-format off _EXPORT_STD template concept viewable_range = range<_Rng> @@ -45,20 +56,19 @@ namespace ranges { concept _Simple_view = view<_Rng> && range && same_as, iterator_t> && same_as, sentinel_t>; + // clang-format on template concept _Valid_movable_box_object = #if _HAS_CXX23 - move_constructible<_Ty> + move_constructible<_Ty> #else // ^^^ C++23 / C++20 vvv - copy_constructible<_Ty> + copy_constructible<_Ty> #endif // C++20 - && _Destructible_object<_Ty>; + && _Destructible_object<_Ty>; template - concept _Has_arrow = input_iterator<_It> - && (is_pointer_v<_It> || _Has_member_arrow<_It&>); - // clang-format on + concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow<_It&>); template using _Maybe_const = conditional_t<_IsConst, const _Ty, _Ty>; diff --git a/stl/inc/span b/stl/inc/span index 22f9f8b8c37..f61c42e1929 100644 --- a/stl/inc/span +++ b/stl/inc/span @@ -17,7 +17,6 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C++20 #include #include - #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -312,16 +311,20 @@ private: using _Mybase::_Mysize; public: - using element_type = _Ty; - using value_type = remove_cv_t<_Ty>; - using size_type = size_t; - using difference_type = ptrdiff_t; - using pointer = _Ty*; - using const_pointer = const _Ty*; - using reference = _Ty&; - using const_reference = const _Ty&; - using iterator = _Span_iterator<_Ty>; - using reverse_iterator = _STD reverse_iterator; + using element_type = _Ty; + using value_type = remove_cv_t<_Ty>; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = _Ty*; + using const_pointer = const _Ty*; + using reference = _Ty&; + using const_reference = const _Ty&; + using iterator = _Span_iterator<_Ty>; + using reverse_iterator = _STD reverse_iterator; +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + using const_iterator = _STD const_iterator; + using const_reverse_iterator = _STD const_iterator; +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) static constexpr size_type extent = _Extent; @@ -617,6 +620,16 @@ public: #endif // _ITERATOR_DEBUG_LEVEL } +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + _NODISCARD constexpr const_iterator cbegin() const noexcept { + return begin(); + } + + _NODISCARD constexpr const_iterator cend() const noexcept { + return end(); + } +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + _NODISCARD constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } @@ -625,6 +638,16 @@ public: return reverse_iterator{begin()}; } +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + _NODISCARD constexpr const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } + + _NODISCARD constexpr const_reverse_iterator crend() const noexcept { + return rend(); + } +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + _NODISCARD constexpr pointer _Unchecked_begin() const noexcept { return _Mydata; } diff --git a/stl/inc/xutility b/stl/inc/xutility index 8d83fa83eb6..cb697f0e4cb 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2233,6 +2233,9 @@ namespace ranges { _RANGES end(__r); }; + _EXPORT_STD template + concept input_range = range<_Rng> && input_iterator>; + _EXPORT_STD template using sentinel_t = decltype(_RANGES end(_STD declval<_Rng&>())); @@ -2426,15 +2429,44 @@ namespace ranges { _EXPORT_STD template using range_rvalue_reference_t = iter_rvalue_reference_t>; +#if _HAS_CXX23 + _EXPORT_STD template + concept constant_range = input_range<_Rng> && _Constant_iterator>; + + template + _NODISCARD constexpr auto& _Possibly_const_range(_Rng& _Range) noexcept { + if constexpr (constant_range && !constant_range<_Rng>) { + return _STD as_const(_Range); + } else { + return _Range; + } + } + + template + _NODISCARD constexpr auto _As_const_pointer(const _Ty* _Ptr) noexcept { + return _Ptr; + } +#endif // _HAS_CXX23 + struct _Cbegin_fn { - // clang-format off +#if _HAS_CXX23 + template <_Should_range_access _Ty, + class _Uty = decltype(_RANGES begin(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))> + _NODISCARD constexpr auto operator()(_Ty&& _Val) const + noexcept(noexcept(const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))})) + requires requires { const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}; } + { + return const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}; + } +#else // ^^^ C++23 / C++20 vvv template > _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(noexcept(_RANGES begin(static_cast<_CTy&&>(_Val)))) - requires requires { _RANGES begin(static_cast<_CTy&&>(_Val)); } { + requires requires { _RANGES begin(static_cast<_CTy&&>(_Val)); } + { return _RANGES begin(static_cast<_CTy&&>(_Val)); } - // clang-format on +#endif // C++20 }; inline namespace _Cpos { @@ -2442,14 +2474,24 @@ namespace ranges { } struct _Cend_fn { - // clang-format off +#if _HAS_CXX23 + template <_Should_range_access _Ty, + class _Uty = decltype(_RANGES end(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))> + _NODISCARD constexpr auto operator()(_Ty&& _Val) const + noexcept(noexcept(const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))})) + requires requires { const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))}; } + { + return const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))}; + } +#else // ^^^ C++23 / C++20 vvv template > _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(noexcept(_RANGES end(static_cast<_CTy&&>(_Val)))) - requires requires { _RANGES end(static_cast<_CTy&&>(_Val)); } { + requires requires { _RANGES end(static_cast<_CTy&&>(_Val)); } + { return _RANGES end(static_cast<_CTy&&>(_Val)); } - // clang-format on +#endif // C++20 }; inline namespace _Cpos { @@ -2592,14 +2634,24 @@ namespace ranges { } struct _Crbegin_fn { - // clang-format off +#if _HAS_CXX23 + template <_Should_range_access _Ty, + class _Uty = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))> + _NODISCARD constexpr auto operator()(_Ty&& _Val) const + noexcept(noexcept(const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))})) + requires requires { const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}; } + { + return const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}; + } +#else // ^^^ C++23 / C++20 vvv template > _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(noexcept(_RANGES rbegin(static_cast<_CTy&&>(_Val)))) - requires requires { _RANGES rbegin(static_cast<_CTy&&>(_Val)); } { + requires requires { _RANGES rbegin(static_cast<_CTy&&>(_Val)); } + { return _RANGES rbegin(static_cast<_CTy&&>(_Val)); } - // clang-format on +#endif // C++20 }; inline namespace _Cpos { @@ -2607,14 +2659,24 @@ namespace ranges { } struct _Crend_fn { - // clang-format off +#if _HAS_CXX23 + template <_Should_range_access _Ty, + class _Uty = decltype(_RANGES rend(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))> + _NODISCARD constexpr auto operator()(_Ty&& _Val) const + noexcept(noexcept(const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))})) + requires requires { const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}; } + { + return const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}; + } +#else // ^^^ C++23 / C++20 vvv template > _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(noexcept(_RANGES rend(static_cast<_CTy&&>(_Val)))) - requires requires { _RANGES rend(static_cast<_CTy&&>(_Val)); } { + requires requires { _RANGES rend(static_cast<_CTy&&>(_Val)); } + { return _RANGES rend(static_cast<_CTy&&>(_Val)); } - // clang-format on +#endif // C++20 }; inline namespace _Cpos { @@ -2823,14 +2885,23 @@ namespace ranges { } struct _Cdata_fn { - // clang-format off +#if _HAS_CXX23 + template <_Should_range_access _Ty> + _NODISCARD constexpr auto operator()(_Ty&& _Val) const + noexcept(noexcept(_RANGES data(_RANGES _Possibly_const_range(_Val)))) + requires requires { _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val))); } + { + return _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val))); + } +#else // ^^^ C++23 / C++20 vvv template > _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(noexcept(_RANGES data(static_cast<_CTy&&>(_Val)))) - requires requires { _RANGES data(static_cast<_CTy&&>(_Val)); } { + requires requires { _RANGES data(static_cast<_CTy&&>(_Val)); } + { return _RANGES data(static_cast<_CTy&&>(_Val)); } - // clang-format on +#endif // C++20 }; inline namespace _Cpos { @@ -2869,9 +2940,6 @@ namespace ranges { _EXPORT_STD template concept output_range = range<_Rng> && output_iterator, _Ty>; - _EXPORT_STD template - concept input_range = range<_Rng> && input_iterator>; - _EXPORT_STD template concept forward_range = range<_Rng> && forward_iterator>; @@ -3192,7 +3260,6 @@ namespace ranges { template concept _Can_empty = requires(_Ty __t) { _RANGES empty(__t); }; - // clang-format off _EXPORT_STD template requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>> class view_interface { @@ -3216,9 +3283,11 @@ namespace ranges { public: #ifdef __clang__ // TRANSITION, LLVM-44833 template - _NODISCARD constexpr bool empty() requires sized_range<_Dx> || forward_range<_Dx> + _NODISCARD constexpr bool empty() + requires sized_range<_Dx> || forward_range<_Dx> #else // ^^^ workaround / no workaround vvv - _NODISCARD constexpr bool empty() requires sized_range<_Derived> || forward_range<_Derived> + _NODISCARD constexpr bool empty() + requires sized_range<_Derived> || forward_range<_Derived> #endif // TRANSITION, LLVM-44833 { auto& _Self = _Cast(); @@ -3231,9 +3300,11 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-44833 template - _NODISCARD constexpr bool empty() const requires sized_range || forward_range + _NODISCARD constexpr bool empty() const + requires sized_range || forward_range #else // ^^^ workaround / no workaround vvv - _NODISCARD constexpr bool empty() const requires sized_range || forward_range + _NODISCARD constexpr bool empty() const + requires sized_range || forward_range #endif // TRANSITION, LLVM-44833 { auto& _Self = _Cast(); @@ -3244,11 +3315,63 @@ namespace ranges { } } +#if _HAS_CXX23 +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr auto cbegin() + requires input_range<_Dx> // Per LWG-3766 +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr auto cbegin() + requires input_range<_Derived> // Per LWG-3766 +#endif // TRANSITION, LLVM-44833 + { + return _RANGES cbegin(_Cast()); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr auto cbegin() const + requires input_range // Per LWG-3766 +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr auto cbegin() const + requires input_range // Per LWG-3766 +#endif // TRANSITION, LLVM-44833 + { + return _RANGES cbegin(_Cast()); + } + #ifdef __clang__ // TRANSITION, LLVM-44833 template - constexpr explicit operator bool() requires _Can_empty<_Dx> + _NODISCARD constexpr auto cend() + requires input_range<_Dx> // Per LWG-3766 #else // ^^^ workaround / no workaround vvv - constexpr explicit operator bool() requires _Can_empty<_Derived> + _NODISCARD constexpr auto cend() + requires input_range<_Derived> // Per LWG-3766 +#endif // TRANSITION, LLVM-44833 + { + return _RANGES cend(_Cast()); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr auto cend() const + requires input_range // Per LWG-3766 +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr auto cend() const + requires input_range // Per LWG-3766 +#endif // TRANSITION, LLVM-44833 + { + return _RANGES cend(_Cast()); + } +#endif // _HAS_CXX23 + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + constexpr explicit operator bool() + requires _Can_empty<_Dx> +#else // ^^^ workaround / no workaround vvv + constexpr explicit operator bool() + requires _Can_empty<_Derived> #endif // TRANSITION, LLVM-44833 { return !_RANGES empty(_Cast()); @@ -3256,9 +3379,11 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-44833 template - constexpr explicit operator bool() const requires _Can_empty + constexpr explicit operator bool() const + requires _Can_empty #else // ^^^ workaround / no workaround vvv - constexpr explicit operator bool() const requires _Can_empty + constexpr explicit operator bool() const + requires _Can_empty #endif // TRANSITION, LLVM-44833 { return !_RANGES empty(_Cast()); @@ -3266,9 +3391,11 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-44833 template - _NODISCARD constexpr auto data() requires contiguous_iterator> + _NODISCARD constexpr auto data() + requires contiguous_iterator> #else // ^^^ workaround / no workaround vvv - _NODISCARD constexpr auto data() requires contiguous_iterator> + _NODISCARD constexpr auto data() + requires contiguous_iterator> #endif // TRANSITION, LLVM-44833 { return _STD to_address(_RANGES begin(_Cast())); @@ -3301,11 +3428,12 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-44833 template - _NODISCARD constexpr auto size() const requires forward_range - && sized_sentinel_for, iterator_t> + _NODISCARD constexpr auto size() const + requires forward_range && sized_sentinel_for, iterator_t> #else // ^^^ workaround / no workaround vvv - _NODISCARD constexpr auto size() const requires forward_range - && sized_sentinel_for, iterator_t> + _NODISCARD constexpr auto size() const + requires forward_range + && sized_sentinel_for, iterator_t> #endif // TRANSITION, LLVM-44833 { auto& _Self = _Cast(); @@ -3314,9 +3442,11 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-44833 template - _NODISCARD constexpr decltype(auto) front() requires forward_range<_Dx> + _NODISCARD constexpr decltype(auto) front() + requires forward_range<_Dx> #else // ^^^ workaround / no workaround vvv - _NODISCARD constexpr decltype(auto) front() requires forward_range<_Derived> + _NODISCARD constexpr decltype(auto) front() + requires forward_range<_Derived> #endif // TRANSITION, LLVM-44833 { auto& _Self = _Cast(); @@ -3328,9 +3458,11 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-44833 template - _NODISCARD constexpr decltype(auto) front() const requires forward_range + _NODISCARD constexpr decltype(auto) front() const + requires forward_range #else // ^^^ workaround / no workaround vvv - _NODISCARD constexpr decltype(auto) front() const requires forward_range + _NODISCARD constexpr decltype(auto) front() const + requires forward_range #endif // TRANSITION, LLVM-44833 { auto& _Self = _Cast(); @@ -3342,9 +3474,11 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-44833 template - _NODISCARD constexpr decltype(auto) back() requires bidirectional_range<_Dx> && common_range<_Dx> + _NODISCARD constexpr decltype(auto) back() + requires bidirectional_range<_Dx> && common_range<_Dx> #else // ^^^ workaround / no workaround vvv - _NODISCARD constexpr decltype(auto) back() requires bidirectional_range<_Derived> && common_range<_Derived> + _NODISCARD constexpr decltype(auto) back() + requires bidirectional_range<_Derived> && common_range<_Derived> #endif // TRANSITION, LLVM-44833 { auto& _Self = _Cast(); @@ -3398,7 +3532,6 @@ namespace ranges { return _RANGES begin(_Self)[_Idx]; } }; - // clang-format on } // namespace ranges // These declarations must be visible to qualified name lookup for _STD get in _Pair_like below, even if hasn't diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 19b3c83e6d4..7b17af1fbd6 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -325,7 +325,7 @@ // P2186R2 Removing Garbage Collection Support // P2273R3 constexpr unique_ptr // P2278R4 cbegin Should Always Return A Constant Iterator -// ("Iterators" section from the paper only) +// (missing views::as_const) // P2291R3 constexpr Integral // P2302R4 ranges::contains, ranges::contains_subrange // P2321R2 zip diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index ad44aa04c4f..95c0064f6f7 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -58,6 +58,14 @@ std/strings/basic.string/string.nonmembers/string_op+/allocator_propagation.pass # libc++ hasn't updated move_iterator for P2520R0 std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp FAIL +# libc++ has not implemented P2278R4: "cbegin should always return a constant iterator" +std/containers/views/views.span/types.pass.cpp FAIL +std/ranges/range.access/begin.pass.cpp FAIL +std/ranges/range.access/data.pass.cpp FAIL +std/ranges/range.access/end.pass.cpp FAIL +std/ranges/range.access/rbegin.pass.cpp FAIL +std/ranges/range.access/rend.pass.cpp FAIL + # libc++ doesn't implement LWG-3692: "zip_view::iterator's operator<=> is overconstrained" std/ranges/range.adaptors/range.zip/iterator/compare.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index c16c1f5ded1..05675346133 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -58,6 +58,14 @@ strings\basic.string\string.nonmembers\string_op+\allocator_propagation.pass.cpp # libc++ hasn't updated move_iterator for P2520R0 iterators\predef.iterators\move.iterators\move.iterator\types.pass.cpp +# libc++ has not implemented P2278R4: "cbegin should always return a constant iterator" +containers\views\views.span\types.pass.cpp +ranges\range.access\begin.pass.cpp +ranges\range.access\data.pass.cpp +ranges\range.access\end.pass.cpp +ranges\range.access\rbegin.pass.cpp +ranges\range.access\rend.pass.cpp + # libc++ doesn't implement LWG-3692: "zip_view::iterator's operator<=> is overconstrained" ranges\range.adaptors\range.zip\iterator\compare.pass.cpp diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 1c4c0db2ce6..8802ab181bb 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -1458,8 +1458,13 @@ concept CanMemberEnd = requires(R&& r) { std::forward(r).end(); }; template concept CanCBegin = requires(R&& r) { ranges::cbegin(std::forward(r)); }; +template +concept CanMemberCBegin = requires(R&& r) { std::forward(r).cbegin(); }; + template concept CanCEnd = requires(R&& r) { ranges::cend(std::forward(r)); }; +template +concept CanMemberCEnd = requires(R&& r) { std::forward(r).cend(); }; template concept CanRBegin = requires(R&& r) { ranges::rbegin(std::forward(r)); }; diff --git a/tests/std/test.lst b/tests/std/test.lst index 65b50c904aa..0284cc00e30 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -548,7 +548,9 @@ tests\P2162R2_std_visit_for_derived_classes_from_variant tests\P2231R1_complete_constexpr_optional_variant tests\P2273R3_constexpr_unique_ptr tests\P2278R4_basic_const_iterator +tests\P2278R4_const_span tests\P2278R4_ranges_const_iterator_machinery +tests\P2278R4_ranges_const_range_machinery tests\P2302R4_ranges_alg_contains tests\P2302R4_ranges_alg_contains_subrange tests\P2321R2_proxy_reference diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index 8779e29c7ab..7076deb301a 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -573,7 +573,6 @@ STATIC_ASSERT(!ranges::view); STATIC_ASSERT(test_begin()); STATIC_ASSERT(test_end()); -STATIC_ASSERT(test_cbegin()); STATIC_ASSERT(test_cend()); STATIC_ASSERT(test_rbegin()); STATIC_ASSERT(test_rend()); @@ -581,15 +580,22 @@ STATIC_ASSERT(test_crbegin()); STATIC_ASSERT(test_crend()); STATIC_ASSERT(test_size()); STATIC_ASSERT(test_empty()); -// Can't use test_data/_cdata here because they use range_value_t and this isn't a range +// Can't use test_data here because it uses range_value_t and this isn't a range STATIC_ASSERT(std::same_as())), int*>); -STATIC_ASSERT(std::same_as())), int const*>); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(!ranges::view); +#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behavior differs in C++20 and C++23 modes +STATIC_ASSERT(test_cbegin()); +STATIC_ASSERT(test_cdata()); +#else // ^^^ C++23 / C++20 vvv +STATIC_ASSERT(test_cbegin()); +// Can't use test_cdata here because it uses range_value_t and this isn't a range +STATIC_ASSERT(std::same_as())), int const*>); +#endif // C++20 + STATIC_ASSERT(test_begin()); STATIC_ASSERT(test_end()); -STATIC_ASSERT(test_cbegin()); STATIC_ASSERT(test_cend()); STATIC_ASSERT(test_rbegin()); STATIC_ASSERT(test_rend()); @@ -597,17 +603,24 @@ STATIC_ASSERT(test_crbegin()); STATIC_ASSERT(test_crend()); STATIC_ASSERT(test_size()); STATIC_ASSERT(test_empty()); -// Can't use test_data/_cdata here because they use range_value_t and this isn't a range +// Can't use test_data here because it uses range_value_t and this isn't a range STATIC_ASSERT(std::same_as())), int const*>); -STATIC_ASSERT(std::same_as())), int const*>); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(!ranges::view); +#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behavior differs in C++20 and C++23 modes +STATIC_ASSERT(test_cbegin()); +STATIC_ASSERT(test_cdata()); +#else // ^^^ C++23 / C++20 vvv +STATIC_ASSERT(test_cbegin()); +// Can't use test_cdata here because it uses range_value_t and this isn't a range +STATIC_ASSERT(std::same_as())), int const*>); +#endif // C++20 + // Validate behavior before/after completing the bound of an array extern int initially_unbounded[]; STATIC_ASSERT(ranges::begin(initially_unbounded) == initially_unbounded); STATIC_ASSERT(!CanEnd); -STATIC_ASSERT(ranges::cbegin(initially_unbounded) == initially_unbounded); STATIC_ASSERT(!CanCEnd); STATIC_ASSERT(!CanRBegin); STATIC_ASSERT(!CanREnd); @@ -616,7 +629,15 @@ STATIC_ASSERT(!CanCREnd); STATIC_ASSERT(!CanSize); STATIC_ASSERT(!CanEmpty); STATIC_ASSERT(ranges::data(initially_unbounded) == initially_unbounded); + +#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behavior differs in C++20 and C++23 modes +STATIC_ASSERT(!CanCBegin); +STATIC_ASSERT(!CanCData); +#else // ^^^ C++23 / C++20 vvv +STATIC_ASSERT(ranges::cbegin(initially_unbounded) == initially_unbounded); STATIC_ASSERT(ranges::cdata(initially_unbounded) == initially_unbounded); +#endif // C++20 + int initially_unbounded[42]; STATIC_ASSERT(ranges::begin(initially_unbounded) == initially_unbounded); STATIC_ASSERT(ranges::end(initially_unbounded) == initially_unbounded + ranges::size(initially_unbounded)); @@ -972,64 +993,100 @@ STATIC_ASSERT(!ranges::view); STATIC_ASSERT(test_begin, std::span::iterator>()); STATIC_ASSERT(test_end, std::span::iterator>()); -STATIC_ASSERT(test_cbegin, std::span::iterator>()); -STATIC_ASSERT(test_cend, std::span::iterator>()); STATIC_ASSERT(test_rbegin, std::reverse_iterator::iterator>>()); STATIC_ASSERT(test_rend, std::reverse_iterator::iterator>>()); -STATIC_ASSERT(test_crbegin, std::reverse_iterator::iterator>>()); -STATIC_ASSERT(test_crend, std::reverse_iterator::iterator>>()); STATIC_ASSERT(test_size, std::size_t>()); STATIC_ASSERT(test_empty, true>()); STATIC_ASSERT(test_data, int*>()); -STATIC_ASSERT(test_cdata, int*>()); STATIC_ASSERT(test_contiguous_range>()); STATIC_ASSERT(ranges::view>); +#if _HAS_CXX23 // behavior of span members differs in C++20 and C++23 modes +STATIC_ASSERT(test_cbegin, std::span::const_iterator>()); +STATIC_ASSERT(test_cend, std::span::const_iterator>()); +STATIC_ASSERT(test_crbegin, std::span::const_reverse_iterator>()); +STATIC_ASSERT(test_crend, std::span::const_reverse_iterator>()); +STATIC_ASSERT(test_cdata, const int*>()); +#else // ^^^ C++23 / C++20 vvv +STATIC_ASSERT(test_cbegin, std::span::iterator>()); +STATIC_ASSERT(test_cend, std::span::iterator>()); +STATIC_ASSERT(test_crbegin, std::reverse_iterator::iterator>>()); +STATIC_ASSERT(test_crend, std::reverse_iterator::iterator>>()); +STATIC_ASSERT(test_cdata, int*>()); +#endif // C++20 + STATIC_ASSERT(test_begin const, std::span::iterator>()); STATIC_ASSERT(test_end const, std::span::iterator>()); -STATIC_ASSERT(test_cbegin const, std::span::iterator>()); -STATIC_ASSERT(test_cend const, std::span::iterator>()); STATIC_ASSERT(test_rbegin const, std::reverse_iterator::iterator>>()); STATIC_ASSERT(test_rend const, std::reverse_iterator::iterator>>()); -STATIC_ASSERT(test_crbegin const, std::reverse_iterator::iterator>>()); -STATIC_ASSERT(test_crend const, std::reverse_iterator::iterator>>()); STATIC_ASSERT(test_size const, std::size_t>()); STATIC_ASSERT(test_empty const, true>()); STATIC_ASSERT(test_data const, int*>()); -STATIC_ASSERT(test_cdata const, int*>()); STATIC_ASSERT(test_contiguous_range const>()); STATIC_ASSERT(!ranges::view const>); +#if _HAS_CXX23 // behavior of const span members differs in C++20 and C++23 modes +STATIC_ASSERT(test_cbegin const, std::span::const_iterator>()); +STATIC_ASSERT(test_cend const, std::span::const_iterator>()); +STATIC_ASSERT(test_crbegin const, std::span::const_reverse_iterator>()); +STATIC_ASSERT(test_crend const, std::span::const_reverse_iterator>()); +STATIC_ASSERT(test_cdata const, const int*>()); +#else // ^^^ C++23 / C++20 vvv +STATIC_ASSERT(test_cbegin const, std::span::iterator>()); +STATIC_ASSERT(test_cend const, std::span::iterator>()); +STATIC_ASSERT(test_crbegin const, std::reverse_iterator::iterator>>()); +STATIC_ASSERT(test_crend const, std::reverse_iterator::iterator>>()); +STATIC_ASSERT(test_cdata const, int*>()); +#endif // C++20 + STATIC_ASSERT(test_begin&, std::span::iterator>()); STATIC_ASSERT(test_end&, std::span::iterator>()); -STATIC_ASSERT(test_cbegin&, std::span::iterator>()); -STATIC_ASSERT(test_cend&, std::span::iterator>()); STATIC_ASSERT(test_rbegin&, std::reverse_iterator::iterator>>()); STATIC_ASSERT(test_rend&, std::reverse_iterator::iterator>>()); -STATIC_ASSERT(test_crbegin&, std::reverse_iterator::iterator>>()); -STATIC_ASSERT(test_crend&, std::reverse_iterator::iterator>>()); STATIC_ASSERT(test_size&, std::size_t>()); STATIC_ASSERT(test_empty&, true>()); STATIC_ASSERT(test_data&, int*>()); -STATIC_ASSERT(test_cdata&, int*>()); STATIC_ASSERT(test_contiguous_range&>()); STATIC_ASSERT(!ranges::view&>); +#if _HAS_CXX23 // behavior of span& members differs in C++20 and C++23 modes +STATIC_ASSERT(test_cbegin&, std::span::const_iterator>()); +STATIC_ASSERT(test_cend&, std::span::const_iterator>()); +STATIC_ASSERT(test_crbegin&, std::span::const_reverse_iterator>()); +STATIC_ASSERT(test_crend&, std::span::const_reverse_iterator>()); +STATIC_ASSERT(test_cdata&, const int*>()); +#else // ^^^ C++23 / C++20 vvv +STATIC_ASSERT(test_cbegin&, std::span::iterator>()); +STATIC_ASSERT(test_cend&, std::span::iterator>()); +STATIC_ASSERT(test_crbegin&, std::reverse_iterator::iterator>>()); +STATIC_ASSERT(test_crend&, std::reverse_iterator::iterator>>()); +STATIC_ASSERT(test_cdata&, int*>()); +#endif // C++20 + STATIC_ASSERT(test_begin const&, std::span::iterator>()); STATIC_ASSERT(test_end const&, std::span::iterator>()); -STATIC_ASSERT(test_cbegin const&, std::span::iterator>()); -STATIC_ASSERT(test_cend const&, std::span::iterator>()); STATIC_ASSERT(test_rbegin const&, std::reverse_iterator::iterator>>()); STATIC_ASSERT(test_rend const&, std::reverse_iterator::iterator>>()); -STATIC_ASSERT(test_crbegin const&, std::reverse_iterator::iterator>>()); -STATIC_ASSERT(test_crend const&, std::reverse_iterator::iterator>>()); STATIC_ASSERT(test_size const&, std::size_t>()); STATIC_ASSERT(test_empty const&, true>()); STATIC_ASSERT(test_data const&, int*>()); -STATIC_ASSERT(test_cdata const&, int*>()); STATIC_ASSERT(test_contiguous_range const&>()); STATIC_ASSERT(!ranges::view const&>); +#if _HAS_CXX23 // behavior of const span& members differs in C++20 and C++23 modes +STATIC_ASSERT(test_cbegin const&, std::span::const_iterator>()); +STATIC_ASSERT(test_cend const&, std::span::const_iterator>()); +STATIC_ASSERT(test_crbegin const&, std::span::const_reverse_iterator>()); +STATIC_ASSERT(test_crend const&, std::span::const_reverse_iterator>()); +STATIC_ASSERT(test_cdata const&, const int*>()); +#else // ^^^ C++23 / C++20 vvv +STATIC_ASSERT(test_cbegin const&, std::span::iterator>()); +STATIC_ASSERT(test_cend const&, std::span::iterator>()); +STATIC_ASSERT(test_crbegin const&, std::reverse_iterator::iterator>>()); +STATIC_ASSERT(test_crend const&, std::reverse_iterator::iterator>>()); +STATIC_ASSERT(test_cdata const&, int*>()); +#endif // C++20 + using valarray_int_iterator = decltype(std::begin(std::declval&>())); using const_valarray_int_iterator = decltype(std::begin(std::declval&>())); STATIC_ASSERT(test_begin>()); diff --git a/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp b/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp index 2d35641a235..87f16ca3c2e 100644 --- a/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp +++ b/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp @@ -95,6 +95,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(!CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(!CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -116,6 +122,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(!CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(!CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -137,6 +149,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(!CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -158,6 +176,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(!CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -179,6 +203,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(!CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -200,6 +230,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(!CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -221,6 +257,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -242,6 +284,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -263,6 +311,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -284,6 +338,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -305,6 +365,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -326,6 +392,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -347,6 +419,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -368,6 +446,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -389,6 +473,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -410,6 +500,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -431,6 +527,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -452,6 +554,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -473,6 +581,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -494,6 +608,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -515,6 +635,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -536,6 +662,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -557,6 +689,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -578,6 +716,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -599,6 +743,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -620,6 +770,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -641,6 +797,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(!CanData); @@ -662,6 +824,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanData); @@ -683,6 +851,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(CanData); @@ -704,6 +878,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(CanData); @@ -725,6 +905,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(!CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(!CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(!CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(!CanBool); STATIC_ASSERT(CanData); @@ -746,6 +932,12 @@ namespace test_view_interface { STATIC_ASSERT(ranges::view); STATIC_ASSERT(CanEmpty); STATIC_ASSERT(CanEmpty); +#if _HAS_CXX23 + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd); +#endif // _HAS_CXX23 STATIC_ASSERT(CanBool); STATIC_ASSERT(CanBool); STATIC_ASSERT(CanData); diff --git a/tests/std/tests/P2278R4_const_span/env.lst b/tests/std/tests/P2278R4_const_span/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2278R4_const_span/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2278R4_const_span/test.cpp b/tests/std/tests/P2278R4_const_span/test.cpp new file mode 100644 index 00000000000..19fd692c808 --- /dev/null +++ b/tests/std/tests/P2278R4_const_span/test.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +using namespace std; + +enum class Const : bool { no, yes }; +enum class Dynamic : bool { no, yes }; + +static_assert(!to_underlying(Const::no) && to_underlying(Const::yes)); +static_assert(!to_underlying(Dynamic::no) && to_underlying(Dynamic::yes)); + +template +constexpr bool test() { + using T = conditional_t; + using Span = span; + using CIt = typename Span::const_iterator; + using CRevIt = typename Span::const_reverse_iterator; + + // Validate iterator properties + static_assert(contiguous_iterator); + static_assert(random_access_iterator); + static_assert(same_as>); + static_assert(same_as>); + static_assert(same_as>); + static_assert(same_as>); + static_assert(same_as, remove_cv_t>); + static_assert(same_as, remove_cv_t>); + static_assert(same_as, const T&>); + static_assert(same_as, const T&>); + + T elems[3] = {1, 22, 333}; + const Span s{elems}; + + { // Validate span::cbegin + same_as auto it = s.cbegin(); + assert(it == s.begin()); + assert(*it == 1); + static_assert(noexcept(s.cbegin())); + } + + { // Validate span::cend + same_as auto it = s.cend(); + assert(it == s.end()); + assert(it[-1] == 333); + static_assert(noexcept(s.cend())); + } + + { // Validate span::crbegin + same_as auto it = s.crbegin(); + assert(it == s.rbegin()); + assert(*it == 333); + static_assert(noexcept(s.crbegin())); + } + + { // Validate span::crend + same_as auto it = s.crend(); + assert(it == s.rend()); + assert(it[-1] == 1); + static_assert(noexcept(s.crend())); + } + + return true; +} + +int main() { + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); + + test(); + test(); + test(); + test(); +} diff --git a/tests/std/tests/P2278R4_ranges_const_iterator_machinery/test.compile.pass.cpp b/tests/std/tests/P2278R4_ranges_const_iterator_machinery/test.compile.pass.cpp index 9a33ffe39d4..892fbf06789 100644 --- a/tests/std/tests/P2278R4_ranges_const_iterator_machinery/test.compile.pass.cpp +++ b/tests/std/tests/P2278R4_ranges_const_iterator_machinery/test.compile.pass.cpp @@ -12,16 +12,16 @@ using namespace std; -template +template concept CanIterConstRef = requires { typename iter_const_reference_t; }; -template +template concept CanConstIterator = requires(It it) { typename const_iterator; { make_const_iterator(move(it)) } -> same_as>; }; -template +template concept CanConstSentinel = requires(Se se) { typename const_sentinel; { make_const_sentinel(move(se)) } -> same_as>; diff --git a/tests/std/tests/P2278R4_ranges_const_range_machinery/env.lst b/tests/std/tests/P2278R4_ranges_const_range_machinery/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2278R4_ranges_const_range_machinery/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp b/tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp new file mode 100644 index 00000000000..e504f96def7 --- /dev/null +++ b/tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp @@ -0,0 +1,240 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// New members (cbegin and cend) of `view_interface` are tested in `P0896R4_ranges_subrange\test.cpp`. +// Updated CPOs (cbegin, cdata, ...) are tested in `P0896R4_ranges_range_machinery\test.cpp` + +using namespace std; + +template +concept CanRangeConstIterator = requires { typename ranges::const_iterator_t; }; + +template +concept CanRangeConstSentinel = requires { typename ranges::const_sentinel_t; }; + +template +concept CanRangeConstReference = requires { typename ranges::range_const_reference_t; }; + +static_assert(!CanRangeConstIterator); +static_assert(!CanRangeConstSentinel); +static_assert(!CanRangeConstReference); + +namespace test_array { + using Arr = int[10]; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const_iterator>); + static_assert(same_as, const_iterator>); + static_assert(same_as, const int&>); + static_assert(!ranges::constant_range); + + using ConstArr = const Arr; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const int*>); + static_assert(same_as, const int*>); + static_assert(same_as, const int&>); + static_assert(ranges::constant_range); +} // namespace test_array + +namespace test_random_access_range { + using Rng = deque; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const_iterator>); + static_assert(same_as, const_iterator>); + static_assert(same_as, const int&>); + static_assert(!ranges::constant_range); + + using ConstRng = const deque; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, ConstRng::const_iterator>); + static_assert(same_as, ConstRng::const_iterator>); + static_assert(same_as, const int&>); + static_assert(ranges::constant_range); +} // namespace test_random_access_range + +namespace test_bidirectional_range { + using Rng = list; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const_iterator>); + static_assert(same_as, const_iterator>); + static_assert(same_as, const int&>); + static_assert(!ranges::constant_range); + + using ConstRng = const list; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, ConstRng::const_iterator>); + static_assert(same_as, ConstRng::const_iterator>); + static_assert(same_as, const int&>); + static_assert(ranges::constant_range); +} // namespace test_bidirectional_range + +namespace test_forward_range { + using Rng = forward_list; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const_iterator>); + static_assert(same_as, const_iterator>); + static_assert(same_as, const int&>); + static_assert(!ranges::constant_range); + + using ConstRng = const forward_list; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, ConstRng::const_iterator>); + static_assert(same_as, ConstRng::const_iterator>); + static_assert(same_as, const int&>); + static_assert(ranges::constant_range); +} // namespace test_forward_range + +namespace test_input_range { + using Rng = ranges::istream_view; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const_iterator>>); + static_assert(same_as, default_sentinel_t>); + static_assert(same_as, const int&>); + static_assert(!ranges::constant_range); +} // namespace test_input_range + +namespace test_prvalue_range { + using Rng = ranges::transform_view>, int (*)(float)>; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const_iterator>>); + static_assert(same_as, const_iterator>>); + static_assert(same_as, int>); + static_assert(ranges::constant_range); + + using ConstRng = const Rng; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const_iterator>>); + static_assert(same_as, const_iterator>>); + static_assert(same_as, int>); + static_assert(ranges::constant_range); +} // namespace test_prvalue_range + +namespace test_vector_bool { + using Vb = vector; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, const_iterator>); + static_assert(same_as, const_iterator>); + static_assert(same_as, bool>); + static_assert(!ranges::constant_range); + + using ConstVb = const vector; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstSentinel); + static_assert(CanRangeConstReference); + static_assert(same_as, ConstVb::const_iterator>); + static_assert(same_as, ConstVb::const_iterator>); + static_assert(same_as, bool>); + static_assert(ranges::constant_range); +} // namespace test_vector_bool + +template +static constexpr void test_cpos(Rng&& rng) { + using ranges::iterator_t, ranges::sentinel_t; + using R = conditional_t && !ranges::constant_range, const Rng&, Rng&>; + + { // Validate ranges::cbegin + using It = iterator_t; + + const same_as> auto it = ranges::cbegin(rng); + if constexpr (equality_comparable) { + if (ranges::forward_range) { // intentionally not if constexpr + assert(it == ranges::begin(rng)); + } + } + + static_assert(noexcept(ranges::cbegin(rng)) + == (noexcept(ranges::begin(rng)) && is_nothrow_constructible_v, It>) ); + } + + { // Validate ranges::cend + using Se = sentinel_t; + + const same_as> auto se = ranges::cend(rng); + if constexpr (equality_comparable) { + assert(se == ranges::end(rng)); + } + + static_assert(noexcept(ranges::cend(rng)) + == (noexcept(ranges::end(rng)) && is_nothrow_constructible_v, Se>) ); + } + + if constexpr (ranges::bidirectional_range) { + if constexpr (CanRBegin) { // Validate ranges::crbegin + using RevIt = decltype(ranges::rbegin(declval())); + + const same_as> auto it = ranges::crbegin(rng); + assert(it == ranges::rbegin(rng)); + + static_assert( + noexcept(ranges::crbegin(rng)) + == (noexcept(ranges::rbegin(rng)) && is_nothrow_constructible_v, RevIt>) ); + } + + if constexpr (CanREnd) { // Validate ranges::crend + using RevSe = decltype(ranges::rend(declval())); + + const same_as> auto it = ranges::crend(rng); + assert(it == ranges::rend(rng)); + + static_assert( + noexcept(ranges::crend(rng)) + == (noexcept(ranges::rend(rng)) && is_nothrow_constructible_v, RevSe>) ); + } + } + + if constexpr (ranges::contiguous_range) { // Validate ranges::cdata + const same_as*> auto ptr = ranges::cdata(rng); + assert(ptr == ranges::data(rng)); + + static_assert(noexcept(ranges::cdata(rng)) == noexcept(ranges::data(rng))); + } +} + +struct instantiator { + template + static constexpr void call() { + int some_ints[] = {1, 2, 3}; + Rng rng{some_ints}; + test_cpos(rng); + } +}; + +int main() { + STATIC_ASSERT((test_in(), true)); + test_in(); +}