diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index fdae5c08f1e8e..1c1f4d78c03fd 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -2,9 +2,9 @@ use crate::intrinsics::transmute_unchecked; use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce}; -use crate::mem::MaybeUninit; +use crate::mem::{ManuallyDrop, MaybeUninit}; use crate::num::NonZero; -use crate::ops::{IndexRange, Range, Try}; +use crate::ops::{Deref as _, DerefMut as _, IndexRange, Range, Try}; use crate::{fmt, ptr}; mod iter_inner; @@ -18,17 +18,17 @@ type InnerUnsized = iter_inner::PolymorphicIter<[MaybeUninit]>; #[rustc_diagnostic_item = "ArrayIntoIter"] #[derive(Clone)] pub struct IntoIter { - inner: InnerSized, + inner: ManuallyDrop>, } impl IntoIter { #[inline] fn unsize(&self) -> &InnerUnsized { - &self.inner + self.inner.deref() } #[inline] fn unsize_mut(&mut self) -> &mut InnerUnsized { - &mut self.inner + self.inner.deref_mut() } } @@ -69,7 +69,7 @@ impl IntoIterator for [T; N] { // SAFETY: The original array was entirely initialized and the the alive // range we're passing here represents that fact. let inner = unsafe { InnerSized::new_unchecked(IndexRange::zero_to(N), data) }; - IntoIter { inner } + IntoIter { inner: ManuallyDrop::new(inner) } } } @@ -146,7 +146,7 @@ impl IntoIter { let alive = unsafe { IndexRange::new_unchecked(initialized.start, initialized.end) }; // SAFETY: one of our safety condition is that these items are initialized. let inner = unsafe { InnerSized::new_unchecked(alive, buffer) }; - IntoIter { inner } + IntoIter { inner: ManuallyDrop::new(inner) } } /// Creates an iterator over `T` which returns no elements. @@ -205,7 +205,7 @@ impl IntoIter { #[inline] pub const fn empty() -> Self { let inner = InnerSized::empty(); - IntoIter { inner } + IntoIter { inner: ManuallyDrop::new(inner) } } /// Returns an immutable slice of all elements that have not been yielded @@ -320,11 +320,20 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] +// Even though all the Drop logic could be completely handled by +// PolymorphicIter, this impl still serves two purposes: +// - Drop has been part of the public API, so we can't remove it +// - the partial_drop function doesn't always get fully optimized away +// for !Drop types and ends up as dead code in the final binary. +// Branching on needs_drop higher in the call-tree allows it to be +// removed by earlier optimization passes. impl Drop for IntoIter { #[inline] fn drop(&mut self) { - // `inner` now handles this, but it'd technically be a breaking change - // to remove this `impl`, even though it's useless. + if crate::mem::needs_drop::() { + // SAFETY: This is the only place where we drop this field. + unsafe { ManuallyDrop::drop(&mut self.inner) } + } } }