diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 2a778e1470d..ecc103fc98c 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2174,8 +2174,10 @@ impl InPlaceDrop { impl Drop for InPlaceDrop { #[inline] fn drop(&mut self) { - unsafe { - ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len())); + if mem::needs_drop::() { + unsafe { + ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len())); + } } } } @@ -2206,26 +2208,14 @@ impl SpecFrom> for Vec { } } -fn write_in_place(src_end: *const T) -> impl FnMut(*mut T, T) -> Result<*mut T, !> { - move |mut dst, item| { - unsafe { - // the InPlaceIterable contract cannot be verified precisely here since - // try_fold has an exclusive reference to the source pointer - // all we can do is check if it's still in range - debug_assert!(dst as *const _ <= src_end, "InPlaceIterable contract violation"); - ptr::write(dst, item); - dst = dst.add(1); - } - Ok(dst) - } -} - fn write_in_place_with_drop( src_end: *const T, ) -> impl FnMut(InPlaceDrop, T) -> Result, !> { move |mut sink, item| { unsafe { - // same caveat as above + // the InPlaceIterable contract cannot be verified precisely here since + // try_fold has an exclusive reference to the source pointer + // all we can do is check if it's still in range debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation"); ptr::write(sink.dst, item); sink.dst = sink.dst.add(1); @@ -2263,23 +2253,16 @@ where (inner.buf.as_ptr(), inner.buf.as_ptr() as *mut T, inner.end as *const T, inner.cap) }; - // use try-fold + // use try-fold since // - it vectorizes better for some iterator adapters // - unlike most internal iteration methods methods it only takes a &mut self - // - lets us thread the write pointer through its innards and get it back in the end - let dst = if mem::needs_drop::() { - // special-case drop handling since it forces us to lug that extra field around which - // can inhibit optimizations - let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf }; - let sink = iterator - .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end)) - .unwrap(); - // iteration succeeded, don't drop head - let sink = mem::ManuallyDrop::new(sink); - sink.dst - } else { - iterator.try_fold::<_, _, Result<_, !>>(dst_buf, write_in_place(dst_end)).unwrap() - }; + // - it lets us thread the write pointer through its innards and get it back in the end + let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf }; + let sink = iterator + .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end)) + .unwrap(); + // iteration succeeded, don't drop head + let dst = mem::ManuallyDrop::new(sink).dst; let src = unsafe { iterator.as_inner().as_into_iter() }; // check if SourceIter and InPlaceIterable contracts were upheld.