Skip to content

Commit c0df1c8

Browse files
committed
remove drain-on-drop behavior from vec::DrainFilter and add #[must_use]
1 parent fa8762b commit c0df1c8

File tree

6 files changed

+32
-131
lines changed

6 files changed

+32
-131
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -753,20 +753,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
753753
return;
754754
}
755755

756-
errors.drain_filter(|error| {
756+
errors.retain(|error| {
757757
let Error::Invalid(
758758
provided_idx,
759759
expected_idx,
760760
Compatibility::Incompatible(Some(e)),
761-
) = error else { return false };
761+
) = error else { return true };
762762
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
763763
let trace =
764764
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
765765
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
766766
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
767-
return true;
767+
return false;
768768
}
769-
false
769+
true
770770
});
771771

772772
// We're done if we found errors, but we already emitted them.

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,11 +1170,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
11701170
};
11711171

11721172
let mut deduped: SsoHashSet<_> = Default::default();
1173-
result.obligations.drain_filter(|projected_obligation| {
1173+
result.obligations.retain(|projected_obligation| {
11741174
if !deduped.insert(projected_obligation.clone()) {
1175-
return true;
1175+
return false;
11761176
}
1177-
false
1177+
true
11781178
});
11791179

11801180
if use_cache {

library/alloc/src/vec/drain_filter.rs

Lines changed: 15 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::alloc::{Allocator, Global};
2-
use core::mem::{ManuallyDrop, SizedTypeProperties};
32
use core::ptr;
43
use core::slice;
54

@@ -20,6 +19,7 @@ use super::Vec;
2019
/// ```
2120
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
2221
#[derive(Debug)]
22+
#[must_use = "iterators are lazy and do nothing unless consumed"]
2323
pub struct DrainFilter<
2424
'a,
2525
T,
@@ -55,59 +55,6 @@ where
5555
pub fn allocator(&self) -> &A {
5656
self.vec.allocator()
5757
}
58-
59-
/// Keep unyielded elements in the source `Vec`.
60-
///
61-
/// # Examples
62-
///
63-
/// ```
64-
/// #![feature(drain_filter)]
65-
/// #![feature(drain_keep_rest)]
66-
///
67-
/// let mut vec = vec!['a', 'b', 'c'];
68-
/// let mut drain = vec.drain_filter(|_| true);
69-
///
70-
/// assert_eq!(drain.next().unwrap(), 'a');
71-
///
72-
/// // This call keeps 'b' and 'c' in the vec.
73-
/// drain.keep_rest();
74-
///
75-
/// // If we wouldn't call `keep_rest()`,
76-
/// // `vec` would be empty.
77-
/// assert_eq!(vec, ['b', 'c']);
78-
/// ```
79-
#[unstable(feature = "drain_keep_rest", issue = "101122")]
80-
pub fn keep_rest(self) {
81-
// At this moment layout looks like this:
82-
//
83-
// _____________________/-- old_len
84-
// / \
85-
// [kept] [yielded] [tail]
86-
// \_______/ ^-- idx
87-
// \-- del
88-
//
89-
// Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
90-
//
91-
// 1. Move [tail] after [kept]
92-
// 2. Update length of the original vec to `old_len - del`
93-
// a. In case of ZST, this is the only thing we want to do
94-
// 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
95-
let mut this = ManuallyDrop::new(self);
96-
97-
unsafe {
98-
// ZSTs have no identity, so we don't need to move them around.
99-
if !T::IS_ZST && this.idx < this.old_len && this.del > 0 {
100-
let ptr = this.vec.as_mut_ptr();
101-
let src = ptr.add(this.idx);
102-
let dst = src.sub(this.del);
103-
let tail_len = this.old_len - this.idx;
104-
src.copy_to(dst, tail_len);
105-
}
106-
107-
let new_len = this.old_len - this.del;
108-
this.vec.set_len(new_len);
109-
}
110-
}
11158
}
11259

11360
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
@@ -154,44 +101,21 @@ where
154101
F: FnMut(&mut T) -> bool,
155102
{
156103
fn drop(&mut self) {
157-
struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
158-
where
159-
F: FnMut(&mut T) -> bool,
160-
{
161-
drain: &'b mut DrainFilter<'a, T, F, A>,
162-
}
163-
164-
impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
165-
where
166-
F: FnMut(&mut T) -> bool,
167-
{
168-
fn drop(&mut self) {
169-
unsafe {
170-
if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
171-
// This is a pretty messed up state, and there isn't really an
172-
// obviously right thing to do. We don't want to keep trying
173-
// to execute `pred`, so we just backshift all the unprocessed
174-
// elements and tell the vec that they still exist. The backshift
175-
// is required to prevent a double-drop of the last successfully
176-
// drained item prior to a panic in the predicate.
177-
let ptr = self.drain.vec.as_mut_ptr();
178-
let src = ptr.add(self.drain.idx);
179-
let dst = src.sub(self.drain.del);
180-
let tail_len = self.drain.old_len - self.drain.idx;
181-
src.copy_to(dst, tail_len);
182-
}
183-
self.drain.vec.set_len(self.drain.old_len - self.drain.del);
184-
}
104+
unsafe {
105+
if self.idx < self.old_len && self.del > 0 {
106+
// This is a pretty messed up state, and there isn't really an
107+
// obviously right thing to do. We don't want to keep trying
108+
// to execute `pred`, so we just backshift all the unprocessed
109+
// elements and tell the vec that they still exist. The backshift
110+
// is required to prevent a double-drop of the last successfully
111+
// drained item prior to a panic in the predicate.
112+
let ptr = self.vec.as_mut_ptr();
113+
let src = ptr.add(self.idx);
114+
let dst = src.sub(self.del);
115+
let tail_len = self.old_len - self.idx;
116+
src.copy_to(dst, tail_len);
185117
}
186-
}
187-
188-
let backshift = BackshiftOnDrop { drain: self };
189-
190-
// Attempt to consume any remaining elements if the filter predicate
191-
// has not yet panicked. We'll backshift any remaining elements
192-
// whether we've already panicked or if the consumption here panics.
193-
if !backshift.drain.panic_flag {
194-
backshift.drain.for_each(drop);
118+
self.vec.set_len(self.old_len - self.del);
195119
}
196120
}
197121
}

library/alloc/src/vec/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2892,6 +2892,12 @@ impl<T, A: Allocator> Vec<T, A> {
28922892
/// If the closure returns false, the element will remain in the vector and will not be yielded
28932893
/// by the iterator.
28942894
///
2895+
/// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating
2896+
/// or the iteration short-circuits, then the remaining elements will be retained.
2897+
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
2898+
///
2899+
/// [`retain`]: Vec::retain
2900+
///
28952901
/// Using this method is equivalent to the following code:
28962902
///
28972903
/// ```

library/alloc/tests/vec.rs

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,36 +1608,7 @@ fn drain_filter_unconsumed() {
16081608
let mut vec = vec![1, 2, 3, 4];
16091609
let drain = vec.drain_filter(|&mut x| x % 2 != 0);
16101610
drop(drain);
1611-
assert_eq!(vec, [2, 4]);
1612-
}
1613-
1614-
#[test]
1615-
fn test_drain_filter_keep_rest() {
1616-
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
1617-
let mut drain = v.drain_filter(|&mut x| x % 2 == 0);
1618-
assert_eq!(drain.next(), Some(0));
1619-
assert_eq!(drain.next(), Some(2));
1620-
1621-
drain.keep_rest();
1622-
assert_eq!(v, &[1, 3, 4, 5, 6]);
1623-
}
1624-
1625-
#[test]
1626-
fn test_drain_filter_keep_rest_all() {
1627-
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
1628-
v.drain_filter(|_| true).keep_rest();
1629-
assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]);
1630-
}
1631-
1632-
#[test]
1633-
fn test_drain_filter_keep_rest_none() {
1634-
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
1635-
let mut drain = v.drain_filter(|_| true);
1636-
1637-
drain.by_ref().for_each(drop);
1638-
1639-
drain.keep_rest();
1640-
assert_eq!(v, &[]);
1611+
assert_eq!(vec, [1, 2, 3, 4]);
16411612
}
16421613

16431614
#[test]

src/librustdoc/clean/inline.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,13 @@ pub(crate) fn try_inline_glob(
158158
.filter_map(|child| child.res.opt_def_id())
159159
.collect();
160160
let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));
161-
items.drain_filter(|item| {
161+
items.retain(|item| {
162162
if let Some(name) = item.name {
163163
// If an item with the same type and name already exists,
164164
// it takes priority over the inlined stuff.
165-
!inlined_names.insert((item.type_(), name))
165+
inlined_names.insert((item.type_(), name))
166166
} else {
167-
false
167+
true
168168
}
169169
});
170170
Some(items)

0 commit comments

Comments
 (0)