Skip to content
Merged
1 change: 1 addition & 0 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -3049,6 +3049,7 @@ _CONSTEXPR20 _FwdIt2 swap_ranges(const _FwdIt1 _First1, const _FwdIt1 _Last1, _F
const auto _UFirst1 = _Get_unwrapped(_First1);
const auto _ULast1 = _Get_unwrapped(_Last1);
const auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_FwdIt1>(_UFirst1, _ULast1));
_Verify_ranges_do_not_overlap(_UFirst1, _ULast1, _UFirst2);
_Seek_wrapped(_First2, _Swap_ranges_unchecked(_UFirst1, _ULast1, _UFirst2));
return _First2;
}
Expand Down
11 changes: 11 additions & 0 deletions stl/inc/vector
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,17 @@ public:
pointer& _Myfirst = _My_data._Myfirst;
pointer& _Mylast = _My_data._Mylast;

#if _ITERATOR_DEBUG_LEVEL == 2
#if _HAS_CXX20
if (!_STD is_constant_evaluated())
#endif // _HAS_CXX20
{
const auto _Valptr = _STD addressof(_Val);
_STL_VERIFY(!(_Unfancy(_Myfirst) <= _Valptr && _Valptr < _Unfancy(_Mylast)),
"assignment value cannot be a reference into the container");
}
#endif // _ITERATOR_DEBUG_LEVEL == 2

constexpr bool _Nothrow_construct =
conjunction_v<is_nothrow_copy_constructible<_Ty>, _Uses_default_construct<_Alloc, _Ty*, const _Ty&>>;

Expand Down
32 changes: 32 additions & 0 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -3669,6 +3669,38 @@ struct _Iter_copy_cat<_SourceIt, _DestIt, false> : _False_trivial_cat {};
template <class _SourceIt, class _DestIt>
struct _Iter_copy_cat<move_iterator<_SourceIt>, _DestIt, false> : _Iter_move_cat<_SourceIt, _DestIt> {};

template <class _Iter1, class _Sent1, class _Iter2>
_CONSTEXPR20 void _Verify_ranges_do_not_overlap(const _Iter1& _First1, const _Sent1& _Last1, const _Iter2& _First2) {
#if _ITERATOR_DEBUG_LEVEL == 2
if constexpr (_Iterators_are_contiguous<_Iter1, _Iter2>
#ifdef __cpp_lib_concepts
&& sized_sentinel_for<_Sent1, _Iter1>
#endif // __cpp_lib_concepts
) {
#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
return;
}
#endif // _HAS_CXX20

const auto _Offset = _Last1 - _First1;
const auto _Ptr1Offset = _Offset * sizeof(*_To_address(_First1));
const auto _Ptr2Offset = _Offset * sizeof(*_To_address(_First2));
// This cast to `cv char*` allows us to compare pointers to distinct types,
// in case one range provides storage for the other.
const auto _PtrFirst1 = reinterpret_cast<const volatile char*>(_To_address(_First1));
const auto _PtrLast1 = _PtrFirst1 + _Ptr1Offset;
const auto _PtrFirst2 = reinterpret_cast<const volatile char*>(_To_address(_First2));
const auto _PtrLast2 = _PtrFirst2 + _Ptr2Offset;
_STL_VERIFY(_PtrLast1 <= _PtrFirst2 || _PtrLast2 <= _PtrFirst1, "ranges should not overlap each other");
}
#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 / _ITERATOR_DEBUG_LEVEL != 2 vvv
(void) _First1;
(void) _Last1;
(void) _First2;
#endif // _ITERATOR_DEBUG_LEVEL != 2 ^^^
}

template <class _CtgIt, class _OutCtgIt>
_OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) {
auto _FirstPtr = _To_address(_First);
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ tests\Dev11_1140665_unique_ptr_array_conversions
tests\Dev11_1150223_shared_mutex
tests\Dev11_1158803_regex_thread_safety
tests\Dev11_1180290_filesystem_error_code
tests\GH_000177_forbidden_aliasing
tests\GH_000342_filebuf_close
tests\GH_000431_copy_move_family
tests\GH_000431_equal_family
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/GH_000177_forbidden_aliasing/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
49 changes: 49 additions & 0 deletions tests/std/tests/GH_000177_forbidden_aliasing/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <vector>

#include <test_death.hpp>
using namespace std;

void test_case_swap_ranges_overlap_1() {
int arr[8] = {10, 20, 30, 40, 50, 60, 70, 80};
swap_ranges(arr + 1, arr + 4, arr + 3);
}

void test_case_swap_ranges_overlap_2() {
int arr[8] = {10, 20, 30, 40, 50, 60, 70, 80};
swap_ranges(arr + 4, arr + 7, arr + 2);
}

void test_case_vector_assign_front() {
vector<int> vec{11, 22, 33};
vec.assign(5, vec.front());
}

void test_case_vector_assign_mid() {
vector<int> vec{11, 22, 33};
vec.assign(5, vec[1]);
}

void test_case_vector_assign_back() {
vector<int> vec{11, 22, 33};
vec.assign(5, vec.back());
}

int main(int argc, char* argv[]) {
std_testing::death_test_executive exec;

#if _ITERATOR_DEBUG_LEVEL == 2
exec.add_death_tests({
test_case_swap_ranges_overlap_1,
test_case_swap_ranges_overlap_2,
test_case_vector_assign_front,
test_case_vector_assign_mid,
test_case_vector_assign_back,
});
#endif // _ITERATOR_DEBUG_LEVEL == 2

return exec.run(argc, argv);
}
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,21 @@ constexpr void test_permutations() {
}
}

constexpr void test_adjacent_swap_ranges() {
int arr[8] = {10, 20, 30, 40, 50, 60, 70, 80};
const int original[8] = {10, 20, 30, 40, 50, 60, 70, 80};
const int modified[8] = {10, 50, 60, 70, 20, 30, 40, 80};

int* const first = arr + 1;
int* const mid = arr + 4;
int* const last = arr + 7;

swap_ranges(first, mid, mid);
assert(equal(begin(arr), end(arr), begin(modified), end(modified)));
swap_ranges(mid, last, first);
assert(equal(begin(arr), end(arr), begin(original), end(original)));
}

constexpr bool test() {
test_copy<input_pointer<const int>, output_pointer<int>>();
test_copy<const int*, int*>();
Expand Down Expand Up @@ -603,6 +618,7 @@ constexpr bool test() {
test_make_heap_and_sort_heap();
test_pop_heap_and_push_heap();
test_permutations();
test_adjacent_swap_ranges();

return true;
}
Expand Down
23 changes: 19 additions & 4 deletions tests/std/tests/VSO_0180466_algorithm_overhauls/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,25 @@ namespace test_lexicographical_compare {

namespace test_std_copy {
void test() {
array<int, 4> target{{42, 43, 44, 45}};
array<int, 2> input{{1729, 1730}};
copy(input.begin(), input.end(), target.begin() + 1);
assert((target == array<int, 4>{{42, 1729, 1730, 45}}));
{
array<int, 4> target{{42, 43, 44, 45}};
array<int, 2> input{{1729, 1730}};
copy(input.begin(), input.end(), target.begin() + 1);
assert((target == array<int, 4>{{42, 1729, 1730, 45}}));
Comment thread
StephanTLavavej marked this conversation as resolved.
}
{
// GH-177: copy different-element-types ranges.
const array<short, 2> input{10, 20};
array<int, 2> target;
copy(input.begin(), input.end(), target.begin());
assert((target == array<int, 2>{{10, 20}}));
}
{
// GH-177: copy partial-overlapping ranges.
array<int, 4> input{10, 20, 30, 40};
copy(input.begin() + 1, input.end(), input.begin());
assert((input == array<int, 4>{{20, 30, 40, 40}}));
}
}
} // namespace test_std_copy

Expand Down