On Mon, 7 Oct 2024, Patrick Palka wrote:

> Tested on x86_64-pc-linux-gnu, does this look OK for trunk only?
> This doesn't seem worth backporting since there should be no
> behavior change.
> 
> -- >8 --
> 
> This implements the library changes in P0849R8 "auto(x): decay-copy
> in the language" which consist of replacing most uses of the
> exposition-only function decay-copy with auto(x) throughout the library
> wording.
> 
> Note the main difference between the two is that decay-copy materializes
> its argument whereas auto(x) doesn't, and so the latter is a no-op when
> its argument is a prvalue.  Effectively the former could introduce an
> unnecessary move constructor call in some contexts.  In C++20 and earlier
> we could emulate auto(x) with decay_t<decltype((x))>(x).

I should note this patch is treating this paper as a DR against C++20,
which should be fine since there should be no behavior change in
practice (especially in light of LWG 3724 which constrains decay-copy
to make it SFINAE-friendly).

> 
> After this paper the only remaining uses of decay-copy in the library
> are in the specification of some range adaptors.  In our implementation
> of those range adaptors I believe decay-copy is already implied which
> is why we don't mirror the wording and use __decay_copy explicitly.  So
> since it's apparently no longer needed this patch goes ahead and removes
> __decay_copy.
> 
> libstdc++-v3/ChangeLog:
> 
>       * c++config (_GLIBCXX_AUTO_CAST): Define.
>       * include/bits/iterator_concepts.h (_Decay_copy, __decay_copy):
>       Remove.
>       (__member_begin, __adl_begin): Use _GLIBCXX_AUTO_CAST instead of
>       __decay_copy as per P0849R8.
>       * include/bits/ranges_base.h (_Begin): Likewise.
>       (__member_end, __adl_end, _End): Likewise.
>       (__member_rbegin, __adl_rbegin, _RBegin): Likewise.
>       (__member_rend, __adl_rend, _Rend): Likewise.
>       (__member_size, __adl_size, _Size): Likewise.
>       (_Data): Likewise.
> ---
>  libstdc++-v3/include/bits/c++config           |  6 +++
>  libstdc++-v3/include/bits/iterator_concepts.h | 13 +-----
>  libstdc++-v3/include/bits/ranges_base.h       | 40 +++++++++----------
>  3 files changed, 28 insertions(+), 31 deletions(-)
> 
> diff --git a/libstdc++-v3/include/bits/c++config 
> b/libstdc++-v3/include/bits/c++config
> index 29d795f687c..fdbf90e28fc 100644
> --- a/libstdc++-v3/include/bits/c++config
> +++ b/libstdc++-v3/include/bits/c++config
> @@ -265,6 +265,12 @@
>  #define _GLIBCXX_NOEXCEPT_QUAL
>  #endif
>  
> +#if __cpp_auto_cast
> +# define _GLIBCXX_AUTO_CAST(X) auto(X)
> +#else
> +# define _GLIBCXX_AUTO_CAST(X) ::std::__decay_t<decltype((X))>(X)
> +#endif
> +
>  // Macro for extern template, ie controlling template linkage via use
>  // of extern keyword on template declaration. As documented in the g++
>  // manual, it inhibits all implicit instantiations and is used
> diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
> b/libstdc++-v3/include/bits/iterator_concepts.h
> index 490a362cdf1..0fcfed56737 100644
> --- a/libstdc++-v3/include/bits/iterator_concepts.h
> +++ b/libstdc++-v3/include/bits/iterator_concepts.h
> @@ -1003,19 +1003,10 @@ namespace ranges
>    {
>      using std::__detail::__class_or_enum;
>  
> -    struct _Decay_copy final
> -    {
> -      template<typename _Tp>
> -     constexpr decay_t<_Tp>
> -     operator()(_Tp&& __t) const
> -     noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>)
> -     { return std::forward<_Tp>(__t); }
> -    } inline constexpr __decay_copy{};
> -
>      template<typename _Tp>
>        concept __member_begin = requires(_Tp& __t)
>       {
> -       { __decay_copy(__t.begin()) } -> input_or_output_iterator;
> +       { _GLIBCXX_AUTO_CAST(__t.begin()) } -> input_or_output_iterator;
>       };
>  
>      // Poison pill so that unqualified lookup doesn't find std::begin.
> @@ -1025,7 +1016,7 @@ namespace ranges
>        concept __adl_begin = __class_or_enum<remove_reference_t<_Tp>>
>       && requires(_Tp& __t)
>       {
> -       { __decay_copy(begin(__t)) } -> input_or_output_iterator;
> +       { _GLIBCXX_AUTO_CAST(begin(__t)) } -> input_or_output_iterator;
>       };
>  
>      // Simplified version of std::ranges::begin that only supports lvalues,
> diff --git a/libstdc++-v3/include/bits/ranges_base.h 
> b/libstdc++-v3/include/bits/ranges_base.h
> index cb2eba1f841..80ff1e300ce 100644
> --- a/libstdc++-v3/include/bits/ranges_base.h
> +++ b/libstdc++-v3/include/bits/ranges_base.h
> @@ -115,9 +115,9 @@ namespace ranges
>         if constexpr (is_array_v<remove_reference_t<_Tp>>)
>           return true;
>         else if constexpr (__member_begin<_Tp>)
> -         return noexcept(__decay_copy(std::declval<_Tp&>().begin()));
> +         return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().begin()));
>         else
> -         return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
> +         return noexcept(_GLIBCXX_AUTO_CAST(begin(std::declval<_Tp&>())));
>       }
>  
>      public:
> @@ -142,7 +142,7 @@ namespace ranges
>      template<typename _Tp>
>        concept __member_end = requires(_Tp& __t)
>       {
> -       { __decay_copy(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>;
> +       { _GLIBCXX_AUTO_CAST(__t.end()) } -> 
> sentinel_for<__range_iter_t<_Tp>>;
>       };
>  
>      // Poison pill so that unqualified lookup doesn't find std::end.
> @@ -152,7 +152,7 @@ namespace ranges
>        concept __adl_end = __class_or_enum<remove_reference_t<_Tp>>
>       && requires(_Tp& __t)
>       {
> -       { __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
> +       { _GLIBCXX_AUTO_CAST(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
>       };
>  
>      struct _End
> @@ -165,9 +165,9 @@ namespace ranges
>         if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
>           return true;
>         else if constexpr (__member_end<_Tp>)
> -         return noexcept(__decay_copy(std::declval<_Tp&>().end()));
> +         return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().end()));
>         else
> -         return noexcept(__decay_copy(end(std::declval<_Tp&>())));
> +         return noexcept(_GLIBCXX_AUTO_CAST(end(std::declval<_Tp&>())));
>       }
>  
>      public:
> @@ -192,7 +192,7 @@ namespace ranges
>      template<typename _Tp>
>        concept __member_rbegin = requires(_Tp& __t)
>       {
> -       { __decay_copy(__t.rbegin()) } -> input_or_output_iterator;
> +       { _GLIBCXX_AUTO_CAST(__t.rbegin()) } -> input_or_output_iterator;
>       };
>  
>      void rbegin() = delete;
> @@ -201,7 +201,7 @@ namespace ranges
>        concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>>
>       && requires(_Tp& __t)
>       {
> -       { __decay_copy(rbegin(__t)) } -> input_or_output_iterator;
> +       { _GLIBCXX_AUTO_CAST(rbegin(__t)) } -> input_or_output_iterator;
>       };
>  
>      template<typename _Tp>
> @@ -219,9 +219,9 @@ namespace ranges
>       _S_noexcept()
>       {
>         if constexpr (__member_rbegin<_Tp>)
> -         return noexcept(__decay_copy(std::declval<_Tp&>().rbegin()));
> +         return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().rbegin()));
>         else if constexpr (__adl_rbegin<_Tp>)
> -         return noexcept(__decay_copy(rbegin(std::declval<_Tp&>())));
> +         return noexcept(_GLIBCXX_AUTO_CAST(rbegin(std::declval<_Tp&>())));
>         else
>           {
>             if constexpr (noexcept(_End{}(std::declval<_Tp&>())))
> @@ -254,7 +254,7 @@ namespace ranges
>      template<typename _Tp>
>        concept __member_rend = requires(_Tp& __t)
>       {
> -       { __decay_copy(__t.rend()) }
> +       { _GLIBCXX_AUTO_CAST(__t.rend()) }
>           -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
>       };
>  
> @@ -264,7 +264,7 @@ namespace ranges
>        concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>>
>       && requires(_Tp& __t)
>       {
> -       { __decay_copy(rend(__t)) }
> +       { _GLIBCXX_AUTO_CAST(rend(__t)) }
>           -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
>       };
>  
> @@ -276,9 +276,9 @@ namespace ranges
>       _S_noexcept()
>       {
>         if constexpr (__member_rend<_Tp>)
> -         return noexcept(__decay_copy(std::declval<_Tp&>().rend()));
> +         return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().rend()));
>         else if constexpr (__adl_rend<_Tp>)
> -         return noexcept(__decay_copy(rend(std::declval<_Tp&>())));
> +         return noexcept(_GLIBCXX_AUTO_CAST(rend(std::declval<_Tp&>())));
>         else
>           {
>             if constexpr (noexcept(_Begin{}(std::declval<_Tp&>())))
> @@ -312,7 +312,7 @@ namespace ranges
>        concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
>       && requires(_Tp& __t)
>       {
> -       { __decay_copy(__t.size()) } -> __detail::__is_integer_like;
> +       { _GLIBCXX_AUTO_CAST(__t.size()) } -> __detail::__is_integer_like;
>       };
>  
>      void size() = delete;
> @@ -322,7 +322,7 @@ namespace ranges
>       && !disable_sized_range<remove_cvref_t<_Tp>>
>       && requires(_Tp& __t)
>       {
> -       { __decay_copy(size(__t)) } -> __detail::__is_integer_like;
> +       { _GLIBCXX_AUTO_CAST(size(__t)) } -> __detail::__is_integer_like;
>       };
>  
>      template<typename _Tp>
> @@ -347,9 +347,9 @@ namespace ranges
>         if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
>           return true;
>         else if constexpr (__member_size<_Tp>)
> -         return noexcept(__decay_copy(std::declval<_Tp&>().size()));
> +         return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().size()));
>         else if constexpr (__adl_size<_Tp>)
> -         return noexcept(__decay_copy(size(std::declval<_Tp&>())));
> +         return noexcept(_GLIBCXX_AUTO_CAST(size(std::declval<_Tp&>())));
>         else if constexpr (__sentinel_size<_Tp>)
>           return noexcept(_End{}(std::declval<_Tp&>())
>                           - _Begin{}(std::declval<_Tp&>()));
> @@ -459,7 +459,7 @@ namespace ranges
>      template<typename _Tp>
>        concept __member_data = requires(_Tp& __t)
>       {
> -       { __decay_copy(__t.data()) } -> __pointer_to_object;
> +       { _GLIBCXX_AUTO_CAST(__t.data()) } -> __pointer_to_object;
>       };
>  
>      template<typename _Tp>
> @@ -473,7 +473,7 @@ namespace ranges
>       _S_noexcept()
>       {
>         if constexpr (__member_data<_Tp>)
> -         return noexcept(__decay_copy(std::declval<_Tp&>().data()));
> +         return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().data()));
>         else
>           return noexcept(_Begin{}(std::declval<_Tp&>()));
>       }
> -- 
> 2.47.0.rc1.33.g90fe3800b9
> 
> 

Reply via email to