diff mbox series

[1/4] libstdc++: Fix use of is_nothrow_assignable_v in <bits/ranges_uninitialized.h>

Message ID 20200303163043.2182013-1-ppalka@redhat.com
State New
Headers show
Series [1/4] libstdc++: Fix use of is_nothrow_assignable_v in <bits/ranges_uninitialized.h> | expand

Commit Message

Patrick Palka March 3, 2020, 4:30 p.m. UTC
We are passing a value type as the first argument to is_nothrow_assignable_v,
but the result of that is always false.  Since this predicate is a part of the
condition that guards the corresponding optimizations for these algorithms, this
bug means these optimizations are never used.  We should be passing a reference
type to is_nothrow_assignable_v instead.

libstdc++-v3/ChangeLog:

	* include/bits/ranges_uninitialized.h
	(uninitialized_copy_fn::operator()): Pass a reference type as the first
	argument to is_nothrow_assignable_v.
	(uninitialized_copy_fn::operator()): Likewise.
	(uninitialized_move_fn::operator()): Likewise.  Return an in_out_result
	with the input iterator stripped of its move_iterator.
	(uninitialized_move_n_fn::operator()): Likewise.
	(uninitialized_fill_fn::operator()): Pass a reference type as the first
	argument to is_nothrow_assignable_v.
	(uninitialized_fill_n_fn::operator()): Likewise.
---
 .../include/bits/ranges_uninitialized.h       | 24 +++++++++++--------
 1 file changed, 14 insertions(+), 10 deletions(-)

Comments

Jonathan Wakely March 3, 2020, 9:35 p.m. UTC | #1
On 03/03/20 11:30 -0500, Patrick Palka wrote:
>We are passing a value type as the first argument to is_nothrow_assignable_v,
>but the result of that is always false.  Since this predicate is a part of the
>condition that guards the corresponding optimizations for these algorithms, this
>bug means these optimizations are never used.  We should be passing a reference
>type to is_nothrow_assignable_v instead.
>
>libstdc++-v3/ChangeLog:
>
>	* include/bits/ranges_uninitialized.h
>	(uninitialized_copy_fn::operator()): Pass a reference type as the first
>	argument to is_nothrow_assignable_v.
>	(uninitialized_copy_fn::operator()): Likewise.
>	(uninitialized_move_fn::operator()): Likewise.  Return an in_out_result
>	with the input iterator stripped of its move_iterator.
>	(uninitialized_move_n_fn::operator()): Likewise.
>	(uninitialized_fill_fn::operator()): Pass a reference type as the first
>	argument to is_nothrow_assignable_v.
>	(uninitialized_fill_n_fn::operator()): Likewise.

OK.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h b/libstdc++-v3/include/bits/ranges_uninitialized.h
index 01e1cad646c..f97a07a9b4a 100644
--- a/libstdc++-v3/include/bits/ranges_uninitialized.h
+++ b/libstdc++-v3/include/bits/ranges_uninitialized.h
@@ -269,7 +269,7 @@  namespace ranges
 	if constexpr (sized_sentinel_for<_ISent, _Iter>
 		      && sized_sentinel_for<_OSent, _Out>
 		      && is_trivial_v<_OutType>
-		      && is_nothrow_assignable_v<_OutType,
+		      && is_nothrow_assignable_v<_OutType&,
 						 iter_reference_t<_Iter>>)
 	  {
 	    auto __d1 = ranges::distance(__ifirst, __ilast);
@@ -316,7 +316,7 @@  namespace ranges
 	using _OutType = remove_reference_t<iter_reference_t<_Out>>;
 	if constexpr (sized_sentinel_for<_Sent, _Out>
 		      && is_trivial_v<_OutType>
-		      && is_nothrow_assignable_v<_OutType,
+		      && is_nothrow_assignable_v<_OutType&,
 						 iter_reference_t<_Iter>>)
 	  {
 	    auto __d = ranges::distance(__ofirst, __olast);
@@ -354,13 +354,15 @@  namespace ranges
 	if constexpr (sized_sentinel_for<_ISent, _Iter>
 		      && sized_sentinel_for<_OSent, _Out>
 		      && is_trivial_v<_OutType>
-		      && is_nothrow_assignable_v<_OutType,
+		      && is_nothrow_assignable_v<_OutType&,
 						 iter_rvalue_reference_t<_Iter>>)
 	  {
 	    auto __d1 = ranges::distance(__ifirst, __ilast);
 	    auto __d2 = ranges::distance(__ofirst, __olast);
-	    return ranges::copy_n(std::make_move_iterator(__ifirst),
-				  std::min(__d1, __d2), __ofirst);
+	    auto [__in, __out]
+	      = ranges::copy_n(std::make_move_iterator(__ifirst),
+			       std::min(__d1, __d2), __ofirst);
+	    return {std::move(__in).base(), __out};
 	  }
 	else
 	  {
@@ -404,12 +406,14 @@  namespace ranges
 	using _OutType = remove_reference_t<iter_reference_t<_Out>>;
 	if constexpr (sized_sentinel_for<_Sent, _Out>
 		      && is_trivial_v<_OutType>
-		      && is_nothrow_assignable_v<_OutType,
+		      && is_nothrow_assignable_v<_OutType&,
 						 iter_rvalue_reference_t<_Iter>>)
 	  {
 	    auto __d = ranges::distance(__ofirst, __olast);
-	    return ranges::copy_n(std::make_move_iterator(__ifirst),
-				  std::min(__n, __d), __ofirst);
+	    auto [__in, __out]
+	      = ranges::copy_n(std::make_move_iterator(__ifirst),
+			       std::min(__n, __d), __ofirst);
+	    return {std::move(__in).base(), __out};
 	  }
 	else
 	  {
@@ -436,7 +440,7 @@  namespace ranges
       {
 	using _ValueType = remove_reference_t<iter_reference_t<_Iter>>;
 	if constexpr (is_trivial_v<_ValueType>
-		      && is_nothrow_assignable_v<_ValueType, const _Tp&>)
+		      && is_nothrow_assignable_v<_ValueType&, const _Tp&>)
 	  return ranges::fill(__first, __last, __x);
 	else
 	  {
@@ -469,7 +473,7 @@  namespace ranges
       {
 	using _ValueType = remove_reference_t<iter_reference_t<_Iter>>;
 	if constexpr (is_trivial_v<_ValueType>
-		      && is_nothrow_assignable_v<_ValueType, const _Tp&>)
+		      && is_nothrow_assignable_v<_ValueType&, const _Tp&>)
 	  return ranges::fill_n(__first, __n, __x);
 	else
 	  {