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.
This commit is contained in:
parent
2ef62aa1a3
commit
27f6b376e8
4 changed files with 48 additions and 2 deletions
|
@ -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};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue