about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-05-19 21:50:45 +0000
committerbors <bors@rust-lang.org>2021-05-19 21:50:45 +0000
commitdf70463ea5d701489d6f53dc780a2c16294d6143 (patch)
treea01a26a59164d97425941e490f60d849436c9d17
parentf94942d8421dc4b1da86d07069571ddb43127235 (diff)
parent7cb4e5180f16ad83d39da9555561360add5fb22d (diff)
downloadrust-df70463ea5d701489d6f53dc780a2c16294d6143.tar.gz
rust-df70463ea5d701489d6f53dc780a2c16294d6143.zip
Auto merge of #85340 - the8472:no-inplaceiterable-on-peekable, r=yaahc
remove InPlaceIterable marker from Peekable due to unsoundness

The unsoundness is not in Peekable per se, it rather is due to the
interaction between Peekable being able to hold an extra item
and vec::IntoIter's clone implementation shortening the allocation.

An alternative solution would be to change IntoIter's clone implementation
to keep enough spare capacity available.

fixes #85322
-rw-r--r--library/alloc/benches/vec.rs1
-rw-r--r--library/alloc/tests/vec.rs13
-rw-r--r--library/core/src/iter/adapters/peekable.rs5
3 files changed, 13 insertions, 6 deletions
diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs
index 48709e89823..c9bdcaa78f3 100644
--- a/library/alloc/benches/vec.rs
+++ b/library/alloc/benches/vec.rs
@@ -468,7 +468,6 @@ fn bench_in_place_recycle(b: &mut Bencher) {
                 .enumerate()
                 .map(|(idx, e)| idx.wrapping_add(e))
                 .fuse()
-                .peekable()
                 .collect::<Vec<usize>>(),
         );
     });
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 4dcc5d30deb..ad69234403b 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1002,7 +1002,6 @@ fn test_from_iter_specialization_with_iterator_adapters() {
         .zip(std::iter::repeat(1usize))
         .map(|(a, b)| a + b)
         .map_while(Option::Some)
-        .peekable()
         .skip(1)
         .map(|e| if e != usize::MAX { Ok(std::num::NonZeroUsize::new(e)) } else { Err(()) });
     assert_in_place_trait(&iter);
@@ -1095,6 +1094,18 @@ fn test_from_iter_specialization_panic_during_drop_leaks() {
     }
 }
 
+// regression test for issue #85322. Peekable previously implemented InPlaceIterable,
+// but due to an interaction with IntoIter's current Clone implementation it failed to uphold
+// the contract.
+#[test]
+fn test_collect_after_iterator_clone() {
+    let v = vec![0; 5];
+    let mut i = v.into_iter().map(|i| i + 1).peekable();
+    i.peek();
+    let v = i.clone().collect::<Vec<_>>();
+    assert_eq!(v, [1, 1, 1, 1, 1]);
+    assert!(v.len() <= v.capacity());
+}
 #[test]
 fn test_cow_from() {
     let borrowed: &[_] = &["borrowed", "(slice)"];
diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs
index 8ee7d0955c6..69bd2996efe 100644
--- a/library/core/src/iter/adapters/peekable.rs
+++ b/library/core/src/iter/adapters/peekable.rs
@@ -1,4 +1,4 @@
-use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
+use crate::iter::{adapters::SourceIter, FusedIterator, TrustedLen};
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator with a `peek()` that returns an optional reference to the next
@@ -356,6 +356,3 @@ where
         unsafe { SourceIter::as_inner(&mut self.iter) }
     }
 }
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}