On Tue, 4 Feb 2025, Patrick Palka wrote: > On Tue, 4 Feb 2025, Patrick Palka wrote: > > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk and perhaps > > 14 (after a long while)? > > > > -- >8 -- > > > > LWG 4027 effectively makes the const range access CPOs ranges::cfoo behave > > more consistently across C++23 and C++20 (pre-P2278R4) and more > > consistently with the std::cfoo range accessors, as the below testcase > > adjustments demonstrate (which mostly consist of reverting workarounds > > added by r14-3771-gf12e26f3496275 and r13-7186-g0d94c6df183375). > > > > In passing fix PR118083 which reports that the input_range constraint on > > possibly-const-range is missing in our implementation. A consequence of > > this is that the const range access CPOs now consistently require the > > type to be a range, and so in some our of tests we need to introduce > > otherwise unused begin/end members. > > ... now with the LWG 4027 testcases added (to cbegin.cc, so that it runs > in both C++20 and C++23 mode):
Ping. > > -- >8 -- > > Subject: [PATCH] libstdc++: Implement LWG 4027 change to possibly-const-range > [PR118083] > > PR libstdc++/118083 > > libstdc++-v3/ChangeLog: > > * include/bits/ranges_base.h > (ranges::__access::__possibly_const_range): Adjust logic as per > LWG 4027. Add missing input_range constraint. > * testsuite/std/ranges/access/cbegin.cc (test05): Verify LWG > 4027 testcases. > * testsuite/std/ranges/access/cdata.cc: Adjust, simplify and > consolidate some tests after the above. > * testsuite/std/ranges/access/cend.cc: Likewise. > * testsuite/std/ranges/access/crbegin.cc: Likewise. > * testsuite/std/ranges/access/crend.cc: Likewise. > * testsuite/std/ranges/adaptors/join.cc: Likewise. > * testsuite/std/ranges/adaptors/take_while.cc: Likewise. > * testsuite/std/ranges/adaptors/transform.cc: Likewise. > --- > libstdc++-v3/include/bits/ranges_base.h | 4 +- > .../testsuite/std/ranges/access/cbegin.cc | 17 ++++++++ > .../testsuite/std/ranges/access/cdata.cc | 21 ++++----- > .../testsuite/std/ranges/access/cend.cc | 30 ++----------- > .../testsuite/std/ranges/access/crbegin.cc | 43 +++++-------------- > .../testsuite/std/ranges/access/crend.cc | 20 +++++---- > .../testsuite/std/ranges/adaptors/join.cc | 8 ++-- > .../std/ranges/adaptors/take_while.cc | 2 - > .../std/ranges/adaptors/transform.cc | 4 -- > 9 files changed, 59 insertions(+), 90 deletions(-) > > diff --git a/libstdc++-v3/include/bits/ranges_base.h > b/libstdc++-v3/include/bits/ranges_base.h > index 4dcfbf66d51..28fe64a9e9d 100644 > --- a/libstdc++-v3/include/bits/ranges_base.h > +++ b/libstdc++-v3/include/bits/ranges_base.h > @@ -642,11 +642,11 @@ namespace ranges > namespace __access > { > #if __glibcxx_ranges_as_const // >= C++23 > - template<typename _Range> > + template<input_range _Range> > constexpr auto& > __possibly_const_range(_Range& __r) noexcept > { > - if constexpr (constant_range<const _Range> && !constant_range<_Range>) > + if constexpr (input_range<const _Range>) > return const_cast<const _Range&>(__r); > else > return __r; > diff --git a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc > b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc > index 5423e782428..66b28f41877 100644 > --- a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc > +++ b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc > @@ -116,10 +116,27 @@ test04() > VERIFY(std::ranges::cbegin(std::move(c)) == std::ranges::begin(c)); > } > > +void > +test05() > +{ > + // LWG 4027 - possibly-const-range should prefer returning const R& > + auto r = std::views::single(0) > + | std::views::transform([](int) { return 0; }); > + using C1 = decltype(std::ranges::cbegin(r)); > + using C1 = decltype(std::cbegin(r)); > + > + [] (auto x) { > + auto r = std::views::single(x) | std::views::lazy_split(0); > + static_assert( ! requires { (*std::ranges::cbegin(r)).front() = 42; }); > + static_assert( ! requires { (*std::cbegin(r)).front() = 42; }); > + }(0); > +} > + > int > main() > { > test01(); > test03(); > test04(); > + test05(); > } > diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc > b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc > index 62c347be43d..f474ab7ec99 100644 > --- a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc > +++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc > @@ -34,20 +34,21 @@ test01() > { > int i = 0; > int j = 0; > + > +#if __cpp_lib_ranges_as_const > + // These overloads mean that range<R> and range<const R> are satisfied. > + const int* begin() const { throw; } > + const int* end() const { throw; } > +#endif > + > int* data() { return &j; } > const R* data() const noexcept { return nullptr; } > }; > static_assert( has_cdata<R&> ); > static_assert( has_cdata<const R&> ); > R r; > -#if ! __cpp_lib_ranges_as_const > VERIFY( std::ranges::cdata(r) == (R*)nullptr ); > static_assert( noexcept(std::ranges::cdata(r)) ); > -#else > - // constant_range<const R> is not satisfied, so cdata(r) == data(r). > - VERIFY( std::ranges::cdata(r) == &r.j ); > - static_assert( ! noexcept(std::ranges::cdata(r)) ); > -#endif > const R& c = r; > VERIFY( std::ranges::cdata(c) == (R*)nullptr ); > static_assert( noexcept(std::ranges::cdata(c)) ); > @@ -58,11 +59,11 @@ test01() > > struct R2 > { > +#if __cpp_lib_ranges_as_const > // These overloads mean that range<R2> and range<const R2> are satisfied. > - int* begin(); > - int* end(); > - const int* begin() const; > - const int* end() const; > + const int* begin() const { throw; } > + const int* end() const { throw; } > +#endif > > int i = 0; > int j = 0; > diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc > b/libstdc++-v3/testsuite/std/ranges/access/cend.cc > index 6194fe7d866..6903c4558a1 100644 > --- a/libstdc++-v3/testsuite/std/ranges/access/cend.cc > +++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc > @@ -52,15 +52,6 @@ struct R > friend const int* end(const R&& r) noexcept { return r.a + 3; } > }; > > -#if __cpp_lib_ranges_as_const > -struct R2 : R > -{ > - // This overload means constant_range<const R2> will be satisfied: > - friend const int* begin(const R2&) noexcept; > - friend const int* end(const R2& r2) noexcept { return r2.a + 2; } > -}; > -#endif > - > struct RV // view on an R > { > R& r; > @@ -79,26 +70,11 @@ test03() > { > R r; > const R& c = r; > -#if ! __cpp_lib_ranges_as_const > VERIFY( std::ranges::cend(r) == std::ranges::end(c) ); > -#else > - // constant_range<const R> is not satisfied, so cend(r) == end(r) instead. > - VERIFY( std::ranges::cend(r) == std::ranges::end(r) ); > - R2 r2; > - const R& c2 = r2; > - // But constant_range<const R2> is satisfied, so cend(r2) == end(c2). > - VERIFY( std::ranges::cend(r2) == std::ranges::end(c2) ); > - VERIFY( std::ranges::cend(r2) == std::ranges::end((const R&)c2) ); > -#endif > VERIFY( std::ranges::cend(c) == std::ranges::end(c) ); > > RV v{r}; > -#if ! __cpp_lib_ranges_as_const > VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(c) ); > -#else > - // constant_range<RV> is already satisfied, so cend(v) == end(r) instead. > - VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(r) ); > -#endif > > const RV cv{r}; > VERIFY( std::ranges::cend(std::move(cv)) == std::ranges::end(c) ); > @@ -107,7 +83,7 @@ test03() > struct RR > { > short s = 0; > - long l = 0; > + short l = 0; > int a[4] = { 0, 1, 2, 3 }; > > const void* begin() const; // return type not an iterator > @@ -115,8 +91,8 @@ struct RR > friend int* end(RR&) { throw 1; } > short* end() noexcept { return &s; } > > - friend const long* begin(const RR&) noexcept; > - const long* end() const { return &l; } > + friend const short* begin(const RR&) noexcept; > + const short* end() const { return &l; } > > friend int* begin(RR&&) noexcept; > friend int* end(RR&& r) { return r.a + 1; } > diff --git a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc > b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc > index 9a07f0b3874..c283ee4e33c 100644 > --- a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc > +++ b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc > @@ -28,6 +28,11 @@ struct R1 > int i = 0; > int j = 0; > > +#if __cpp_lib_ranges_as_const > + const int *begin() const; > + const int *end() const; > +#endif > + > const int* rbegin() const { return &i; } > friend const int* rbegin(const R1&& r) { return &r.j; } > }; > @@ -36,6 +41,11 @@ struct R1V // view on an R1 > { > R1& r; > > +#if __cpp_lib_ranges_as_const > + const int *begin() const; > + const int *end() const; > +#endif > + > friend const long* rbegin(R1V&) { return nullptr; } > friend const int* rbegin(const R1V& rv) noexcept { return rv.r.rbegin(); } > }; > @@ -43,26 +53,6 @@ struct R1V // view on an R1 > // Allow ranges::end to work with R1V&& > template<> constexpr bool std::ranges::enable_borrowed_range<R1V> = true; > > -#if __cpp_lib_ranges_as_const > -struct R1VC // view on an R1 > -{ > - R1& r; > - > - friend const long* rbegin(R1VC&); // this is not defined > - friend const int* rbegin(const R1VC& rv) noexcept { return rv.r.rbegin(); } > - > - // The following ensure that the following are satisfied: > - // constant_range<const R1VC> && ! constant_range<R1VC> > - friend int* begin(R1VC&); > - friend int* end(R1VC&); > - friend const int* begin(const R1VC&); > - friend const int* end(const R1VC&); > -}; > - > -// Allow ranges::end to work with R1VC&& > -template<> constexpr bool std::ranges::enable_borrowed_range<R1VC> = true; > -#endif > - > void > test01() > { > @@ -72,21 +62,8 @@ test01() > VERIFY( std::ranges::crbegin(c) == std::ranges::rbegin(c) ); > > R1V v{r}; > -#if ! __cpp_lib_ranges_as_const > VERIFY( std::ranges::crbegin(v) == std::ranges::rbegin(c) ); > VERIFY( std::ranges::crbegin(std::move(v)) == std::ranges::rbegin(c) ); > -#else > - // constant_range<const R1V> is not satisfied, so crbegin(v) == rbegin(v). > - VERIFY( std::ranges::crbegin(v) == (long*)nullptr ); > - VERIFY( std::ranges::crbegin(std::move(v)) == (long*)nullptr ); > - R1VC v2{r}; > - // But constant_range<const R1VC> is satisfied: > - VERIFY( std::ranges::crbegin(v2) == std::ranges::rbegin(c) ); > - VERIFY( std::ranges::crbegin(std::move(v2)) == std::ranges::rbegin(c) ); > - const R1VC cv2{r}; > - VERIFY( std::ranges::crbegin(cv2) == std::ranges::rbegin(c) ); > - VERIFY( std::ranges::crbegin(std::move(cv2)) == std::ranges::rbegin(c) ); > -#endif > > const R1V cv{r}; > VERIFY( std::ranges::crbegin(cv) == std::ranges::rbegin(c) ); > diff --git a/libstdc++-v3/testsuite/std/ranges/access/crend.cc > b/libstdc++-v3/testsuite/std/ranges/access/crend.cc > index 6f7dce28200..d4530e530e1 100644 > --- a/libstdc++-v3/testsuite/std/ranges/access/crend.cc > +++ b/libstdc++-v3/testsuite/std/ranges/access/crend.cc > @@ -28,6 +28,11 @@ struct R1 > int i = 0; > int j = 0; > > +#if __cpp_lib_ranges_as_const > + const int *begin() const; > + const int *end() const; > +#endif > + > constexpr const int* rbegin() const { return &i; } > constexpr const int* rend() const { return &i + 1; } > friend constexpr const int* rbegin(const R1&& r) { return &r.j; } > @@ -78,6 +83,11 @@ struct R3 > { > int i = 0; > > +#if __cpp_lib_ranges_as_const > + const int *begin() const; > + const int *end() const; > +#endif > + > const int* rbegin() const noexcept { return &i + 1; } > const long* rend() const noexcept { return nullptr; } // not a sentinel > for rbegin() > > @@ -89,9 +99,11 @@ struct R4 > { > int i = 0; > > +#if __cpp_lib_ranges_as_const > // These members mean that range<R4> and range<const R4> are satisfied. > const short* begin() const { return 0; } > const short* end() const { return 0; } > +#endif > > const int* rbegin() const noexcept { return &i + 1; } > const long* rend() const noexcept { return nullptr; } // not a sentinel > for rbegin() > @@ -105,16 +117,8 @@ test03() > { > R3 r; > const R3& c = r; > -#if ! __cpp_lib_ranges_as_const > VERIFY( std::ranges::crend(r) == std::ranges::rend(c) ); > static_assert( !noexcept(std::ranges::crend(r)) ); > -#else > - // constant_range<const R3> is not satisfied, so crend(r) is equivalent > - // to const_sentinel{rend(r)}, which is ill-formed because range<R3> > - // is not satisfied. > - static_assert( not std::ranges::range<R3> ); > - static_assert( not std::ranges::range<const R3> ); > -#endif > VERIFY( std::ranges::crend(c) == std::ranges::rend(c) ); > static_assert( !noexcept(std::ranges::crend(c)) ); > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc > b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc > index 9e1c526b4ca..2861115c22a 100644 > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc > @@ -113,15 +113,15 @@ test06() > > // Verify that _Iterator<false> is implicitly convertible to > _Iterator<true>. > static_assert(!std::same_as<decltype(ranges::begin(v)), > - decltype(std::as_const(v).begin())>); > - auto a = std::as_const(v).begin(); > + decltype(ranges::cbegin(v))>); > + auto a = std::cbegin(v); > a = ranges::begin(v); > > // Verify that _Sentinel<false> is implicitly convertible to > _Sentinel<true>. > static_assert(!ranges::common_range<decltype(v)>); > static_assert(!std::same_as<decltype(ranges::end(v)), > - decltype(std::as_const(v).end())>); > - auto b = std::as_const(v).end(); > + decltype(ranges::cend(v))>); > + auto b = ranges::cend(v); > b = ranges::end(v); > } > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc > b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc > index 38757d27d48..f09919bedc4 100644 > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc > @@ -63,10 +63,8 @@ test03() > > // Verify that _Sentinel<false> is implicitly convertible to > _Sentinel<true>. > static_assert(!ranges::common_range<decltype(v)>); > -#if ! __cpp_lib_ranges_as_const > static_assert(!std::same_as<decltype(ranges::end(v)), > decltype(ranges::cend(v))>); > -#endif > auto b = ranges::cend(v); > b = ranges::end(v); > } > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > index 934d2f65dcf..1788db1ce8d 100644 > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > @@ -107,20 +107,16 @@ test05() > auto r = ranges::subrange{i, std::default_sentinel}; > auto v = r | views::transform(std::negate{}); > > -#if ! __cpp_lib_ranges_as_const > // Verify that _Iterator<false> is implicitly convertible to > _Iterator<true>. > static_assert(!std::same_as<decltype(ranges::begin(v)), > decltype(ranges::cbegin(v))>); > -#endif > auto a = ranges::cbegin(v); > a = ranges::begin(v); > > -#if ! __cpp_lib_ranges_as_const > // Verify that _Sentinel<false> is implicitly convertible to > _Sentinel<true>. > static_assert(!ranges::common_range<decltype(v)>); > static_assert(!std::same_as<decltype(ranges::end(v)), > decltype(ranges::cend(v))>); > -#endif > auto b = ranges::cend(v); > b = ranges::end(v); > } > -- > 2.48.1.220.gbc204b7427 > > > > > > > > PR libstdc++/118083 > > > > libstdc++-v3/ChangeLog: > > > > * include/bits/ranges_base.h > > (ranges::__access::__possibly_const_range): Adjust logic as per > > LWG 4027. Add missing input_range constraint. > > * testsuite/std/ranges/access/cdata.cc: Adjust, simplify and > > consolidate some tests after the above. > > * testsuite/std/ranges/access/cend.cc: Likewise. > > * testsuite/std/ranges/access/crbegin.cc: Likewise. > > * testsuite/std/ranges/access/crend.cc: Likewise. > > * testsuite/std/ranges/adaptors/join.cc: Likewise. > > * testsuite/std/ranges/adaptors/take_while.cc: Likewise. > > * testsuite/std/ranges/adaptors/transform.cc: Likewise. > > --- > > libstdc++-v3/include/bits/ranges_base.h | 4 +- > > .../testsuite/std/ranges/access/cdata.cc | 21 ++++----- > > .../testsuite/std/ranges/access/cend.cc | 30 ++----------- > > .../testsuite/std/ranges/access/crbegin.cc | 43 +++++-------------- > > .../testsuite/std/ranges/access/crend.cc | 20 +++++---- > > .../testsuite/std/ranges/adaptors/join.cc | 8 ++-- > > .../std/ranges/adaptors/take_while.cc | 2 - > > .../std/ranges/adaptors/transform.cc | 4 -- > > 8 files changed, 42 insertions(+), 90 deletions(-) > > > > diff --git a/libstdc++-v3/include/bits/ranges_base.h > > b/libstdc++-v3/include/bits/ranges_base.h > > index 4dcfbf66d51..28fe64a9e9d 100644 > > --- a/libstdc++-v3/include/bits/ranges_base.h > > +++ b/libstdc++-v3/include/bits/ranges_base.h > > @@ -642,11 +642,11 @@ namespace ranges > > namespace __access > > { > > #if __glibcxx_ranges_as_const // >= C++23 > > - template<typename _Range> > > + template<input_range _Range> > > constexpr auto& > > __possibly_const_range(_Range& __r) noexcept > > { > > - if constexpr (constant_range<const _Range> && !constant_range<_Range>) > > + if constexpr (input_range<const _Range>) > > return const_cast<const _Range&>(__r); > > else > > return __r; > > diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc > > b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc > > index 62c347be43d..f474ab7ec99 100644 > > --- a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc > > +++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc > > @@ -34,20 +34,21 @@ test01() > > { > > int i = 0; > > int j = 0; > > + > > +#if __cpp_lib_ranges_as_const > > + // These overloads mean that range<R> and range<const R> are satisfied. > > + const int* begin() const { throw; } > > + const int* end() const { throw; } > > +#endif > > + > > int* data() { return &j; } > > const R* data() const noexcept { return nullptr; } > > }; > > static_assert( has_cdata<R&> ); > > static_assert( has_cdata<const R&> ); > > R r; > > -#if ! __cpp_lib_ranges_as_const > > VERIFY( std::ranges::cdata(r) == (R*)nullptr ); > > static_assert( noexcept(std::ranges::cdata(r)) ); > > -#else > > - // constant_range<const R> is not satisfied, so cdata(r) == data(r). > > - VERIFY( std::ranges::cdata(r) == &r.j ); > > - static_assert( ! noexcept(std::ranges::cdata(r)) ); > > -#endif > > const R& c = r; > > VERIFY( std::ranges::cdata(c) == (R*)nullptr ); > > static_assert( noexcept(std::ranges::cdata(c)) ); > > @@ -58,11 +59,11 @@ test01() > > > > struct R2 > > { > > +#if __cpp_lib_ranges_as_const > > // These overloads mean that range<R2> and range<const R2> are > > satisfied. > > - int* begin(); > > - int* end(); > > - const int* begin() const; > > - const int* end() const; > > + const int* begin() const { throw; } > > + const int* end() const { throw; } > > +#endif > > > > int i = 0; > > int j = 0; > > diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc > > b/libstdc++-v3/testsuite/std/ranges/access/cend.cc > > index 6194fe7d866..6903c4558a1 100644 > > --- a/libstdc++-v3/testsuite/std/ranges/access/cend.cc > > +++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc > > @@ -52,15 +52,6 @@ struct R > > friend const int* end(const R&& r) noexcept { return r.a + 3; } > > }; > > > > -#if __cpp_lib_ranges_as_const > > -struct R2 : R > > -{ > > - // This overload means constant_range<const R2> will be satisfied: > > - friend const int* begin(const R2&) noexcept; > > - friend const int* end(const R2& r2) noexcept { return r2.a + 2; } > > -}; > > -#endif > > - > > struct RV // view on an R > > { > > R& r; > > @@ -79,26 +70,11 @@ test03() > > { > > R r; > > const R& c = r; > > -#if ! __cpp_lib_ranges_as_const > > VERIFY( std::ranges::cend(r) == std::ranges::end(c) ); > > -#else > > - // constant_range<const R> is not satisfied, so cend(r) == end(r) > > instead. > > - VERIFY( std::ranges::cend(r) == std::ranges::end(r) ); > > - R2 r2; > > - const R& c2 = r2; > > - // But constant_range<const R2> is satisfied, so cend(r2) == end(c2). > > - VERIFY( std::ranges::cend(r2) == std::ranges::end(c2) ); > > - VERIFY( std::ranges::cend(r2) == std::ranges::end((const R&)c2) ); > > -#endif > > VERIFY( std::ranges::cend(c) == std::ranges::end(c) ); > > > > RV v{r}; > > -#if ! __cpp_lib_ranges_as_const > > VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(c) ); > > -#else > > - // constant_range<RV> is already satisfied, so cend(v) == end(r) instead. > > - VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(r) ); > > -#endif > > > > const RV cv{r}; > > VERIFY( std::ranges::cend(std::move(cv)) == std::ranges::end(c) ); > > @@ -107,7 +83,7 @@ test03() > > struct RR > > { > > short s = 0; > > - long l = 0; > > + short l = 0; > > int a[4] = { 0, 1, 2, 3 }; > > > > const void* begin() const; // return type not an iterator > > @@ -115,8 +91,8 @@ struct RR > > friend int* end(RR&) { throw 1; } > > short* end() noexcept { return &s; } > > > > - friend const long* begin(const RR&) noexcept; > > - const long* end() const { return &l; } > > + friend const short* begin(const RR&) noexcept; > > + const short* end() const { return &l; } > > > > friend int* begin(RR&&) noexcept; > > friend int* end(RR&& r) { return r.a + 1; } > > diff --git a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc > > b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc > > index 9a07f0b3874..c283ee4e33c 100644 > > --- a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc > > +++ b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc > > @@ -28,6 +28,11 @@ struct R1 > > int i = 0; > > int j = 0; > > > > +#if __cpp_lib_ranges_as_const > > + const int *begin() const; > > + const int *end() const; > > +#endif > > + > > const int* rbegin() const { return &i; } > > friend const int* rbegin(const R1&& r) { return &r.j; } > > }; > > @@ -36,6 +41,11 @@ struct R1V // view on an R1 > > { > > R1& r; > > > > +#if __cpp_lib_ranges_as_const > > + const int *begin() const; > > + const int *end() const; > > +#endif > > + > > friend const long* rbegin(R1V&) { return nullptr; } > > friend const int* rbegin(const R1V& rv) noexcept { return rv.r.rbegin(); > > } > > }; > > @@ -43,26 +53,6 @@ struct R1V // view on an R1 > > // Allow ranges::end to work with R1V&& > > template<> constexpr bool std::ranges::enable_borrowed_range<R1V> = true; > > > > -#if __cpp_lib_ranges_as_const > > -struct R1VC // view on an R1 > > -{ > > - R1& r; > > - > > - friend const long* rbegin(R1VC&); // this is not defined > > - friend const int* rbegin(const R1VC& rv) noexcept { return > > rv.r.rbegin(); } > > - > > - // The following ensure that the following are satisfied: > > - // constant_range<const R1VC> && ! constant_range<R1VC> > > - friend int* begin(R1VC&); > > - friend int* end(R1VC&); > > - friend const int* begin(const R1VC&); > > - friend const int* end(const R1VC&); > > -}; > > - > > -// Allow ranges::end to work with R1VC&& > > -template<> constexpr bool std::ranges::enable_borrowed_range<R1VC> = true; > > -#endif > > - > > void > > test01() > > { > > @@ -72,21 +62,8 @@ test01() > > VERIFY( std::ranges::crbegin(c) == std::ranges::rbegin(c) ); > > > > R1V v{r}; > > -#if ! __cpp_lib_ranges_as_const > > VERIFY( std::ranges::crbegin(v) == std::ranges::rbegin(c) ); > > VERIFY( std::ranges::crbegin(std::move(v)) == std::ranges::rbegin(c) ); > > -#else > > - // constant_range<const R1V> is not satisfied, so crbegin(v) == > > rbegin(v). > > - VERIFY( std::ranges::crbegin(v) == (long*)nullptr ); > > - VERIFY( std::ranges::crbegin(std::move(v)) == (long*)nullptr ); > > - R1VC v2{r}; > > - // But constant_range<const R1VC> is satisfied: > > - VERIFY( std::ranges::crbegin(v2) == std::ranges::rbegin(c) ); > > - VERIFY( std::ranges::crbegin(std::move(v2)) == std::ranges::rbegin(c) ); > > - const R1VC cv2{r}; > > - VERIFY( std::ranges::crbegin(cv2) == std::ranges::rbegin(c) ); > > - VERIFY( std::ranges::crbegin(std::move(cv2)) == std::ranges::rbegin(c) ); > > -#endif > > > > const R1V cv{r}; > > VERIFY( std::ranges::crbegin(cv) == std::ranges::rbegin(c) ); > > diff --git a/libstdc++-v3/testsuite/std/ranges/access/crend.cc > > b/libstdc++-v3/testsuite/std/ranges/access/crend.cc > > index 6f7dce28200..d4530e530e1 100644 > > --- a/libstdc++-v3/testsuite/std/ranges/access/crend.cc > > +++ b/libstdc++-v3/testsuite/std/ranges/access/crend.cc > > @@ -28,6 +28,11 @@ struct R1 > > int i = 0; > > int j = 0; > > > > +#if __cpp_lib_ranges_as_const > > + const int *begin() const; > > + const int *end() const; > > +#endif > > + > > constexpr const int* rbegin() const { return &i; } > > constexpr const int* rend() const { return &i + 1; } > > friend constexpr const int* rbegin(const R1&& r) { return &r.j; } > > @@ -78,6 +83,11 @@ struct R3 > > { > > int i = 0; > > > > +#if __cpp_lib_ranges_as_const > > + const int *begin() const; > > + const int *end() const; > > +#endif > > + > > const int* rbegin() const noexcept { return &i + 1; } > > const long* rend() const noexcept { return nullptr; } // not a sentinel > > for rbegin() > > > > @@ -89,9 +99,11 @@ struct R4 > > { > > int i = 0; > > > > +#if __cpp_lib_ranges_as_const > > // These members mean that range<R4> and range<const R4> are satisfied. > > const short* begin() const { return 0; } > > const short* end() const { return 0; } > > +#endif > > > > const int* rbegin() const noexcept { return &i + 1; } > > const long* rend() const noexcept { return nullptr; } // not a sentinel > > for rbegin() > > @@ -105,16 +117,8 @@ test03() > > { > > R3 r; > > const R3& c = r; > > -#if ! __cpp_lib_ranges_as_const > > VERIFY( std::ranges::crend(r) == std::ranges::rend(c) ); > > static_assert( !noexcept(std::ranges::crend(r)) ); > > -#else > > - // constant_range<const R3> is not satisfied, so crend(r) is equivalent > > - // to const_sentinel{rend(r)}, which is ill-formed because range<R3> > > - // is not satisfied. > > - static_assert( not std::ranges::range<R3> ); > > - static_assert( not std::ranges::range<const R3> ); > > -#endif > > VERIFY( std::ranges::crend(c) == std::ranges::rend(c) ); > > static_assert( !noexcept(std::ranges::crend(c)) ); > > > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc > > b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc > > index 9e1c526b4ca..2861115c22a 100644 > > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc > > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc > > @@ -113,15 +113,15 @@ test06() > > > > // Verify that _Iterator<false> is implicitly convertible to > > _Iterator<true>. > > static_assert(!std::same_as<decltype(ranges::begin(v)), > > - decltype(std::as_const(v).begin())>); > > - auto a = std::as_const(v).begin(); > > + decltype(ranges::cbegin(v))>); > > + auto a = std::cbegin(v); > > a = ranges::begin(v); > > > > // Verify that _Sentinel<false> is implicitly convertible to > > _Sentinel<true>. > > static_assert(!ranges::common_range<decltype(v)>); > > static_assert(!std::same_as<decltype(ranges::end(v)), > > - decltype(std::as_const(v).end())>); > > - auto b = std::as_const(v).end(); > > + decltype(ranges::cend(v))>); > > + auto b = ranges::cend(v); > > b = ranges::end(v); > > } > > > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc > > b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc > > index 38757d27d48..f09919bedc4 100644 > > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc > > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc > > @@ -63,10 +63,8 @@ test03() > > > > // Verify that _Sentinel<false> is implicitly convertible to > > _Sentinel<true>. > > static_assert(!ranges::common_range<decltype(v)>); > > -#if ! __cpp_lib_ranges_as_const > > static_assert(!std::same_as<decltype(ranges::end(v)), > > decltype(ranges::cend(v))>); > > -#endif > > auto b = ranges::cend(v); > > b = ranges::end(v); > > } > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > > b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > > index 934d2f65dcf..1788db1ce8d 100644 > > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > > @@ -107,20 +107,16 @@ test05() > > auto r = ranges::subrange{i, std::default_sentinel}; > > auto v = r | views::transform(std::negate{}); > > > > -#if ! __cpp_lib_ranges_as_const > > // Verify that _Iterator<false> is implicitly convertible to > > _Iterator<true>. > > static_assert(!std::same_as<decltype(ranges::begin(v)), > > decltype(ranges::cbegin(v))>); > > -#endif > > auto a = ranges::cbegin(v); > > a = ranges::begin(v); > > > > -#if ! __cpp_lib_ranges_as_const > > // Verify that _Sentinel<false> is implicitly convertible to > > _Sentinel<true>. > > static_assert(!ranges::common_range<decltype(v)>); > > static_assert(!std::same_as<decltype(ranges::end(v)), > > decltype(ranges::cend(v))>); > > -#endif > > auto b = ranges::cend(v); > > b = ranges::end(v); > > } > > -- > > 2.48.1.220.gbc204b7427 > > > > >