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
> > 
> > 
> 

Reply via email to