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