Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions library/core/src/array/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -18,17 +18,17 @@ type InnerUnsized<T> = iter_inner::PolymorphicIter<[MaybeUninit<T>]>;
#[rustc_diagnostic_item = "ArrayIntoIter"]
#[derive(Clone)]
pub struct IntoIter<T, const N: usize> {
inner: InnerSized<T, N>,
inner: ManuallyDrop<InnerSized<T, N>>,
}

impl<T, const N: usize> IntoIter<T, N> {
#[inline]
fn unsize(&self) -> &InnerUnsized<T> {
&self.inner
self.inner.deref()
}
#[inline]
fn unsize_mut(&mut self) -> &mut InnerUnsized<T> {
&mut self.inner
self.inner.deref_mut()
}
}

Expand Down Expand Up @@ -69,7 +69,7 @@ impl<T, const N: usize> 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) }
}
}

Expand Down Expand Up @@ -146,7 +146,7 @@ impl<T, const N: usize> IntoIter<T, N> {
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.
Expand Down Expand Up @@ -205,7 +205,7 @@ impl<T, const N: usize> IntoIter<T, N> {
#[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
Expand Down Expand Up @@ -320,11 +320,20 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
}

#[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<T, const N: usize> Drop for IntoIter<T, N> {
#[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::<T>() {
// SAFETY: This is the only place where we drop this field.
unsafe { ManuallyDrop::drop(&mut self.inner) }
}
}
}

Expand Down
Loading