Auto merge of #147353 - the8472:nondrop-array-iter, r=scottmcm
only call polymorphic array iter drop machinery when the type requires it I saw a bunch of dead, empty `<[core::mem::maybe_uninit::MaybeUninit<T>; N] as core::array::iter::iter_inner::PartialDrop>::partial_drop` functions when compiling with more than 1 CGU. Let's see if we can help optimizations to eliminate stuff earlier. r? ghost
This commit is contained in:
commit
fb24b04b09
1 changed files with 19 additions and 10 deletions
|
|
@ -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<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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue