Skip to content

Commit a981f1e

Browse files
Fix handling of array rvalues for ranges::cbegin and its friends (#3316)
1 parent f5de9ad commit a981f1e

File tree

2 files changed

+80
-30
lines changed

2 files changed

+80
-30
lines changed

stl/inc/xutility

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,17 +2472,34 @@ namespace ranges {
24722472
_NODISCARD constexpr auto _As_const_pointer(const _Ty* _Ptr) noexcept {
24732473
return _Ptr;
24742474
}
2475+
2476+
template <class _Ty>
2477+
using _Begin_on_const = decltype(_RANGES begin(_RANGES _Possibly_const_range(_STD declval<_Ty&>())));
2478+
2479+
// TRANSITION, LLVM-55945
2480+
template <class _Ty>
2481+
concept _Range_accessible_and_begin_adaptable =
2482+
_Should_range_access<_Ty>
2483+
&& requires(
2484+
_Ty& _Val) { const_iterator<_Begin_on_const<_Ty>>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}; };
2485+
2486+
template <class _Ty>
2487+
using _End_on_const = decltype(_RANGES end(_RANGES _Possibly_const_range(_STD declval<_Ty&>())));
2488+
2489+
// TRANSITION, LLVM-55945
2490+
template <class _Ty>
2491+
concept _Range_accessible_and_end_adaptable =
2492+
_Should_range_access<_Ty>
2493+
&& requires(
2494+
_Ty& _Val) { const_sentinel<_End_on_const<_Ty>>{_RANGES end(_RANGES _Possibly_const_range(_Val))}; };
24752495
#endif // _HAS_CXX23
24762496

24772497
struct _Cbegin_fn {
24782498
#if _HAS_CXX23
2479-
template <_Should_range_access _Ty,
2480-
class _Uty = decltype(_RANGES begin(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))>
2481-
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
2482-
noexcept(noexcept(const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}))
2483-
requires requires { const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}; }
2484-
{
2485-
return const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))};
2499+
template <_Range_accessible_and_begin_adaptable _Ty>
2500+
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(
2501+
noexcept(const_iterator<_Begin_on_const<_Ty>>{_RANGES begin(_RANGES _Possibly_const_range(_Val))})) {
2502+
return const_iterator<_Begin_on_const<_Ty>>{_RANGES begin(_RANGES _Possibly_const_range(_Val))};
24862503
}
24872504
#else // ^^^ C++23 / C++20 vvv
24882505
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
@@ -2501,13 +2518,10 @@ namespace ranges {
25012518

25022519
struct _Cend_fn {
25032520
#if _HAS_CXX23
2504-
template <_Should_range_access _Ty,
2505-
class _Uty = decltype(_RANGES end(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))>
2521+
template <_Range_accessible_and_end_adaptable _Ty>
25062522
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
2507-
noexcept(noexcept(const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))}))
2508-
requires requires { const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))}; }
2509-
{
2510-
return const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))};
2523+
noexcept(noexcept(const_sentinel<_End_on_const<_Ty>>{_RANGES end(_RANGES _Possibly_const_range(_Val))})) {
2524+
return const_sentinel<_End_on_const<_Ty>>{_RANGES end(_RANGES _Possibly_const_range(_Val))};
25112525
}
25122526
#else // ^^^ C++23 / C++20 vvv
25132527
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
@@ -2663,15 +2677,34 @@ namespace ranges {
26632677
_EXPORT_STD inline constexpr _Rend::_Cpo rend;
26642678
}
26652679

2680+
#if _HAS_CXX23
2681+
template <class _Ty>
2682+
using _Rbegin_on_const = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(_STD declval<_Ty&>())));
2683+
2684+
// TRANSITION, LLVM-55945
2685+
template <class _Ty>
2686+
concept _Range_accessible_and_rbegin_adaptable =
2687+
_Should_range_access<_Ty>
2688+
&& requires(
2689+
_Ty& _Val) { const_iterator<_Rbegin_on_const<_Ty>>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}; };
2690+
2691+
template <class _Ty>
2692+
using _Rend_on_const = decltype(_RANGES rend(_RANGES _Possibly_const_range(_STD declval<_Ty&>())));
2693+
2694+
// TRANSITION, LLVM-55945
2695+
template <class _Ty>
2696+
concept _Range_accessible_and_rend_adaptable =
2697+
_Should_range_access<_Ty>
2698+
&& requires(
2699+
_Ty& _Val) { const_sentinel<_Rend_on_const<_Ty>>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}; };
2700+
#endif // _HAS_CXX23
2701+
26662702
struct _Crbegin_fn {
26672703
#if _HAS_CXX23
2668-
template <_Should_range_access _Ty,
2669-
class _Uty = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))>
2670-
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
2671-
noexcept(noexcept(const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}))
2672-
requires requires { const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}; }
2673-
{
2674-
return const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))};
2704+
template <_Range_accessible_and_rbegin_adaptable _Ty>
2705+
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(
2706+
noexcept(const_iterator<_Rbegin_on_const<_Ty>>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))})) {
2707+
return const_iterator<_Rbegin_on_const<_Ty>>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))};
26752708
}
26762709
#else // ^^^ C++23 / C++20 vvv
26772710
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
@@ -2690,13 +2723,10 @@ namespace ranges {
26902723

26912724
struct _Crend_fn {
26922725
#if _HAS_CXX23
2693-
template <_Should_range_access _Ty,
2694-
class _Uty = decltype(_RANGES rend(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))>
2726+
template <_Range_accessible_and_rend_adaptable _Ty>
26952727
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
2696-
noexcept(noexcept(const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}))
2697-
requires requires { const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}; }
2698-
{
2699-
return const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))};
2728+
noexcept(noexcept(const_sentinel<_Rend_on_const<_Ty>>{_RANGES rend(_RANGES _Possibly_const_range(_Val))})) {
2729+
return const_sentinel<_Rend_on_const<_Ty>>{_RANGES rend(_RANGES _Possibly_const_range(_Val))};
27002730
}
27012731
#else // ^^^ C++23 / C++20 vvv
27022732
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
@@ -2915,13 +2945,19 @@ namespace ranges {
29152945
_EXPORT_STD inline constexpr _Data::_Cpo data;
29162946
}
29172947

2948+
#if _HAS_CXX23
2949+
// TRANSITION, LLVM-55945
2950+
template <class _Ty>
2951+
concept _Range_accessible_and_data_adaptable =
2952+
_Should_range_access<_Ty>
2953+
&& requires(_Ty& _Val) { _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val))); };
2954+
#endif // _HAS_CXX23
2955+
29182956
struct _Cdata_fn {
29192957
#if _HAS_CXX23
2920-
template <_Should_range_access _Ty>
2958+
template <_Range_accessible_and_data_adaptable _Ty>
29212959
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
2922-
noexcept(noexcept(_RANGES data(_RANGES _Possibly_const_range(_Val))))
2923-
requires requires { _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val))); }
2924-
{
2960+
noexcept(noexcept(_RANGES data(_RANGES _Possibly_const_range(_Val)))) {
29252961
return _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val)));
29262962
}
29272963
#else // ^^^ C++23 / C++20 vvv

tests/std/tests/P0896R4_ranges_range_machinery/test.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,20 @@ struct initially_incomplete;
660660
extern initially_incomplete array_of_incomplete[42];
661661
STATIC_ASSERT(ranges::size(array_of_incomplete) == 42);
662662
STATIC_ASSERT(!ranges::empty(array_of_incomplete));
663+
664+
// begin, end, rbegin, rend, and data (and their c variations) should reject rvalues of array of incomplete elements
665+
// with substitution failures
666+
STATIC_ASSERT(!CanBegin<initially_incomplete (&&)[42]>);
667+
STATIC_ASSERT(!CanCBegin<initially_incomplete (&&)[42]>);
668+
STATIC_ASSERT(!CanEnd<initially_incomplete (&&)[42]>);
669+
STATIC_ASSERT(!CanCEnd<initially_incomplete (&&)[42]>);
670+
STATIC_ASSERT(!CanRBegin<initially_incomplete (&&)[42]>);
671+
STATIC_ASSERT(!CanCRBegin<initially_incomplete (&&)[42]>);
672+
STATIC_ASSERT(!CanREnd<initially_incomplete (&&)[42]>);
673+
STATIC_ASSERT(!CanCREnd<initially_incomplete (&&)[42]>);
674+
STATIC_ASSERT(!CanData<initially_incomplete (&&)[42]>);
675+
STATIC_ASSERT(!CanCData<initially_incomplete (&&)[42]>);
676+
663677
struct initially_incomplete {};
664678
initially_incomplete array_of_incomplete[42];
665679

0 commit comments

Comments
 (0)