Skip to content

Commit 584d32e

Browse files
committed
Auto merge of #154535 - JonathanBrouwer:rollup-jU7CiZw, r=JonathanBrouwer
Rollup of 4 pull requests Successful merges: - #153632 (Fix Vec::const_make_global for 0 capacity and ZST's) - #154190 (Don't fuse in `MapWindows`) - #154512 (Constify comparisons and `Clone` for `core::mem::Alignment`) - #154520 (Add doc links to `ExtractIf` of `BTree{Set,Map}` and `LinkedList`)
2 parents 148adf2 + b7ea4b7 commit 584d32e

9 files changed

Lines changed: 103 additions & 46 deletions

File tree

library/alloc/src/collections/btree/map.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2102,7 +2102,9 @@ impl<K, V> Default for Values<'_, K, V> {
21022102
}
21032103
}
21042104

2105-
/// An iterator produced by calling `extract_if` on BTreeMap.
2105+
/// This `struct` is created by the [`extract_if`] method on [`BTreeMap`].
2106+
///
2107+
/// [`extract_if`]: BTreeMap::extract_if
21062108
#[stable(feature = "btree_extract_if", since = "1.91.0")]
21072109
#[must_use = "iterators are lazy and do nothing unless consumed; \
21082110
use `retain` or `extract_if().for_each(drop)` to remove and discard elements"]

library/alloc/src/collections/btree/set.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1547,7 +1547,9 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet<T, A> {
15471547
}
15481548
}
15491549

1550-
/// An iterator produced by calling `extract_if` on BTreeSet.
1550+
/// This `struct` is created by the [`extract_if`] method on [`BTreeSet`].
1551+
///
1552+
/// [`extract_if`]: BTreeSet::extract_if
15511553
#[stable(feature = "btree_extract_if", since = "1.91.0")]
15521554
#[must_use = "iterators are lazy and do nothing unless consumed; \
15531555
use `retain` or `extract_if().for_each(drop)` to remove and discard elements"]

library/alloc/src/collections/linked_list.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1942,7 +1942,9 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
19421942
}
19431943
}
19441944

1945-
/// An iterator produced by calling `extract_if` on LinkedList.
1945+
/// This `struct` is created by the [`extract_if`] method on [`LinkedList`].
1946+
///
1947+
/// [`extract_if`]: LinkedList::extract_if
19461948
#[stable(feature = "extract_if", since = "1.87.0")]
19471949
#[must_use = "iterators are lazy and do nothing unless consumed; \
19481950
use `extract_if().for_each(drop)` to remove and discard elements"]

library/alloc/src/vec/mod.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -898,9 +898,17 @@ impl<T> Vec<T> {
898898
where
899899
T: Freeze,
900900
{
901-
unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) };
902-
let me = ManuallyDrop::new(self);
903-
unsafe { slice::from_raw_parts(me.as_ptr(), me.len) }
901+
// `const_make_global` requires the pointer to point to the beginning of a heap allocation,
902+
// which is not the case when `self.capacity()` is 0, or if `T::IS_ZST`,
903+
// which is why we instead return a new slice in this case.
904+
if self.capacity() == 0 || T::IS_ZST {
905+
let me = ManuallyDrop::new(self);
906+
unsafe { slice::from_raw_parts(NonNull::<T>::dangling().as_ptr(), me.len) }
907+
} else {
908+
unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) };
909+
let me = ManuallyDrop::new(self);
910+
unsafe { slice::from_raw_parts(me.as_ptr(), me.len) }
911+
}
904912
}
905913
}
906914

library/alloctests/tests/vec.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2764,3 +2764,25 @@ fn const_heap() {
27642764

27652765
assert_eq!([1, 2, 4, 8, 16, 32], X);
27662766
}
2767+
2768+
// regression test for issue #153158. `const_make_global` previously assumed `Vec<T>`'s buf
2769+
// always has a heap allocation, which lead to compilation errors.
2770+
#[test]
2771+
fn const_make_global_empty_or_zst_regression() {
2772+
const EMPTY_SLICE: &'static [i32] = {
2773+
let empty_vec: Vec<i32> = Vec::new();
2774+
empty_vec.const_make_global()
2775+
};
2776+
2777+
assert_eq!(EMPTY_SLICE, &[]);
2778+
2779+
const ZST_SLICE: &'static [()] = {
2780+
let mut zst_vec: Vec<()> = Vec::new();
2781+
zst_vec.push(());
2782+
zst_vec.push(());
2783+
zst_vec.push(());
2784+
zst_vec.const_make_global()
2785+
};
2786+
2787+
assert_eq!(ZST_SLICE, &[(), (), ()]);
2788+
}

library/core/src/iter/adapters/map_windows.rs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ pub struct MapWindows<I: Iterator, F, const N: usize> {
1414
}
1515

1616
struct MapWindowsInner<I: Iterator, const N: usize> {
17-
// We fuse the inner iterator because there shouldn't be "holes" in
18-
// the sliding window. Once the iterator returns a `None`, we make
19-
// our `MapWindows` iterator return `None` forever.
20-
iter: Option<I>,
17+
iter: I,
2118
// Since iterators are assumed lazy, i.e. it only yields an item when
2219
// `Iterator::next()` is called, and `MapWindows` is not an exception.
2320
//
@@ -26,7 +23,7 @@ struct MapWindowsInner<I: Iterator, const N: usize> {
2623
// we collect the first `N` items yielded from the inner iterator and
2724
// put it into the buffer.
2825
//
29-
// When the inner iterator has returned a `None` (i.e. fused), we take
26+
// When the inner iterator has returned a `None`, we take
3027
// away this `buffer` and leave it `None` to reclaim its resources.
3128
//
3229
// FIXME: should we shrink the size of `buffer` using niche optimization?
@@ -64,19 +61,16 @@ impl<I: Iterator, F, const N: usize> MapWindows<I, F, N> {
6461
impl<I: Iterator, const N: usize> MapWindowsInner<I, N> {
6562
#[inline]
6663
fn new(iter: I) -> Self {
67-
Self { iter: Some(iter), buffer: None }
64+
Self { iter, buffer: None }
6865
}
6966

7067
fn next_window(&mut self) -> Option<&[I::Item; N]> {
71-
let iter = self.iter.as_mut()?;
7268
match self.buffer {
7369
// It is the first time to advance. We collect
7470
// the first `N` items from `self.iter` to initialize `self.buffer`.
75-
None => self.buffer = Buffer::try_from_iter(iter),
76-
Some(ref mut buffer) => match iter.next() {
71+
None => self.buffer = Buffer::try_from_iter(&mut self.iter),
72+
Some(ref mut buffer) => match self.iter.next() {
7773
None => {
78-
// Fuse the inner iterator since it yields a `None`.
79-
self.iter.take();
8074
self.buffer.take();
8175
}
8276
// Advance the iterator. We first call `next` before changing our buffer
@@ -89,8 +83,7 @@ impl<I: Iterator, const N: usize> MapWindowsInner<I, N> {
8983
}
9084

9185
fn size_hint(&self) -> (usize, Option<usize>) {
92-
let Some(ref iter) = self.iter else { return (0, Some(0)) };
93-
let (lo, hi) = iter.size_hint();
86+
let (lo, hi) = self.iter.size_hint();
9487
if self.buffer.is_some() {
9588
// If the first `N` items are already yielded by the inner iterator,
9689
// the size hint is then equal to the that of the inner iterator's.
@@ -253,12 +246,10 @@ where
253246
}
254247
}
255248

256-
// Note that even if the inner iterator not fused, the `MapWindows` is still fused,
257-
// because we don't allow "holes" in the mapping window.
258249
#[unstable(feature = "iter_map_windows", issue = "87155")]
259250
impl<I, F, R, const N: usize> FusedIterator for MapWindows<I, F, N>
260251
where
261-
I: Iterator,
252+
I: FusedIterator,
262253
F: FnMut(&[I::Item; N]) -> R,
263254
{
264255
}

library/core/src/iter/traits/iterator.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,11 +1657,6 @@ pub const trait Iterator {
16571657
/// items yielded by `self`). If 𝑘 is less than `N`, this method yields an
16581658
/// empty iterator.
16591659
///
1660-
/// The returned iterator implements [`FusedIterator`], because once `self`
1661-
/// returns `None`, even if it returns a `Some(T)` again in the next iterations,
1662-
/// we cannot put it into a contiguous array buffer, and thus the returned iterator
1663-
/// should be fused.
1664-
///
16651660
/// [`slice::windows()`]: slice::windows
16661661
/// [`FusedIterator`]: crate::iter::FusedIterator
16671662
///
@@ -1722,7 +1717,7 @@ pub const trait Iterator {
17221717
/// assert_eq!(it.next(), None);
17231718
/// ```
17241719
///
1725-
/// For non-fused iterators, they are fused after `map_windows`.
1720+
/// For non-fused iterators, the window is reset after `None` is yielded.
17261721
///
17271722
/// ```
17281723
/// #![feature(iter_map_windows)]
@@ -1739,44 +1734,47 @@ pub const trait Iterator {
17391734
/// let val = self.state;
17401735
/// self.state = self.state + 1;
17411736
///
1742-
/// // yields `0..5` first, then only even numbers since `6..`.
1743-
/// if val < 5 || val % 2 == 0 {
1744-
/// Some(val)
1745-
/// } else {
1737+
/// // Skip every 5th number
1738+
/// if (val + 1) % 5 == 0 {
17461739
/// None
1740+
/// } else {
1741+
/// Some(val)
17471742
/// }
17481743
/// }
17491744
/// }
17501745
///
17511746
///
17521747
/// let mut iter = NonFusedIterator::default();
17531748
///
1754-
/// // yields 0..5 first.
17551749
/// assert_eq!(iter.next(), Some(0));
17561750
/// assert_eq!(iter.next(), Some(1));
17571751
/// assert_eq!(iter.next(), Some(2));
17581752
/// assert_eq!(iter.next(), Some(3));
1759-
/// assert_eq!(iter.next(), Some(4));
1760-
/// // then we can see our iterator going back and forth
17611753
/// assert_eq!(iter.next(), None);
1754+
/// assert_eq!(iter.next(), Some(5));
17621755
/// assert_eq!(iter.next(), Some(6));
1763-
/// assert_eq!(iter.next(), None);
1756+
/// assert_eq!(iter.next(), Some(7));
17641757
/// assert_eq!(iter.next(), Some(8));
17651758
/// assert_eq!(iter.next(), None);
1759+
/// assert_eq!(iter.next(), Some(10));
1760+
/// assert_eq!(iter.next(), Some(11));
17661761
///
1767-
/// // however, with `.map_windows()`, it is fused.
17681762
/// let mut iter = NonFusedIterator::default()
17691763
/// .map_windows(|arr: &[_; 2]| *arr);
17701764
///
17711765
/// assert_eq!(iter.next(), Some([0, 1]));
17721766
/// assert_eq!(iter.next(), Some([1, 2]));
17731767
/// assert_eq!(iter.next(), Some([2, 3]));
1774-
/// assert_eq!(iter.next(), Some([3, 4]));
17751768
/// assert_eq!(iter.next(), None);
17761769
///
1777-
/// // it will always return `None` after the first time.
1778-
/// assert_eq!(iter.next(), None);
1770+
/// assert_eq!(iter.next(), Some([5, 6]));
1771+
/// assert_eq!(iter.next(), Some([6, 7]));
1772+
/// assert_eq!(iter.next(), Some([7, 8]));
17791773
/// assert_eq!(iter.next(), None);
1774+
///
1775+
/// assert_eq!(iter.next(), Some([10, 11]));
1776+
/// assert_eq!(iter.next(), Some([11, 12]));
1777+
/// assert_eq!(iter.next(), Some([12, 13]));
17801778
/// assert_eq!(iter.next(), None);
17811779
/// ```
17821780
#[inline]

library/core/src/mem/alignment.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use crate::{cmp, fmt, hash, mem, num};
1111
/// Note that particularly large alignments, while representable in this type,
1212
/// are likely not to be supported by actual allocators and linkers.
1313
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
14-
#[derive(Copy, Clone, PartialEq, Eq)]
14+
#[derive(Copy)]
15+
#[derive_const(Clone, PartialEq, Eq)]
1516
#[repr(transparent)]
1617
pub struct Alignment {
1718
// This field is never used directly (nor is the enum),
@@ -303,15 +304,17 @@ impl const From<Alignment> for usize {
303304
}
304305

305306
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
306-
impl cmp::Ord for Alignment {
307+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
308+
impl const cmp::Ord for Alignment {
307309
#[inline]
308310
fn cmp(&self, other: &Self) -> cmp::Ordering {
309311
self.as_nonzero_usize().cmp(&other.as_nonzero_usize())
310312
}
311313
}
312314

313315
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
314-
impl cmp::PartialOrd for Alignment {
316+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
317+
impl const cmp::PartialOrd for Alignment {
315318
#[inline]
316319
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
317320
Some(self.cmp(other))
@@ -336,7 +339,8 @@ impl const Default for Alignment {
336339
}
337340

338341
#[cfg(target_pointer_width = "16")]
339-
#[derive(Copy, Clone, PartialEq, Eq)]
342+
#[derive(Copy)]
343+
#[derive_const(Clone, PartialEq, Eq)]
340344
#[repr(usize)]
341345
enum AlignmentEnum {
342346
_Align1Shl0 = 1 << 0,
@@ -358,7 +362,8 @@ enum AlignmentEnum {
358362
}
359363

360364
#[cfg(target_pointer_width = "32")]
361-
#[derive(Copy, Clone, PartialEq, Eq)]
365+
#[derive(Copy)]
366+
#[derive_const(Clone, PartialEq, Eq)]
362367
#[repr(usize)]
363368
enum AlignmentEnum {
364369
_Align1Shl0 = 1 << 0,
@@ -396,7 +401,8 @@ enum AlignmentEnum {
396401
}
397402

398403
#[cfg(target_pointer_width = "64")]
399-
#[derive(Copy, Clone, PartialEq, Eq)]
404+
#[derive(Copy)]
405+
#[derive_const(Clone, PartialEq, Eq)]
400406
#[repr(usize)]
401407
enum AlignmentEnum {
402408
_Align1Shl0 = 1 << 0,

library/coretests/tests/iter/adapters/map_windows.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,29 @@ fn test_size_hint() {
284284
check_size_hint::<5>((5, Some(5)), (1, Some(1)));
285285
check_size_hint::<5>((5, Some(10)), (1, Some(6)));
286286
}
287+
288+
#[test]
289+
fn test_unfused() {
290+
#[derive(Default)]
291+
struct UnfusedIter(usize);
292+
impl Iterator for UnfusedIter {
293+
type Item = usize;
294+
295+
fn next(&mut self) -> Option<usize> {
296+
let curr = self.0;
297+
self.0 += 1;
298+
if curr % 7 == 0 { None } else { Some(curr) }
299+
}
300+
}
301+
302+
let mut iter = UnfusedIter(1).map_windows(|a: &[_; 3]| *a);
303+
assert_eq!(iter.by_ref().collect::<Vec<_>>(), vec![[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]);
304+
assert_eq!(
305+
iter.by_ref().collect::<Vec<_>>(),
306+
vec![[8, 9, 10], [9, 10, 11], [10, 11, 12], [11, 12, 13]]
307+
);
308+
assert_eq!(
309+
iter.by_ref().collect::<Vec<_>>(),
310+
vec![[15, 16, 17], [16, 17, 18], [17, 18, 19], [18, 19, 20]]
311+
);
312+
}

0 commit comments

Comments
 (0)