diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index e7a10d2220b05..e3a6e90566f5e 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2102,7 +2102,9 @@ impl Default for Values<'_, K, V> { } } -/// An iterator produced by calling `extract_if` on BTreeMap. +/// This `struct` is created by the [`extract_if`] method on [`BTreeMap`]. +/// +/// [`extract_if`]: BTreeMap::extract_if #[stable(feature = "btree_extract_if", since = "1.91.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `retain` or `extract_if().for_each(drop)` to remove and discard elements"] diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index af6f5c7d70177..db8007834432c 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1547,7 +1547,9 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet { } } -/// An iterator produced by calling `extract_if` on BTreeSet. +/// This `struct` is created by the [`extract_if`] method on [`BTreeSet`]. +/// +/// [`extract_if`]: BTreeSet::extract_if #[stable(feature = "btree_extract_if", since = "1.91.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `retain` or `extract_if().for_each(drop)` to remove and discard elements"] diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 674828b8e7ded..1816349e45f4f 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1942,7 +1942,9 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { } } -/// An iterator produced by calling `extract_if` on LinkedList. +/// This `struct` is created by the [`extract_if`] method on [`LinkedList`]. +/// +/// [`extract_if`]: LinkedList::extract_if #[stable(feature = "extract_if", since = "1.87.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `extract_if().for_each(drop)` to remove and discard elements"] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a2fe730c1acc7..942b2b9d2dadf 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -898,9 +898,17 @@ impl Vec { where T: Freeze, { - unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) }; - let me = ManuallyDrop::new(self); - unsafe { slice::from_raw_parts(me.as_ptr(), me.len) } + // `const_make_global` requires the pointer to point to the beginning of a heap allocation, + // which is not the case when `self.capacity()` is 0, or if `T::IS_ZST`, + // which is why we instead return a new slice in this case. + if self.capacity() == 0 || T::IS_ZST { + let me = ManuallyDrop::new(self); + unsafe { slice::from_raw_parts(NonNull::::dangling().as_ptr(), me.len) } + } else { + unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) }; + let me = ManuallyDrop::new(self); + unsafe { slice::from_raw_parts(me.as_ptr(), me.len) } + } } } diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 5ab305f7a5048..db7da0db47d74 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2764,3 +2764,25 @@ fn const_heap() { assert_eq!([1, 2, 4, 8, 16, 32], X); } + +// regression test for issue #153158. `const_make_global` previously assumed `Vec`'s buf +// always has a heap allocation, which lead to compilation errors. +#[test] +fn const_make_global_empty_or_zst_regression() { + const EMPTY_SLICE: &'static [i32] = { + let empty_vec: Vec = Vec::new(); + empty_vec.const_make_global() + }; + + assert_eq!(EMPTY_SLICE, &[]); + + const ZST_SLICE: &'static [()] = { + let mut zst_vec: Vec<()> = Vec::new(); + zst_vec.push(()); + zst_vec.push(()); + zst_vec.push(()); + zst_vec.const_make_global() + }; + + assert_eq!(ZST_SLICE, &[(), (), ()]); +} diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index cef556319143e..9398fbbe8a1cd 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -14,10 +14,7 @@ pub struct MapWindows { } struct MapWindowsInner { - // We fuse the inner iterator because there shouldn't be "holes" in - // the sliding window. Once the iterator returns a `None`, we make - // our `MapWindows` iterator return `None` forever. - iter: Option, + iter: I, // Since iterators are assumed lazy, i.e. it only yields an item when // `Iterator::next()` is called, and `MapWindows` is not an exception. // @@ -26,7 +23,7 @@ struct MapWindowsInner { // we collect the first `N` items yielded from the inner iterator and // put it into the buffer. // - // When the inner iterator has returned a `None` (i.e. fused), we take + // When the inner iterator has returned a `None`, we take // away this `buffer` and leave it `None` to reclaim its resources. // // FIXME: should we shrink the size of `buffer` using niche optimization? @@ -64,19 +61,16 @@ impl MapWindows { impl MapWindowsInner { #[inline] fn new(iter: I) -> Self { - Self { iter: Some(iter), buffer: None } + Self { iter, buffer: None } } fn next_window(&mut self) -> Option<&[I::Item; N]> { - let iter = self.iter.as_mut()?; match self.buffer { // It is the first time to advance. We collect // the first `N` items from `self.iter` to initialize `self.buffer`. - None => self.buffer = Buffer::try_from_iter(iter), - Some(ref mut buffer) => match iter.next() { + None => self.buffer = Buffer::try_from_iter(&mut self.iter), + Some(ref mut buffer) => match self.iter.next() { None => { - // Fuse the inner iterator since it yields a `None`. - self.iter.take(); self.buffer.take(); } // Advance the iterator. We first call `next` before changing our buffer @@ -89,8 +83,7 @@ impl MapWindowsInner { } fn size_hint(&self) -> (usize, Option) { - let Some(ref iter) = self.iter else { return (0, Some(0)) }; - let (lo, hi) = iter.size_hint(); + let (lo, hi) = self.iter.size_hint(); if self.buffer.is_some() { // If the first `N` items are already yielded by the inner iterator, // the size hint is then equal to the that of the inner iterator's. @@ -253,12 +246,10 @@ where } } -// Note that even if the inner iterator not fused, the `MapWindows` is still fused, -// because we don't allow "holes" in the mapping window. #[unstable(feature = "iter_map_windows", issue = "87155")] impl FusedIterator for MapWindows where - I: Iterator, + I: FusedIterator, F: FnMut(&[I::Item; N]) -> R, { } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 11b1c04ce0e20..943e869d74380 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1657,11 +1657,6 @@ pub const trait Iterator { /// items yielded by `self`). If 𝑘 is less than `N`, this method yields an /// empty iterator. /// - /// The returned iterator implements [`FusedIterator`], because once `self` - /// returns `None`, even if it returns a `Some(T)` again in the next iterations, - /// we cannot put it into a contiguous array buffer, and thus the returned iterator - /// should be fused. - /// /// [`slice::windows()`]: slice::windows /// [`FusedIterator`]: crate::iter::FusedIterator /// @@ -1722,7 +1717,7 @@ pub const trait Iterator { /// assert_eq!(it.next(), None); /// ``` /// - /// For non-fused iterators, they are fused after `map_windows`. + /// For non-fused iterators, the window is reset after `None` is yielded. /// /// ``` /// #![feature(iter_map_windows)] @@ -1739,11 +1734,11 @@ pub const trait Iterator { /// let val = self.state; /// self.state = self.state + 1; /// - /// // yields `0..5` first, then only even numbers since `6..`. - /// if val < 5 || val % 2 == 0 { - /// Some(val) - /// } else { + /// // Skip every 5th number + /// if (val + 1) % 5 == 0 { /// None + /// } else { + /// Some(val) /// } /// } /// } @@ -1751,32 +1746,35 @@ pub const trait Iterator { /// /// let mut iter = NonFusedIterator::default(); /// - /// // yields 0..5 first. /// assert_eq!(iter.next(), Some(0)); /// assert_eq!(iter.next(), Some(1)); /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), Some(3)); - /// assert_eq!(iter.next(), Some(4)); - /// // then we can see our iterator going back and forth /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next(), Some(5)); /// assert_eq!(iter.next(), Some(6)); - /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next(), Some(7)); /// assert_eq!(iter.next(), Some(8)); /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next(), Some(10)); + /// assert_eq!(iter.next(), Some(11)); /// - /// // however, with `.map_windows()`, it is fused. /// let mut iter = NonFusedIterator::default() /// .map_windows(|arr: &[_; 2]| *arr); /// /// assert_eq!(iter.next(), Some([0, 1])); /// assert_eq!(iter.next(), Some([1, 2])); /// assert_eq!(iter.next(), Some([2, 3])); - /// assert_eq!(iter.next(), Some([3, 4])); /// assert_eq!(iter.next(), None); /// - /// // it will always return `None` after the first time. - /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next(), Some([5, 6])); + /// assert_eq!(iter.next(), Some([6, 7])); + /// assert_eq!(iter.next(), Some([7, 8])); /// assert_eq!(iter.next(), None); + /// + /// assert_eq!(iter.next(), Some([10, 11])); + /// assert_eq!(iter.next(), Some([11, 12])); + /// assert_eq!(iter.next(), Some([12, 13])); /// assert_eq!(iter.next(), None); /// ``` #[inline] diff --git a/library/core/src/mem/alignment.rs b/library/core/src/mem/alignment.rs index 69a5f66ff5d20..a8c4c8ea78ff7 100644 --- a/library/core/src/mem/alignment.rs +++ b/library/core/src/mem/alignment.rs @@ -11,7 +11,8 @@ use crate::{cmp, fmt, hash, mem, num}; /// Note that particularly large alignments, while representable in this type, /// are likely not to be supported by actual allocators and linkers. #[unstable(feature = "ptr_alignment_type", issue = "102070")] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[repr(transparent)] pub struct Alignment { // This field is never used directly (nor is the enum), @@ -303,7 +304,8 @@ impl const From for usize { } #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl cmp::Ord for Alignment { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const cmp::Ord for Alignment { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.as_nonzero_usize().cmp(&other.as_nonzero_usize()) @@ -311,7 +313,8 @@ impl cmp::Ord for Alignment { } #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl cmp::PartialOrd for Alignment { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const cmp::PartialOrd for Alignment { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) @@ -336,7 +339,8 @@ impl const Default for Alignment { } #[cfg(target_pointer_width = "16")] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, @@ -358,7 +362,8 @@ enum AlignmentEnum { } #[cfg(target_pointer_width = "32")] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, @@ -396,7 +401,8 @@ enum AlignmentEnum { } #[cfg(target_pointer_width = "64")] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs index 0cddfff4022df..4246d06b8b177 100644 --- a/library/core/src/range/iter.rs +++ b/library/core/src/range/iter.rs @@ -11,7 +11,7 @@ use crate::{intrinsics, mem}; pub struct RangeIter(legacy::Range); impl RangeIter { - #[unstable(feature = "new_range_api", issue = "125687")] + #[unstable(feature = "new_range_remainder", issue = "154458")] /// Returns the remainder of the range being iterated over. /// /// # Examples @@ -184,7 +184,7 @@ impl RangeInclusiveIter { /// iter.by_ref().for_each(drop); /// assert!(iter.remainder().is_none()); /// ``` - #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] + #[unstable(feature = "new_range_remainder", issue = "154458")] pub fn remainder(self) -> Option> { if self.0.is_empty() { return None; @@ -340,7 +340,7 @@ impl RangeFromIter { /// ``` #[inline] #[rustc_inherit_overflow_checks] - #[unstable(feature = "new_range_api", issue = "125687")] + #[unstable(feature = "new_range_remainder", issue = "154458")] pub fn remainder(self) -> RangeFrom { // Need to handle this case even if overflow-checks are disabled, // because a `RangeFromIter` could be exhausted in a crate with diff --git a/library/coretests/tests/iter/adapters/map_windows.rs b/library/coretests/tests/iter/adapters/map_windows.rs index 01cebc9b27fd8..994ec087e5e8b 100644 --- a/library/coretests/tests/iter/adapters/map_windows.rs +++ b/library/coretests/tests/iter/adapters/map_windows.rs @@ -284,3 +284,29 @@ fn test_size_hint() { check_size_hint::<5>((5, Some(5)), (1, Some(1))); check_size_hint::<5>((5, Some(10)), (1, Some(6))); } + +#[test] +fn test_unfused() { + #[derive(Default)] + struct UnfusedIter(usize); + impl Iterator for UnfusedIter { + type Item = usize; + + fn next(&mut self) -> Option { + let curr = self.0; + self.0 += 1; + if curr % 7 == 0 { None } else { Some(curr) } + } + } + + let mut iter = UnfusedIter(1).map_windows(|a: &[_; 3]| *a); + assert_eq!(iter.by_ref().collect::>(), vec![[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]); + assert_eq!( + iter.by_ref().collect::>(), + vec![[8, 9, 10], [9, 10, 11], [10, 11, 12], [11, 12, 13]] + ); + assert_eq!( + iter.by_ref().collect::>(), + vec![[15, 16, 17], [16, 17, 18], [17, 18, 19], [18, 19, 20]] + ); +} diff --git a/tests/codegen-llvm/fromrangeiter-overflow-checks.rs b/tests/codegen-llvm/fromrangeiter-overflow-checks.rs index 0d640178f459a..8662a6456c8bf 100644 --- a/tests/codegen-llvm/fromrangeiter-overflow-checks.rs +++ b/tests/codegen-llvm/fromrangeiter-overflow-checks.rs @@ -11,6 +11,7 @@ #![crate_type = "lib"] #![feature(new_range_api)] +#![feature(new_range_remainder)] use std::range::RangeFrom; diff --git a/tests/ui/iterators/rangefrom-overflow-debug.rs b/tests/ui/iterators/rangefrom-overflow-debug.rs index 9a1bc6910a044..7eafbadc62fb1 100644 --- a/tests/ui/iterators/rangefrom-overflow-debug.rs +++ b/tests/ui/iterators/rangefrom-overflow-debug.rs @@ -2,7 +2,7 @@ //@ needs-unwind //@ compile-flags: -O -C debug_assertions=yes -#![feature(new_range_api)] +#![feature(new_range_remainder)] use std::panic; diff --git a/tests/ui/iterators/rangefrom-overflow-ndebug.rs b/tests/ui/iterators/rangefrom-overflow-ndebug.rs index 4ce9b0636383c..f1a6301c50d99 100644 --- a/tests/ui/iterators/rangefrom-overflow-ndebug.rs +++ b/tests/ui/iterators/rangefrom-overflow-ndebug.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -O -C debug_assertions=no -#![feature(new_range_api)] +#![feature(new_range_remainder)] fn main() { let mut it = core::range::RangeFrom::from(u8::MAX..).into_iter(); diff --git a/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs b/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs index 7e3b0fc308405..af432afacabb6 100644 --- a/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs +++ b/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs @@ -2,7 +2,7 @@ //@ needs-unwind //@ compile-flags: -O -C overflow-checks=yes -#![feature(new_range_api)] +#![feature(new_range_remainder)] use std::panic; diff --git a/tests/ui/range/new_range_stability.rs b/tests/ui/range/new_range_stability.rs index 0b2965ecba237..71a0f02e58968 100644 --- a/tests/ui/range/new_range_stability.rs +++ b/tests/ui/range/new_range_stability.rs @@ -19,7 +19,7 @@ fn range_inclusive(mut r: RangeInclusive) { let mut i = r.into_iter(); i.next(); - i.remainder(); + i.remainder(); //~ ERROR unstable } fn range_to_inclusive(mut r: RangeToInclusive) { diff --git a/tests/ui/range/new_range_stability.stderr b/tests/ui/range/new_range_stability.stderr index 747c39d001eb4..64ef6a4166873 100644 --- a/tests/ui/range/new_range_stability.stderr +++ b/tests/ui/range/new_range_stability.stderr @@ -28,16 +28,26 @@ LL | use std::range::RangeIter; = help: add `#![feature(new_range_api)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: use of unstable library feature `new_range_api` +error[E0658]: use of unstable library feature `new_range_remainder` + --> $DIR/new_range_stability.rs:22:7 + | +LL | i.remainder(); + | ^^^^^^^^^ + | + = note: see issue #154458 for more information + = help: add `#![feature(new_range_remainder)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `new_range_remainder` --> $DIR/new_range_stability.rs:43:7 | LL | i.remainder(); | ^^^^^^^^^ | - = note: see issue #125687 for more information - = help: add `#![feature(new_range_api)]` to the crate attributes to enable + = note: see issue #154458 for more information + = help: add `#![feature(new_range_remainder)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`.