about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThe 8472 <git@infinite-source.de>2022-11-15 19:51:49 +0100
committerThe 8472 <git@infinite-source.de>2023-06-14 09:24:51 +0200
commitb7ce7edd87c984997137eb067df2a32d4d66470c (patch)
tree9536891d648676ce153ade1777bf7a24aa2b1499
parentb687e84aebe871f8dc76424ceee30379d3b3381f (diff)
downloadrust-b7ce7edd87c984997137eb067df2a32d4d66470c.tar.gz
rust-b7ce7edd87c984997137eb067df2a32d4d66470c.zip
remove drain-on-drop behavior from linked_list::DrainFilter and add #[must_use]
-rw-r--r--library/alloc/src/collections/linked_list.rs32
-rw-r--r--library/alloc/src/collections/linked_list/tests.rs12
2 files changed, 14 insertions, 30 deletions
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index 4cd34ac2fa7..2e00e286edc 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -1030,6 +1030,10 @@ impl<T, A: Allocator> LinkedList<T, A> {
     /// If the closure returns false, the element will remain in the list and will not be yielded
     /// by the iterator.
     ///
+    /// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating
+    /// or the iteration short-circuits, then the remaining elements will be retained.
+    /// Use `drain_filter().for_each(drop)` if you do not need the returned iterator.
+    ///
     /// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of
     /// whether you choose to keep or remove it.
     ///
@@ -1805,6 +1809,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
 
 /// An iterator produced by calling `drain_filter` on LinkedList.
 #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct DrainFilter<
     'a,
     T: 'a,
@@ -1850,33 +1855,6 @@ where
 }
 
 #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
-where
-    F: FnMut(&mut T) -> bool,
-{
-    fn drop(&mut self) {
-        struct DropGuard<'r, 'a, T, F, A: Allocator>(&'r mut DrainFilter<'a, T, F, A>)
-        where
-            F: FnMut(&mut T) -> bool;
-
-        impl<'r, 'a, T, F, A: Allocator> Drop for DropGuard<'r, 'a, T, F, A>
-        where
-            F: FnMut(&mut T) -> bool,
-        {
-            fn drop(&mut self) {
-                self.0.for_each(drop);
-            }
-        }
-
-        while let Some(item) = self.next() {
-            let guard = DropGuard(self);
-            drop(item);
-            mem::forget(guard);
-        }
-    }
-}
-
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
 impl<T: fmt::Debug, F> fmt::Debug for DrainFilter<'_, T, F>
 where
     F: FnMut(&mut T) -> bool,
diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs
index 6a0ea618362..7627b3e8bdc 100644
--- a/library/alloc/src/collections/linked_list/tests.rs
+++ b/library/alloc/src/collections/linked_list/tests.rs
@@ -1005,17 +1005,23 @@ fn drain_filter_drop_panic_leak() {
     q.push_front(d1.spawn(Panic::InDrop));
     q.push_front(d0.spawn(Panic::Never));
 
-    catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).unwrap_err();
+    catch_unwind(AssertUnwindSafe(|| q.drain_filter(|_| true).for_each(drop))).unwrap_err();
 
     assert_eq!(d0.dropped(), 1);
     assert_eq!(d1.dropped(), 1);
+    assert_eq!(d2.dropped(), 0);
+    assert_eq!(d3.dropped(), 0);
+    assert_eq!(d4.dropped(), 0);
+    assert_eq!(d5.dropped(), 0);
+    assert_eq!(d6.dropped(), 0);
+    assert_eq!(d7.dropped(), 0);
+    drop(q);
     assert_eq!(d2.dropped(), 1);
     assert_eq!(d3.dropped(), 1);
     assert_eq!(d4.dropped(), 1);
     assert_eq!(d5.dropped(), 1);
     assert_eq!(d6.dropped(), 1);
     assert_eq!(d7.dropped(), 1);
-    assert!(q.is_empty());
 }
 
 #[test]
@@ -1045,7 +1051,7 @@ fn drain_filter_pred_panic_leak() {
     q.push_front(D(0));
 
     catch_unwind(AssertUnwindSafe(|| {
-        drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }))
+        q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }).for_each(drop)
     }))
     .ok();