diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2024-10-13 19:14:04 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2024-10-13 19:27:23 +0100 |
commit | 27f6b376e8e196c7c85c8b47436cd2f2993768da (patch) | |
tree | 70ad8c01b4fb74bd8e886d5c94f25548d130ec25 | |
parent | 2ef62aa1a3fb7ece56b0f7a8ba79ef7eac0991ec (diff) | |
download | gcc-27f6b376e8e196c7c85c8b47436cd2f2993768da.zip gcc-27f6b376e8e196c7c85c8b47436cd2f2993768da.tar.gz gcc-27f6b376e8e196c7c85c8b47436cd2f2993768da.tar.bz2 |
libstdc++: Fix ranges::copy_backward for a single memcpyable element [PR117121]
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.
4 files changed, 48 insertions, 2 deletions
diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h index 40c628b..3c8d461 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 e3b722c..a283e6f 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 206748d..855ee3e 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 50deb5d..d46fb90 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 } |