libstdc++: Fix ref_view branch of views::as_const [PR119135]

Message ID 20250313034525.3142058-1-ppalka@redhat.com
State Committed
Headers
Series libstdc++: Fix ref_view branch of views::as_const [PR119135] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed

Commit Message

Patrick Palka March 13, 2025, 3:45 a.m. UTC
  Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and
perhaps 13?

N.B. the use of a constrained auto instead of a separate static_assert
in the testcase is unfortunate but I opted for local consistency for
now.

-- >8 --

Unlike for span<X> and empty_view<X>, the range_reference_t of
ref_view<X> doesn't correspond to X.  This patch fixes the ref_view
branch of views::as_const to correctly query the underlying range
type X.

	PR libstdc++/119135

libstdc++-v3/ChangeLog:

	* include/std/ranges: Include <utility>.
	(views::__detail::__is_ref_view): Replace with ...
	(views::__detail::__is_constable_ref_view): ... this.
	(views::_AsConst::operator()): Correct the ref_view branch.
	* testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
	test.
---
 libstdc++-v3/include/std/ranges                      | 12 ++++++------
 .../testsuite/std/ranges/adaptors/as_const/1.cc      |  4 ++++
 2 files changed, 10 insertions(+), 6 deletions(-)
  

Comments

Patrick Palka March 13, 2025, 3:50 a.m. UTC | #1
On Wed, 12 Mar 2025, Patrick Palka wrote:

> Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and
> perhaps 13?
> 
> N.B. the use of a constrained auto instead of a separate static_assert
> in the testcase is unfortunate but I opted for local consistency for
> now.
> 
> -- >8 --
> 
> Unlike for span<X> and empty_view<X>, the range_reference_t of
> ref_view<X> doesn't correspond to X.  This patch fixes the ref_view
> branch of views::as_const to correctly query the underlying range
> type X.
> 
> 	PR libstdc++/119135
> 
> libstdc++-v3/ChangeLog:
> 
> 	* include/std/ranges: Include <utility>.
> 	(views::__detail::__is_ref_view): Replace with ...
> 	(views::__detail::__is_constable_ref_view): ... this.
> 	(views::_AsConst::operator()): Correct the ref_view branch.
> 	* testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
> 	test.
> ---
>  libstdc++-v3/include/std/ranges                      | 12 ++++++------
>  .../testsuite/std/ranges/adaptors/as_const/1.cc      |  4 ++++
>  2 files changed, 10 insertions(+), 6 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index c2a2d6f4e05..31d62454895 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -48,6 +48,7 @@
>  #include <string_view>
>  #include <tuple>
>  #if __cplusplus > 202002L
> +#include <utility>
>  #include <variant>
>  #endif
>  #include <bits/ranges_util.h>
> @@ -9324,10 +9325,11 @@ namespace views::__adaptor
>      namespace __detail
>      {
>        template<typename _Tp>
> -	inline constexpr bool __is_ref_view = false;
> +	inline constexpr bool __is_constable_ref_view = false;
>  
>        template<typename _Range>
> -	inline constexpr bool __is_ref_view<ref_view<_Range>> = true;
> +	inline constexpr bool __is_constable_ref_view<ref_view<_Range>>
> +	  = constant_range<const _Range>;
>  
>        template<typename _Range>
>  	concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); };
> @@ -9349,10 +9351,8 @@ namespace views::__adaptor
>  	  return views::empty<const element_type>;
>  	else if constexpr (std::__detail::__is_span<_Tp>)
>  	  return span<const element_type, _Tp::extent>(std::forward<_Range>(__r));
> -	else if constexpr (__detail::__is_ref_view<_Tp>
> -			   && constant_range<const element_type>)
> -	  return ref_view(static_cast<const element_type&>
> -			  (std::forward<_Range>(__r).base()));
> +	else if constexpr (__detail::__is_constable_ref_view<_Tp>)
> +	  return ref_view(std::as_const(__r.base()));

Whoops, just noticed that I got rid of the perfect forwarding of __r
here for no good reason.  It shouldn't matter since its base() member
function is const, but consider the std::forward restored for
consistency.

>  	else if constexpr (is_lvalue_reference_v<_Range>
>  			   && constant_range<const _Tp>
>  			   && !view<_Tp>)
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> index c36786a8c5f..3f1f8eb1772 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> @@ -63,6 +63,10 @@ test03()
>    std::vector<int> v;
>    std::same_as<ranges::ref_view<const std::vector<int>>>
>      auto r = views::as_const(v);
> +
> +  // PR libstdc++/119135
> +  std::same_as<ranges::ref_view<const std::vector<int>>>
> +    auto r2 = views::as_const(views::all(v));
>  }
>  
>  int
> -- 
> 2.49.0.rc1.37.ge969bc8759
> 
>
  
Patrick Palka March 13, 2025, 3:51 a.m. UTC | #2
On Wed, 12 Mar 2025, Patrick Palka wrote:

> On Wed, 12 Mar 2025, Patrick Palka wrote:
> 
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and
> > perhaps 13?
> > 
> > N.B. the use of a constrained auto instead of a separate static_assert
> > in the testcase is unfortunate but I opted for local consistency for
> > now.
> > 
> > -- >8 --
> > 
> > Unlike for span<X> and empty_view<X>, the range_reference_t of
> > ref_view<X> doesn't correspond to X.  This patch fixes the ref_view
> > branch of views::as_const to correctly query the underlying range
> > type X.
> > 
> > 	PR libstdc++/119135
> > 
> > libstdc++-v3/ChangeLog:
> > 
> > 	* include/std/ranges: Include <utility>.
> > 	(views::__detail::__is_ref_view): Replace with ...
> > 	(views::__detail::__is_constable_ref_view): ... this.
> > 	(views::_AsConst::operator()): Correct the ref_view branch.
> > 	* testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
> > 	test.
> > ---
> >  libstdc++-v3/include/std/ranges                      | 12 ++++++------
> >  .../testsuite/std/ranges/adaptors/as_const/1.cc      |  4 ++++
> >  2 files changed, 10 insertions(+), 6 deletions(-)
> > 
> > diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> > index c2a2d6f4e05..31d62454895 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -48,6 +48,7 @@
> >  #include <string_view>
> >  #include <tuple>
> >  #if __cplusplus > 202002L
> > +#include <utility>
> >  #include <variant>
> >  #endif
> >  #include <bits/ranges_util.h>
> > @@ -9324,10 +9325,11 @@ namespace views::__adaptor
> >      namespace __detail
> >      {
> >        template<typename _Tp>
> > -	inline constexpr bool __is_ref_view = false;
> > +	inline constexpr bool __is_constable_ref_view = false;
> >  
> >        template<typename _Range>
> > -	inline constexpr bool __is_ref_view<ref_view<_Range>> = true;
> > +	inline constexpr bool __is_constable_ref_view<ref_view<_Range>>
> > +	  = constant_range<const _Range>;
> >  
> >        template<typename _Range>
> >  	concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); };
> > @@ -9349,10 +9351,8 @@ namespace views::__adaptor
> >  	  return views::empty<const element_type>;
> >  	else if constexpr (std::__detail::__is_span<_Tp>)
> >  	  return span<const element_type, _Tp::extent>(std::forward<_Range>(__r));
> > -	else if constexpr (__detail::__is_ref_view<_Tp>
> > -			   && constant_range<const element_type>)
> > -	  return ref_view(static_cast<const element_type&>
> > -			  (std::forward<_Range>(__r).base()));
> > +	else if constexpr (__detail::__is_constable_ref_view<_Tp>)
> > +	  return ref_view(std::as_const(__r.base()));
> 
> Whoops, just noticed that I got rid of the perfect forwarding of __r
> here for no good reason.  It shouldn't matter since its base() member
> function is const, but consider the std::forward restored for
> consistency.

Like so:

-- >8 --

Subject: [PATCH v2] libstdc++: Fix ref_view branch of views::as_const [PR119135]

Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and
perhaps 13?

N.B. the use of a constrained auto instead of a separate static_assert
in the testcase is unfortunate but I opted for local consistency for
now.

-- >8 --

Unlike for span<X> and empty_view<X>, the range_reference_t of
ref_view<X> doesn't correspond to X.  This patch fixes the ref_view
branch of views::as_const to correctly query its underlying range
type X.

	PR libstdc++/119135

libstdc++-v3/ChangeLog:

	* include/std/ranges: Include <utility>.
	(views::__detail::__is_ref_view): Replace with ...
	(views::__detail::__is_constable_ref_view): ... this.
	(views::_AsConst::operator()): Correct the ref_view branch.
	* testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
	test.
---
 libstdc++-v3/include/std/ranges                      | 12 ++++++------
 .../testsuite/std/ranges/adaptors/as_const/1.cc      |  4 ++++
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index c2a2d6f4e05..ef277b81bd3 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -48,6 +48,7 @@
 #include <string_view>
 #include <tuple>
 #if __cplusplus > 202002L
+#include <utility>
 #include <variant>
 #endif
 #include <bits/ranges_util.h>
@@ -9324,10 +9325,11 @@ namespace views::__adaptor
     namespace __detail
     {
       template<typename _Tp>
-	inline constexpr bool __is_ref_view = false;
+	inline constexpr bool __is_constable_ref_view = false;
 
       template<typename _Range>
-	inline constexpr bool __is_ref_view<ref_view<_Range>> = true;
+	inline constexpr bool __is_constable_ref_view<ref_view<_Range>>
+	  = constant_range<const _Range>;
 
       template<typename _Range>
 	concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); };
@@ -9349,10 +9351,8 @@ namespace views::__adaptor
 	  return views::empty<const element_type>;
 	else if constexpr (std::__detail::__is_span<_Tp>)
 	  return span<const element_type, _Tp::extent>(std::forward<_Range>(__r));
-	else if constexpr (__detail::__is_ref_view<_Tp>
-			   && constant_range<const element_type>)
-	  return ref_view(static_cast<const element_type&>
-			  (std::forward<_Range>(__r).base()));
+	else if constexpr (__detail::__is_constable_ref_view<_Tp>)
+	  return ref_view(std::as_const(std::forward<_Range>(__r).base()));
 	else if constexpr (is_lvalue_reference_v<_Range>
 			   && constant_range<const _Tp>
 			   && !view<_Tp>)
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
index c36786a8c5f..3f1f8eb1772 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
@@ -63,6 +63,10 @@ test03()
   std::vector<int> v;
   std::same_as<ranges::ref_view<const std::vector<int>>>
     auto r = views::as_const(v);
+
+  // PR libstdc++/119135
+  std::same_as<ranges::ref_view<const std::vector<int>>>
+    auto r2 = views::as_const(views::all(v));
 }
 
 int
  
Tomasz Kaminski March 13, 2025, 9:45 a.m. UTC | #3
On Thu, Mar 13, 2025 at 4:55 AM Patrick Palka <ppalka@redhat.com> wrote:

> On Wed, 12 Mar 2025, Patrick Palka wrote:
>
> > On Wed, 12 Mar 2025, Patrick Palka wrote:
> >
> > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and
> > > perhaps 13?
> > >
> > > N.B. the use of a constrained auto instead of a separate static_assert
> > > in the testcase is unfortunate but I opted for local consistency for
> > > now.
> > >
> > > -- >8 --
> > >
> > > Unlike for span<X> and empty_view<X>, the range_reference_t of
> > > ref_view<X> doesn't correspond to X.  This patch fixes the ref_view
> > > branch of views::as_const to correctly query the underlying range
> > > type X.
> > >
> > >     PR libstdc++/119135
> > >
> > > libstdc++-v3/ChangeLog:
> > >
> > >     * include/std/ranges: Include <utility>.
> > >     (views::__detail::__is_ref_view): Replace with ...
> > >     (views::__detail::__is_constable_ref_view): ... this.
> > >     (views::_AsConst::operator()): Correct the ref_view branch.
> > >     * testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
> > >     test.
> > > ---
> > >  libstdc++-v3/include/std/ranges                      | 12 ++++++------
> > >  .../testsuite/std/ranges/adaptors/as_const/1.cc      |  4 ++++
> > >  2 files changed, 10 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/libstdc++-v3/include/std/ranges
> b/libstdc++-v3/include/std/ranges
> > > index c2a2d6f4e05..31d62454895 100644
> > > --- a/libstdc++-v3/include/std/ranges
> > > +++ b/libstdc++-v3/include/std/ranges
> > > @@ -48,6 +48,7 @@
> > >  #include <string_view>
> > >  #include <tuple>
> > >  #if __cplusplus > 202002L
> > > +#include <utility>
> > >  #include <variant>
> > >  #endif
> > >  #include <bits/ranges_util.h>
> > > @@ -9324,10 +9325,11 @@ namespace views::__adaptor
> > >      namespace __detail
> > >      {
> > >        template<typename _Tp>
> > > -   inline constexpr bool __is_ref_view = false;
> > > +   inline constexpr bool __is_constable_ref_view = false;
> > >
> > >        template<typename _Range>
> > > -   inline constexpr bool __is_ref_view<ref_view<_Range>> = true;
> > > +   inline constexpr bool __is_constable_ref_view<ref_view<_Range>>
> > > +     = constant_range<const _Range>;
> > >
> > >        template<typename _Range>
> > >     concept __can_as_const_view = requires {
> as_const_view(std::declval<_Range>()); };
> > > @@ -9349,10 +9351,8 @@ namespace views::__adaptor
> > >       return views::empty<const element_type>;
> > >     else if constexpr (std::__detail::__is_span<_Tp>)
> > >       return span<const element_type,
> _Tp::extent>(std::forward<_Range>(__r));
> > > -   else if constexpr (__detail::__is_ref_view<_Tp>
> > > -                      && constant_range<const element_type>)
> > > -     return ref_view(static_cast<const element_type&>
> > > -                     (std::forward<_Range>(__r).base()));
> > > +   else if constexpr (__detail::__is_constable_ref_view<_Tp>)
> > > +     return ref_view(std::as_const(__r.base()));
> >
> > Whoops, just noticed that I got rid of the perfect forwarding of __r
> > here for no good reason.  It shouldn't matter since its base() member
> > function is const, but consider the std::forward restored for
> > consistency.
>
LGTM
For span/empty_view/ref_view this does not matter, just triggers another
specialization of forward.
But I agree we should consistently use/not-use this forwards for these
types.

>
> Like so:
>
> -- >8 --
>
> Subject: [PATCH v2] libstdc++: Fix ref_view branch of views::as_const
> [PR119135]
>
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and
> perhaps 13?
>
> N.B. the use of a constrained auto instead of a separate static_assert
> in the testcase is unfortunate but I opted for local consistency for
> now.
>
> -- >8 --
>
> Unlike for span<X> and empty_view<X>, the range_reference_t of
> ref_view<X> doesn't correspond to X.  This patch fixes the ref_view
> branch of views::as_const to correctly query its underlying range
> type X.
>
>         PR libstdc++/119135
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/ranges: Include <utility>.
>         (views::__detail::__is_ref_view): Replace with ...
>         (views::__detail::__is_constable_ref_view): ... this.
>         (views::_AsConst::operator()): Correct the ref_view branch.
>         * testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
>         test.
> ---
>  libstdc++-v3/include/std/ranges                      | 12 ++++++------
>  .../testsuite/std/ranges/adaptors/as_const/1.cc      |  4 ++++
>  2 files changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/ranges
> b/libstdc++-v3/include/std/ranges
> index c2a2d6f4e05..ef277b81bd3 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -48,6 +48,7 @@
>  #include <string_view>
>  #include <tuple>
>  #if __cplusplus > 202002L
> +#include <utility>
>  #include <variant>
>  #endif
>  #include <bits/ranges_util.h>
> @@ -9324,10 +9325,11 @@ namespace views::__adaptor
>      namespace __detail
>      {
>        template<typename _Tp>
> -       inline constexpr bool __is_ref_view = false;
> +       inline constexpr bool __is_constable_ref_view = false;
>
>        template<typename _Range>
> -       inline constexpr bool __is_ref_view<ref_view<_Range>> = true;
> +       inline constexpr bool __is_constable_ref_view<ref_view<_Range>>
> +         = constant_range<const _Range>;
>
>        template<typename _Range>
>         concept __can_as_const_view = requires {
> as_const_view(std::declval<_Range>()); };
> @@ -9349,10 +9351,8 @@ namespace views::__adaptor
>           return views::empty<const element_type>;
>         else if constexpr (std::__detail::__is_span<_Tp>)
>           return span<const element_type,
> _Tp::extent>(std::forward<_Range>(__r));
> -       else if constexpr (__detail::__is_ref_view<_Tp>
> -                          && constant_range<const element_type>)
> -         return ref_view(static_cast<const element_type&>
> -                         (std::forward<_Range>(__r).base()));
> +       else if constexpr (__detail::__is_constable_ref_view<_Tp>)
> +         return ref_view(std::as_const(std::forward<_Range>(__r).base()));
>         else if constexpr (is_lvalue_reference_v<_Range>
>                            && constant_range<const _Tp>
>                            && !view<_Tp>)
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> index c36786a8c5f..3f1f8eb1772 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> @@ -63,6 +63,10 @@ test03()
>    std::vector<int> v;
>    std::same_as<ranges::ref_view<const std::vector<int>>>
>      auto r = views::as_const(v);
> +
> +  // PR libstdc++/119135
> +  std::same_as<ranges::ref_view<const std::vector<int>>>
> +    auto r2 = views::as_const(views::all(v));
>  }
>
>  int
> --
> 2.49.0.rc1.37.ge969bc8759
>
>
  
Jonathan Wakely March 13, 2025, 11:34 a.m. UTC | #4
On Thu, 13 Mar 2025 at 03:54, Patrick Palka <ppalka@redhat.com> wrote:
>
> On Wed, 12 Mar 2025, Patrick Palka wrote:
>
> > On Wed, 12 Mar 2025, Patrick Palka wrote:
> >
> > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and
> > > perhaps 13?


OK for trunk and 14 and 13.


> > >
> > > N.B. the use of a constrained auto instead of a separate static_assert
> > > in the testcase is unfortunate but I opted for local consistency for
> > > now.
> > >
> > > -- >8 --
> > >
> > > Unlike for span<X> and empty_view<X>, the range_reference_t of
> > > ref_view<X> doesn't correspond to X.  This patch fixes the ref_view
> > > branch of views::as_const to correctly query the underlying range
> > > type X.
> > >
> > >     PR libstdc++/119135
> > >
> > > libstdc++-v3/ChangeLog:
> > >
> > >     * include/std/ranges: Include <utility>.
> > >     (views::__detail::__is_ref_view): Replace with ...
> > >     (views::__detail::__is_constable_ref_view): ... this.
> > >     (views::_AsConst::operator()): Correct the ref_view branch.
> > >     * testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
> > >     test.
> > > ---
> > >  libstdc++-v3/include/std/ranges                      | 12 ++++++------
> > >  .../testsuite/std/ranges/adaptors/as_const/1.cc      |  4 ++++
> > >  2 files changed, 10 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> > > index c2a2d6f4e05..31d62454895 100644
> > > --- a/libstdc++-v3/include/std/ranges
> > > +++ b/libstdc++-v3/include/std/ranges
> > > @@ -48,6 +48,7 @@
> > >  #include <string_view>
> > >  #include <tuple>
> > >  #if __cplusplus > 202002L
> > > +#include <utility>
> > >  #include <variant>
> > >  #endif
> > >  #include <bits/ranges_util.h>
> > > @@ -9324,10 +9325,11 @@ namespace views::__adaptor
> > >      namespace __detail
> > >      {
> > >        template<typename _Tp>
> > > -   inline constexpr bool __is_ref_view = false;
> > > +   inline constexpr bool __is_constable_ref_view = false;
> > >
> > >        template<typename _Range>
> > > -   inline constexpr bool __is_ref_view<ref_view<_Range>> = true;
> > > +   inline constexpr bool __is_constable_ref_view<ref_view<_Range>>
> > > +     = constant_range<const _Range>;
> > >
> > >        template<typename _Range>
> > >     concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); };
> > > @@ -9349,10 +9351,8 @@ namespace views::__adaptor
> > >       return views::empty<const element_type>;
> > >     else if constexpr (std::__detail::__is_span<_Tp>)
> > >       return span<const element_type, _Tp::extent>(std::forward<_Range>(__r));
> > > -   else if constexpr (__detail::__is_ref_view<_Tp>
> > > -                      && constant_range<const element_type>)
> > > -     return ref_view(static_cast<const element_type&>
> > > -                     (std::forward<_Range>(__r).base()));
> > > +   else if constexpr (__detail::__is_constable_ref_view<_Tp>)
> > > +     return ref_view(std::as_const(__r.base()));
> >
> > Whoops, just noticed that I got rid of the perfect forwarding of __r
> > here for no good reason.  It shouldn't matter since its base() member
> > function is const, but consider the std::forward restored for
> > consistency.
>
> Like so:
>
> -- >8 --
>
> Subject: [PATCH v2] libstdc++: Fix ref_view branch of views::as_const [PR119135]
>
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and
> perhaps 13?
>
> N.B. the use of a constrained auto instead of a separate static_assert
> in the testcase is unfortunate but I opted for local consistency for
> now.
>
> -- >8 --
>
> Unlike for span<X> and empty_view<X>, the range_reference_t of
> ref_view<X> doesn't correspond to X.  This patch fixes the ref_view
> branch of views::as_const to correctly query its underlying range
> type X.
>
>         PR libstdc++/119135
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/ranges: Include <utility>.
>         (views::__detail::__is_ref_view): Replace with ...
>         (views::__detail::__is_constable_ref_view): ... this.
>         (views::_AsConst::operator()): Correct the ref_view branch.
>         * testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
>         test.
> ---
>  libstdc++-v3/include/std/ranges                      | 12 ++++++------
>  .../testsuite/std/ranges/adaptors/as_const/1.cc      |  4 ++++
>  2 files changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index c2a2d6f4e05..ef277b81bd3 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -48,6 +48,7 @@
>  #include <string_view>
>  #include <tuple>
>  #if __cplusplus > 202002L
> +#include <utility>
>  #include <variant>
>  #endif
>  #include <bits/ranges_util.h>
> @@ -9324,10 +9325,11 @@ namespace views::__adaptor
>      namespace __detail
>      {
>        template<typename _Tp>
> -       inline constexpr bool __is_ref_view = false;
> +       inline constexpr bool __is_constable_ref_view = false;
>
>        template<typename _Range>
> -       inline constexpr bool __is_ref_view<ref_view<_Range>> = true;
> +       inline constexpr bool __is_constable_ref_view<ref_view<_Range>>
> +         = constant_range<const _Range>;
>
>        template<typename _Range>
>         concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); };
> @@ -9349,10 +9351,8 @@ namespace views::__adaptor
>           return views::empty<const element_type>;
>         else if constexpr (std::__detail::__is_span<_Tp>)
>           return span<const element_type, _Tp::extent>(std::forward<_Range>(__r));
> -       else if constexpr (__detail::__is_ref_view<_Tp>
> -                          && constant_range<const element_type>)
> -         return ref_view(static_cast<const element_type&>
> -                         (std::forward<_Range>(__r).base()));
> +       else if constexpr (__detail::__is_constable_ref_view<_Tp>)
> +         return ref_view(std::as_const(std::forward<_Range>(__r).base()));
>         else if constexpr (is_lvalue_reference_v<_Range>
>                            && constant_range<const _Tp>
>                            && !view<_Tp>)
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> index c36786a8c5f..3f1f8eb1772 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
> @@ -63,6 +63,10 @@ test03()
>    std::vector<int> v;
>    std::same_as<ranges::ref_view<const std::vector<int>>>
>      auto r = views::as_const(v);
> +
> +  // PR libstdc++/119135
> +  std::same_as<ranges::ref_view<const std::vector<int>>>
> +    auto r2 = views::as_const(views::all(v));
>  }
>
>  int
> --
> 2.49.0.rc1.37.ge969bc8759
>
  

Patch

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index c2a2d6f4e05..31d62454895 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -48,6 +48,7 @@ 
 #include <string_view>
 #include <tuple>
 #if __cplusplus > 202002L
+#include <utility>
 #include <variant>
 #endif
 #include <bits/ranges_util.h>
@@ -9324,10 +9325,11 @@  namespace views::__adaptor
     namespace __detail
     {
       template<typename _Tp>
-	inline constexpr bool __is_ref_view = false;
+	inline constexpr bool __is_constable_ref_view = false;
 
       template<typename _Range>
-	inline constexpr bool __is_ref_view<ref_view<_Range>> = true;
+	inline constexpr bool __is_constable_ref_view<ref_view<_Range>>
+	  = constant_range<const _Range>;
 
       template<typename _Range>
 	concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); };
@@ -9349,10 +9351,8 @@  namespace views::__adaptor
 	  return views::empty<const element_type>;
 	else if constexpr (std::__detail::__is_span<_Tp>)
 	  return span<const element_type, _Tp::extent>(std::forward<_Range>(__r));
-	else if constexpr (__detail::__is_ref_view<_Tp>
-			   && constant_range<const element_type>)
-	  return ref_view(static_cast<const element_type&>
-			  (std::forward<_Range>(__r).base()));
+	else if constexpr (__detail::__is_constable_ref_view<_Tp>)
+	  return ref_view(std::as_const(__r.base()));
 	else if constexpr (is_lvalue_reference_v<_Range>
 			   && constant_range<const _Tp>
 			   && !view<_Tp>)
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
index c36786a8c5f..3f1f8eb1772 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
@@ -63,6 +63,10 @@  test03()
   std::vector<int> v;
   std::same_as<ranges::ref_view<const std::vector<int>>>
     auto r = views::as_const(v);
+
+  // PR libstdc++/119135
+  std::same_as<ranges::ref_view<const std::vector<int>>>
+    auto r2 = views::as_const(views::all(v));
 }
 
 int