diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index fe7b3576e2f5f..0dc277785e825 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -84,6 +84,135 @@ impl<T, const N: usize> IntoIter<T, N> {
         IntoIterator::into_iter(array)
     }
 
+    /// Creates an iterator over the elements in a partially-initialized buffer.
+    ///
+    /// If you have a fully-initialized array, then use [`IntoIterator`].
+    /// But this is useful for returning partial results from unsafe code.
+    ///
+    /// # Safety
+    ///
+    /// - The `buffer[initialized]` elements must all be initialized.
+    /// - The range must be canonical, with `initialized.start <= initialized.end`.
+    /// - The range must in in-bounds for the buffer, with `initialized.end <= N`.
+    ///   (Like how indexing `[0][100..100]` fails despite the range being empty.)
+    ///
+    /// It's sound to have more elements initialized than mentioned, though that
+    /// will most likely result in them being leaked.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(array_into_iter_constructors)]
+    ///
+    /// #![feature(maybe_uninit_array_assume_init)]
+    /// #![feature(maybe_uninit_uninit_array)]
+    /// use std::array::IntoIter;
+    /// use std::mem::MaybeUninit;
+    ///
+    /// # // Hi!  Thanks for reading the code.  This is restricted to `Copy` because
+    /// # // otherwise it could leak.  A fully-general version this would need a drop
+    /// # // guard to handle panics from the iterator, but this works for an example.
+    /// fn next_chunk<T: Copy, const N: usize>(
+    ///     it: &mut impl Iterator<Item = T>,
+    /// ) -> Result<[T; N], IntoIter<T, N>> {
+    ///     let mut buffer = MaybeUninit::uninit_array();
+    ///     let mut i = 0;
+    ///     while i < N {
+    ///         match it.next() {
+    ///             Some(x) => {
+    ///                 buffer[i].write(x);
+    ///                 i += 1;
+    ///             }
+    ///             None => {
+    ///                 // SAFETY: We've initialized the first `i` items
+    ///                 unsafe {
+    ///                     return Err(IntoIter::new_unchecked(buffer, 0..i));
+    ///                 }
+    ///             }
+    ///         }
+    ///     }
+    ///
+    ///     // SAFETY: We've initialized all N items
+    ///     unsafe { Ok(MaybeUninit::array_assume_init(buffer)) }
+    /// }
+    ///
+    /// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap();
+    /// assert_eq!(r, [10, 11, 12, 13]);
+    /// let r: IntoIter<_, 40> = next_chunk(&mut (10..16)).unwrap_err();
+    /// assert_eq!(r.collect::<Vec<_>>(), vec![10, 11, 12, 13, 14, 15]);
+    /// ```
+    #[unstable(feature = "array_into_iter_constructors", issue = "91583")]
+    #[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")]
+    pub const unsafe fn new_unchecked(
+        buffer: [MaybeUninit<T>; N],
+        initialized: Range<usize>,
+    ) -> Self {
+        Self { data: buffer, alive: initialized }
+    }
+
+    /// Creates an iterator over `T` which returns no elements.
+    ///
+    /// If you just need an empty iterator, then use
+    /// [`iter::empty()`](crate::iter::empty) instead.
+    /// And if you need an empty array, use `[]`.
+    ///
+    /// But this is useful when you need an `array::IntoIter<T, N>` *specifically*.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(array_into_iter_constructors)]
+    /// use std::array::IntoIter;
+    ///
+    /// let empty = IntoIter::<i32, 3>::empty();
+    /// assert_eq!(empty.len(), 0);
+    /// assert_eq!(empty.as_slice(), &[]);
+    ///
+    /// let empty = IntoIter::<std::convert::Infallible, 200>::empty();
+    /// assert_eq!(empty.len(), 0);
+    /// ```
+    ///
+    /// `[1, 2].into_iter()` and `[].into_iter()` have different types
+    /// ```should_fail,edition2021
+    /// #![feature(array_into_iter_constructors)]
+    /// use std::array::IntoIter;
+    ///
+    /// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
+    ///     if b {
+    ///         [1, 2, 3, 4].into_iter()
+    ///     } else {
+    ///         [].into_iter() // error[E0308]: mismatched types
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// But using this method you can get an empty iterator of appropriate size:
+    /// ```edition2021
+    /// #![feature(array_into_iter_constructors)]
+    /// use std::array::IntoIter;
+    ///
+    /// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
+    ///     if b {
+    ///         [1, 2, 3, 4].into_iter()
+    ///     } else {
+    ///         IntoIter::empty()
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(get_bytes(true).collect::<Vec<_>>(), vec![1, 2, 3, 4]);
+    /// assert_eq!(get_bytes(false).collect::<Vec<_>>(), vec![]);
+    /// ```
+    #[unstable(feature = "array_into_iter_constructors", issue = "91583")]
+    #[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")]
+    pub const fn empty() -> Self {
+        let buffer = MaybeUninit::uninit_array();
+        let initialized = 0..0;
+
+        // SAFETY: We're telling it that none of the elements are initialized,
+        // which is trivially true.  And ∀N: usize, 0 <= N.
+        unsafe { Self::new_unchecked(buffer, initialized) }
+    }
+
     /// Returns an immutable slice of all elements that have not been yielded
     /// yet.
     #[stable(feature = "array_value_iter", since = "1.51.0")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index b0f9368b0c068..78383b54c5d1e 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -101,6 +101,7 @@
 #![feature(const_align_of_val)]
 #![feature(const_alloc_layout)]
 #![feature(const_arguments_as_str)]
+#![feature(const_array_into_iter_constructors)]
 #![feature(const_bigint_helper_methods)]
 #![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
@@ -138,6 +139,7 @@
 #![feature(const_type_name)]
 #![feature(const_default_impls)]
 #![feature(duration_consts_float)]
+#![feature(maybe_uninit_uninit_array)]
 #![feature(ptr_metadata)]
 #![feature(slice_ptr_get)]
 #![feature(str_internals)]