Skip to content

Commit f73050e

Browse files
authored
[libc++] Fix several double-moves in the code base (#104616)
This patch hardens the "test iterators" we use to test algorithms by ensuring that they don't get double-moved. As a result of this hardening, the tests started reporting multiple failures where we would double-move iterators, which are being fixed in this patch. In particular: - Fixed a double-move in pstl.partition - Add coverage for begin()/end() in subrange tests - Fix tests for ranges::ends_with and ranges::contains, which were incorrectly calling begin() twice on the same subrange containing non-copyable input iterators. Fixes #100709
1 parent 31e55d4 commit f73050e

File tree

20 files changed

+526
-337
lines changed

20 files changed

+526
-337
lines changed

libcxx/include/__algorithm/partition.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator, _Forw
2929
__partition_impl(_ForwardIterator __first, _Sentinel __last, _Predicate __pred, forward_iterator_tag) {
3030
while (true) {
3131
if (__first == __last)
32-
return std::make_pair(std::move(__first), std::move(__first));
32+
return std::make_pair(__first, __first);
3333
if (!__pred(*__first))
3434
break;
3535
++__first;

libcxx/include/__pstl/backends/default.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ struct __is_partitioned<__default_backend_tag, _ExecutionPolicy> {
163163
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
164164
operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {
165165
using _FindIfNot = __dispatch<__find_if_not, __current_configuration, _ExecutionPolicy>;
166-
auto __maybe_first = _FindIfNot()(__policy, std::move(__first), std::move(__last), __pred);
166+
auto __maybe_first = _FindIfNot()(__policy, std::move(__first), __last, __pred);
167167
if (__maybe_first == nullopt)
168168
return nullopt;
169169

libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ test()
9898

9999
int main(int, char**)
100100
{
101+
test<forward_iterator<int*> >();
101102
test<bidirectional_iterator<int*> >();
102103
test<random_access_iterator<int*> >();
103104
test<int*>();
104105

105106
#if TEST_STD_VER >= 20
107+
static_assert(test<forward_iterator<int*>>());
106108
static_assert(test<bidirectional_iterator<int*>>());
107109
static_assert(test<random_access_iterator<int*>>());
108110
static_assert(test<int*>());

libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,78 +65,78 @@ constexpr void test_iterators() {
6565
using ValueT = std::iter_value_t<Iter>;
6666
{ // simple tests
6767
ValueT a[] = {1, 2, 3, 4, 5, 6};
68-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6)));
6968
{
70-
std::same_as<bool> decltype(auto) ret = std::ranges::contains(whole.begin(), whole.end(), 3);
69+
std::same_as<bool> decltype(auto) ret = std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3);
7170
assert(ret);
7271
}
7372
{
73+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6)));
7474
std::same_as<bool> decltype(auto) ret = std::ranges::contains(whole, 3);
7575
assert(ret);
7676
}
7777
}
7878

7979
{ // check that a range with a single element works
8080
ValueT a[] = {32};
81-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1)));
8281
{
83-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
82+
bool ret = std::ranges::contains(Iter(a), Sent(Iter(a + 1)), 32);
8483
assert(ret);
8584
}
8685
{
87-
bool ret = std::ranges::contains(whole, 32);
86+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1)));
87+
bool ret = std::ranges::contains(whole, 32);
8888
assert(ret);
8989
}
9090
}
9191

9292
{ // check that an empty range works
9393
std::array<ValueT, 0> a = {};
94-
auto whole = std::ranges::subrange(Iter(a.data()), Sent(Iter(a.data())));
9594
{
96-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 1);
95+
bool ret = std::ranges::contains(Iter(a.data()), Sent(Iter(a.data())), 1);
9796
assert(!ret);
9897
}
9998
{
100-
bool ret = std::ranges::contains(whole, 1);
99+
auto whole = std::ranges::subrange(Iter(a.data()), Sent(Iter(a.data())));
100+
bool ret = std::ranges::contains(whole, 1);
101101
assert(!ret);
102102
}
103103
}
104104

105105
{ // check that the first element matches
106106
ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100};
107-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10)));
108107
{
109-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
108+
bool ret = std::ranges::contains(Iter(a), Sent(Iter(a + 10)), 32);
110109
assert(ret);
111110
}
112111
{
113-
bool ret = std::ranges::contains(whole, 32);
112+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10)));
113+
bool ret = std::ranges::contains(whole, 32);
114114
assert(ret);
115115
}
116116
}
117117

118118
{ // check that the last element matches
119119
ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32};
120-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9)));
121120
{
122-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
121+
bool ret = std::ranges::contains(Iter(a), Sent(Iter(a + 9)), 32);
123122
assert(ret);
124123
}
125124
{
126-
bool ret = std::ranges::contains(whole, 32);
125+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9)));
126+
bool ret = std::ranges::contains(whole, 32);
127127
assert(ret);
128128
}
129129
}
130130

131131
{ // no match
132132
ValueT a[] = {13, 1, 21, 4, 5};
133-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5)));
134133
{
135-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 10);
134+
bool ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10);
136135
assert(!ret);
137136
}
138137
{
139-
bool ret = std::ranges::contains(whole, 10);
138+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5)));
139+
bool ret = std::ranges::contains(whole, 10);
140140
assert(!ret);
141141
}
142142
}

0 commit comments

Comments
 (0)