From 9e411b26e484e059e263bb2ede3faa62965ba6cd Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 27 Oct 2022 18:03:34 +0200 Subject: [PATCH 01/21] Update `yvals_core` comment --- stl/inc/yvals_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From d62a3517535c5803eaf2deb0ee76043a6f6fa267 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 28 Oct 2022 03:10:30 +0200 Subject: [PATCH 02/21] Add `const_iterator_t`, `range_const_reference_t` + fix some formatting in `` --- stl/inc/ranges | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 40df5e21dba..1d273a48fe8 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -33,32 +33,36 @@ namespace ranges { template inline constexpr bool _Is_initializer_list = _Is_specialization_v, initializer_list>; - // clang-format off +#if _HAS_CXX23 + _EXPORT_STD template + using const_iterator_t = const_iterator>; + + _EXPORT_STD template + using range_const_reference_t = iter_const_reference_t>; +#endif // _HAS_CXX23 + _EXPORT_STD template concept viewable_range = range<_Rng> - && ((view> && constructible_from, _Rng>) - || (!view> - && (is_lvalue_reference_v<_Rng> - || (movable> && !_Is_initializer_list<_Rng>)))); + && ((view> && constructible_from, _Rng>) + || (!view> + && (is_lvalue_reference_v<_Rng> + || (movable> && !_Is_initializer_list<_Rng>) ))); template - concept _Simple_view = view<_Rng> && range - && same_as, iterator_t> - && same_as, sentinel_t>; + concept _Simple_view = view<_Rng> && range && same_as, iterator_t> + && same_as, sentinel_t>; 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>; From edad266d5e43e86d3aeaaf4615216116665ce3bb Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 28 Oct 2022 03:15:35 +0200 Subject: [PATCH 03/21] Implement CPOs --- stl/inc/xutility | 104 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 18 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 8d83fa83eb6..94a9bd81592 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 // Per LWG-3768 + constexpr auto& _Possibly_const_range(_Rng& _Range) { + if constexpr (constant_range && !constant_range<_Rng>) { + return const_cast(_Range); + } else { + return _Range; + } + } + + template + 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(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(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(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(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>; From dd3339b5a41f958f44188032abfe86b624b90dce Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 28 Oct 2022 03:18:08 +0200 Subject: [PATCH 04/21] New members of `ranges::view_interface` (+formatting fixes) --- stl/inc/xutility | 109 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 22 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 94a9bd81592..9e7677abb72 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3260,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 { @@ -3284,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(); @@ -3299,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(); @@ -3312,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()); @@ -3324,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()); @@ -3334,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())); @@ -3369,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(); @@ -3382,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(); @@ -3396,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(); @@ -3410,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(); @@ -3466,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 From 5aae7a6236b67c95a729a864b07aa5249b8b6317 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 28 Oct 2022 03:18:54 +0200 Subject: [PATCH 05/21] Changes to `span` (+formatting fixes) --- stl/inc/span | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) 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; } From 7e2b66a4206859b159102456a8e06a204d55c548 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 28 Oct 2022 03:27:34 +0200 Subject: [PATCH 06/21] `span` tests --- tests/std/test.lst | 1 + tests/std/tests/P2278R4_const_span/env.lst | 4 + tests/std/tests/P2278R4_const_span/test.cpp | 81 +++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 tests/std/tests/P2278R4_const_span/env.lst create mode 100644 tests/std/tests/P2278R4_const_span/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index 65b50c904aa..c56520deec8 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -548,6 +548,7 @@ 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\P2302R4_ranges_alg_contains tests\P2302R4_ranges_alg_contains_subrange 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..68a7fb95c51 --- /dev/null +++ b/tests/std/tests/P2278R4_const_span/test.cpp @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#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(); +} From 4445960b14c522848a73d4bd4ff67a4e57472bc6 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sat, 29 Oct 2022 20:03:20 +0200 Subject: [PATCH 07/21] Fix new CPOs: * Mark `_Possibly_const_range` as `noexcept` * Mark `_Possibly_const_range` and `_As_const_pointer` as `_NODISCARD` * Use `declval` (instead of `declval`) inside of CPOs' template decl * Add workaround in `_Possibly_const_range` for yet (possibly) unreported MSVC error --- stl/inc/xutility | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 9e7677abb72..cbc1530ab31 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2434,16 +2434,20 @@ namespace ranges { concept constant_range = input_range<_Rng> && _Constant_iterator>; template // Per LWG-3768 - constexpr auto& _Possibly_const_range(_Rng& _Range) { + _NODISCARD constexpr auto& _Possibly_const_range(_Rng& _Range) noexcept { if constexpr (constant_range && !constant_range<_Rng>) { +#ifndef __clang__ // TRANSITION, DevCom-??????? + return _STD as_const(_Range); +#else // ^^^ workaround / no workaround vvv return const_cast(_Range); +#endif // TRANSITION, DevCom-??????? } else { return _Range; } } template - constexpr auto _As_const_pointer(const _Ty* _Ptr) noexcept { + _NODISCARD constexpr auto _As_const_pointer(const _Ty* _Ptr) noexcept { return _Ptr; } #endif // _HAS_CXX23 @@ -2451,7 +2455,7 @@ namespace ranges { struct _Cbegin_fn { #if _HAS_CXX23 template <_Should_range_access _Ty, - class _Uty = decltype(_RANGES begin(_RANGES _Possibly_const_range(declval<_Ty>())))> + class _Uty = decltype(_RANGES begin(_RANGES _Possibly_const_range(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))}; } @@ -2476,7 +2480,7 @@ namespace ranges { struct _Cend_fn { #if _HAS_CXX23 template <_Should_range_access _Ty, - class _Uty = decltype(_RANGES end(_RANGES _Possibly_const_range(declval<_Ty>())))> + class _Uty = decltype(_RANGES end(_RANGES _Possibly_const_range(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))}; } @@ -2636,7 +2640,7 @@ namespace ranges { struct _Crbegin_fn { #if _HAS_CXX23 template <_Should_range_access _Ty, - class _Uty = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(declval<_Ty>())))> + class _Uty = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(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))}; } @@ -2661,7 +2665,7 @@ namespace ranges { struct _Crend_fn { #if _HAS_CXX23 template <_Should_range_access _Ty, - class _Uty = decltype(_RANGES rend(_RANGES _Possibly_const_range(declval<_Ty>())))> + class _Uty = decltype(_RANGES rend(_RANGES _Possibly_const_range(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))}; } From e7bda7db3e5be30c19b82011e17f1dc12689403c Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sat, 29 Oct 2022 20:09:14 +0200 Subject: [PATCH 08/21] Adjust tests in `P0896R4_ranges_range_machinery` to new CPOs --- .../P0896R4_ranges_range_machinery/test.cpp | 111 +++++++++++++----- 1 file changed, 84 insertions(+), 27 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index 8779e29c7ab..d77b0084726 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 they use 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 behaviour 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 they use 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 they use 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 behaviour 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 they use 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 behaviour 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 // behaviour 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 // behaviour 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 // behaviour 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 // behaviour 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>()); From aebfb3600d33efae0ef09909b48c801f5598f0a1 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sat, 29 Oct 2022 20:33:42 +0200 Subject: [PATCH 09/21] Drive-by: `typename` -> `class` in another `const_iterator` test --- .../test.compile.pass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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>; From ed18abe95c87ad0db42c200cfb99c4699efd7398 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sat, 29 Oct 2022 20:59:45 +0200 Subject: [PATCH 10/21] Test new members of `view_interface` --- tests/std/include/range_algorithm_support.hpp | 5 + .../test.compile.pass.cpp | 192 ++++++++++++++++++ 2 files changed, 197 insertions(+) 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/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); From a8c2300560cbf71f81a2d302eb5a640b3d390186 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sat, 29 Oct 2022 21:03:27 +0200 Subject: [PATCH 11/21] Add missing tests --- tests/std/test.lst | 1 + .../env.lst | 4 + .../test.cpp | 210 ++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 tests/std/tests/P2278R4_ranges_const_range_machinery/env.lst create mode 100644 tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index c56520deec8..0284cc00e30 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -550,6 +550,7 @@ 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/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..f244d86fd14 --- /dev/null +++ b/tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp @@ -0,0 +1,210 @@ +// 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 CanRangeConstReference = requires { typename ranges::range_const_reference_t; }; + +static_assert(!CanRangeConstIterator); +static_assert(!CanRangeConstReference); + +namespace test_array { + using Arr = int[10]; + static_assert(CanRangeConstIterator); + static_assert(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + static_assert(same_as, const_iterator>>); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(CanRangeConstReference); + 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(); +} From ff5fe5d1d28cbd713a802cdb6ec43c0d84480628 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 1 Nov 2022 14:42:02 +0100 Subject: [PATCH 12/21] LWG-3768 is considered NAD --- stl/inc/xutility | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index cbc1530ab31..36d27284c67 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2433,7 +2433,7 @@ namespace ranges { _EXPORT_STD template concept constant_range = input_range<_Rng> && _Constant_iterator>; - template // Per LWG-3768 + template _NODISCARD constexpr auto& _Possibly_const_range(_Rng& _Range) noexcept { if constexpr (constant_range && !constant_range<_Rng>) { #ifndef __clang__ // TRANSITION, DevCom-??????? From 89a80c13bd1d56bfe2608b620efc061fc97a7ae3 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 1 Nov 2022 16:14:12 +0100 Subject: [PATCH 13/21] Skip failing LLVM/libcxx tests --- tests/libcxx/expected_results.txt | 8 ++++++++ tests/libcxx/skipped_tests.txt | 8 ++++++++ 2 files changed, 16 insertions(+) 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..f89779f3bf6 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" +std/containers/views/views.span/types.pass.cpp +std/ranges/range.access/begin.pass.cpp +std/ranges/range.access/data.pass.cpp +std/ranges/range.access/end.pass.cpp +std/ranges/range.access/rbegin.pass.cpp +std/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 From 9cf4a1244f89a3ddd714687235219bb6d03a08ab Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 1 Nov 2022 19:10:43 +0100 Subject: [PATCH 14/21] Bring back one `clang-format [off/on]` --- stl/inc/ranges | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 1d273a48fe8..0dc72bfb692 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -41,16 +41,19 @@ namespace ranges { using range_const_reference_t = iter_const_reference_t>; #endif // _HAS_CXX23 + // clang-format off _EXPORT_STD template concept viewable_range = range<_Rng> - && ((view> && constructible_from, _Rng>) - || (!view> - && (is_lvalue_reference_v<_Rng> - || (movable> && !_Is_initializer_list<_Rng>) ))); + && ((view> && constructible_from, _Rng>) + || (!view> + && (is_lvalue_reference_v<_Rng> + || (movable> && !_Is_initializer_list<_Rng>)))); template - concept _Simple_view = view<_Rng> && range && same_as, iterator_t> - && same_as, sentinel_t>; + concept _Simple_view = view<_Rng> && range + && same_as, iterator_t> + && same_as, sentinel_t>; + // clang-format on template concept _Valid_movable_box_object = From c563b579b71a4c00547557b2dad7f09e0ad640e3 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 1 Nov 2022 21:32:45 +0100 Subject: [PATCH 15/21] Update bug workaround --- stl/inc/xutility | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 36d27284c67..6fd6e436f79 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2436,11 +2436,11 @@ namespace ranges { template _NODISCARD constexpr auto& _Possibly_const_range(_Rng& _Range) noexcept { if constexpr (constant_range && !constant_range<_Rng>) { -#ifndef __clang__ // TRANSITION, DevCom-??????? +#ifndef __clang__ // TRANSITION, DevCom-10187107 return _STD as_const(_Range); #else // ^^^ workaround / no workaround vvv return const_cast(_Range); -#endif // TRANSITION, DevCom-??????? +#endif // TRANSITION, DevCom-10187107 } else { return _Range; } From 57a857dedb50de968d03a906fea8b5a1c32bc222 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 2 Nov 2022 13:21:52 +0100 Subject: [PATCH 16/21] Implement LWG-3770 --- stl/inc/ranges | 3 ++ .../test.cpp | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/stl/inc/ranges b/stl/inc/ranges index 0dc72bfb692..69dccf7f418 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -37,6 +37,9 @@ namespace ranges { _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 diff --git a/tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp b/tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp index f244d86fd14..e504f96def7 100644 --- a/tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp +++ b/tests/std/tests/P2278R4_ranges_const_range_machinery/test.cpp @@ -21,24 +21,32 @@ 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 @@ -46,15 +54,19 @@ 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 @@ -62,15 +74,19 @@ 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 @@ -78,15 +94,19 @@ 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 @@ -94,8 +114,10 @@ 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 @@ -103,15 +125,19 @@ 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 @@ -119,15 +145,19 @@ 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 From 7aa3c77fae977b7a8c50721bf40a0ea9f2516668 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 2 Nov 2022 13:31:54 +0100 Subject: [PATCH 17/21] Change `possibly-const-range` to use `std::as_const` instead of `const_cast` (as @strega-nil-ms suggested) --- stl/inc/xutility | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 6fd6e436f79..6aa3f325b0c 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2436,11 +2436,7 @@ namespace ranges { template _NODISCARD constexpr auto& _Possibly_const_range(_Rng& _Range) noexcept { if constexpr (constant_range && !constant_range<_Rng>) { -#ifndef __clang__ // TRANSITION, DevCom-10187107 return _STD as_const(_Range); -#else // ^^^ workaround / no workaround vvv - return const_cast(_Range); -#endif // TRANSITION, DevCom-10187107 } else { return _Range; } From 0af99e6c8a782684be6a0db1bc245c62494eb8f0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 7 Nov 2022 18:22:01 -0800 Subject: [PATCH 18/21] Fix skipped_tests.txt. --- tests/libcxx/skipped_tests.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index f89779f3bf6..05675346133 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -59,12 +59,12 @@ strings\basic.string\string.nonmembers\string_op+\allocator_propagation.pass.cpp iterators\predef.iterators\move.iterators\move.iterator\types.pass.cpp # libc++ has not implemented P2278R4: "cbegin should always return a constant iterator" -std/containers/views/views.span/types.pass.cpp -std/ranges/range.access/begin.pass.cpp -std/ranges/range.access/data.pass.cpp -std/ranges/range.access/end.pass.cpp -std/ranges/range.access/rbegin.pass.cpp -std/ranges/range.access/rend.pass.cpp +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 From fb894cd28baa305a63b6e106b6f6cd33d98b7d52 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 7 Nov 2022 18:23:19 -0800 Subject: [PATCH 19/21] Qualify _STD declval. --- stl/inc/xutility | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 6aa3f325b0c..cb697f0e4cb 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2451,7 +2451,7 @@ namespace ranges { struct _Cbegin_fn { #if _HAS_CXX23 template <_Should_range_access _Ty, - class _Uty = decltype(_RANGES begin(_RANGES _Possibly_const_range(declval<_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))}; } @@ -2476,7 +2476,7 @@ namespace ranges { struct _Cend_fn { #if _HAS_CXX23 template <_Should_range_access _Ty, - class _Uty = decltype(_RANGES end(_RANGES _Possibly_const_range(declval<_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))}; } @@ -2636,7 +2636,7 @@ namespace ranges { struct _Crbegin_fn { #if _HAS_CXX23 template <_Should_range_access _Ty, - class _Uty = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(declval<_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))}; } @@ -2661,7 +2661,7 @@ namespace ranges { struct _Crend_fn { #if _HAS_CXX23 template <_Should_range_access _Ty, - class _Uty = decltype(_RANGES rend(_RANGES _Possibly_const_range(declval<_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))}; } From 87f610ea68a0037833ec01810aab0261fae318e7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 7 Nov 2022 18:25:24 -0800 Subject: [PATCH 20/21] Comment nitpicks. --- .../P0896R4_ranges_range_machinery/test.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index d77b0084726..7076deb301a 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -580,17 +580,17 @@ STATIC_ASSERT(test_crbegin()); STATIC_ASSERT(test_crend()); STATIC_ASSERT(test_size()); STATIC_ASSERT(test_empty()); -// Can't use test_data 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(!ranges::range); STATIC_ASSERT(!ranges::view); -#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behaviour differs in C++20 and C++23 modes +#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 they use range_value_t and this isn't a range +// 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 @@ -603,17 +603,17 @@ STATIC_ASSERT(test_crbegin()); STATIC_ASSERT(test_crend()); STATIC_ASSERT(test_size()); STATIC_ASSERT(test_empty()); -// Can't use test_data 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(!ranges::range); STATIC_ASSERT(!ranges::view); -#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behaviour differs in C++20 and C++23 modes +#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 they use range_value_t and this isn't a range +// 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 @@ -630,7 +630,7 @@ STATIC_ASSERT(!CanSize); STATIC_ASSERT(!CanEmpty); STATIC_ASSERT(ranges::data(initially_unbounded) == initially_unbounded); -#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behaviour differs in C++20 and C++23 modes +#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 @@ -1001,7 +1001,7 @@ STATIC_ASSERT(test_data, int*>()); STATIC_ASSERT(test_contiguous_range>()); STATIC_ASSERT(ranges::view>); -#if _HAS_CXX23 // behaviour of span members differs in C++20 and C++23 modes +#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>()); @@ -1025,7 +1025,7 @@ STATIC_ASSERT(test_data const, int*>()); STATIC_ASSERT(test_contiguous_range const>()); STATIC_ASSERT(!ranges::view const>); -#if _HAS_CXX23 // behaviour of const span members differs in C++20 and C++23 modes +#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>()); @@ -1049,7 +1049,7 @@ STATIC_ASSERT(test_data&, int*>()); STATIC_ASSERT(test_contiguous_range&>()); STATIC_ASSERT(!ranges::view&>); -#if _HAS_CXX23 // behaviour of span& members differs in C++20 and C++23 modes +#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>()); @@ -1073,7 +1073,7 @@ STATIC_ASSERT(test_data const&, int*>()); STATIC_ASSERT(test_contiguous_range const&>()); STATIC_ASSERT(!ranges::view const&>); -#if _HAS_CXX23 // behaviour of const span& members differs in C++20 and C++23 modes +#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>()); From 506533e13ad38eaf9123f3487428463d4154c1b2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 7 Nov 2022 18:26:01 -0800 Subject: [PATCH 21/21] Header nitpick. --- tests/std/tests/P2278R4_const_span/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P2278R4_const_span/test.cpp b/tests/std/tests/P2278R4_const_span/test.cpp index 68a7fb95c51..19fd692c808 100644 --- a/tests/std/tests/P2278R4_const_span/test.cpp +++ b/tests/std/tests/P2278R4_const_span/test.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include using namespace std;