On Tue, 28 Jan 2025 at 16:00, Patrick Palka <ppa...@redhat.com> wrote:
>
> On Mon, 27 Jan 2025, Patrick Palka wrote:
>
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14?
> >
> > -- >8 --
> >
> > This case was incorrectly failing in C++23 mode even after P2492R2
> > because the perfect forwarding simplification mechanism assumed bound
> > arguments are copy-constructible which is no longer necessarily true
> > after that paper.
>
> On closer inspection this isn't quite right: the mechanism has for a
> while intended to check for copy-constructibility of the bound arguments
> (even before P2492R2), but it used the wrong predicate:
> is_trivially_copyable instead of is_trivially_copy_constructible.
> Here's a simpler fix that's more suitable for backporting.
>
> Disabling the mechanism outright in C++23 mode and relying on deducing
> "this" is still desirable but I reckon that's more stage 1 material.
>
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14?

OK for both, thanks.

>
> -- >8 --
>
> Subject: [PATCH] libstdc++: Fix views::transform(move_only_fn{}) forwarding
>  [PR118413]
>
> The range adaptor perfect forwarding simplification mechanism is currently
> only enabled for trivially copyable bound arguments, to prevent undesirable
> copies of complex objects.  But "trivially copyable" is the wrong property
> to check for here, since a move-only type with a trivial move constructor
> is considered trivially copyable, and after P2492R2 we can't assume that the
> bound arguments are copy-constructible.  This patch makes the mechanism
> more specifically check for trivial copy constructibility instead so that
> it's properly disabled for move-only bound arguments.
>
>         PR libstdc++/118413
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/ranges (views::__adaptor::_Partial): Refine
>         constraints on the "simple" partial specializations to require
>         is_trivially_copy_constructible_v instead of
>         is_trivially_copyable_v.
>         * testsuite/std/ranges/adaptors/adjacent_transform/1.cc (test04):
>         Test partial application of a move-only function as well.
>         * testsuite/std/ranges/adaptors/transform.cc (test09): Likewise.
> ---
>  libstdc++-v3/include/std/ranges                               | 4 ++--
>  .../testsuite/std/ranges/adaptors/adjacent_transform/1.cc     | 1 +
>  libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc       | 2 ++
>  3 files changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index ad69a94b21f..5c795a90fbc 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -1145,7 +1145,7 @@ namespace views::__adaptor
>    // which makes overload resolution failure diagnostics more concise.
>    template<typename _Adaptor, typename... _Args>
>      requires __adaptor_has_simple_extra_args<_Adaptor, _Args...>
> -      && (is_trivially_copyable_v<_Args> && ...)
> +      && (is_trivially_copy_constructible_v<_Args> && ...)
>      struct _Partial<_Adaptor, _Args...> : 
> _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>>
>      {
>        tuple<_Args...> _M_args;
> @@ -1176,7 +1176,7 @@ namespace views::__adaptor
>    // where _Adaptor accepts a single extra argument.
>    template<typename _Adaptor, typename _Arg>
>      requires __adaptor_has_simple_extra_args<_Adaptor, _Arg>
> -      && is_trivially_copyable_v<_Arg>
> +      && is_trivially_copy_constructible_v<_Arg>
>      struct _Partial<_Adaptor, _Arg> : 
> _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>>
>      {
>        _Arg _M_arg;
> diff --git 
> a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc 
> b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
> index a5791b3da70..772e4b3b6a0 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
> @@ -110,6 +110,7 @@ test04()
>    };
>    // P2494R2 Relaxing range adaptors to allow for move only types
>    static_assert( requires { views::pairwise_transform(x, move_only{}); } );
> +  static_assert( requires { x | views::pairwise_transform(move_only{}); } );
>  }
>
>  int
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc 
> b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
> index dfc91fb5e1f..934d2f65dcf 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
> @@ -191,8 +191,10 @@ test09()
>  #if __cpp_lib_ranges >= 202207L
>    // P2494R2 Relaxing range adaptors to allow for move only types
>    static_assert( requires { transform(x, move_only{}); } );
> +  static_assert( requires { x | transform(move_only{}); } ); // PR 
> libstdc++/118413
>  #else
>    static_assert( ! requires { transform(x, move_only{}); } );
> +  static_assert( ! requires { x | transform(move_only{}); } );
>  #endif
>  }
>
> --
> 2.48.1.91.g5f8f7081f7
>
>
> > It'd be easy enough to fix the mechanism, but in
> > C++23 mode the mechanism is no longer useful since we can just rely on
> > deducing 'this' to implement perfect forwarding with a single overload
> > (and done in r14-7150-gd2cb4693a0b383).  So this patch just disables
> > the mechanism in C++23 mode so that the generic implementation is always
> > used.
> >
> >       PR libstdc++/118413
> >
> > libstdc++-v3/ChangeLog:
> >
> >       * include/std/ranges
> >       (_GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING): New.
> >       (__closure_has_simple_call_op): Only define in C++20 mode.
> >       (__closure_has_simple_extra_args): Likewise.
> >       (_Partial, _Pipe): Likewise, for the "simple" partial
> >       specializations.
> >       (*::_S_has_simple_call_op): Likewise.
> >       (*::_S_has_simple_extra_args): Likewise.
> >       * testsuite/std/ranges/adaptors/100577.cc: Disable some
> >       implementation detail checks in C++23 mode.
> >       * testsuite/std/ranges/adaptors/transform.cc (test09): Also test
> >       partially applying the move-only function.
> > ---
> >  libstdc++-v3/include/std/ranges               | 53 +++++++++++++++++++
> >  .../testsuite/std/ranges/adaptors/100577.cc   |  4 +-
> >  .../std/ranges/adaptors/transform.cc          |  2 +
> >  3 files changed, 58 insertions(+), 1 deletion(-)
> >
> > diff --git a/libstdc++-v3/include/std/ranges 
> > b/libstdc++-v3/include/std/ranges
> > index ad69a94b21f..a2b8748bea6 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -1028,6 +1028,16 @@ namespace views::__adaptor
> >       }
> >      };
> >
> > +#if __cplusplus <= 202003L
> > +  // In C++20 mode we simplify perfect forwarding of a range adaptor 
> > closure's
> > +  // bound arguments when possible (according to their types), for sake of 
> > compile
> > +  // times and diagnostic quality.  In C++23 mode we instead rely on 
> > deducing 'this'
> > +  // to idiomatically implement perfect forwarding.  Note that this means 
> > the
> > +  // simplification logic doesn't consider C++23 <ranges> changes such as 
> > P2492R2.
> > +# define _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING 1
> > +#endif
> > +
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >    // True if the range adaptor closure _Adaptor has a simple operator(), 
> > i.e.
> >    // one that's not overloaded according to constness or value category of 
> > the
> >    // _Adaptor object.
> > @@ -1039,6 +1049,7 @@ namespace views::__adaptor
> >    template<typename _Adaptor, typename... _Args>
> >      concept __adaptor_has_simple_extra_args = 
> > _Adaptor::_S_has_simple_extra_args
> >        || _Adaptor::template _S_has_simple_extra_args<_Args...>;
> > +#endif
> >
> >    // A range adaptor closure that represents partial application of
> >    // the range adaptor _Adaptor with arguments _Args.
> > @@ -1139,6 +1150,7 @@ namespace views::__adaptor
> >  #endif
> >      };
> >
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >    // Partial specialization of the primary template for the case where the 
> > extra
> >    // arguments of the adaptor can always be safely and efficiently 
> > forwarded by
> >    // const reference.  This lets us get away with a single operator() 
> > overload,
> > @@ -1195,6 +1207,7 @@ namespace views::__adaptor
> >
> >        static constexpr bool _S_has_simple_call_op = true;
> >      };
> > +#endif // _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >
> >    template<typename _Lhs, typename _Rhs, typename _Range>
> >      concept __pipe_invocable
> > @@ -1245,6 +1258,7 @@ namespace views::__adaptor
> >  #endif
> >      };
> >
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >    // A partial specialization of the above primary template for the case 
> > where
> >    // both adaptor operands have a simple operator().  This in turn lets us
> >    // implement composition using a single simple operator(), which makes
> > @@ -1271,6 +1285,7 @@ namespace views::__adaptor
> >
> >        static constexpr bool _S_has_simple_call_op = true;
> >      };
> > +#endif // _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >  } // namespace views::__adaptor
> >
> >  #if __cpp_lib_ranges >= 202202L
> > @@ -1454,7 +1469,9 @@ namespace views::__adaptor
> >           return owning_view{std::forward<_Range>(__r)};
> >       }
> >
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_call_op = true;
> > +#endif
> >      };
> >
> >      inline constexpr _All all;
> > @@ -1872,7 +1889,9 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_Filter>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >      };
> >
> >      inline constexpr _Filter filter;
> > @@ -2260,7 +2279,9 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_Transform>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >      };
> >
> >      inline constexpr _Transform transform;
> > @@ -2494,12 +2515,14 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_Take>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        // The count argument of views::take is not always simple -- it can 
> > be
> >        // e.g. a move-only class that's implicitly convertible to the 
> > difference
> >        // type.  But an integer-like count argument is surely simple.
> >        template<typename _Tp>
> >       static constexpr bool _S_has_simple_extra_args
> >         = ranges::__detail::__is_integer_like<_Tp>;
> > +#endif
> >      };
> >
> >      inline constexpr _Take take;
> > @@ -2621,7 +2644,9 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_TakeWhile>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >      };
> >
> >      inline constexpr _TakeWhile take_while;
> > @@ -2777,9 +2802,11 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_Drop>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        template<typename _Tp>
> >       static constexpr bool _S_has_simple_extra_args
> >         = _Take::_S_has_simple_extra_args<_Tp>;
> > +#endif
> >      };
> >
> >      inline constexpr _Drop drop;
> > @@ -2866,7 +2893,9 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_DropWhile>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >      };
> >
> >      inline constexpr _DropWhile drop_while;
> > @@ -3273,7 +3302,9 @@ namespace views::__adaptor
> >         return join_view<all_t<_Range>>{std::forward<_Range>(__r)};
> >       }
> >
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_call_op = true;
> > +#endif
> >      };
> >
> >      inline constexpr _Join join;
> > @@ -3730,6 +3761,7 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_LazySplit>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        // The pattern argument of views::lazy_split is not always simple -- 
> > it can be
> >        // a non-view range, the value category of which affects whether the 
> > call
> >        // is well-formed.  But a scalar or a view pattern argument is surely
> > @@ -3738,6 +3770,7 @@ namespace views::__adaptor
> >       static constexpr bool _S_has_simple_extra_args
> >         = is_scalar_v<_Pattern> || (view<_Pattern>
> >                                     && copy_constructible<_Pattern>);
> > +#endif
> >      };
> >
> >      inline constexpr _LazySplit lazy_split;
> > @@ -3937,9 +3970,11 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_Split>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        template<typename _Pattern>
> >       static constexpr bool _S_has_simple_extra_args
> >         = _LazySplit::_S_has_simple_extra_args<_Pattern>;
> > +#endif
> >      };
> >
> >      inline constexpr _Split split;
> > @@ -4074,7 +4109,9 @@ namespace views::__adaptor
> >           return common_view{std::forward<_Range>(__r)};
> >       }
> >
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_call_op = true;
> > +#endif
> >      };
> >
> >      inline constexpr _Common common;
> > @@ -4207,7 +4244,9 @@ namespace views::__adaptor
> >           return reverse_view{std::forward<_Range>(__r)};
> >       }
> >
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_call_op = true;
> > +#endif
> >      };
> >
> >      inline constexpr _Reverse reverse;
> > @@ -4598,7 +4637,9 @@ namespace views::__adaptor
> >           return elements_view<all_t<_Range>, 
> > _Nm>{std::forward<_Range>(__r)};
> >         }
> >
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >       static constexpr bool _S_has_simple_call_op = true;
> > +#endif
> >        };
> >
> >      template<size_t _Nm>
> > @@ -6061,7 +6102,9 @@ namespace views::__adaptor
> >
> >       using __adaptor::_RangeAdaptor<_AdjacentTransform>::operator();
> >       static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >       static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >        };
> >
> >      template<size_t _Nm>
> > @@ -6617,7 +6660,9 @@ namespace views::__adaptor
> >
> >        using __adaptor::_RangeAdaptor<_Chunk>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >      };
> >
> >      inline constexpr _Chunk chunk;
> > @@ -6992,7 +7037,9 @@ namespace views::__adaptor
> >
> >        using __adaptor::_RangeAdaptor<_Slide>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >      };
> >
> >      inline constexpr _Slide slide;
> > @@ -7187,7 +7234,9 @@ namespace views::__adaptor
> >
> >        using __adaptor::_RangeAdaptor<_ChunkBy>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >      };
> >
> >      inline constexpr _ChunkBy chunk_by;
> > @@ -7715,9 +7764,11 @@ namespace views::__adaptor
> >
> >        using _RangeAdaptor<_JoinWith>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        template<typename _Pattern>
> >       static constexpr bool _S_has_simple_extra_args
> >         = _LazySplit::_S_has_simple_extra_args<_Pattern>;
> > +#endif
> >      };
> >
> >      inline constexpr _JoinWith join_with;
> > @@ -8333,7 +8384,9 @@ namespace views::__adaptor
> >
> >        using __adaptor::_RangeAdaptor<_Stride>::operator();
> >        static constexpr int _S_arity = 2;
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >        static constexpr bool _S_has_simple_extra_args = true;
> > +#endif
> >      };
> >
> >      inline constexpr _Stride stride;
> > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc 
> > b/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc
> > index 53c81be7f02..eaa8454b318 100644
> > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc
> > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc
> > @@ -31,6 +31,7 @@ namespace views = std::ranges::views;
> >  void
> >  test01()
> >  {
> > +#ifdef _GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING
> >    // Verify adaptors are deemed to have simple extra arguments when 
> > appropriate.
> >    using views::__adaptor::__adaptor_has_simple_extra_args;
> >    using std::identity;
> > @@ -78,6 +79,7 @@ test01()
> >    static_assert(!__closure_has_simple_call_op<decltype(a12a | a00)>);
> >    static_assert(!__closure_has_simple_call_op<decltype(a00 | a12a)>);
> >  #endif
> > +#endif
> >  }
> >
> >  void
> > @@ -135,7 +137,7 @@ test03()
> >  void
> >  test04()
> >  {
> > -#if __STDC_HOSTED__
> > +#if defined(_GLIBCXX_RANGES_SIMPLIFY_ADAPTOR_FORWARDING) && __STDC_HOSTED__
> >    // Non-trivially-copyable extra arguments make a closure not simple.
> >    using F = std::function<bool(bool)>;
> >    static_assert(!std::is_trivially_copyable_v<F>);
> > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc 
> > b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
> > index dfc91fb5e1f..934d2f65dcf 100644
> > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
> > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
> > @@ -191,8 +191,10 @@ test09()
> >  #if __cpp_lib_ranges >= 202207L
> >    // P2494R2 Relaxing range adaptors to allow for move only types
> >    static_assert( requires { transform(x, move_only{}); } );
> > +  static_assert( requires { x | transform(move_only{}); } ); // PR 
> > libstdc++/118413
> >  #else
> >    static_assert( ! requires { transform(x, move_only{}); } );
> > +  static_assert( ! requires { x | transform(move_only{}); } );
> >  #endif
> >  }
> >
> > --
> > 2.48.1.91.g5f8f7081f7
> >
> >
>

Reply via email to