From b5e834472fb95c719583f892425071ffc650bb40 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 31 Aug 2026 20:50:19 -0700 Subject: [PATCH] `alloc` crate: shrink undocumented `unsafe` blocks Reduce the scope of `unsafe` blocks that are not yet documented by moving safe operations out of the blocks, making it easier to add the missing documentation in the future. --- library/alloc/src/boxed/thin.rs | 98 ++++++++++--------- .../alloc/src/collections/binary_heap/mod.rs | 4 +- library/alloc/src/collections/btree/map.rs | 6 +- library/alloc/src/collections/btree/node.rs | 16 +-- library/alloc/src/collections/linked_list.rs | 56 +++++------ .../alloc/src/collections/vec_deque/mod.rs | 26 ++--- .../src/collections/vec_deque/spec_extend.rs | 4 +- .../alloc/src/collections/vec_deque/splice.rs | 4 +- library/alloc/src/rc.rs | 2 +- library/alloc/src/slice.rs | 8 +- library/alloc/src/str.rs | 4 +- library/alloc/src/sync.rs | 2 +- library/alloc/src/vec/in_place_collect.rs | 8 +- library/alloc/src/vec/mod.rs | 18 ++-- library/alloc/src/vec/spec_from_iter.rs | 2 +- 15 files changed, 133 insertions(+), 125 deletions(-) diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 98904aa500669..ef0d5a3d18aae 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -165,10 +165,10 @@ impl DerefMut for ThinBox { #[unstable(feature = "thin_box", issue = "92791")] impl Drop for ThinBox { fn drop(&mut self) { + let value = self.deref_mut(); + let value = value as *mut T; // ignore-tidy-undocumented-unsafe unsafe { - let value = self.deref_mut(); - let value = value as *mut T; self.with_header().drop::(value); } } @@ -240,34 +240,38 @@ impl WithHeader { alloc::handle_alloc_error(Layout::new::<()>()); }; - // ignore-tidy-undocumented-unsafe - unsafe { - // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so - // we use `layout.dangling()` for this case, which should have a valid - // alignment for both `T` and `H`. - let ptr = if layout.size() == 0 { - // Some paranoia checking, mostly so that the ThinBox tests are - // more able to catch issues. - debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST); - layout.dangling_ptr() - } else { - let ptr = alloc::alloc(layout); - if ptr.is_null() { - alloc::handle_alloc_error(layout); - } - // Safety: - // - The size is at least `aligned_header_size`. + // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so + // we use `layout.dangling()` for this case, which should have a valid + // alignment for both `T` and `H`. + let ptr = if layout.size() == 0 { + // Some paranoia checking, mostly so that the ThinBox tests are + // more able to catch issues. + debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST); + layout.dangling_ptr() + } else { + // ignore-tidy-undocumented-unsafe + let ptr = unsafe { alloc::alloc(layout) }; + if ptr.is_null() { + alloc::handle_alloc_error(layout); + } + // SAFETY: + // - The size is at least `aligned_header_size`. + unsafe { let ptr = ptr.add(value_offset) as *mut _; NonNull::new_unchecked(ptr) - }; + } + }; - let result = WithHeader(ptr, PhantomData); + let result = WithHeader(ptr, PhantomData); + + // ignore-tidy-undocumented-unsafe + unsafe { ptr::write(result.header(), header); ptr::write(result.value().cast(), value); - - result } + + result } /// Non-panicking version of `new`. @@ -278,35 +282,39 @@ impl WithHeader { return Err(core::alloc::AllocError); }; - // ignore-tidy-undocumented-unsafe - unsafe { - // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so - // we use `layout.dangling()` for this case, which should have a valid - // alignment for both `T` and `H`. - let ptr = if layout.size() == 0 { - // Some paranoia checking, mostly so that the ThinBox tests are - // more able to catch issues. - debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST); - layout.dangling_ptr() - } else { - let ptr = alloc::alloc(layout); - if ptr.is_null() { - return Err(core::alloc::AllocError); - } - - // Safety: - // - The size is at least `aligned_header_size`. + // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so + // we use `layout.dangling()` for this case, which should have a valid + // alignment for both `T` and `H`. + let ptr = if layout.size() == 0 { + // Some paranoia checking, mostly so that the ThinBox tests are + // more able to catch issues. + debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST); + layout.dangling_ptr() + } else { + // ignore-tidy-undocumented-unsafe + let ptr = unsafe { alloc::alloc(layout) }; + if ptr.is_null() { + return Err(core::alloc::AllocError); + } + + // SAFETY: + // - The size is at least `aligned_header_size`. + unsafe { let ptr = ptr.add(value_offset) as *mut _; NonNull::new_unchecked(ptr) - }; + } + }; + + let result = WithHeader(ptr, PhantomData); - let result = WithHeader(ptr, PhantomData); + // ignore-tidy-undocumented-unsafe + unsafe { ptr::write(result.header(), header); ptr::write(result.value().cast(), value); - - Ok(result) } + + Ok(result) } // `Dyn` is `?Sized` type like `[u32]`, and `T` is ZST type like `[u32; 0]`. diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 0fc83871c815f..f0e48dde5e951 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -1574,9 +1574,9 @@ impl<'a, T> Hole<'a, T> { unsafe fn move_to(&mut self, index: usize) { debug_assert!(index != self.pos); debug_assert!(index < self.data.len()); + let ptr = self.data.as_mut_ptr(); // ignore-tidy-undocumented-unsafe unsafe { - let ptr = self.data.as_mut_ptr(); let index_ptr: *const _ = ptr.add(index); let hole_ptr = ptr.add(self.pos); ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); @@ -1589,9 +1589,9 @@ impl Drop for Hole<'_, T> { #[inline] fn drop(&mut self) { // fill the hole again + let pos = self.pos; // ignore-tidy-undocumented-unsafe unsafe { - let pos = self.pos; ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1); } } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 2f60fd1f74d35..55ef4d59864e7 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -280,10 +280,10 @@ impl Clone for BTreeMap { // We can't destructure subtree directly // because BTreeMap implements Drop - // ignore-tidy-undocumented-unsafe - let (subroot, sublength) = unsafe { + let (subroot, sublength) = { let subtree = ManuallyDrop::new(subtree); - let root = ptr::read(&subtree.root); + // ignore-tidy-undocumented-unsafe + let root = unsafe { ptr::read(&subtree.root) }; let length = subtree.length; (root, length) }; diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index c97f7ac00474a..3859d857d0518 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -1875,11 +1875,11 @@ pub(super) mod marker { /// # Safety /// The slice has more than `idx` elements. unsafe fn slice_insert(slice: &mut [MaybeUninit], idx: usize, val: T) { + let len = slice.len(); + debug_assert!(len > idx); + let slice_ptr = slice.as_mut_ptr(); // ignore-tidy-undocumented-unsafe unsafe { - let len = slice.len(); - debug_assert!(len > idx); - let slice_ptr = slice.as_mut_ptr(); if len > idx + 1 { ptr::copy(slice_ptr.add(idx), slice_ptr.add(idx + 1), len - idx - 1); } @@ -1893,11 +1893,11 @@ unsafe fn slice_insert(slice: &mut [MaybeUninit], idx: usize, val: T) { /// # Safety /// The slice has more than `idx` elements. unsafe fn slice_remove(slice: &mut [MaybeUninit], idx: usize) -> T { + let len = slice.len(); + debug_assert!(idx < len); + let slice_ptr = slice.as_mut_ptr(); // ignore-tidy-undocumented-unsafe unsafe { - let len = slice.len(); - debug_assert!(idx < len); - let slice_ptr = slice.as_mut_ptr(); let ret = (*slice_ptr.add(idx)).assume_init_read(); ptr::copy(slice_ptr.add(idx + 1), slice_ptr.add(idx), len - idx - 1); ret @@ -1909,9 +1909,9 @@ unsafe fn slice_remove(slice: &mut [MaybeUninit], idx: usize) -> T { /// # Safety /// The slice has at least `distance` elements. unsafe fn slice_shl(slice: &mut [MaybeUninit], distance: usize) { + let slice_ptr = slice.as_mut_ptr(); // ignore-tidy-undocumented-unsafe unsafe { - let slice_ptr = slice.as_mut_ptr(); ptr::copy(slice_ptr.add(distance), slice_ptr, slice.len() - distance); } } @@ -1921,9 +1921,9 @@ unsafe fn slice_shl(slice: &mut [MaybeUninit], distance: usize) { /// # Safety /// The slice has at least `distance` elements. unsafe fn slice_shr(slice: &mut [MaybeUninit], distance: usize) { + let slice_ptr = slice.as_mut_ptr(); // ignore-tidy-undocumented-unsafe unsafe { - let slice_ptr = slice.as_mut_ptr(); ptr::copy(slice_ptr, slice_ptr.add(distance), slice.len() - distance); } } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 953cffc1c396d..2c1245524a0cf 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1679,20 +1679,20 @@ impl<'a, T> CursorMut<'a, T> { /// inserted at the start of the `LinkedList`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn splice_after(&mut self, list: LinkedList) { + let Some((splice_head, splice_tail, splice_len)) = list.detach_all_nodes() else { + return; + }; // ignore-tidy-undocumented-unsafe unsafe { - let Some((splice_head, splice_tail, splice_len)) = list.detach_all_nodes() else { - return; - }; let node_next = match self.current { None => self.list.head, Some(node) => node.as_ref().next, }; self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len); - if self.current.is_none() { - // The "ghost" non-element's index has changed. - self.index = self.list.len; - } + } + if self.current.is_none() { + // The "ghost" non-element's index has changed. + self.index = self.list.len; } } @@ -1702,19 +1702,19 @@ impl<'a, T> CursorMut<'a, T> { /// inserted at the end of the `LinkedList`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn splice_before(&mut self, list: LinkedList) { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; // ignore-tidy-undocumented-unsafe unsafe { - let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { - Some(parts) => parts, - _ => return, - }; let node_prev = match self.current { None => self.list.tail, Some(node) => node.as_ref().prev, }; self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len); - self.index += splice_len; } + self.index += splice_len; } } @@ -1725,19 +1725,19 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { /// inserted at the front of the `LinkedList`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn insert_after(&mut self, item: T) { + let spliced_node = + Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0; // ignore-tidy-undocumented-unsafe unsafe { - let spliced_node = - Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0; let node_next = match self.current { None => self.list.head, Some(node) => node.as_ref().next, }; self.list.splice_nodes(self.current, node_next, spliced_node, spliced_node, 1); - if self.current.is_none() { - // The "ghost" non-element's index has changed. - self.index = self.list.len; - } + } + if self.current.is_none() { + // The "ghost" non-element's index has changed. + self.index = self.list.len; } } @@ -1747,17 +1747,17 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { /// inserted at the end of the `LinkedList`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn insert_before(&mut self, item: T) { + let spliced_node = + Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0; // ignore-tidy-undocumented-unsafe unsafe { - let spliced_node = - Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0; let node_prev = match self.current { None => self.list.tail, Some(node) => node.as_ref().prev, }; self.list.splice_nodes(node_prev, self.current, spliced_node, spliced_node, 1); - self.index += 1; } + self.index += 1; } /// Removes the current element from the `LinkedList`. @@ -1799,14 +1799,14 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { unlinked_node.as_mut().prev = None; unlinked_node.as_mut().next = None; - Some(LinkedList { - head: Some(unlinked_node), - tail: Some(unlinked_node), - len: 1, - alloc: self.list.alloc.clone(), - marker: PhantomData, - }) } + Some(LinkedList { + head: Some(unlinked_node), + tail: Some(unlinked_node), + len: 1, + alloc: self.list.alloc.clone(), + marker: PhantomData, + }) } /// Splits the list into two after the current element. This will return a diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 08abf0e5c5a68..6494eaacfeeb4 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1455,6 +1455,12 @@ impl VecDeque { #[doc(alias = "retain_front")] #[stable(feature = "deque_extras", since = "1.16.0")] pub fn truncate(&mut self, len: usize) { + if len >= self.len { + return; + } + + let (front, back) = self.as_mut_slices(); + // SAFETY: // * Any slice passed to `drop_in_place` is valid; the second case has // `len <= front.len()` and returning on `len > self.len()` ensures @@ -1462,11 +1468,6 @@ impl VecDeque { // * The head of the VecDeque is moved before calling `drop_in_place`, // so no value is dropped twice if `drop_in_place` panics unsafe { - if len >= self.len { - return; - } - - let (front, back) = self.as_mut_slices(); if len > front.len() { let begin = len - front.len(); let drop_back = back.get_unchecked_mut(begin..) as *mut _; @@ -1508,14 +1509,15 @@ impl VecDeque { #[doc(alias = "truncate_front")] #[stable(feature = "vec_deque_truncate_front", since = "1.99.0")] pub fn retain_back(&mut self, len: usize) { + if len >= self.len { + // No action is taken + return; + } + + let (front, back) = self.as_mut_slices(); + // ignore-tidy-undocumented-unsafe unsafe { - if len >= self.len { - // No action is taken - return; - } - - let (front, back) = self.as_mut_slices(); if len > back.len() { // The 'back' slice remains unchanged. // front.len() + back.len() == self.len, so 'end' is non-negative @@ -2773,9 +2775,9 @@ impl VecDeque { } self.reserve(other.len); + let (left, right) = other.as_slices(); // ignore-tidy-undocumented-unsafe unsafe { - let (left, right) = other.as_slices(); self.copy_slice(self.to_wrapped_index(self.len), left); // no overflow, because self.capacity() >= old_cap + left.len() >= self.len + left.len() self.copy_slice(self.to_wrapped_index(self.len + left.len()), right); diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index fe39a0145d3a9..358f19d720ed6 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -86,8 +86,8 @@ impl SpecExtend> for Ve // ignore-tidy-undocumented-unsafe unsafe { self.copy_slice(self.to_wrapped_index(self.len), slice); - self.len += slice.len(); } + self.len += slice.len(); iterator.forget_remaining_elements_and_dealloc(); } } @@ -113,8 +113,8 @@ where // ignore-tidy-undocumented-unsafe unsafe { self.copy_slice(self.to_wrapped_index(self.len), slice); - self.len += slice.len(); } + self.len += slice.len(); } } diff --git a/library/alloc/src/collections/vec_deque/splice.rs b/library/alloc/src/collections/vec_deque/splice.rs index 4edd26c1e1e22..93e5a0b4addf0 100644 --- a/library/alloc/src/collections/vec_deque/splice.rs +++ b/library/alloc/src/collections/vec_deque/splice.rs @@ -64,10 +64,10 @@ impl Drop for Splice<'_, I, A> { // At this point draining is done and the only remaining tasks are splicing // and moving things into the final place. + let tail_len = self.drain.tail_len; // #elements behind the drain + // ignore-tidy-undocumented-unsafe unsafe { - let tail_len = self.drain.tail_len; // #elements behind the drain - if tail_len == 0 { self.drain.deque.as_mut().extend(self.replace_with.by_ref()); return; diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index b4822d98bb45a..6e549cec25f76 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2395,9 +2395,9 @@ impl Rc { #[cfg(not(no_global_oom_handling))] fn from_box_in(src: Box) -> Rc { + let value_size = size_of_val(&*src); // ignore-tidy-undocumented-unsafe unsafe { - let value_size = size_of_val(&*src); let ptr = Self::allocate_for_ptr_in(&*src, Box::allocator(&src)); // Copy value as bytes diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 541b3413f71ba..7708b523ced86 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -474,12 +474,10 @@ impl [T] { #[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[inline] pub const fn into_vec(self: Box) -> Vec { + let len = self.len(); + let (b, alloc) = Box::into_raw_with_allocator(self); // ignore-tidy-undocumented-unsafe - unsafe { - let len = self.len(); - let (b, alloc) = Box::into_raw_with_allocator(self); - Vec::from_raw_parts_in(b as *mut T, len, len, alloc) - } + unsafe { Vec::from_raw_parts_in(b as *mut T, len, len, alloc) } } /// Creates a vector by copying a slice `n` times. diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 72c8fc08fb8ff..cd1c149c3c4fc 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -181,10 +181,10 @@ where result.extend_from_slice(first); + let pos = result.len(); + debug_assert!(reserved_len >= pos); // ignore-tidy-undocumented-unsafe unsafe { - let pos = result.len(); - debug_assert!(reserved_len >= pos); let target = result.spare_capacity_mut().get_unchecked_mut(..reserved_len - pos); // Convert the separator and slices to slices of MaybeUninit diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 27192cf686c12..7547b8e1604de 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -860,9 +860,9 @@ impl Arc { // Now we can properly initialize the inner value and turn our weak // reference into a strong reference. + let inner = init_ptr.as_ptr(); // ignore-tidy-undocumented-unsafe unsafe { - let inner = init_ptr.as_ptr(); ptr::write(&raw mut (*inner).data, data); // The above write to the data field must be visible to any threads which diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 2fc958968fdd6..451b61fda7501 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -340,12 +340,12 @@ fn write_in_place_with_drop( src_end: *const T, ) -> impl FnMut(InPlaceDrop, T) -> Result, !> { move |mut sink, item| { + // 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"); // ignore-tidy-undocumented-unsafe 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!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation"); ptr::write(sink.dst, item); // Since this executes user code which can panic we have to bump the pointer // after each step. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 120483356d81c..49be5f72c1aac 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1733,10 +1733,10 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn into_boxed_slice(mut self) -> Box<[T], A> { + self.shrink_to_fit(); + let me = ManuallyDrop::new(self); // ignore-tidy-undocumented-unsafe unsafe { - self.shrink_to_fit(); - let me = ManuallyDrop::new(self); let buf = ptr::read(&me.buf); let len = me.len(); buf.into_box(len).assume_init() @@ -2449,10 +2449,10 @@ impl Vec { if index >= len { return None; } + // infallible + let ret; // ignore-tidy-undocumented-unsafe unsafe { - // infallible - let ret; { // the place we are taking from. let ptr = self.as_mut_ptr().add(index); @@ -2464,8 +2464,8 @@ impl Vec { ptr::copy(ptr.add(1), ptr, len - index - 1); } self.set_len(len - 1); - Some(ret) } + Some(ret) } /// Retains only the elements specified by the predicate. @@ -2906,9 +2906,9 @@ impl Vec { if self.len == 0 { None } else { + self.len -= 1; // ignore-tidy-undocumented-unsafe unsafe { - self.len -= 1; core::hint::assert_unchecked(self.len < self.capacity()); Some(ptr::read(self.as_ptr().add(self.len()))) } @@ -4067,9 +4067,9 @@ impl IntoIterator for Vec { /// ``` #[inline] fn into_iter(self) -> Self::IntoIter { + let me = ManuallyDrop::new(self); // ignore-tidy-undocumented-unsafe unsafe { - let me = ManuallyDrop::new(self); let alloc = ManuallyDrop::new(ptr::read(me.allocator())); let buf = me.buf.non_null(); let begin = buf.as_ptr(); @@ -4175,10 +4175,10 @@ impl Vec { (low, high) ); self.reserve(additional); + let ptr = self.as_mut_ptr(); + let mut local_len = SetLenOnDrop::new(&mut self.len); // ignore-tidy-undocumented-unsafe unsafe { - let ptr = self.as_mut_ptr(); - let mut local_len = SetLenOnDrop::new(&mut self.len); iterator.for_each(move |element| { ptr::write(ptr.add(local_len.current_len()), element); // Since the loop executes user code which can panic we have to update diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index 3da17e4aebd57..97850c7426045 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -46,9 +46,9 @@ impl SpecFromIter> for Vec { // But it is a conservative choice. let has_advanced = iterator.buf != iterator.ptr; if !has_advanced || iterator.len() >= iterator.cap / 2 { + let it = ManuallyDrop::new(iterator); // ignore-tidy-undocumented-unsafe unsafe { - let it = ManuallyDrop::new(iterator); if has_advanced { ptr::copy(it.ptr.as_ptr(), it.buf.as_ptr(), it.len()); }