aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2024-10-13 19:14:04 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2024-10-13 19:27:23 +0100
commit27f6b376e8e196c7c85c8b47436cd2f2993768da (patch)
tree70ad8c01b4fb74bd8e886d5c94f25548d130ec25
parent2ef62aa1a3fb7ece56b0f7a8ba79ef7eac0991ec (diff)
downloadgcc-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.
-rw-r--r--libstdc++-v3/include/bits/ranges_algobase.h5
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/copy/108846.cc15
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/copy_backward/108846.cc15
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/copy_n/108846.cc15
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
}