From 23980573e218f83cd81cfb950c8ad1a133492ba8 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 11 May 2025 21:42:59 +0300 Subject: [PATCH 1/8] Use `_Verify_ranges_do_not_overlap` in more places --- stl/inc/algorithm | 24 ++++++++++ tests/std/test.lst | 1 + .../tests/GH_005472_do_not_overlap/env.lst | 4 ++ .../tests/GH_005472_do_not_overlap/test.cpp | 46 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 tests/std/tests/GH_005472_do_not_overlap/env.lst create mode 100644 tests/std/tests/GH_005472_do_not_overlap/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 6d7e76ed4af..7be8c76a97f 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1790,6 +1790,7 @@ namespace ranges { _EXPORT_STD template _CONSTEXPR20 _OutIt copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy each satisfying _Pred _STD _Adl_verify_range(_First, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_unverified(_Dest); @@ -1858,6 +1859,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + for (; _First != _Last; ++_First) { if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { *_Output = *_First; @@ -4452,6 +4455,7 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Oldval, const _Ty& _Newval) { // copy replacing each matching _Oldval with _Newval _STD _Adl_verify_range(_First, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_n(_Dest, _STD _Idl_distance<_InIt>(_UFirst, _ULast)); @@ -4534,6 +4538,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty1*>); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + for (; _First != _Last; ++_First, (void) ++_Output) { if constexpr (_Can_vectorize_replace_copy<_Out, iter_value_t<_It>, _Ty2>) { *_Output = _STD invoke(_Proj, *_First) == _Oldval ? _Newval : *_First; @@ -4558,6 +4564,7 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, const _Ty& _Val) { // copy replacing each satisfying _Pred with _Val _STD _Adl_verify_range(_First, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_n(_Dest, _STD _Idl_distance<_InIt>(_UFirst, _ULast)); @@ -4607,6 +4614,8 @@ namespace ranges { auto _ULast = _RANGES _Unwrap_sent<_It>(_STD move(_Last)); const auto _Count = _RANGES _Idl_distance<_It>(_UFirst, _ULast); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + auto _UResult = _Replace_copy_if_unchecked(_STD move(_UFirst), _STD move(_ULast), _STD _Get_unwrapped_n(_STD move(_Output), _Count), _STD _Pass_fn(_Pred), _Newval, _STD _Pass_fn(_Proj)); @@ -4821,6 +4830,7 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt remove_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Val) { // copy omitting each matching _Val _STD _Adl_verify_range(_First, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_unverified(_Dest); @@ -4877,6 +4887,7 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy omitting each element satisfying _Pred _STD _Adl_verify_range(_First, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_unverified(_Dest); @@ -5076,6 +5087,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty*>); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + #if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Vector_alg_in_find_is_safe<_It, _Ty> && _Output_iterator_for_vector_alg_is_safe<_Out, _It>() && sized_sentinel_for<_Se, _It> && is_same_v<_Pj, identity>) { @@ -5161,6 +5174,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + for (; _First != _Last; ++_First) { if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { *_Output = *_First; @@ -5339,6 +5354,7 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy compressing pairs that match _STD _Adl_verify_range(_First, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); @@ -5492,6 +5508,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); _STL_INTERNAL_STATIC_ASSERT(_Can_reread_or_store<_It, _Out>); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + if (_First == _Last) { return {_STD move(_First), _STD move(_Output)}; } @@ -5615,6 +5633,7 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) { // copy reversing elements in [_First, _Last) _STD _Adl_verify_range(_First, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); const auto _UFirst = _STD _Get_unwrapped(_First); auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_n(_Dest, _STD _Idl_distance<_BidIt>(_UFirst, _ULast)); @@ -5706,6 +5725,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>); _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + #if _USE_STD_VECTOR_ALGORITHMS if constexpr (contiguous_iterator<_It> && contiguous_iterator<_Out>) { using _Elem = remove_reference_t>; @@ -5851,6 +5872,7 @@ _CONSTEXPR20 _OutIt rotate_copy(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last, _OutIt // copy rotating [_First, _Last) _STD _Adl_verify_range(_First, _Mid); _STD _Adl_verify_range(_Mid, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); const auto _UFirst = _STD _Get_unwrapped(_First); const auto _UMid = _STD _Get_unwrapped(_Mid); const auto _ULast = _STD _Get_unwrapped(_Last); @@ -5917,6 +5939,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>); _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + auto _UResult1 = _RANGES _Copy_unchecked(_Mid, _STD move(_Last), _STD move(_Output)); auto _UResult2 = _RANGES _Copy_unchecked(_STD move(_First), _STD move(_Mid), _STD move(_UResult1.out)); return {_STD move(_UResult1.in), _STD move(_UResult2.out)}; diff --git a/tests/std/test.lst b/tests/std/test.lst index 32e116d37d3..87f84f36107 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -263,6 +263,7 @@ tests\GH_005276_system_error_heap_use_after_free tests\GH_005315_destructor_tombstones tests\GH_005402_string_with_volatile_range tests\GH_005421_vector_algorithms_integer_class_type_iterator +tests\GH_005472_do_not_overlap tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function diff --git a/tests/std/tests/GH_005472_do_not_overlap/env.lst b/tests/std/tests/GH_005472_do_not_overlap/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_005472_do_not_overlap/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_005472_do_not_overlap/test.cpp b/tests/std/tests/GH_005472_do_not_overlap/test.cpp new file mode 100644 index 00000000000..fd2b3b95f36 --- /dev/null +++ b/tests/std/tests/GH_005472_do_not_overlap/test.cpp @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// env.lst defines _MSVC_STL_HARDENING to 1. + +#include + +#include + +using namespace std; + +int arr[3] = {}; + +int main(int argc, char* argv[]) { +#if _ITERATOR_DEBUG_LEVEL == 2 + std_testing::death_test_executive exec; + + exec.add_death_tests({ + +[] { swap_ranges(arr, arr + 2, arr + 1); }, + +[] { copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }); }, + +[] { reverse_copy(arr, arr + 2, arr + 1); }, + +[] { replace_copy(arr, arr + 2, arr + 1, 1, 2); }, + +[] { replace_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }, 2); }, + +[] { rotate_copy(arr, arr + 1, arr + 2, arr + 1); }, + +[] { remove_copy(arr, arr + 2, arr + 1, 1); }, + +[] { remove_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }); }, + +[] { unique_copy(arr, arr + 2, arr + 1); }, +#if _HAS_CXX20 + +[] { ranges::copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }); }, + +[] { ranges::reverse_copy(arr, arr + 2, arr + 1); }, + +[] { ranges::replace_copy(arr, arr + 2, arr + 1, 1, 2); }, + +[] { ranges::replace_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }, 2); }, + +[] { ranges::rotate_copy(arr, arr + 1, arr + 2, arr + 1); }, + +[] { ranges::remove_copy(arr, arr + 2, arr + 1, 1); }, + +[] { ranges::remove_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }); }, + +[] { ranges::unique_copy(arr, arr + 2, arr + 1); }, +#endif // _HAS_CXX20 + }); + + return exec.run(argc, argv); +#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 / _ITERATOR_DEBUG_LEVEL != 2 vvv + (void) argc; + (void) argv; + return 0; // This test is only for iterator debug mode +#endif // ^^^ _ITERATOR_DEBUG_LEVEL != 2 ^^^ +} From 4b5e9aa9631b3f08fe6e9cb254bb88a823f542b3 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 11 May 2025 21:57:41 +0300 Subject: [PATCH 2/8] -copypasta and you can see where I copied the death test from --- tests/std/tests/GH_005472_do_not_overlap/test.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/std/tests/GH_005472_do_not_overlap/test.cpp b/tests/std/tests/GH_005472_do_not_overlap/test.cpp index fd2b3b95f36..6af009d2ab6 100644 --- a/tests/std/tests/GH_005472_do_not_overlap/test.cpp +++ b/tests/std/tests/GH_005472_do_not_overlap/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// env.lst defines _MSVC_STL_HARDENING to 1. - #include #include From 573785e6e2e2947000dc1779110f42500ff77565 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 11 May 2025 22:28:44 +0300 Subject: [PATCH 3/8] remove the check from copycats --- stl/inc/algorithm | 12 ------------ tests/std/tests/GH_005472_do_not_overlap/test.cpp | 8 -------- 2 files changed, 20 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 7be8c76a97f..15a55fd2518 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1790,7 +1790,6 @@ namespace ranges { _EXPORT_STD template _CONSTEXPR20 _OutIt copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy each satisfying _Pred _STD _Adl_verify_range(_First, _Last); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_unverified(_Dest); @@ -1859,8 +1858,6 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); - for (; _First != _Last; ++_First) { if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { *_Output = *_First; @@ -4830,7 +4827,6 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt remove_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Val) { // copy omitting each matching _Val _STD _Adl_verify_range(_First, _Last); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_unverified(_Dest); @@ -4887,7 +4883,6 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy omitting each element satisfying _Pred _STD _Adl_verify_range(_First, _Last); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_unverified(_Dest); @@ -5087,8 +5082,6 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty*>); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); - #if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Vector_alg_in_find_is_safe<_It, _Ty> && _Output_iterator_for_vector_alg_is_safe<_Out, _It>() && sized_sentinel_for<_Se, _It> && is_same_v<_Pj, identity>) { @@ -5174,8 +5167,6 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); - for (; _First != _Last; ++_First) { if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { *_Output = *_First; @@ -5354,7 +5345,6 @@ _EXPORT_STD template _CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy compressing pairs that match _STD _Adl_verify_range(_First, _Last); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Dest); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); @@ -5508,8 +5498,6 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); _STL_INTERNAL_STATIC_ASSERT(_Can_reread_or_store<_It, _Out>); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); - if (_First == _Last) { return {_STD move(_First), _STD move(_Output)}; } diff --git a/tests/std/tests/GH_005472_do_not_overlap/test.cpp b/tests/std/tests/GH_005472_do_not_overlap/test.cpp index 6af009d2ab6..18f134c2103 100644 --- a/tests/std/tests/GH_005472_do_not_overlap/test.cpp +++ b/tests/std/tests/GH_005472_do_not_overlap/test.cpp @@ -15,23 +15,15 @@ int main(int argc, char* argv[]) { exec.add_death_tests({ +[] { swap_ranges(arr, arr + 2, arr + 1); }, - +[] { copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }); }, +[] { reverse_copy(arr, arr + 2, arr + 1); }, +[] { replace_copy(arr, arr + 2, arr + 1, 1, 2); }, +[] { replace_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }, 2); }, +[] { rotate_copy(arr, arr + 1, arr + 2, arr + 1); }, - +[] { remove_copy(arr, arr + 2, arr + 1, 1); }, - +[] { remove_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }); }, - +[] { unique_copy(arr, arr + 2, arr + 1); }, #if _HAS_CXX20 - +[] { ranges::copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }); }, +[] { ranges::reverse_copy(arr, arr + 2, arr + 1); }, +[] { ranges::replace_copy(arr, arr + 2, arr + 1, 1, 2); }, +[] { ranges::replace_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }, 2); }, +[] { ranges::rotate_copy(arr, arr + 1, arr + 2, arr + 1); }, - +[] { ranges::remove_copy(arr, arr + 2, arr + 1, 1); }, - +[] { ranges::remove_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }); }, - +[] { ranges::unique_copy(arr, arr + 2, arr + 1); }, #endif // _HAS_CXX20 }); From b8f30a5107e373d579b10632fad11095aadb0965 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 11 May 2025 22:51:47 +0300 Subject: [PATCH 4/8] Don't use moved out iterator --- stl/inc/algorithm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 15a55fd2518..e6d2b4fe90d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -4607,12 +4607,11 @@ namespace ranges { _STATIC_CALL_OPERATOR constexpr replace_copy_if_result<_It, _Out> operator()( _It _First, _Se _Last, _Out _Output, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) _CONST_CALL_OPERATOR { _STD _Adl_verify_range(_First, _Last); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); auto _UFirst = _RANGES _Unwrap_iter<_Se>(_STD move(_First)); auto _ULast = _RANGES _Unwrap_sent<_It>(_STD move(_Last)); const auto _Count = _RANGES _Idl_distance<_It>(_UFirst, _ULast); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); - auto _UResult = _Replace_copy_if_unchecked(_STD move(_UFirst), _STD move(_ULast), _STD _Get_unwrapped_n(_STD move(_Output), _Count), _STD _Pass_fn(_Pred), _Newval, _STD _Pass_fn(_Proj)); From 02087ff5be75f6b9417d0faa125d8f8e5fc38bd2 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 15 May 2025 20:16:03 +0300 Subject: [PATCH 5/8] Common baby! --- stl/inc/algorithm | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index e6d2b4fe90d..fe005e72d51 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -4501,7 +4501,7 @@ namespace ranges { auto _UFirst = _RANGES _Unwrap_iter<_Se>(_STD move(_First)); auto _ULast = _RANGES _Unwrap_sent<_It>(_STD move(_Last)); const auto _Count = _RANGES _Idl_distance<_It>(_UFirst, _ULast); - auto _UResult = _Replace_copy_unchecked(_STD move(_UFirst), _STD move(_ULast), + auto _UResult = _Replace_copy_common(_STD move(_UFirst), _STD move(_ULast), _STD _Get_unwrapped_n(_STD move(_Output), _Count), _Oldval, _Newval, _STD _Pass_fn(_Proj)); _STD _Seek_wrapped(_First, _STD move(_UResult.in)); @@ -4516,8 +4516,8 @@ namespace ranges { _Out _Output, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) _CONST_CALL_OPERATOR { const auto _Count = _RANGES _Idl_distance(_Range); auto _First = _RANGES begin(_Range); - auto _UResult = _Replace_copy_unchecked(_RANGES _Unwrap_range_iter<_Rng>(_STD move(_First)), _Uend(_Range), - _STD _Get_unwrapped_n(_STD move(_Output), _Count), _Oldval, _Newval, _STD _Pass_fn(_Proj)); + auto _UResult = _Replace_copy_common(_RANGES _Unwrap_range_iter<_Rng>(_STD move(_First)), _Uend(_Range), + _STD _Get_unwrapped_n(_STD move(_Output), _Count), _Oldval, _Newval, _STD _Pass_fn(_Proj)); _STD _Seek_wrapped(_First, _STD move(_UResult.in)); _STD _Seek_wrapped(_Output, _STD move(_UResult.out)); @@ -4526,7 +4526,7 @@ namespace ranges { private: template - _NODISCARD static constexpr replace_copy_result<_It, _Out> _Replace_copy_unchecked( + _NODISCARD static constexpr replace_copy_result<_It, _Out> _Replace_copy_common( _It _First, const _Se _Last, _Out _Output, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj) { // copy [_First, _Last) to _Output while replacing projected _Oldval with _Newval _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); @@ -4607,12 +4607,11 @@ namespace ranges { _STATIC_CALL_OPERATOR constexpr replace_copy_if_result<_It, _Out> operator()( _It _First, _Se _Last, _Out _Output, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) _CONST_CALL_OPERATOR { _STD _Adl_verify_range(_First, _Last); - _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); auto _UFirst = _RANGES _Unwrap_iter<_Se>(_STD move(_First)); auto _ULast = _RANGES _Unwrap_sent<_It>(_STD move(_Last)); const auto _Count = _RANGES _Idl_distance<_It>(_UFirst, _ULast); - auto _UResult = _Replace_copy_if_unchecked(_STD move(_UFirst), _STD move(_ULast), + auto _UResult = _Replace_copy_if_common(_STD move(_UFirst), _STD move(_ULast), _STD _Get_unwrapped_n(_STD move(_Output), _Count), _STD _Pass_fn(_Pred), _Newval, _STD _Pass_fn(_Proj)); _STD _Seek_wrapped(_First, _STD move(_UResult.in)); @@ -4627,9 +4626,8 @@ namespace ranges { _Rng&& _Range, _Out _Output, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) _CONST_CALL_OPERATOR { const auto _Count = _RANGES _Idl_distance(_Range); auto _First = _RANGES begin(_Range); - auto _UResult = _Replace_copy_if_unchecked(_RANGES _Unwrap_range_iter<_Rng>(_STD move(_First)), - _Uend(_Range), _STD _Get_unwrapped_n(_STD move(_Output), _Count), _STD _Pass_fn(_Pred), _Newval, - _STD _Pass_fn(_Proj)); + auto _UResult = _Replace_copy_if_common(_RANGES _Unwrap_range_iter<_Rng>(_STD move(_First)), _Uend(_Range), + _STD _Get_unwrapped_n(_STD move(_Output), _Count), _STD _Pass_fn(_Pred), _Newval, _STD _Pass_fn(_Proj)); _STD _Seek_wrapped(_First, _STD move(_UResult.in)); _STD _Seek_wrapped(_Output, _STD move(_UResult.out)); @@ -4638,7 +4636,7 @@ namespace ranges { private: template - _NODISCARD static constexpr replace_copy_if_result<_It, _Out> _Replace_copy_if_unchecked( + _NODISCARD static constexpr replace_copy_if_result<_It, _Out> _Replace_copy_if_common( _It _First, const _Se _Last, _Out _Output, _Pr _Pred, const _Ty& _Newval, _Pj _Proj) { // copy [_First, _Last) to _Output while replacing _Oldval with _Newval if projected _Oldval fulfills _Pred _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); @@ -4647,6 +4645,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + _STD _Verify_ranges_do_not_overlap(_First, _Last, _Output); + for (; _First != _Last; ++_First, (void) ++_Output) { if constexpr (_Can_vectorize_replace_copy<_Out, iter_value_t<_It>, _Ty>) { *_Output = _STD invoke(_Pred, _STD invoke(_Proj, *_First)) ? _Newval : *_First; @@ -5895,7 +5895,7 @@ namespace ranges { auto _UFirst = _RANGES _Unwrap_iter<_Se>(_STD move(_First)); auto _ULast = _RANGES _Unwrap_sent<_It>(_STD move(_Last)); const auto _Count = _RANGES _Idl_distance<_It>(_UFirst, _ULast); - auto _UResult = _Rotate_copy_unchecked(_STD move(_UFirst), _RANGES _Unwrap_iter<_Se>(_STD move(_Mid)), + auto _UResult = _Rotate_copy_common(_STD move(_UFirst), _RANGES _Unwrap_iter<_Se>(_STD move(_Mid)), _STD move(_ULast), _STD _Get_unwrapped_n(_STD move(_Output), _Count)); _STD _Seek_wrapped(_First, _STD move(_UResult.in)); @@ -5910,15 +5910,15 @@ namespace ranges { _STD _Adl_verify_range(_RANGES begin(_Range), _Mid); _STD _Adl_verify_range(_Mid, _RANGES end(_Range)); const auto _Count = _RANGES _Idl_distance(_Range); - auto _UResult = _Rotate_copy_unchecked(_Ubegin(_Range), _RANGES _Unwrap_range_iter<_Rng>(_STD move(_Mid)), - _Uend(_Range), _STD _Get_unwrapped_n(_STD move(_Output), _Count)); + auto _UResult = _Rotate_copy_common(_Ubegin(_Range), _RANGES _Unwrap_range_iter<_Rng>(_STD move(_Mid)), + _Uend(_Range), _STD _Get_unwrapped_n(_STD move(_Output), _Count)); _STD _Seek_wrapped(_Output, _STD move(_UResult.out)); return {_RANGES _Rewrap_iterator(_Range, _STD move(_UResult.in)), _STD move(_Output)}; } private: template - _NODISCARD static constexpr rotate_copy_result<_It, _Out> _Rotate_copy_unchecked( + _NODISCARD static constexpr rotate_copy_result<_It, _Out> _Rotate_copy_common( _It _First, _It _Mid, _Se _Last, _Out _Output) { // Copy the content of [_Mid, _Last) and [_First, _Mid) to _Output _STL_INTERNAL_STATIC_ASSERT(forward_iterator<_It>); From 4103c0292d30421256ed261f65ba1fb7a5e1dcea Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 15 May 2025 20:40:16 +0300 Subject: [PATCH 6/8] we know types --- tests/std/tests/GH_005472_do_not_overlap/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/GH_005472_do_not_overlap/test.cpp b/tests/std/tests/GH_005472_do_not_overlap/test.cpp index 18f134c2103..66af8464a09 100644 --- a/tests/std/tests/GH_005472_do_not_overlap/test.cpp +++ b/tests/std/tests/GH_005472_do_not_overlap/test.cpp @@ -17,12 +17,12 @@ int main(int argc, char* argv[]) { +[] { swap_ranges(arr, arr + 2, arr + 1); }, +[] { reverse_copy(arr, arr + 2, arr + 1); }, +[] { replace_copy(arr, arr + 2, arr + 1, 1, 2); }, - +[] { replace_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }, 2); }, + +[] { replace_copy_if(arr, arr + 2, arr + 1, [](int) { return false; }, 2); }, +[] { rotate_copy(arr, arr + 1, arr + 2, arr + 1); }, #if _HAS_CXX20 +[] { ranges::reverse_copy(arr, arr + 2, arr + 1); }, +[] { ranges::replace_copy(arr, arr + 2, arr + 1, 1, 2); }, - +[] { ranges::replace_copy_if(arr, arr + 2, arr + 1, [](auto) { return false; }, 2); }, + +[] { ranges::replace_copy_if(arr, arr + 2, arr + 1, [](int) { return false; }, 2); }, +[] { ranges::rotate_copy(arr, arr + 1, arr + 2, arr + 1); }, #endif // _HAS_CXX20 }); From 965485b353be2d0278be0fa55b6cd8bdb9c4b5d2 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 15 May 2025 20:44:51 +0300 Subject: [PATCH 7/8] range of overloads! --- tests/std/tests/GH_005472_do_not_overlap/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/GH_005472_do_not_overlap/test.cpp b/tests/std/tests/GH_005472_do_not_overlap/test.cpp index 66af8464a09..80025c59240 100644 --- a/tests/std/tests/GH_005472_do_not_overlap/test.cpp +++ b/tests/std/tests/GH_005472_do_not_overlap/test.cpp @@ -21,9 +21,13 @@ int main(int argc, char* argv[]) { +[] { rotate_copy(arr, arr + 1, arr + 2, arr + 1); }, #if _HAS_CXX20 +[] { ranges::reverse_copy(arr, arr + 2, arr + 1); }, + +[] { ranges::reverse_copy(ranges::subrange(arr, arr + 2), arr + 1); }, +[] { ranges::replace_copy(arr, arr + 2, arr + 1, 1, 2); }, + +[] { ranges::replace_copy(ranges::subrange(arr, arr + 2), arr + 1, 1, 2); }, +[] { ranges::replace_copy_if(arr, arr + 2, arr + 1, [](int) { return false; }, 2); }, + +[] { ranges::replace_copy_if(ranges::subrange(arr, arr + 2), arr + 1, [](int) { return false; }, 2); }, +[] { ranges::rotate_copy(arr, arr + 1, arr + 2, arr + 1); }, + +[] { ranges::rotate_copy(ranges::subrange(arr, arr + 2), arr + 1, arr + 1); }, #endif // _HAS_CXX20 }); From efcaa5153ce68c8a96ad6905d0b51eaef07180f2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 16 May 2025 03:47:02 -0700 Subject: [PATCH 8/8] `` for `ranges::subrange`. --- tests/std/tests/GH_005472_do_not_overlap/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/GH_005472_do_not_overlap/test.cpp b/tests/std/tests/GH_005472_do_not_overlap/test.cpp index 80025c59240..ff246460dda 100644 --- a/tests/std/tests/GH_005472_do_not_overlap/test.cpp +++ b/tests/std/tests/GH_005472_do_not_overlap/test.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include