diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 6d7e76ed4af..fe005e72d51 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -4452,6 +4452,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)); @@ -4500,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)); @@ -4515,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)); @@ -4525,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>); @@ -4534,6 +4535,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 +4561,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,7 +4611,7 @@ namespace ranges { 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)); @@ -4622,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)); @@ -4633,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>); @@ -4642,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; @@ -5615,6 +5620,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 +5712,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 +5859,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); @@ -5886,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)); @@ -5901,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>); @@ -5917,6 +5926,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..ff246460dda --- /dev/null +++ b/tests/std/tests/GH_005472_do_not_overlap/test.cpp @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#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); }, + +[] { reverse_copy(arr, arr + 2, arr + 1); }, + +[] { replace_copy(arr, arr + 2, arr + 1, 1, 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::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 + }); + + 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 ^^^ +}