Skip to content

Commit eaabc75

Browse files
committed
[libc++] Fix several double-moves in the code base
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 c4bf949 commit eaabc75

File tree

8 files changed

+314
-150
lines changed

8 files changed

+314
-150
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: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,78 +65,84 @@ 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
{
69+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6)));
7070
std::same_as<bool> decltype(auto) ret = std::ranges::contains(whole.begin(), whole.end(), 3);
7171
assert(ret);
7272
}
7373
{
74+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6)));
7475
std::same_as<bool> decltype(auto) ret = std::ranges::contains(whole, 3);
7576
assert(ret);
7677
}
7778
}
7879

7980
{ // check that a range with a single element works
8081
ValueT a[] = {32};
81-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1)));
8282
{
83-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
83+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1)));
84+
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
8485
assert(ret);
8586
}
8687
{
87-
bool ret = std::ranges::contains(whole, 32);
88+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1)));
89+
bool ret = std::ranges::contains(whole, 32);
8890
assert(ret);
8991
}
9092
}
9193

9294
{ // check that an empty range works
9395
std::array<ValueT, 0> a = {};
94-
auto whole = std::ranges::subrange(Iter(a.data()), Sent(Iter(a.data())));
9596
{
96-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 1);
97+
auto whole = std::ranges::subrange(Iter(a.data()), Sent(Iter(a.data())));
98+
bool ret = std::ranges::contains(whole.begin(), whole.end(), 1);
9799
assert(!ret);
98100
}
99101
{
100-
bool ret = std::ranges::contains(whole, 1);
102+
auto whole = std::ranges::subrange(Iter(a.data()), Sent(Iter(a.data())));
103+
bool ret = std::ranges::contains(whole, 1);
101104
assert(!ret);
102105
}
103106
}
104107

105108
{ // check that the first element matches
106109
ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100};
107-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10)));
108110
{
109-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
111+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10)));
112+
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
110113
assert(ret);
111114
}
112115
{
113-
bool ret = std::ranges::contains(whole, 32);
116+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10)));
117+
bool ret = std::ranges::contains(whole, 32);
114118
assert(ret);
115119
}
116120
}
117121

118122
{ // check that the last element matches
119123
ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32};
120-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9)));
121124
{
122-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
125+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9)));
126+
bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
123127
assert(ret);
124128
}
125129
{
126-
bool ret = std::ranges::contains(whole, 32);
130+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9)));
131+
bool ret = std::ranges::contains(whole, 32);
127132
assert(ret);
128133
}
129134
}
130135

131136
{ // no match
132137
ValueT a[] = {13, 1, 21, 4, 5};
133-
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5)));
134138
{
135-
bool ret = std::ranges::contains(whole.begin(), whole.end(), 10);
139+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5)));
140+
bool ret = std::ranges::contains(whole.begin(), whole.end(), 10);
136141
assert(!ret);
137142
}
138143
{
139-
bool ret = std::ranges::contains(whole, 10);
144+
auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5)));
145+
bool ret = std::ranges::contains(whole, 10);
140146
assert(!ret);
141147
}
142148
}

0 commit comments

Comments
 (0)