diff mbox series

[committed] libstdc++: Fix ranges::copy_backward for a single memcpyable element [PR117121]

Message ID 20241013183600.1649098-1-jwakely@redhat.com
State New
Headers show
Series [committed] libstdc++: Fix ranges::copy_backward for a single memcpyable element [PR117121] | expand

Commit Message

Jonathan Wakely Oct. 13, 2024, 6:35 p.m. UTC
Tested x86_64-linux. Pushed to trunk.

-- >8 --

The result iterator needs to be decremented before writing to it.

Improve the PR 108846 tests for all of std::copy, std::copy_n,
std::copy_backward, and the std::ranges versions.

libstdc++-v3/ChangeLog:

	PR libstdc++/117121
	* include/bits/ranges_algobase.h (copy_backward): Decrement
	output iterator before assigning one element through it.
	* testsuite/25_algorithms/copy/108846.cc: Ensure the algorithm's
	effects are correct for a single memcpyable element.
	* testsuite/25_algorithms/copy_backward/108846.cc: Likewise.
	* testsuite/25_algorithms/copy_n/108846.cc: Likewise.
---
 libstdc++-v3/include/bits/ranges_algobase.h       |  5 +++--
 .../testsuite/25_algorithms/copy/108846.cc        | 15 +++++++++++++++
 .../25_algorithms/copy_backward/108846.cc         | 15 +++++++++++++++
 .../testsuite/25_algorithms/copy_n/108846.cc      | 15 +++++++++++++++
 4 files changed, 48 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index 40c628b3818..3c8d46198c5 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -418,12 +418,13 @@  namespace ranges
 		{
 		  using _ValueTypeI = iter_value_t<_Iter>;
 		  auto __num = __last - __first;
+		  __result -= __num;
 		  if (__num > 1) [[likely]]
-		    __builtin_memmove(__result - __num, __first,
+		    __builtin_memmove(__result, __first,
 				      sizeof(_ValueTypeI) * __num);
 		  else if (__num == 1)
 		    ranges::__assign_one<_IsMove>(__first, __result);
-		  return {__first + __num, __result - __num};
+		  return {__first + __num, __result};
 		}
 	    }
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/108846.cc b/libstdc++-v3/testsuite/25_algorithms/copy/108846.cc
index e3b722c068a..a283e6fcd9f 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy/108846.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy/108846.cc
@@ -25,10 +25,15 @@  test_pr108846()
     B *src = &dsrc;
     // If this is optimized to memmove it will overwrite tail padding.
     std::copy(src, src+1, dst);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy(src, src+1, dst);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }
 
@@ -52,10 +57,15 @@  test_non_const_copy_assign()
     B2 *src = &dsrc;
     // Ensure the not-taken trivial copy path works for this type.
     std::copy(src, src+1, dst);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy(src, src+1, dst);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }
 
@@ -81,10 +91,15 @@  test_non_const_copy_assign_trivial()
     B3 *src = &dsrc;
     // If this is optimized to memmove it will overwrite tail padding.
     std::copy(src, src+1, dst);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy(src, src+1, dst);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_backward/108846.cc b/libstdc++-v3/testsuite/25_algorithms/copy_backward/108846.cc
index 206748d92d3..855ee3e182f 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy_backward/108846.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_backward/108846.cc
@@ -25,10 +25,15 @@  test_pr108846()
     B *src = &dsrc;
     // If this is optimized to memmove it will overwrite tail padding.
     std::copy_backward(src, src+1, dst+1);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy_backward(src, src+1, dst+1);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }
 
@@ -52,10 +57,15 @@  test_non_const_copy_assign()
     B2 *src = &dsrc;
     // Ensure the not-taken trivial copy path works for this type.
     std::copy_backward(src, src+1, dst+1);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy_backward(src, src+1, dst+1);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }
 
@@ -81,10 +91,15 @@  test_non_const_copy_assign_trivial()
     B3 *src = &dsrc;
     // If this is optimized to memmove it will overwrite tail padding.
     std::copy_backward(src, src+1, dst+1);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy_backward(src, src+1, dst+1);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/108846.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/108846.cc
index 50deb5dd051..d46fb9006e2 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy_n/108846.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/108846.cc
@@ -25,10 +25,15 @@  test_pr108846()
     B *src = &dsrc;
     // If this is optimized to memmove it will overwrite tail padding.
     std::copy_n(src, 1, dst);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy_n(src, 1, dst);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }
 
@@ -52,10 +57,15 @@  test_non_const_copy_assign()
     B2 *src = &dsrc;
     // Ensure the not-taken trivial copy path works for this type.
     std::copy_n(src, 1, dst);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy_n(src, 1, dst);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }
 
@@ -79,10 +89,15 @@  test_non_const_copy_assign_trivial()
     B3 *src = &dsrc;
     // If this is optimized to memmove it will overwrite tail padding.
     std::copy_n(src, 1, dst);
+    // Check tail padding is unchanged:
     VERIFY(ddst.x == 3);
+    // Check B subobject was copied:
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #if __cpp_lib_ranges >= 201911L
+    ddst.i = ddst.j = 99;
     std::ranges::copy_n(src, 1, dst);
     VERIFY(ddst.x == 3);
+    VERIFY(ddst.i == 4 && ddst.j == 5);
 #endif
 }