about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThe8472 <git@infinite-source.de>2019-11-23 14:32:20 +0100
committerThe8472 <git@infinite-source.de>2020-09-03 20:59:17 +0200
commit00a32eb54f65c11cd2f4d10c2414dd633fab3c5b (patch)
treee8f0e7bb35e3c0cc52c5c1850a8dbebe750bf8a8
parent8c816b96dd549d24146f6c4be410fcf7526221d1 (diff)
downloadrust-00a32eb54f65c11cd2f4d10c2414dd633fab3c5b.tar.gz
rust-00a32eb54f65c11cd2f4d10c2414dd633fab3c5b.zip
fix some in-place-collect edge-cases
- it's an allocation optimization, so don't attempt to do it on ZSTs
- drop the tail of partially exhausted iters
-rw-r--r--library/alloc/src/vec.rs13
1 files changed, 13 insertions, 0 deletions
diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs
index fdc7738e733..1e7f95a25cc 100644
--- a/library/alloc/src/vec.rs
+++ b/library/alloc/src/vec.rs
@@ -2192,6 +2192,12 @@ fn from_into_iter_source<T, I>(mut iterator: I) -> Vec<T>
 where
     I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source = IntoIter<T>>,
 {
+    // This specialization only makes sense if we're juggling real allocations.
+    // Additionally some of the pointer arithmetic would panic on ZSTs.
+    if mem::size_of::<T>() == 0 {
+        return SpecFromNested::from_iter(iterator);
+    }
+
     let src_buf = iterator.as_inner().buf.as_ptr();
     let src_end = iterator.as_inner().end;
     let dst = src_buf;
@@ -2238,6 +2244,13 @@ where
     debug_assert_eq!(src_buf, src.buf.as_ptr());
     debug_assert!(dst as *const _ <= src.ptr, "InPlaceIterable contract violation");
 
+    if mem::needs_drop::<T>() {
+        // drop tail if iterator was only partially exhaused
+        unsafe {
+            ptr::drop_in_place(src.as_mut_slice());
+        }
+    }
+
     let vec = unsafe {
         let len = dst.offset_from(src_buf) as usize;
         Vec::from_raw_parts(src.buf.as_ptr(), len, src.cap)