]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix ranges::copy_backward for a single memcpyable element [PR117121]
authorJonathan Wakely <jwakely@redhat.com>
Sun, 13 Oct 2024 18:14:04 +0000 (19:14 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Sun, 13 Oct 2024 18:27:23 +0000 (19:27 +0100)
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
libstdc++-v3/testsuite/25_algorithms/copy/108846.cc
libstdc++-v3/testsuite/25_algorithms/copy_backward/108846.cc
libstdc++-v3/testsuite/25_algorithms/copy_n/108846.cc

index 40c628b38182df34b3f287311b9f444834b08c0a..3c8d46198c5dd30528e312dbf6d5472ed256dd30 100644 (file)
@@ -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};
                }
            }
 
index e3b722c068abaeb1ab79332af20f84127074bf85..a283e6fcd9fb10f52baea88c1980f8d427f910a0 100644 (file)
@@ -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
 }
 
index 206748d92d33b666aa9dfd0914228daf4c9a670a..855ee3e182f7348c10154440ea328e3649954e46 100644 (file)
@@ -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
 }
 
index 50deb5dd051041181b85329893a41d29816e48db..d46fb9006e2d52bfe0bbc5b0528d820710f22f33 100644 (file)
@@ -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
 }