Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --This is technically different from as there's no UAF. However, using with has undefined behavior if you use the last/original element after moving the iterator, since the field has noalias properties. <details<summaryMiri Backtrace</summary<p</p</detailsWrapping the element using (or once we have that) should make this sound.
See also:
The minimal example is actually this: Because eagerly calls drop for . This basically boils down to Which is indeed I quite strongly think that this is a bug in miri and/or ( should use inside of itself probably?). That being said this is not yet decided (again, see the UCG issue) :/
WG-prioritization assigning priority (). label -I-prioritize +P-critical
Yeah, it should -- someone just has to implement first. ;) See
I tweaked the title because while there is an experimental Miri flag to make Unique magical, codegen only has special treatment for Box.

Discussion:
<ins> use crate::fmt; </ins> use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator}; <del> use crate::mem::ManuallyDrop; </del> <ins> use crate::mem::{self, MaybeUninit}; </ins> use crate::num::NonZero; /// Creates a new iterator that repeats a single element a given number of times.

#[inline] #[stable(feature = "iter_repeat_n", since = "1.82.0")] pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> { <del> let mut element = ManuallyDrop::new(element); if count == 0 { // SAFETY: we definitely haven't dropped it yet, since we only just got // passed it in, and because the count is zero the instance we're about // to create won't drop it, so to avoid leaking we need to now. unsafe { ManuallyDrop::drop(&mut element) }; } </del> <ins> let element = if count == 0 { // `element` gets dropped eagerly. MaybeUninit::uninit() } else { MaybeUninit::new(element) }; </ins> RepeatN { element, count } }

/// /// This `struct` is created by the [`repeat_n()`] function. /// See its documentation for more. <del> #[derive(Clone, Debug)] </del> #[stable(feature = "iter_repeat_n", since = "1.82.0")] pub struct RepeatN<A> { count: usize, <del> // Invariant: has been dropped iff count == 0. element: ManuallyDrop<A>, </del> <ins> // Invariant: uninit iff count == 0. element: MaybeUninit<A>, </ins> } impl<A> RepeatN<A> { <ins> /// Returns the element if it hasn't been dropped already. fn element_ref(&self) -> Option<&A> { if self.count > 0 { // SAFETY: The count is non-zero, so it must be initialized. Some(unsafe { self.element.assume_init_ref() }) } else { None } } </ins> /// If we haven't already dropped the element, return it in an option. /// /// Clears the count so it won't be dropped again later.

fn take_element(&mut self) -> Option<A> { if self.count > 0 { self.count = 0; <ins> let element = mem::replace(&mut self.element, MaybeUninit::uninit()); </ins> // SAFETY: We just set count to zero so it won't be dropped again, // and it used to be non-zero so it hasn't already been dropped. <del> unsafe { Some(ManuallyDrop::take(&mut self.element)) } </del> <ins> unsafe { Some(element.assume_init()) } </ins> } else { None }

} #[stable(feature = "iter_repeat_n", since = "1.82.0")] <ins> impl<A: Clone> Clone for RepeatN<A> { fn clone(&self) -> RepeatN<A> { RepeatN { count: self.count, element: self.element_ref().cloned().map_or_else(MaybeUninit::uninit, MaybeUninit::new), } } } #[stable(feature = "iter_repeat_n", since = "1.82.0")] impl<A: fmt::Debug> fmt::Debug for RepeatN<A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RepeatN") .field("count", &self.count) .field("element", &self.element_ref()) .finish() } } #[stable(feature = "iter_repeat_n", since = "1.82.0")] </ins> impl<A> Drop for RepeatN<A> { fn drop(&mut self) { self.take_element();

// SAFETY: the check above ensured that the count used to be non-zero, // so element hasn't been dropped yet, and we just lowered the count to // zero so it won't be dropped later, and thus it's okay to take it here. <del> unsafe { ManuallyDrop::take(&mut self.element) } </del> <ins> unsafe { mem::replace(&mut self.element, MaybeUninit::uninit()).assume_init() } </ins> } else { <del> A::clone(&self.element) </del> <ins> // SAFETY: the count is non-zero, so it must have not been dropped yet. let element = unsafe { self.element.assume_init_ref() }; A::clone(element) </ins> } } }

drop((x0, x1, x2)); assert_eq!(count.get(), 3); } <ins> #[test] fn test_repeat_n_soundness() { let x = std::iter::repeat_n(String::from("use after free"), 0); println!("{x:?}"); pub struct PanicOnClone; impl Clone for PanicOnClone { fn clone(&self) -> Self { unreachable!() } } // `repeat_n` should drop the element immediately if `count` is zero. // `Clone` should then not try to clone the element. let x = std::iter::repeat_n(PanicOnClone, 0); let _ = x.clone(); let mut y = std::iter::repeat_n(Box::new(0), 1); let x = y.next().unwrap(); let _z = y; assert_eq!(0, *x); } </ins>