From c7e60e77ea4dd7474143e93af7192ff4588084d8 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 5 Jan 2022 02:28:30 +0100 Subject: [PATCH 01/13] add benchmark --- library/core/benches/iter.rs | 24 ++++++++++++++++++++++++ library/core/benches/lib.rs | 1 + 2 files changed, 25 insertions(+) diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index 24257ba98785d..6ff2ea93471d2 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -367,3 +367,27 @@ fn bench_partial_cmp(b: &mut Bencher) { fn bench_lt(b: &mut Bencher) { b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box))) } + +#[bench] +fn bench_trusted_random_access_adapters(b: &mut Bencher) { + let vec1: Vec<_> = (0usize..100000).collect(); + let vec2 = black_box(vec1.clone()); + b.iter(|| { + let mut iter = vec1 + .iter() + .copied() + .enumerate() + .map(|(idx, e)| idx.wrapping_add(e)) + .zip(vec2.iter().copied()) + .map(|(a, b)| a.wrapping_add(b)) + .fuse(); + let mut acc = 0; + let size = iter.size(); + for i in 0..size { + // SAFETY: TRA requirements are satisfied by 0..size iteration and then dropping the + // iterator. + acc += unsafe { iter.__iterator_get_unchecked(i) }; + } + acc + }) +} diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs index d5e1ec083f95d..f1f1ae6e4635d 100644 --- a/library/core/benches/lib.rs +++ b/library/core/benches/lib.rs @@ -3,6 +3,7 @@ #![feature(flt2dec)] #![feature(int_log)] #![feature(test)] +#![feature(trusted_random_access)] extern crate test; From f6dea9728665260a19b7f212a70ab1cf719f4cad Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 5 Jan 2022 02:22:39 +0100 Subject: [PATCH 02/13] This aligns the inline attributes of existing `__iterator_get_unchecked` with those of `next()` on adapters that have both. It improves the performance of iterators using unchecked access when building in incremental mode (due to the larger CGU count?). It might negatively affect incremental compile times for better runtime results, but considering that the equivalent `next()` implementations also are `#[inline]` and usually are more complex this should be ok. ``` ./x.py bench library/core -i --stage 0 --test-args bench_trusted_random_access OLD: 119,172 ns/iter NEW: 17,714 ns/iter ``` --- library/core/src/iter/adapters/enumerate.rs | 1 + library/core/src/iter/adapters/map.rs | 1 + library/core/src/iter/adapters/zip.rs | 2 ++ library/core/src/slice/iter/macros.rs | 1 + 4 files changed, 5 insertions(+) diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 84e4618844a61..10b4db84b3904 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -129,6 +129,7 @@ where #[rustc_inherit_overflow_checks] #[doc(hidden)] + #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 4b03449972c9a..6cbb35dc7c629 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -125,6 +125,7 @@ where } #[doc(hidden)] + #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index f50e71da20f16..de44bd66501e2 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -554,6 +554,7 @@ pub unsafe trait TrustedRandomAccessNoCoerce: Sized { /// /// Same requirements calling `get_unchecked` directly. #[doc(hidden)] +#[inline] pub(in crate::iter::adapters) unsafe fn try_get_unchecked(it: &mut I, idx: usize) -> I::Item where I: Iterator, @@ -576,6 +577,7 @@ unsafe impl SpecTrustedRandomAccess for I { } unsafe impl SpecTrustedRandomAccess for I { + #[inline] unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index b74ab28fc092a..78bf3381b4d26 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -326,6 +326,7 @@ macro_rules! iterator { } #[doc(hidden)] + #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // SAFETY: the caller must guarantee that `i` is in bounds of // the underlying slice, so `i` cannot overflow an `isize`, and From f1b9b121173b878934669b9842a4a0cd21c68acd Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 23 Jan 2022 17:08:38 +0100 Subject: [PATCH 03/13] add iterator benchmarks for `for _ in` loops so we can bench the desugaring --- library/core/benches/iter.rs | 56 +++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index 6ff2ea93471d2..af629794dcd78 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -146,12 +146,23 @@ fn bench_for_each_chain_ref_fold(b: &mut Bencher) { /// Helper to benchmark `sum` for iterators taken by value which /// can optimize `fold`, and by reference which cannot. macro_rules! bench_sums { - ($bench_sum:ident, $bench_ref_sum:ident, $iter:expr) => { + ($bench_sum:ident, $bench_sum_loop:ident, $bench_ref_sum:ident, $iter:expr) => { #[bench] fn $bench_sum(b: &mut Bencher) { b.iter(|| -> i64 { $iter.map(black_box).sum() }); } + #[bench] + fn $bench_sum_loop(b: &mut Bencher) { + b.iter(|| -> i64 { + let mut acc = 0; + for i in $iter.map(black_box) { + acc += i; + } + acc + }); + } + #[bench] fn $bench_ref_sum(b: &mut Bencher) { b.iter(|| -> i64 { $iter.map(black_box).by_ref().sum() }); @@ -161,138 +172,161 @@ macro_rules! bench_sums { bench_sums! { bench_flat_map_sum, + bench_flat_map_sum_loop, bench_flat_map_ref_sum, (0i64..1000).flat_map(|x| x..x+1000) } bench_sums! { bench_flat_map_chain_sum, + bench_flat_map_chain_sum_loop, bench_flat_map_chain_ref_sum, (0i64..1000000).flat_map(|x| once(x).chain(once(x))) } bench_sums! { bench_enumerate_sum, + bench_enumerate_sum_loop, bench_enumerate_ref_sum, (0i64..1000000).enumerate().map(|(i, x)| x * i as i64) } bench_sums! { bench_enumerate_chain_sum, + bench_enumerate_chain_sum_loop, bench_enumerate_chain_ref_sum, (0i64..1000000).chain(0..1000000).enumerate().map(|(i, x)| x * i as i64) } bench_sums! { bench_filter_sum, + bench_filter_sum_loop, bench_filter_ref_sum, (0i64..1000000).filter(|x| x % 3 == 0) } bench_sums! { bench_filter_chain_sum, + bench_filter_chain_sum_loop, bench_filter_chain_ref_sum, (0i64..1000000).chain(0..1000000).filter(|x| x % 3 == 0) } bench_sums! { bench_filter_map_sum, + bench_filter_map_sum_loop, bench_filter_map_ref_sum, (0i64..1000000).filter_map(|x| x.checked_mul(x)) } bench_sums! { bench_filter_map_chain_sum, + bench_filter_map_chain_sum_loop, bench_filter_map_chain_ref_sum, (0i64..1000000).chain(0..1000000).filter_map(|x| x.checked_mul(x)) } bench_sums! { bench_fuse_sum, + bench_fuse_sum_loop, bench_fuse_ref_sum, (0i64..1000000).fuse() } bench_sums! { bench_fuse_chain_sum, + bench_fuse_chain_sum_loop, bench_fuse_chain_ref_sum, (0i64..1000000).chain(0..1000000).fuse() } bench_sums! { bench_inspect_sum, + bench_inspect_sum_loop, bench_inspect_ref_sum, (0i64..1000000).inspect(|_| {}) } bench_sums! { bench_inspect_chain_sum, + bench_inspect_chain_sum_loop, bench_inspect_chain_ref_sum, (0i64..1000000).chain(0..1000000).inspect(|_| {}) } bench_sums! { bench_peekable_sum, + bench_peekable_sum_loop, bench_peekable_ref_sum, (0i64..1000000).peekable() } bench_sums! { bench_peekable_chain_sum, + bench_peekable_chain_sum_loop, bench_peekable_chain_ref_sum, (0i64..1000000).chain(0..1000000).peekable() } bench_sums! { bench_skip_sum, + bench_skip_sum_loop, bench_skip_ref_sum, (0i64..1000000).skip(1000) } bench_sums! { bench_skip_chain_sum, + bench_skip_chain_sum_loop, bench_skip_chain_ref_sum, (0i64..1000000).chain(0..1000000).skip(1000) } bench_sums! { bench_skip_while_sum, + bench_skip_while_sum_loop, bench_skip_while_ref_sum, (0i64..1000000).skip_while(|&x| x < 1000) } bench_sums! { bench_skip_while_chain_sum, + bench_skip_while_chain_sum_loop, bench_skip_while_chain_ref_sum, (0i64..1000000).chain(0..1000000).skip_while(|&x| x < 1000) } bench_sums! { bench_take_while_chain_sum, + bench_take_while_chain_sum_loop, bench_take_while_chain_ref_sum, (0i64..1000000).chain(1000000..).take_while(|&x| x < 1111111) } bench_sums! { bench_cycle_take_sum, + bench_cycle_take_sum_loop, bench_cycle_take_ref_sum, (0..10000).cycle().take(1000000) } bench_sums! { bench_cycle_skip_take_sum, + bench_cycle_skip_take_sum_loop, bench_cycle_skip_take_ref_sum, (0..100000).cycle().skip(1000000).take(1000000) } bench_sums! { bench_cycle_take_skip_sum, + bench_cycle_take_skip_sum_loop, bench_cycle_take_skip_ref_sum, (0..100000).cycle().take(1000000).skip(100000) } bench_sums! { bench_skip_cycle_skip_zip_add_sum, + bench_skip_cycle_skip_zip_add_sum_loop, bench_skip_cycle_skip_zip_add_ref_sum, (0..100000).skip(100).cycle().skip(100) .zip((0..100000).cycle().skip(10)) @@ -368,6 +402,26 @@ fn bench_lt(b: &mut Bencher) { b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box))) } +#[bench] +fn bench_desugar(b: &mut Bencher) { + let vec1: Vec<_> = (0usize..100000).collect(); + let vec2 = black_box(vec1.clone()); + b.iter(|| { + let iter = vec1 + .iter() + .enumerate() + .map(|(idx, e)| idx.wrapping_add(*e)) + .zip(vec2.iter()) + .map(|(a, b)| a.wrapping_add(*b)) + .fuse(); + let mut acc = 0; + for i in iter { + acc += i; + } + acc + }) +} + #[bench] fn bench_trusted_random_access_adapters(b: &mut Bencher) { let vec1: Vec<_> = (0usize..100000).collect(); From 0eacaabd8e5902033c148c97be6dd65a832a826e Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 17 Jan 2022 23:37:59 +0100 Subject: [PATCH 04/13] Use TrustedRandomAccess for `for _ in` loops --- library/core/src/iter/loop_desugar.rs | 76 ++++++++++++++++++++++ library/core/src/iter/mod.rs | 1 + library/core/src/iter/traits/collect.rs | 2 +- library/core/tests/iter/adapters/cloned.rs | 2 +- library/core/tests/iter/adapters/zip.rs | 4 +- 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 library/core/src/iter/loop_desugar.rs diff --git a/library/core/src/iter/loop_desugar.rs b/library/core/src/iter/loop_desugar.rs new file mode 100644 index 0000000000000..75627fdf4fa08 --- /dev/null +++ b/library/core/src/iter/loop_desugar.rs @@ -0,0 +1,76 @@ +use crate::iter::IntoIterator as RealIntoIterator; +use crate::iter::TrustedRandomAccessNoCoerce; + +#[unstable(feature = "trusted_random_access", issue = "none")] +#[doc(hidden)] + +pub trait IntoIterator { + type IntoIter: Iterator; + + #[unstable(feature = "trusted_random_access", issue = "none")] + // #[cfg_attr(not(bootstrap), lang = "loop_desugar")] + #[cfg_attr(not(bootstrap), lang = "into_iter")] + fn into_iter(self) -> Self::IntoIter; +} + +impl IntoIterator for C { + type IntoIter = ForLoopDesugar; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + ForLoopDesugar { iter: ::into_iter(self), idx: 0 } + } +} + +#[derive(Debug)] +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +pub struct ForLoopDesugar { + iter: I, + idx: usize, +} + +#[unstable(feature = "trusted_random_access", issue = "none")] +impl Iterator for ForLoopDesugar { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + // self.iter.next_spec(&mut self.idx) + self.next_spec() + } +} + +trait DesugarSpec { + fn next_spec(&mut self) -> Option; +} + +impl DesugarSpec for ForLoopDesugar +where + I: Iterator, +{ + #[inline] + default fn next_spec(&mut self) -> Option { + self.iter.next() + } +} + +impl DesugarSpec for ForLoopDesugar +where + I: TrustedRandomAccessNoCoerce + Iterator, +{ + #[inline] + fn next_spec(&mut self) -> Option { + let idx = self.idx; + if idx < self.iter.size() { + // SAFETY: idx can't overflow since size is a usize. idx is always + // less than size, so the index is always valid. + unsafe { + self.idx = idx.unchecked_add(1); + Some(self.iter.__iterator_get_unchecked(idx)) + } + } else { + None + } + } +} diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 22b76ea66ff15..b51160b48b382 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -419,6 +419,7 @@ pub use self::adapters::{Intersperse, IntersperseWith}; pub(crate) use self::adapters::{try_process, ByRefSized}; mod adapters; +mod loop_desugar; mod range; mod sources; mod traits; diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 7b75ab96ee7de..7a90aa1302892 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -262,7 +262,7 @@ pub trait IntoIterator { /// assert_eq!(Some(3), iter.next()); /// assert_eq!(None, iter.next()); /// ``` - #[lang = "into_iter"] + #[cfg_attr(bootstrap, lang = "into_iter")] #[stable(feature = "rust1", since = "1.0.0")] fn into_iter(self) -> Self::IntoIter; } diff --git a/library/core/tests/iter/adapters/cloned.rs b/library/core/tests/iter/adapters/cloned.rs index 78babb7feab18..24b6431f0a6a0 100644 --- a/library/core/tests/iter/adapters/cloned.rs +++ b/library/core/tests/iter/adapters/cloned.rs @@ -31,7 +31,7 @@ fn test_cloned_side_effects() { .zip(&[1]); for _ in iter {} } - assert_eq!(count, 2); + assert_eq!(count, 1); } #[test] diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs index 585cfbb90e40c..e2f0f8da4e0e0 100644 --- a/library/core/tests/iter/adapters/zip.rs +++ b/library/core/tests/iter/adapters/zip.rs @@ -119,7 +119,7 @@ fn test_zip_cloned_sideffectful() { for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} - assert_eq!(&xs, &[1, 1, 1, 0][..]); + assert_eq!(&xs, &[1, 1, 0, 0][..]); assert_eq!(&ys, &[1, 1][..]); let xs = [CountClone::new(), CountClone::new()]; @@ -138,7 +138,7 @@ fn test_zip_map_sideffectful() { for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + assert_eq!(&xs, &[1, 1, 1, 1, 0, 0]); assert_eq!(&ys, &[1, 1, 1, 1]); let mut xs = [0; 4]; From 7d10cafc69eb0efe5dab58a00b50dda77afd2c4a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 23 Jan 2022 18:47:12 +0100 Subject: [PATCH 05/13] bless diagnostics --- ...age_markers.main.RemoveStorageMarkers.diff | 44 ++++++++++++------- src/test/ui/consts/const-fn-error.stderr | 2 +- src/test/ui/consts/const-for.stderr | 2 +- src/test/ui/issues/issue-20605.stderr | 6 +-- src/test/ui/issues/issue-33941.rs | 1 + src/test/ui/issues/issue-33941.stderr | 14 +++++- src/test/ui/issues/issue-61108.stderr | 2 +- src/test/ui/issues/issue-64559.stderr | 2 +- src/test/ui/issues/issue-83924.stderr | 2 +- src/test/ui/loops/issue-82916.stderr | 2 +- .../ui/moves/move-fn-self-receiver.stderr | 5 +++ src/test/ui/never_type/issue-52443.stderr | 2 +- .../suggestions/borrow-for-loop-head.stderr | 2 +- src/test/ui/suggestions/for-i-in-vec.stderr | 4 +- .../ui/suggestions/slice-issue-87994.stderr | 12 ++--- 15 files changed, 66 insertions(+), 36 deletions(-) diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff index 5131e2f088d3d..7b23f466e0239 100644 --- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff +++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff @@ -4,32 +4,37 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/remove_storage_markers.rs:6:11: 6:11 let mut _1: i32; // in scope 0 at $DIR/remove_storage_markers.rs:7:9: 7:16 - let mut _2: std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _2: std::iter::loop_desugar::ForLoopDesugar>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 let mut _3: std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 let mut _5: (); // in scope 0 at $DIR/remove_storage_markers.rs:6:1: 11:2 let _6: (); // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 let mut _7: std::option::Option; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 - let mut _8: &mut std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 - let mut _9: &mut std::ops::Range; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _8: &mut std::iter::loop_desugar::ForLoopDesugar>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _9: &mut std::iter::loop_desugar::ForLoopDesugar>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 let mut _10: isize; // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6 let mut _11: !; // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6 let mut _13: i32; // in scope 0 at $DIR/remove_storage_markers.rs:9:16: 9:17 scope 1 { debug sum => _1; // in scope 1 at $DIR/remove_storage_markers.rs:7:9: 7:16 - let mut _4: std::ops::Range; // in scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _4: std::iter::loop_desugar::ForLoopDesugar>; // in scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 scope 2 { debug iter => _4; // in scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 let _12: i32; // in scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10 scope 3 { debug i => _12; // in scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 } - scope 5 (inlined iter::range::>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 - debug self => _8; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL - let mut _14: &mut std::ops::Range; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 6 (inlined > as Iterator>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 + debug self => _8; // in scope 6 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + let mut _16: &mut std::iter::loop_desugar::ForLoopDesugar>; // in scope 6 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL } } - scope 4 (inlined as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 - debug self => _3; // in scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + scope 4 (inlined as iter::loop_desugar::IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 + debug self => _3; // in scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + let mut _14: std::ops::Range; // in scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + let mut _15: std::ops::Range; // in scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + scope 5 (inlined as IntoIterator>::into_iter) { // at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + debug self => _15; // in scope 5 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + } } } @@ -41,7 +46,14 @@ Deinit(_3); // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 (_3.0: i32) = const 0_i32; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 (_3.1: i32) = const 10_i32; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 - _2 = move _3; // scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +- StorageLive(_14); // scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL +- StorageLive(_15); // scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + _15 = move _3; // scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + _14 = move _15; // scope 5 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +- StorageDead(_15); // scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + (_2.0: std::ops::Range) = move _14; // scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + (_2.1: usize) = const 0_usize; // scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL +- StorageDead(_14); // scope 4 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL - StorageDead(_3); // scope 1 at $DIR/remove_storage_markers.rs:8:18: 8:19 - StorageLive(_4); // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 _4 = move _2; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 @@ -55,12 +67,12 @@ - StorageLive(_9); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 _9 = &mut _4; // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 _8 = &mut (*_9); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 -- StorageLive(_14); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL - _14 = &mut (*_8); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL - _7 = as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL +- StorageLive(_16); // scope 6 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + _16 = &mut (*_8); // scope 6 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + _7 = > as iter::loop_desugar::DesugarSpec>::next_spec(move _16) -> bb4; // scope 6 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL // mir::Constant - // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL - // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range) -> Option< as iter::range::RangeIteratorImpl>::Item> { as iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar()) } + // + span: $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + // + literal: Const { ty: for<'r> fn(&'r mut iter::loop_desugar::ForLoopDesugar>) -> Option {> as iter::loop_desugar::DesugarSpec>::next_spec}, val: Value(Scalar()) } } bb2: { @@ -91,7 +103,7 @@ } bb4: { -- StorageDead(_14); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL +- StorageDead(_16); // scope 6 at $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL - StorageDead(_8); // scope 2 at $DIR/remove_storage_markers.rs:8:18: 8:19 _10 = discriminant(_7); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr index 4d53cfc35e1c4..cc77e01d6a60a 100644 --- a/src/test/ui/consts/const-fn-error.stderr +++ b/src/test/ui/consts/const-fn-error.stderr @@ -35,7 +35,7 @@ LL | for i in 0..x { = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0015]: cannot call non-const fn ` as Iterator>::next` in constant functions +error[E0015]: cannot call non-const fn `> as Iterator>::next` in constant functions --> $DIR/const-fn-error.rs:5:14 | LL | for i in 0..x { diff --git a/src/test/ui/consts/const-for.stderr b/src/test/ui/consts/const-for.stderr index b0dc43eb8e850..f4f803149f2e3 100644 --- a/src/test/ui/consts/const-for.stderr +++ b/src/test/ui/consts/const-for.stderr @@ -11,7 +11,7 @@ LL | impl IntoIterator for I { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants +error[E0015]: cannot call non-const fn `> as Iterator>::next` in constants --> $DIR/const-for.rs:5:14 | LL | for _ in 0..5 {} diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index 41eefe3f8e9b5..2cb9ef77769f8 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -2,10 +2,10 @@ error[E0277]: the size for values of type `dyn Iterator` cann --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } - | ^^^^^^^ expected an implementor of trait `IntoIterator` + | ^^^^^^^ expected an implementor of trait `iter::loop_desugar::IntoIterator` | - = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied - = note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator` + = note: the trait bound `dyn Iterator: iter::loop_desugar::IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `iter::loop_desugar::IntoIterator` for `dyn Iterator` help: consider mutably borrowing here | LL | for item in &mut *things { *item = 0 } diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs index a1213623e6f94..f3b8b26f0c9dc 100644 --- a/src/test/ui/issues/issue-33941.rs +++ b/src/test/ui/issues/issue-33941.rs @@ -6,4 +6,5 @@ fn main() { for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch //~^ ERROR type mismatch //~| ERROR type mismatch + //~| ERROR type mismatch } diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index e1ce6eed98efb..29265208364e6 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -33,6 +33,18 @@ LL | for _ in HashMap::new().iter().cloned() {} found reference `&_` = note: required because of the requirements on the impl of `Iterator` for `Cloned>` -error: aborting due to 3 previous errors +error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` + --> $DIR/issue-33941.rs:6:14 + | +LL | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference + | + = note: expected tuple `(&_, &_)` + found reference `&_` + = note: required because of the requirements on the impl of `Iterator` for `Cloned>` + = note: 1 redundant requirement hidden + = note: required because of the requirements on the impl of `Iterator` for `iter::loop_desugar::ForLoopDesugar>>` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index e5b671d7b7ab0..23abb5de089e0 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -10,7 +10,7 @@ LL | bad_letters.push('s'); | ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move | note: this function takes ownership of the receiver `self`, which moves `bad_letters` - --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + --> $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index ef178bbd15538..274e1264005b0 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -11,7 +11,7 @@ LL | let _closure = || orig; | value used here after move | note: this function takes ownership of the receiver `self`, which moves `orig` - --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + --> $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ diff --git a/src/test/ui/issues/issue-83924.stderr b/src/test/ui/issues/issue-83924.stderr index 767571cddbeea..77b901eea9cdd 100644 --- a/src/test/ui/issues/issue-83924.stderr +++ b/src/test/ui/issues/issue-83924.stderr @@ -11,7 +11,7 @@ LL | for n in v { | ^ value used here after move | note: this function takes ownership of the receiver `self`, which moves `v` - --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + --> $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ diff --git a/src/test/ui/loops/issue-82916.stderr b/src/test/ui/loops/issue-82916.stderr index 57d76016c4539..efc8d7e0805cd 100644 --- a/src/test/ui/loops/issue-82916.stderr +++ b/src/test/ui/loops/issue-82916.stderr @@ -10,7 +10,7 @@ LL | let z = x; | ^ value used here after move | note: this function takes ownership of the receiver `self`, which moves `x` - --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + --> $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr index 3a686121a9283..79568a2ed1f28 100644 --- a/src/test/ui/moves/move-fn-self-receiver.stderr +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -123,6 +123,11 @@ LL | for _val in implicit_into_iter {} LL | implicit_into_iter; | ^^^^^^^^^^^^^^^^^^ value used here after move | +note: this function takes ownership of the receiver `self`, which moves `implicit_into_iter` + --> $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ help: consider iterating over a slice of the `Vec`'s content to avoid moving into the `for` loop | LL | for _val in &implicit_into_iter {} diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr index 8c1755205f025..af211b201ae9f 100644 --- a/src/test/ui/never_type/issue-52443.stderr +++ b/src/test/ui/never_type/issue-52443.stderr @@ -60,7 +60,7 @@ LL | [(); { for _ in 0usize.. {}; 0}]; = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants +error[E0015]: cannot call non-const fn `> as Iterator>::next` in constants --> $DIR/issue-52443.rs:9:21 | LL | [(); { for _ in 0usize.. {}; 0}]; diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr index 1059e3d1525aa..124e64bdb4f01 100644 --- a/src/test/ui/suggestions/borrow-for-loop-head.stderr +++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr @@ -16,7 +16,7 @@ LL | for j in a { | ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop | note: this function takes ownership of the receiver `self`, which moves `a` - --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + --> $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ diff --git a/src/test/ui/suggestions/for-i-in-vec.stderr b/src/test/ui/suggestions/for-i-in-vec.stderr index 88be9e30a7641..3d2becd763de5 100644 --- a/src/test/ui/suggestions/for-i-in-vec.stderr +++ b/src/test/ui/suggestions/for-i-in-vec.stderr @@ -8,7 +8,7 @@ LL | for _ in self.v { | move occurs because `self.v` has type `Vec`, which does not implement the `Copy` trait | note: this function takes ownership of the receiver `self`, which moves `self.v` - --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + --> $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ @@ -41,7 +41,7 @@ LL | for loader in *LOADERS { | move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait | note: this function takes ownership of the receiver `self`, which moves value - --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + --> $SRC_DIR/core/src/iter/loop_desugar.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ diff --git a/src/test/ui/suggestions/slice-issue-87994.stderr b/src/test/ui/suggestions/slice-issue-87994.stderr index fd2a44f9a82ba..e208208cf3a84 100644 --- a/src/test/ui/suggestions/slice-issue-87994.stderr +++ b/src/test/ui/suggestions/slice-issue-87994.stderr @@ -2,10 +2,10 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation --> $DIR/slice-issue-87994.rs:3:12 | LL | for _ in v[1..] { - | ^^^^^^ expected an implementor of trait `IntoIterator` + | ^^^^^^ expected an implementor of trait `iter::loop_desugar::IntoIterator` | - = note: the trait bound `[i32]: IntoIterator` is not satisfied - = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` + = note: the trait bound `[i32]: iter::loop_desugar::IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `iter::loop_desugar::IntoIterator` for `[i32]` help: consider borrowing here | LL | for _ in &v[1..] { @@ -32,10 +32,10 @@ error[E0277]: the size for values of type `[K]` cannot be known at compilation t --> $DIR/slice-issue-87994.rs:11:13 | LL | for i2 in v2[1..] { - | ^^^^^^^ expected an implementor of trait `IntoIterator` + | ^^^^^^^ expected an implementor of trait `iter::loop_desugar::IntoIterator` | - = note: the trait bound `[K]: IntoIterator` is not satisfied - = note: required because of the requirements on the impl of `IntoIterator` for `[K]` + = note: the trait bound `[K]: iter::loop_desugar::IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `iter::loop_desugar::IntoIterator` for `[K]` help: consider borrowing here | LL | for i2 in &v2[1..] { From 0b534b32701a4082e66bff6126a18e9137090aa4 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 9 Apr 2022 20:19:06 +0200 Subject: [PATCH 06/13] Remove fake IntoIterator trait, invoke ForLoopDesugar directly and run cleanup on drop The on-drop cleanup will enable using TRA in try_fold(&mut self) and implementing TRA for &mut Iterator --- compiler/rustc_hir/src/lang_items.rs | 6 +- .../alloc/src/collections/vec_deque/iter.rs | 9 ++ .../src/collections/vec_deque/iter_mut.rs | 9 ++ library/alloc/src/vec/in_place_collect.rs | 3 + library/alloc/src/vec/into_iter.rs | 25 ++++ library/core/src/iter/adapters/cloned.rs | 7 + library/core/src/iter/adapters/copied.rs | 7 + library/core/src/iter/adapters/enumerate.rs | 7 + library/core/src/iter/adapters/fuse.rs | 9 ++ library/core/src/iter/adapters/map.rs | 7 + library/core/src/iter/adapters/zip.rs | 12 ++ library/core/src/iter/loop_desugar.rs | 71 +++++---- library/core/src/iter/range.rs | 11 ++ library/core/src/iter/traits/iterator.rs | 2 +- library/core/src/lib.rs | 1 + library/core/src/slice/iter.rs | 138 ++++++++++++++++++ library/core/src/str/iter.rs | 6 + 17 files changed, 299 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 9318ebb40b09b..34cb193e51e6c 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -314,8 +314,10 @@ language_item_table! { ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant, GenericRequirement::None; IntoFutureIntoFuture, sym::into_future, into_future_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None; + + IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; + IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; + PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index e8290809276fb..519a368ac42ee 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -211,4 +211,13 @@ unsafe impl TrustedRandomAccess for Iter<'_, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccessNoCoerce for Iter<'_, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let _ = self.advance_by(num); + } else { + let _ = self.advance_back_by(num); + } + } } diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index ee2df0d516012..867599326bf46 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -160,4 +160,13 @@ unsafe impl TrustedRandomAccess for IterMut<'_, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccessNoCoerce for IterMut<'_, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let _ = self.advance_by(num); + } else { + let _ = self.advance_back_by(num); + } + } } diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 282af8cc33fdd..543b0156a2d22 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -275,6 +275,9 @@ where drop_guard.dst = dst.add(1); } } + // FIXME: this should run the TrustedRandomAccess cleanup code. + // currently not running it is ok because IntoIter only implements TRA for Copy types + // but if we relax that the cleanup will be needed mem::forget(drop_guard); len } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 03c532bb69769..63de8e1259671 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -291,6 +291,31 @@ where T: NonDrop, { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = true; + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + if mem::size_of::() == 0 { + // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound + // effectively results in unsigned pointers representing positions 0..usize::MAX, + // which is valid for ZSTs. + self.ptr = unsafe { arith_offset(self.ptr as *const i8, num as isize) as *mut T } + } else { + // SAFETY: the caller must guarantee that `num` is in bounds + self.ptr = unsafe { self.ptr.add(num) }; + } + } else { + if mem::size_of::() == 0 { + // SAFETY: same as above + self.end = unsafe { + arith_offset(self.end as *const i8, num.wrapping_neg() as isize) as *mut T + } + } else { + // SAFETY: same as above + self.end = unsafe { self.end.offset(num.wrapping_neg() as isize) }; + } + } + } } #[cfg(not(no_global_oom_handling))] diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 71a5a4ea831ff..678cd2ef27b26 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -132,6 +132,13 @@ where I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = true; + + const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; + + #[inline] + fn cleanup(&mut self, num: usize, forward: bool) { + self.it.cleanup(num, forward); + } } #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index e5f2886dcafad..f244d69401209 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -158,6 +158,13 @@ where I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; + + const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; + + #[inline] + fn cleanup(&mut self, num: usize, forward: bool) { + self.it.cleanup(num, forward); + } } #[stable(feature = "iter_copied", since = "1.36.0")] diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 10b4db84b3904..da205dccf3527 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -241,6 +241,13 @@ where I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; + + const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; + + #[inline] + fn cleanup(&mut self, num: usize, forward: bool) { + self.iter.cleanup(num, forward); + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index fbf752c6f2024..0f8d559f1b5fa 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -231,6 +231,15 @@ where I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; + + const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; + + #[inline] + fn cleanup(&mut self, num: usize, forward: bool) { + if let Some(iter) = self.iter.as_mut() { + iter.cleanup(num, forward); + } + } } /// Fuse specialization trait diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 6cbb35dc7c629..95450aac62dee 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -199,6 +199,13 @@ where I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = true; + + const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; + + #[inline] + fn cleanup(&mut self, num: usize, forward: bool) { + self.iter.cleanup(num, forward); + } } #[unstable(issue = "none", feature = "inplace_iteration")] diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index de44bd66501e2..0b7adf14d6ebf 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -400,6 +400,13 @@ where B: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT; + + const NEEDS_CLEANUP: bool = A::NEEDS_CLEANUP || B::NEEDS_CLEANUP; + + fn cleanup(&mut self, num: usize, forward: bool) { + self.a.cleanup(num, forward); + self.b.cleanup(num, forward); + } } #[stable(feature = "fused", since = "1.26.0")] @@ -542,9 +549,14 @@ pub unsafe trait TrustedRandomAccessNoCoerce: Sized { { self.size_hint().0 } + /// `true` if getting an iterator element may have side effects. /// Remember to take inner iterators into account. const MAY_HAVE_SIDE_EFFECT: bool; + + const NEEDS_CLEANUP: bool; + + fn cleanup(&mut self, num: usize, forward: bool); } /// Like `Iterator::__iterator_get_unchecked`, but doesn't require the compiler to diff --git a/library/core/src/iter/loop_desugar.rs b/library/core/src/iter/loop_desugar.rs index 75627fdf4fa08..53d6295639940 100644 --- a/library/core/src/iter/loop_desugar.rs +++ b/library/core/src/iter/loop_desugar.rs @@ -1,64 +1,72 @@ -use crate::iter::IntoIterator as RealIntoIterator; +use crate::iter::IntoIterator; use crate::iter::TrustedRandomAccessNoCoerce; -#[unstable(feature = "trusted_random_access", issue = "none")] -#[doc(hidden)] - -pub trait IntoIterator { - type IntoIter: Iterator; - - #[unstable(feature = "trusted_random_access", issue = "none")] - // #[cfg_attr(not(bootstrap), lang = "loop_desugar")] - #[cfg_attr(not(bootstrap), lang = "into_iter")] - fn into_iter(self) -> Self::IntoIter; -} - -impl IntoIterator for C { - type IntoIter = ForLoopDesugar; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - ForLoopDesugar { iter: ::into_iter(self), idx: 0 } - } -} - #[derive(Debug)] #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -pub struct ForLoopDesugar { +pub struct ForLoopDesugar { iter: I, idx: usize, } -#[unstable(feature = "trusted_random_access", issue = "none")] -impl Iterator for ForLoopDesugar { - type Item = I::Item; +impl ForLoopDesugar { + #[inline] + #[cfg_attr(not(bootstrap), lang = "into_iter")] + #[cfg_attr(bootstrap, allow(dead_code))] + pub fn new(it: impl IntoIterator) -> Self { + let mut desugar = ForLoopDesugar { iter: it.into_iter(), idx: 0 }; + desugar.setup(); + desugar + } #[inline] - fn next(&mut self) -> Option { - // self.iter.next_spec(&mut self.idx) + #[cfg_attr(not(bootstrap), lang = "next")] + #[cfg_attr(bootstrap, allow(dead_code))] + pub fn next(&mut self) -> Option { self.next_spec() } } +unsafe impl<#[may_dangle] I: Iterator> Drop for ForLoopDesugar { + #[inline] + fn drop(&mut self) { + self.cleanup(); + } +} + trait DesugarSpec { + fn setup(&mut self); + fn next_spec(&mut self) -> Option; + + fn cleanup(&mut self); } impl DesugarSpec for ForLoopDesugar where I: Iterator, { + #[inline] + default fn setup(&mut self) {} + #[inline] default fn next_spec(&mut self) -> Option { self.iter.next() } + + #[inline] + default fn cleanup(&mut self) {} } impl DesugarSpec for ForLoopDesugar where I: TrustedRandomAccessNoCoerce + Iterator, { + #[inline] + fn setup(&mut self) { + let _ = self.iter.advance_by(0); + } + #[inline] fn next_spec(&mut self) -> Option { let idx = self.idx; @@ -73,4 +81,11 @@ where None } } + + #[inline] + fn cleanup(&mut self) { + if I::NEEDS_CLEANUP { + self.iter.cleanup(self.idx, true); + } + } } diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 0ae94c05da658..7ed3eeaeb5e16 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -502,7 +502,18 @@ macro_rules! unsafe_range_trusted_random_access_impl { #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccessNoCoerce for ops::Range<$t> { + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let _ = self.advance_by(num); + } else { + let _ = self.advance_back_by(num); + } + } + const MAY_HAVE_SIDE_EFFECT: bool = false; + + const NEEDS_CLEANUP: bool = false; } )*) } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 69f06fb06ef5d..9c0dec4587f1f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -94,8 +94,8 @@ pub trait Iterator { /// assert_eq!(None, iter.next()); /// assert_eq!(None, iter.next()); /// ``` - #[lang = "next"] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(bootstrap, lang = "next")] fn next(&mut self) -> Option; /// Returns the bounds on the remaining length of the iterator. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1612aa582ad17..daf3458ba51d8 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -174,6 +174,7 @@ #![feature(deprecated_suggestion)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] +#![feature(dropck_eyepatch)] #![feature(rustdoc_internals)] #![feature(exhaustive_patterns)] #![feature(doc_cfg_hide)] diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 98dd1521d0e85..c0f011b7c25af 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1376,6 +1376,15 @@ unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Windows<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + self.v = &self.v[num..]; + } else { + self.v = &self.v[..self.v.len() - num]; + } + } } /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a @@ -1560,6 +1569,19 @@ unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let len = self.v.len(); + let start = cmp::min(len, self.chunk_size * num); + self.v = &self.v[start..]; + } else { + let remaining = self.len() - num; + let end = remaining * self.chunk_size; + self.v = &self.v[..end]; + } + } } /// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` @@ -1728,6 +1750,20 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + let len = self.len(); + let v = mem::replace(&mut self.v, &mut []); + if forward { + let start = self.chunk_size * num; + self.v = &mut v[start..]; + } else { + let remaining = len - num; + let end = remaining * self.chunk_size; + self.v = &mut v[..end]; + } + } } /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a @@ -1888,6 +1924,17 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let start = self.chunk_size * num; + self.v = &self.v[start..]; + } else { + let end = self.v.len() - (self.chunk_size * num); + self.v = &self.v[..end]; + } + } } /// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` @@ -2045,6 +2092,18 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExactMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + let v = mem::replace(&mut self.v, &mut []); + if forward { + let start = self.chunk_size * num; + self.v = &mut v[start..]; + } else { + let end = v.len() - (self.chunk_size * num); + self.v = &mut v[..end]; + } + } } /// A windowed iterator over a slice in overlapping chunks (`N` elements at a @@ -2290,6 +2349,11 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunks<'a, T, N> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + self.iter.cleanup(num, forward); + } } /// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements @@ -2409,6 +2473,11 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunksMut<'a, T, N> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + self.iter.cleanup(num, forward); + } } /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a @@ -2583,6 +2652,18 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let end = self.v.len().saturating_sub(self.chunk_size * num); + self.v = &self.v[..end]; + } else { + let remainder = self.len() - num; + let start = self.v.len() - remainder * self.chunk_size; + self.v = &self.v[start..]; + } + } } /// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` @@ -2755,6 +2836,20 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + let len = self.len(); + let v = mem::replace(&mut self.v, &mut []); + self.v = if forward { + let end = v.len().saturating_sub(self.chunk_size * num); + &mut v[..end] + } else { + let remainder = len - num; + let start = v.len() - remainder * self.chunk_size; + &mut v[start..] + }; + } } /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a @@ -2919,6 +3014,17 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let end = self.v.len() - (self.chunk_size * num); + self.v = &self.v[..end]; + } else { + let start = self.chunk_size * num; + self.v = &self.v[start..]; + } + } } /// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` @@ -3080,6 +3186,18 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExactMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + fn cleanup(&mut self, num: usize, forward: bool) { + let v = mem::replace(&mut self.v, &mut []); + if forward { + let end = v.len() - (self.chunk_size * num); + self.v = &mut v[..end]; + } else { + let start = self.chunk_size * num; + self.v = &mut v[start..]; + } + } } #[doc(hidden)] @@ -3090,6 +3208,16 @@ unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Iter<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + #[inline] + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let _ = self.advance_by(num); + } else { + let _ = self.advance_back_by(num); + } + } } #[doc(hidden)] @@ -3100,6 +3228,16 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for IterMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + #[inline] + fn cleanup(&mut self, num: usize, forward: bool) { + if forward { + let _ = self.advance_by(num); + } else { + let _ = self.advance_back_by(num); + } + } } /// An iterator over slice in (non-overlapping) chunks separated by a predicate. diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index e529bccbc7999..da9d130431fb7 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -354,6 +354,12 @@ unsafe impl TrustedRandomAccess for Bytes<'_> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccessNoCoerce for Bytes<'_> { const MAY_HAVE_SIDE_EFFECT: bool = false; + const NEEDS_CLEANUP: bool = false; + + #[inline] + fn cleanup(&mut self, num: usize, forward: bool) { + self.0.cleanup(num, forward); + } } /// This macro generates a Clone impl for string pattern API From a56524a879e54ba2f9658f8c24947d0ac0357557 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 9 Apr 2022 20:42:36 +0200 Subject: [PATCH 07/13] simplify iter::Zip This removes all TrustedRandomAccess specialization from Zip, which means Zip::next no longer gets optimized as well. But since for loop desugaring uses TRA we retain most of the benefits. We're still losing optimizations on fold, try_fold and reverse iteration. But those can be re-specialized more easily. --- .../alloc/src/collections/vec_deque/iter.rs | 1 - .../src/collections/vec_deque/iter_mut.rs | 1 - library/alloc/src/vec/into_iter.rs | 1 - library/core/src/iter/adapters/cloned.rs | 2 - library/core/src/iter/adapters/copied.rs | 2 - library/core/src/iter/adapters/enumerate.rs | 2 - library/core/src/iter/adapters/fuse.rs | 2 - library/core/src/iter/adapters/map.rs | 2 - library/core/src/iter/adapters/zip.rs | 308 ++---------------- library/core/src/iter/range.rs | 2 - library/core/src/slice/iter.rs | 13 - library/core/src/str/iter.rs | 1 - 12 files changed, 32 insertions(+), 305 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index 519a368ac42ee..f1a1c72a4e2cc 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -210,7 +210,6 @@ unsafe impl TrustedRandomAccess for Iter<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccessNoCoerce for Iter<'_, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 867599326bf46..5b1d26194a461 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -159,7 +159,6 @@ unsafe impl TrustedRandomAccess for IterMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccessNoCoerce for IterMut<'_, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 63de8e1259671..2ad941980b42c 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -290,7 +290,6 @@ unsafe impl TrustedRandomAccessNoCoerce for IntoIter where T: NonDrop, { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = true; fn cleanup(&mut self, num: usize, forward: bool) { diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 678cd2ef27b26..e763ab557137d 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -131,8 +131,6 @@ unsafe impl TrustedRandomAccessNoCoerce for Cloned where I: TrustedRandomAccessNoCoerce, { - const MAY_HAVE_SIDE_EFFECT: bool = true; - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; #[inline] diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index f244d69401209..e985938ba904f 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -157,8 +157,6 @@ unsafe impl TrustedRandomAccessNoCoerce for Copied where I: TrustedRandomAccessNoCoerce, { - const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; #[inline] diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index da205dccf3527..a95ec433b443e 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -240,8 +240,6 @@ unsafe impl TrustedRandomAccessNoCoerce for Enumerate where I: TrustedRandomAccessNoCoerce, { - const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; #[inline] diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 0f8d559f1b5fa..8af54f9b09241 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -230,8 +230,6 @@ unsafe impl TrustedRandomAccessNoCoerce for Fuse where I: TrustedRandomAccessNoCoerce, { - const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; #[inline] diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 95450aac62dee..5035fa752fea1 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -198,8 +198,6 @@ unsafe impl TrustedRandomAccessNoCoerce for Map where I: TrustedRandomAccessNoCoerce, { - const MAY_HAVE_SIDE_EFFECT: bool = true; - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; #[inline] diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 0b7adf14d6ebf..fb1fe93a3c33e 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -13,23 +13,11 @@ use crate::iter::{InPlaceIterable, SourceIter, TrustedLen}; pub struct Zip { a: A, b: B, - // index, len and a_len are only used by the specialized version of zip - index: usize, - len: usize, - a_len: usize, } + impl Zip { pub(in crate::iter) fn new(a: A, b: B) -> Zip { - ZipImpl::new(a, b) - } - fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> { - while let Some(x) = Iterator::next(self) { - if n == 0 { - return Some(x); - } - n -= 1; - } - None + Zip { a, b } } } @@ -68,7 +56,7 @@ where A: IntoIterator, B: IntoIterator, { - ZipImpl::new(a.into_iter(), b.into_iter()) + Zip::new(a.into_iter(), b.into_iter()) } #[stable(feature = "rust1", since = "1.0.0")] @@ -81,133 +69,17 @@ where #[inline] fn next(&mut self) -> Option { - ZipImpl::next(self) + let x = self.a.next()?; + let y = self.b.next()?; + Some((x, y)) } #[inline] fn size_hint(&self) -> (usize, Option) { - ZipImpl::size_hint(self) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - ZipImpl::nth(self, n) - } - - #[inline] - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item - where - Self: TrustedRandomAccessNoCoerce, - { - // SAFETY: `ZipImpl::__iterator_get_unchecked` has same safety - // requirements as `Iterator::__iterator_get_unchecked`. - unsafe { ZipImpl::get_unchecked(self, idx) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Zip -where - A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator, -{ - #[inline] - fn next_back(&mut self) -> Option<(A::Item, B::Item)> { - ZipImpl::next_back(self) - } -} - -// Zip specialization trait -#[doc(hidden)] -trait ZipImpl { - type Item; - fn new(a: A, b: B) -> Self; - fn next(&mut self) -> Option; - fn size_hint(&self) -> (usize, Option); - fn nth(&mut self, n: usize) -> Option; - fn next_back(&mut self) -> Option - where - A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator; - // This has the same safety requirements as `Iterator::__iterator_get_unchecked` - unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item - where - Self: Iterator + TrustedRandomAccessNoCoerce; -} - -// Work around limitations of specialization, requiring `default` impls to be repeated -// in intermediary impls. -macro_rules! zip_impl_general_defaults { - () => { - default fn new(a: A, b: B) -> Self { - Zip { - a, - b, - index: 0, // unused - len: 0, // unused - a_len: 0, // unused - } - } - - #[inline] - default fn next(&mut self) -> Option<(A::Item, B::Item)> { - let x = self.a.next()?; - let y = self.b.next()?; - Some((x, y)) - } - - #[inline] - default fn nth(&mut self, n: usize) -> Option { - self.super_nth(n) - } - - #[inline] - default fn next_back(&mut self) -> Option<(A::Item, B::Item)> - where - A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator, - { - // The function body below only uses `self.a/b.len()` and `self.a/b.next_back()` - // and doesn’t call `next_back` too often, so this implementation is safe in - // the `TrustedRandomAccessNoCoerce` specialization - - let a_sz = self.a.len(); - let b_sz = self.b.len(); - if a_sz != b_sz { - // Adjust a, b to equal length - if a_sz > b_sz { - for _ in 0..a_sz - b_sz { - self.a.next_back(); - } - } else { - for _ in 0..b_sz - a_sz { - self.b.next_back(); - } - } - } - match (self.a.next_back(), self.b.next_back()) { - (Some(x), Some(y)) => Some((x, y)), - (None, None) => None, - _ => unreachable!(), - } - } - }; -} - -// General Zip impl -#[doc(hidden)] -impl ZipImpl for Zip -where - A: Iterator, - B: Iterator, -{ - type Item = (A::Item, B::Item); + // for TRA: + //let size = cmp::min(self.a.size(), self.b.size()); + //(size, Some(size)) - zip_impl_general_defaults! {} - - #[inline] - default fn size_hint(&self) -> (usize, Option) { let (a_lower, a_upper) = self.a.size_hint(); let (b_lower, b_upper) = self.b.size_hint(); @@ -223,154 +95,44 @@ where (lower, upper) } - default unsafe fn get_unchecked(&mut self, _idx: usize) -> ::Item + #[inline] + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, { - unreachable!("Always specialized"); - } -} - -#[doc(hidden)] -impl ZipImpl for Zip -where - A: TrustedRandomAccessNoCoerce + Iterator, - B: TrustedRandomAccessNoCoerce + Iterator, -{ - zip_impl_general_defaults! {} - - #[inline] - default fn size_hint(&self) -> (usize, Option) { - let size = cmp::min(self.a.size(), self.b.size()); - (size, Some(size)) - } - - #[inline] - unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item { - let idx = self.index + idx; // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. - unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } + unsafe { (try_get_unchecked(&mut self.a, idx), try_get_unchecked(&mut self.b, idx)) } } } -#[doc(hidden)] -impl ZipImpl for Zip +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Zip where - A: TrustedRandomAccess + Iterator, - B: TrustedRandomAccess + Iterator, + A: DoubleEndedIterator + ExactSizeIterator, + B: DoubleEndedIterator + ExactSizeIterator, { - fn new(a: A, b: B) -> Self { - let a_len = a.size(); - let len = cmp::min(a_len, b.size()); - Zip { a, b, index: 0, len, a_len } - } - #[inline] - fn next(&mut self) -> Option<(A::Item, B::Item)> { - if self.index < self.len { - let i = self.index; - // since get_unchecked executes code which can panic we increment the counters beforehand - // so that the same index won't be accessed twice, as required by TrustedRandomAccess - self.index += 1; - // SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()` - unsafe { - Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i))) - } - } else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len { - let i = self.index; - // as above, increment before executing code that may panic - self.index += 1; - self.len += 1; - // match the base implementation's potential side effects - // SAFETY: we just checked that `i` < `self.a.len()` - unsafe { - self.a.__iterator_get_unchecked(i); - } - None - } else { - None - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.len - self.index; - (len, Some(len)) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let delta = cmp::min(n, self.len - self.index); - let end = self.index + delta; - while self.index < end { - let i = self.index; - // since get_unchecked executes code which can panic we increment the counters beforehand - // so that the same index won't be accessed twice, as required by TrustedRandomAccess - self.index += 1; - if A::MAY_HAVE_SIDE_EFFECT { - // SAFETY: the usage of `cmp::min` to calculate `delta` - // ensures that `end` is smaller than or equal to `self.len`, - // so `i` is also smaller than `self.len`. - unsafe { - self.a.__iterator_get_unchecked(i); - } - } - if B::MAY_HAVE_SIDE_EFFECT { - // SAFETY: same as above. - unsafe { - self.b.__iterator_get_unchecked(i); - } - } - } - - self.super_nth(n - delta) - } - - #[inline] - fn next_back(&mut self) -> Option<(A::Item, B::Item)> - where - A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator, - { - if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT { - let sz_a = self.a.size(); - let sz_b = self.b.size(); - // Adjust a, b to equal length, make sure that only the first call - // of `next_back` does this, otherwise we will break the restriction - // on calls to `self.next_back()` after calling `get_unchecked()`. - if sz_a != sz_b { - let sz_a = self.a.size(); - if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len { - for _ in 0..sz_a - self.len { - // since next_back() may panic we increment the counters beforehand - // to keep Zip's state in sync with the underlying iterator source - self.a_len -= 1; - self.a.next_back(); - } - debug_assert_eq!(self.a_len, self.len); + fn next_back(&mut self) -> Option<(A::Item, B::Item)> { + let a_sz = self.a.len(); + let b_sz = self.b.len(); + if a_sz != b_sz { + // Adjust a, b to equal length + if a_sz > b_sz { + for _ in 0..a_sz - b_sz { + self.a.next_back(); } - let sz_b = self.b.size(); - if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len { - for _ in 0..sz_b - self.len { - self.b.next_back(); - } + } else { + for _ in 0..b_sz - a_sz { + self.b.next_back(); } } } - if self.index < self.len { - // since get_unchecked executes code which can panic we increment the counters beforehand - // so that the same index won't be accessed twice, as required by TrustedRandomAccess - self.len -= 1; - self.a_len -= 1; - let i = self.len; - // SAFETY: `i` is smaller than the previous value of `self.len`, - // which is also smaller than or equal to `self.a.len()` and `self.b.len()` - unsafe { - Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i))) - } - } else { - None + match (self.a.next_back(), self.b.next_back()) { + (Some(x), Some(y)) => Some((x, y)), + (None, None) => None, + _ => unreachable!(), } } } @@ -399,8 +161,6 @@ where A: TrustedRandomAccessNoCoerce, B: TrustedRandomAccessNoCoerce, { - const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT; - const NEEDS_CLEANUP: bool = A::NEEDS_CLEANUP || B::NEEDS_CLEANUP; fn cleanup(&mut self, num: usize, forward: bool) { @@ -550,10 +310,6 @@ pub unsafe trait TrustedRandomAccessNoCoerce: Sized { self.size_hint().0 } - /// `true` if getting an iterator element may have side effects. - /// Remember to take inner iterators into account. - const MAY_HAVE_SIDE_EFFECT: bool; - const NEEDS_CLEANUP: bool; fn cleanup(&mut self, num: usize, forward: bool); diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 7ed3eeaeb5e16..c7ebf6d6ddfe2 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -511,8 +511,6 @@ macro_rules! unsafe_range_trusted_random_access_impl { } } - const MAY_HAVE_SIDE_EFFECT: bool = false; - const NEEDS_CLEANUP: bool = false; } )*) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index c0f011b7c25af..cbed5a2348fde 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1375,7 +1375,6 @@ unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Windows<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -1568,7 +1567,6 @@ unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -1749,7 +1747,6 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksMut<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -1923,7 +1920,6 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2091,7 +2087,6 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExactMut<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2348,7 +2343,6 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunks<'a, T, N> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2472,7 +2466,6 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunksMut<'a, T, N> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2651,7 +2644,6 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2835,7 +2827,6 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksMut<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -3013,7 +3004,6 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -3185,7 +3175,6 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExactMut<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -3207,7 +3196,6 @@ unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Iter<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; #[inline] @@ -3227,7 +3215,6 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccessNoCoerce for IterMut<'a, T> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; #[inline] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index da9d130431fb7..5fbe13a2363f6 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -353,7 +353,6 @@ unsafe impl TrustedRandomAccess for Bytes<'_> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccessNoCoerce for Bytes<'_> { - const MAY_HAVE_SIDE_EFFECT: bool = false; const NEEDS_CLEANUP: bool = false; #[inline] From e6d6e5c733c8b18c5417b2eb59efaf8faaac0326 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 13 Apr 2022 19:20:48 +0200 Subject: [PATCH 08/13] Reimplement TrustedRandomAccess specializations for Zip::fold and Zip::try_fold Previously these optimizations automatically fell out of the default implementation for `fold` and `try_fold` because `next()` was specialized. Since that is gone we now need to implement it explicitly. --- library/core/src/iter/adapters/zip.rs | 98 +++++++++++++++++++++++++ library/core/tests/iter/adapters/zip.rs | 13 ---- 2 files changed, 98 insertions(+), 13 deletions(-) diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index fb1fe93a3c33e..0f41322a95df2 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -2,6 +2,7 @@ use crate::cmp; use crate::fmt::{self, Debug}; use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; use crate::iter::{InPlaceIterable, SourceIter, TrustedLen}; +use crate::ops::Try; /// An iterator that iterates two other iterators simultaneously. /// @@ -95,6 +96,14 @@ where (lower, upper) } + fn fold(self, init: T, f: F) -> T + where + Self: Sized, + F: FnMut(T, Self::Item) -> T, + { + self.spec_fold(init, f) + } + #[inline] #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item @@ -137,6 +146,95 @@ where } } +trait ZipSpec: Iterator { + fn spec_fold(self, init: T, f: F) -> T + where + Self: Sized, + F: FnMut(T, Self::Item) -> T; + + fn spec_try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try; + +} + +impl ZipSpec for Zip +where + A: Iterator, + B: Iterator, +{ + default fn spec_fold(mut self, init: T, mut f: F) -> T + where + Self: Sized, + F: FnMut(T, Self::Item) -> T, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x); + } + accum + } + + default fn spec_try_fold(&mut self, init: T, mut f: F) -> R + where + Self: Sized, + F: FnMut(T, Self::Item) -> R, + R: Try, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x)?; + } + try { accum } + } +} + +impl ZipSpec for Zip +where + A: Iterator, + B: Iterator, + Self: TrustedRandomAccess, +{ + fn spec_fold(mut self, init: T, mut f: F) -> T + where + Self: Sized, + F: FnMut(T, Self::Item) -> T, + { + let _ = self.advance_by(0); + let len = self.size(); + let mut accum = init; + for i in 0..len { + // SAFETY: each item is only accessed once and we run the cleanup function afterwards + let x = unsafe { self.__iterator_get_unchecked(i) }; + accum = f(accum, x); + } + // FIXME drop-guard or use ForLoopDesugar + self.cleanup(len, true); + accum + } + + fn spec_try_fold(&mut self, init: T, mut f: F) -> R + where + Self: Sized, + F: FnMut(T, Self::Item) -> R, + R: Try, + { + let _ = self.advance_by(0); + let len = self.size(); + let mut accum = init; + for i in 0..len { + // SAFETY: each item is only accessed once and we run the cleanup function afterwards + let x = unsafe { self.__iterator_get_unchecked(i) }; + accum = f(accum, x)?; + } + // FIXME drop-guard or use ForLoopDesugar + self.cleanup(len, true); + try { accum } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Zip where diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs index e2f0f8da4e0e0..70e049586c78b 100644 --- a/library/core/tests/iter/adapters/zip.rs +++ b/library/core/tests/iter/adapters/zip.rs @@ -174,19 +174,6 @@ fn test_zip_map_rev_sideffectful() { assert_eq!(&ys, &[1, 1, 1, 1]); } -#[test] -fn test_zip_nested_sideffectful() { - let mut xs = [0; 6]; - let ys = [0; 4]; - - { - // test that it has the side effect nested inside enumerate - let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); - it.count(); - } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); -} - #[test] fn test_zip_nth_back_side_effects_exhausted() { let mut a = Vec::new(); From a66cd5bf387b6bf79d496353a84f7b68a0e1d029 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 19 Apr 2022 19:42:33 +0200 Subject: [PATCH 09/13] specialize Zip::size_hint for TrustedRandomAccess --- library/core/src/iter/adapters/zip.rs | 42 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 0f41322a95df2..3da3393a73b88 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -77,23 +77,7 @@ where #[inline] fn size_hint(&self) -> (usize, Option) { - // for TRA: - //let size = cmp::min(self.a.size(), self.b.size()); - //(size, Some(size)) - - let (a_lower, a_upper) = self.a.size_hint(); - let (b_lower, b_upper) = self.b.size_hint(); - - let lower = cmp::min(a_lower, b_lower); - - let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => Some(cmp::min(x, y)), - (Some(x), None) => Some(x), - (None, Some(y)) => Some(y), - (None, None) => None, - }; - - (lower, upper) + self.spec_size_hint() } fn fold(self, init: T, f: F) -> T @@ -158,6 +142,7 @@ trait ZipSpec: Iterator { F: FnMut(B, Self::Item) -> R, R: Try; + fn spec_size_hint(&self) -> (usize, Option); } impl ZipSpec for Zip @@ -189,6 +174,23 @@ where } try { accum } } + + #[inline] + default fn spec_size_hint(&self) -> (usize, Option) { + let (a_lower, a_upper) = self.a.size_hint(); + let (b_lower, b_upper) = self.b.size_hint(); + + let lower = cmp::min(a_lower, b_lower); + + let upper = match (a_upper, b_upper) { + (Some(x), Some(y)) => Some(cmp::min(x, y)), + (Some(x), None) => Some(x), + (None, Some(y)) => Some(y), + (None, None) => None, + }; + + (lower, upper) + } } impl ZipSpec for Zip @@ -233,6 +235,12 @@ where self.cleanup(len, true); try { accum } } + + #[inline] + fn spec_size_hint(&self) -> (usize, Option) { + let size = cmp::min(self.a.size_hint().0, self.b.size_hint().0); + (size, Some(size)) + } } #[stable(feature = "rust1", since = "1.0.0")] From aec68464b89efc5e543fe28806352033c7ce72ea Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 19 Apr 2022 19:44:50 +0200 Subject: [PATCH 10/13] remove TrustedRandomAccess vs. TrustedRandomAccessNoCoerce distinction TRA is no longer used for single-step (`next()`) specializations, only loops and after each loop we bring the iterator back into a safe state, meaning coercions are now safe because the user code will not have access to an iterator instance that would be unsafe to coerce. --- .../alloc/src/collections/vec_deque/iter.rs | 8 +- .../src/collections/vec_deque/iter_mut.rs | 8 +- library/alloc/src/vec/in_place_collect.rs | 12 +-- library/alloc/src/vec/into_iter.rs | 10 +-- library/core/src/iter/adapters/cloned.rs | 14 +--- library/core/src/iter/adapters/copied.rs | 14 +--- library/core/src/iter/adapters/enumerate.rs | 14 +--- library/core/src/iter/adapters/fuse.rs | 11 +-- library/core/src/iter/adapters/map.rs | 14 +--- library/core/src/iter/adapters/mod.rs | 3 - library/core/src/iter/adapters/zip.rs | 44 ++-------- library/core/src/iter/loop_desugar.rs | 4 +- library/core/src/iter/mod.rs | 2 - library/core/src/iter/range.rs | 12 +-- library/core/src/iter/traits/iterator.rs | 4 +- library/core/src/slice/iter.rs | 80 ++++--------------- library/core/src/str/iter.rs | 9 +-- 17 files changed, 61 insertions(+), 202 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index f1a1c72a4e2cc..1b4cb5b8a2d9e 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -1,5 +1,5 @@ use core::fmt; -use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; +use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; use core::mem::MaybeUninit; use core::ops::Try; @@ -205,11 +205,7 @@ unsafe impl TrustedLen for Iter<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Iter<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for Iter<'_, T> { +unsafe impl TrustedRandomAccess for Iter<'_, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 5b1d26194a461..85321549d0a14 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -1,5 +1,5 @@ use core::fmt; -use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; +use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; use core::marker::PhantomData; use super::{count, wrap_index, RingSlices}; @@ -154,11 +154,7 @@ unsafe impl TrustedLen for IterMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for IterMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for IterMut<'_, T> { +unsafe impl TrustedRandomAccess for IterMut<'_, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 543b0156a2d22..a7f251d12245d 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -60,7 +60,7 @@ //! # O(1) collect //! //! The main iteration itself is further specialized when the iterator implements -//! [`TrustedRandomAccessNoCoerce`] to let the optimizer see that it is a counted loop with a single +//! [`TrustedRandomAccess`] to let the optimizer see that it is a counted loop with a single //! [induction variable]. This can turn some iterators into a noop, i.e. it reduces them from O(n) to //! O(1). This particular optimization is quite fickle and doesn't always work, see [#79308] //! @@ -70,7 +70,7 @@ //! Since unchecked accesses through that trait do not advance the read pointer of `IntoIter` //! this would interact unsoundly with the requirements about dropping the tail described above. //! But since the normal `Drop` implementation of `IntoIter` would suffer from the same problem it -//! is only correct for `TrustedRandomAccessNoCoerce` to be implemented when the items don't +//! is only correct for `TrustedRandomAccess` to be implemented when the items don't //! have a destructor. Thus that implicit requirement also makes the specialization safe to use for //! in-place collection. //! Note that this safety concern is about the correctness of `impl Drop for IntoIter`, @@ -134,7 +134,7 @@ //! } //! vec.truncate(write_idx); //! ``` -use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce}; +use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccess}; use core::mem::{self, ManuallyDrop}; use core::ptr::{self}; @@ -195,7 +195,7 @@ where // itself once IntoIter goes out of scope. // If the drop panics then we also leak any elements collected into dst_buf. // - // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce + // Note: This access to the source wouldn't be allowed by the TrustedRandomIterator // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the // module documenttation why this is ok anyway. src.forget_allocation_drop_remaining(); @@ -230,7 +230,7 @@ trait SpecInPlaceCollect: Iterator { /// collected. `end` is the last writable element of the allocation and used for bounds checks. /// /// This method is specialized and one of its implementations makes use of - /// `Iterator::__iterator_get_unchecked` calls with a `TrustedRandomAccessNoCoerce` bound + /// `Iterator::__iterator_get_unchecked` calls with a `TrustedRandomAccess` bound /// on `I` which means the caller of this method must take the safety conditions /// of that trait into consideration. fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize; @@ -256,7 +256,7 @@ where impl SpecInPlaceCollect for I where - I: Iterator + TrustedRandomAccessNoCoerce, + I: Iterator + TrustedRandomAccess, { #[inline] fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 2ad941980b42c..6f8db2f53836e 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -4,9 +4,7 @@ use crate::alloc::{Allocator, Global}; use crate::raw_vec::RawVec; use core::fmt; use core::intrinsics::arith_offset; -use core::iter::{ - FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, -}; +use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; use core::ops::Deref; @@ -200,7 +198,7 @@ impl Iterator for IntoIter { #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { // SAFETY: the caller must guarantee that `i` is in bounds of the // `Vec`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` @@ -284,9 +282,7 @@ impl NonDrop for T {} #[doc(hidden)] #[unstable(issue = "none", feature = "std_internals")] -// TrustedRandomAccess (without NoCoerce) must not be implemented because -// subtypes/supertypes of `T` might not be `NonDrop` -unsafe impl TrustedRandomAccessNoCoerce for IntoIter +unsafe impl TrustedRandomAccess for IntoIter where T: NonDrop, { diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index e763ab557137d..31a47035569a6 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,6 +1,4 @@ -use crate::iter::adapters::{ - zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce, -}; +use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; use crate::iter::{FusedIterator, TrustedLen}; use crate::ops::Try; @@ -63,7 +61,7 @@ where #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -123,13 +121,9 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Cloned where I: TrustedRandomAccess {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for Cloned +unsafe impl TrustedRandomAccess for Cloned where - I: TrustedRandomAccessNoCoerce, + I: TrustedRandomAccess, { const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index e985938ba904f..f3dda72ad9c5a 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,6 +1,4 @@ -use crate::iter::adapters::{ - zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce, -}; +use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; use crate::iter::{FusedIterator, TrustedLen}; use crate::ops::Try; @@ -84,7 +82,7 @@ where #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -149,13 +147,9 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Copied where I: TrustedRandomAccess {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for Copied +unsafe impl TrustedRandomAccess for Copied where - I: TrustedRandomAccessNoCoerce, + I: TrustedRandomAccess, { const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index a95ec433b443e..68b253a58bcfd 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -1,6 +1,4 @@ -use crate::iter::adapters::{ - zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, -}; +use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::Try; @@ -132,7 +130,7 @@ where #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -232,13 +230,9 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Enumerate where I: TrustedRandomAccess {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for Enumerate +unsafe impl TrustedRandomAccess for Enumerate where - I: TrustedRandomAccessNoCoerce, + I: TrustedRandomAccess, { const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 8af54f9b09241..fe32ae85b8625 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -2,7 +2,6 @@ use crate::intrinsics; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::{ DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, - TrustedRandomAccessNoCoerce, }; use crate::ops::Try; @@ -132,7 +131,7 @@ where #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { match self.iter { // SAFETY: the caller must uphold the contract for @@ -222,13 +221,9 @@ unsafe impl TrustedLen for Fuse where I: TrustedLen {} // // This is safe to implement as `Fuse` is just forwarding these to the wrapped iterator `I`, which // preserves these properties. -unsafe impl TrustedRandomAccess for Fuse where I: TrustedRandomAccess {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for Fuse +unsafe impl TrustedRandomAccess for Fuse where - I: TrustedRandomAccessNoCoerce, + I: TrustedRandomAccess, { const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 5035fa752fea1..1d9f811923d2e 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -1,7 +1,5 @@ use crate::fmt; -use crate::iter::adapters::{ - zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, -}; +use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::Try; @@ -128,7 +126,7 @@ where #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -190,13 +188,9 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Map where I: TrustedRandomAccess {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for Map +unsafe impl TrustedRandomAccess for Map where - I: TrustedRandomAccessNoCoerce, + I: TrustedRandomAccess, { const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 4500b44b7e9af..a9647172e160d 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -55,9 +55,6 @@ pub use self::map_while::MapWhile; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::zip::TrustedRandomAccess; -#[unstable(feature = "trusted_random_access", issue = "none")] -pub use self::zip::TrustedRandomAccessNoCoerce; - #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::zip::zip; diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 3da3393a73b88..d2e507a95fab0 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -92,7 +92,7 @@ where #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -257,15 +257,6 @@ unsafe impl TrustedRandomAccess for Zip where A: TrustedRandomAccess, B: TrustedRandomAccess, -{ -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for Zip -where - A: TrustedRandomAccessNoCoerce, - B: TrustedRandomAccessNoCoerce, { const NEEDS_CLEANUP: bool = A::NEEDS_CLEANUP || B::NEEDS_CLEANUP; @@ -328,9 +319,7 @@ impl ZipFmt for Zip { } } -impl ZipFmt - for Zip -{ +impl ZipFmt for Zip { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // It's *not safe* to call fmt on the contained iterators, since once // we start iterating they're in strange, potentially unsafe, states. @@ -344,7 +333,7 @@ impl usize where @@ -450,7 +418,7 @@ unsafe impl SpecTrustedRandomAccess for I { } } -unsafe impl SpecTrustedRandomAccess for I { +unsafe impl SpecTrustedRandomAccess for I { #[inline] unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for diff --git a/library/core/src/iter/loop_desugar.rs b/library/core/src/iter/loop_desugar.rs index 53d6295639940..52c16404515e2 100644 --- a/library/core/src/iter/loop_desugar.rs +++ b/library/core/src/iter/loop_desugar.rs @@ -1,5 +1,5 @@ use crate::iter::IntoIterator; -use crate::iter::TrustedRandomAccessNoCoerce; +use crate::iter::TrustedRandomAccess; #[derive(Debug)] #[doc(hidden)] @@ -60,7 +60,7 @@ where impl DesugarSpec for ForLoopDesugar where - I: TrustedRandomAccessNoCoerce + Iterator, + I: TrustedRandomAccess + Iterator, { #[inline] fn setup(&mut self) { diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index b51160b48b382..7c6c8c7269285 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -406,8 +406,6 @@ pub use self::adapters::SourceIter; pub use self::adapters::StepBy; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::adapters::TrustedRandomAccess; -#[unstable(feature = "trusted_random_access", issue = "none")] -pub use self::adapters::TrustedRandomAccessNoCoerce; #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index c7ebf6d6ddfe2..11b98340545a8 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -3,9 +3,7 @@ use crate::convert::TryFrom; use crate::mem; use crate::ops::{self, Try}; -use super::{ - FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, TrustedStep, -}; +use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep}; // Safety: All invariants are upheld. macro_rules! unsafe_impl_trusted_step { @@ -497,11 +495,7 @@ macro_rules! unsafe_range_trusted_random_access_impl { ($($t:ty)*) => ($( #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] - unsafe impl TrustedRandomAccess for ops::Range<$t> {} - - #[doc(hidden)] - #[unstable(feature = "trusted_random_access", issue = "none")] - unsafe impl TrustedRandomAccessNoCoerce for ops::Range<$t> { + unsafe impl TrustedRandomAccess for ops::Range<$t> { fn cleanup(&mut self, num: usize, forward: bool) { if forward { @@ -764,7 +758,7 @@ impl Iterator for ops::Range { #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index // that is in bounds. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 9c0dec4587f1f..420f26946ce7c 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3,7 +3,7 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; use super::super::ByRefSized; -use super::super::TrustedRandomAccessNoCoerce; +use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; @@ -3763,7 +3763,7 @@ pub trait Iterator { #[unstable(feature = "trusted_random_access", issue = "none")] unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item where - Self: TrustedRandomAccessNoCoerce, + Self: TrustedRandomAccess, { unreachable!("Always specialized"); } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index cbed5a2348fde..58780c54382d1 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -7,7 +7,7 @@ use crate::cmp; use crate::cmp::Ordering; use crate::fmt; use crate::intrinsics::{assume, exact_div, unchecked_sub}; -use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; +use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; use crate::marker::{PhantomData, Send, Sized, Sync}; use crate::mem; use crate::num::NonZeroUsize; @@ -1370,11 +1370,7 @@ impl FusedIterator for Windows<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Windows<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -1562,11 +1558,7 @@ impl FusedIterator for Chunks<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -1742,11 +1734,7 @@ impl FusedIterator for ChunksMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -1915,11 +1903,7 @@ impl FusedIterator for ChunksExact<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2082,11 +2066,7 @@ impl FusedIterator for ChunksExactMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExactMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2338,11 +2318,7 @@ impl FusedIterator for ArrayChunks<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {} - -#[doc(hidden)] -#[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunks<'a, T, N> { +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2461,11 +2437,7 @@ impl FusedIterator for ArrayChunksMut<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {} - -#[doc(hidden)] -#[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunksMut<'a, T, N> { +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2639,11 +2611,7 @@ impl FusedIterator for RChunks<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2822,11 +2790,7 @@ impl FusedIterator for RChunksMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -2999,11 +2963,7 @@ impl FusedIterator for RChunksExact<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -3170,11 +3130,7 @@ impl FusedIterator for RChunksExactMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExactMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { const NEEDS_CLEANUP: bool = false; fn cleanup(&mut self, num: usize, forward: bool) { @@ -3191,11 +3147,7 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExactMut<'a, T> { #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Iter<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { const NEEDS_CLEANUP: bool = false; #[inline] @@ -3210,11 +3162,7 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Iter<'a, T> { #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccessNoCoerce for IterMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { const NEEDS_CLEANUP: bool = false; #[inline] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 5fbe13a2363f6..214a93d4f5e1c 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -3,8 +3,7 @@ use crate::char; use crate::fmt::{self, Write}; use crate::iter::{Chain, FlatMap, Flatten}; -use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen}; -use crate::iter::{TrustedRandomAccess, TrustedRandomAccessNoCoerce}; +use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen, TrustedRandomAccess}; use crate::ops::Try; use crate::option; use crate::slice::{self, Split as SliceSplit}; @@ -348,11 +347,7 @@ unsafe impl TrustedLen for Bytes<'_> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Bytes<'_> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccessNoCoerce for Bytes<'_> { +unsafe impl TrustedRandomAccess for Bytes<'_> { const NEEDS_CLEANUP: bool = false; #[inline] From 9686822a032c6c4c6201a0acc2989af9514d868a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 20 Apr 2022 00:39:18 +0200 Subject: [PATCH 11/13] move TrustedRandomAccess into its own module --- library/core/src/iter/adapters/cloned.rs | 3 +- library/core/src/iter/adapters/copied.rs | 3 +- library/core/src/iter/adapters/enumerate.rs | 4 +- library/core/src/iter/adapters/fuse.rs | 2 +- library/core/src/iter/adapters/map.rs | 4 +- library/core/src/iter/adapters/mod.rs | 3 - library/core/src/iter/adapters/zip.rs | 103 +----------------- library/core/src/iter/mod.rs | 4 +- library/core/src/iter/traits/mod.rs | 3 + .../src/iter/traits/trusted_random_access.rs | 99 +++++++++++++++++ 10 files changed, 117 insertions(+), 111 deletions(-) create mode 100644 library/core/src/iter/traits/trusted_random_access.rs diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 31a47035569a6..dc06a09abf038 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,4 +1,5 @@ -use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; +use crate::iter::traits::trusted_random_access::try_get_unchecked; +use crate::iter::traits::TrustedRandomAccess; use crate::iter::{FusedIterator, TrustedLen}; use crate::ops::Try; diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index f3dda72ad9c5a..0e0407bf3a796 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,4 +1,5 @@ -use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; +use crate::iter::traits::trusted_random_access::try_get_unchecked; +use crate::iter::traits::TrustedRandomAccess; use crate::iter::{FusedIterator, TrustedLen}; use crate::ops::Try; diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 68b253a58bcfd..a2c1501807667 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -1,4 +1,6 @@ -use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; +use crate::iter::adapters::SourceIter; +use crate::iter::traits::trusted_random_access::try_get_unchecked; +use crate::iter::traits::TrustedRandomAccess; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::Try; diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index fe32ae85b8625..47d8fb5b8bd10 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,5 +1,5 @@ use crate::intrinsics; -use crate::iter::adapters::zip::try_get_unchecked; +use crate::iter::traits::trusted_random_access::try_get_unchecked; use crate::iter::{ DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, }; diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 1d9f811923d2e..c6a5c2ca2f063 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -1,5 +1,7 @@ use crate::fmt; -use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; +use crate::iter::adapters::SourceIter; +use crate::iter::traits::trusted_random_access::try_get_unchecked; +use crate::iter::traits::TrustedRandomAccess; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::Try; diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index a9647172e160d..452dd1df746c5 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -52,9 +52,6 @@ pub use self::intersperse::{Intersperse, IntersperseWith}; #[stable(feature = "iter_map_while", since = "1.57.0")] pub use self::map_while::MapWhile; -#[unstable(feature = "trusted_random_access", issue = "none")] -pub use self::zip::TrustedRandomAccess; - #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::zip::zip; diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index d2e507a95fab0..9ed29699b4fa2 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -1,7 +1,8 @@ use crate::cmp; use crate::fmt::{self, Debug}; +use crate::iter::traits::trusted_random_access::try_get_unchecked; use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; -use crate::iter::{InPlaceIterable, SourceIter, TrustedLen}; +use crate::iter::{InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess}; use crate::ops::Try; /// An iterator that iterates two other iterators simultaneously. @@ -326,103 +327,3 @@ impl ZipFmt::__iterator_get_unchecked(&mut self, idx)` -/// must be safe to call provided the following conditions are met. -/// -/// 1. `0 <= idx` and `idx < self.size()`. -/// 2. If `Self: !Clone`, then `self.__iterator_get_unchecked(idx)` is never called with the same -/// index on `self` more than once. -/// 3. After `self.__iterator_get_unchecked(idx)` has been called, then `self.next_back()` will -/// only be called at most `self.size() - idx - 1` times. If `Self: Clone` and `self` is cloned, -/// then this number is calculated for `self` and its clone individually, -/// but `self.next_back()` calls that happened before the cloning count for both `self` and the clone. -/// 4. After `self.__iterator_get_unchecked(idx)` has been called, then only the following methods -/// will be called on `self` or on any new clones of `self`: -/// * `std::clone::Clone::clone` -/// * `std::iter::Iterator::size_hint` -/// * `std::iter::DoubleEndedIterator::next_back` -/// * `std::iter::ExactSizeIterator::len` -/// * `std::iter::Iterator::__iterator_get_unchecked` -/// * `std::iter::TrustedRandomAccess::size` -/// -/// Further, given that these conditions are met, it must guarantee that: -/// -/// * It does not change the value returned from `size_hint` -/// * It must be safe to call the methods listed above on `self` after calling -/// `self.__iterator_get_unchecked(idx)`, assuming that the required traits are implemented. -/// * It must also be safe to drop `self` after calling `self.__iterator_get_unchecked(idx)`. -// -// FIXME: Clarify interaction with SourceIter/InPlaceIterable. Calling `SourceIter::as_inner` -// after `__iterator_get_unchecked` is supposed to be allowed. -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -#[rustc_specialization_trait] -pub unsafe trait TrustedRandomAccess: Sized { - // Convenience method. - fn size(&self) -> usize - where - Self: Iterator, - { - self.size_hint().0 - } - - const NEEDS_CLEANUP: bool; - - fn cleanup(&mut self, num: usize, forward: bool); -} - -/// Like `Iterator::__iterator_get_unchecked`, but doesn't require the compiler to -/// know that `U: TrustedRandomAccess`. -/// -/// ## Safety -/// -/// Same requirements calling `get_unchecked` directly. -#[doc(hidden)] -#[inline] -pub(in crate::iter::adapters) unsafe fn try_get_unchecked(it: &mut I, idx: usize) -> I::Item -where - I: Iterator, -{ - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { it.try_get_unchecked(idx) } -} - -unsafe trait SpecTrustedRandomAccess: Iterator { - /// If `Self: TrustedRandomAccess`, it must be safe to call - /// `Iterator::__iterator_get_unchecked(self, index)`. - unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item; -} - -unsafe impl SpecTrustedRandomAccess for I { - default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item { - panic!("Should only be called on TrustedRandomAccess iterators"); - } -} - -unsafe impl SpecTrustedRandomAccess for I { - #[inline] - unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { self.__iterator_get_unchecked(index) } - } -} diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 7c6c8c7269285..3e4f1fb3cdf2b 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -383,6 +383,8 @@ pub use self::traits::FusedIterator; pub use self::traits::InPlaceIterable; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::traits::TrustedRandomAccess; #[unstable(feature = "trusted_step", issue = "85731")] pub use self::traits::TrustedStep; #[stable(feature = "rust1", since = "1.0.0")] @@ -404,8 +406,6 @@ pub use self::adapters::MapWhile; pub use self::adapters::SourceIter; #[stable(feature = "iterator_step_by", since = "1.28.0")] pub use self::adapters::StepBy; -#[unstable(feature = "trusted_random_access", issue = "none")] -pub use self::adapters::TrustedRandomAccess; #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index ed0fb634dbf05..26aa66bb45ba7 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -4,6 +4,7 @@ mod double_ended; mod exact_size; mod iterator; mod marker; +pub(crate) mod trusted_random_access; #[stable(feature = "rust1", since = "1.0.0")] pub use self::{ @@ -19,3 +20,5 @@ pub use self::{ pub use self::marker::InPlaceIterable; #[unstable(feature = "trusted_step", issue = "85731")] pub use self::marker::TrustedStep; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::trusted_random_access::TrustedRandomAccess; diff --git a/library/core/src/iter/traits/trusted_random_access.rs b/library/core/src/iter/traits/trusted_random_access.rs new file mode 100644 index 0000000000000..6c0fafde0160a --- /dev/null +++ b/library/core/src/iter/traits/trusted_random_access.rs @@ -0,0 +1,99 @@ +/// An iterator whose items are random-accessible efficiently +/// +/// # Safety +/// +/// The iterator's `size_hint` must be exact and cheap to call. +/// +/// `TrustedRandomAccess::size` may not be overridden. +/// +/// All subtypes and all supertypes of `Self` must also implement `TrustedRandomAccess`. +/// In particular, this means that types with non-invariant parameters usually can not have +/// an impl for `TrustedRandomAccess` that depends on any trait bounds on such parameters, except +/// for bounds that come from the respective struct/enum definition itself, or bounds involving +/// traits that themselves come with a guarantee similar to this one. +/// +/// If `Self: ExactSizeIterator` then `self.len()` must always produce results consistent +/// with `self.size()`. +/// +/// If `Self: Iterator`, then `::__iterator_get_unchecked(&mut self, idx)` +/// must be safe to call provided the following conditions are met. +/// +/// 1. `0 <= idx` and `idx < self.size()`. +/// 2. If `Self: !Clone`, then `self.__iterator_get_unchecked(idx)` is never called with the same +/// index on `self` more than once. +/// 3. After `self.__iterator_get_unchecked(idx)` has been called, then `self.next_back()` will +/// only be called at most `self.size() - idx - 1` times. If `Self: Clone` and `self` is cloned, +/// then this number is calculated for `self` and its clone individually, +/// but `self.next_back()` calls that happened before the cloning count for both `self` and the clone. +/// 4. After `self.__iterator_get_unchecked(idx)` has been called, then only the following methods +/// will be called on `self` or on any new clones of `self`: +/// * `std::clone::Clone::clone` +/// * `std::iter::Iterator::size_hint` +/// * `std::iter::DoubleEndedIterator::next_back` +/// * `std::iter::ExactSizeIterator::len` +/// * `std::iter::Iterator::__iterator_get_unchecked` +/// * `std::iter::TrustedRandomAccess::size` +/// +/// Further, given that these conditions are met, it must guarantee that: +/// +/// * It does not change the value returned from `size_hint` +/// * It must be safe to call the methods listed above on `self` after calling +/// `self.__iterator_get_unchecked(idx)`, assuming that the required traits are implemented. +/// * It must also be safe to drop `self` after calling `self.__iterator_get_unchecked(idx)`. +// +// FIXME: Clarify interaction with SourceIter/InPlaceIterable. Calling `SourceIter::as_inner` +// after `__iterator_get_unchecked` is supposed to be allowed. +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +#[rustc_specialization_trait] +pub unsafe trait TrustedRandomAccess: Sized { + // Convenience method. + fn size(&self) -> usize + where + Self: Iterator, + { + self.size_hint().0 + } + + const NEEDS_CLEANUP: bool; + + fn cleanup(&mut self, num: usize, forward: bool); +} + +/// Like `Iterator::__iterator_get_unchecked`, but doesn't require the compiler to +/// know that `U: TrustedRandomAccess`. +/// +/// ## Safety +/// +/// Same requirements calling `get_unchecked` directly. +#[doc(hidden)] +#[inline] +pub(in crate::iter) unsafe fn try_get_unchecked(it: &mut I, idx: usize) -> I::Item +where + I: Iterator, +{ + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + unsafe { it.try_get_unchecked(idx) } +} + +unsafe trait SpecTrustedRandomAccess: Iterator { + /// If `Self: TrustedRandomAccess`, it must be safe to call + /// `Iterator::__iterator_get_unchecked(self, index)`. + unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item; +} + +unsafe impl SpecTrustedRandomAccess for I { + default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item { + panic!("Should only be called on TrustedRandomAccess iterators"); + } +} + +unsafe impl SpecTrustedRandomAccess for I { + #[inline] + unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + unsafe { self.__iterator_get_unchecked(index) } + } +} From 14f829a8a0a6d59d970876c396cc33817b5255c3 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 20 Apr 2022 02:01:42 +0200 Subject: [PATCH 12/13] Use marker/specialization traits instead of associated consts to signal the need for pre/post loop calls The loop setup and cleanup functions are only required for some specific iterators. To avoid emitting IR when they're not needed even in debug mode we need to use the type system instead of const-DCE because the constants would only be known after monomorphization. --- .../alloc/src/collections/vec_deque/iter.rs | 2 - .../src/collections/vec_deque/iter_mut.rs | 2 - library/alloc/src/vec/into_iter.rs | 11 +++- library/core/src/iter/adapters/cloned.rs | 26 +++++++- library/core/src/iter/adapters/copied.rs | 26 +++++++- library/core/src/iter/adapters/enumerate.rs | 28 +++++++- library/core/src/iter/adapters/fuse.rs | 22 ++++++- library/core/src/iter/adapters/map.rs | 28 +++++++- library/core/src/iter/adapters/zip.rs | 58 ++++++++++++++++- library/core/src/iter/loop_desugar.rs | 64 +++++++++++++------ library/core/src/iter/mod.rs | 7 +- library/core/src/iter/range.rs | 2 - library/core/src/iter/traits/mod.rs | 5 +- .../src/iter/traits/trusted_random_access.rs | 27 +++++++- library/core/src/lib.rs | 1 + library/core/src/slice/iter.rs | 26 -------- library/core/src/str/iter.rs | 2 - 17 files changed, 258 insertions(+), 79 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index 1b4cb5b8a2d9e..7f7d7e668a20f 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -206,8 +206,6 @@ unsafe impl TrustedLen for Iter<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for Iter<'_, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { if forward { let _ = self.advance_by(num); diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 85321549d0a14..09a75fc9b20ce 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -155,8 +155,6 @@ unsafe impl TrustedLen for IterMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for IterMut<'_, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { if forward { let _ = self.advance_by(num); diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 6f8db2f53836e..6ca973761add7 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -4,7 +4,10 @@ use crate::alloc::{Allocator, Global}; use crate::raw_vec::RawVec; use core::fmt; use core::intrinsics::arith_offset; -use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess}; +use core::iter::{ + FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess, + TrustedRandomAccessNeedsCleanup, +}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; use core::ops::Deref; @@ -286,8 +289,6 @@ unsafe impl TrustedRandomAccess for IntoIter where T: NonDrop, { - const NEEDS_CLEANUP: bool = true; - fn cleanup(&mut self, num: usize, forward: bool) { if forward { if mem::size_of::() == 0 { @@ -313,6 +314,10 @@ where } } +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] +unsafe impl TrustedRandomAccessNeedsCleanup for IntoIter where T: NonDrop {} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index dc06a09abf038..15b3245ce62eb 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,5 +1,8 @@ use crate::iter::traits::trusted_random_access::try_get_unchecked; -use crate::iter::traits::TrustedRandomAccess; +use crate::iter::traits::{ + TrustedRandomAccess, TrustedRandomAccessNeedsCleanup, TrustedRandomAccessNeedsForwardSetup, + TrustedRandomAccessNeedsReverseSetup, +}; use crate::iter::{FusedIterator, TrustedLen}; use crate::ops::Try; @@ -126,14 +129,31 @@ unsafe impl TrustedRandomAccess for Cloned where I: TrustedRandomAccess, { - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; - #[inline] fn cleanup(&mut self, num: usize, forward: bool) { self.it.cleanup(num, forward); } } +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsCleanup for Cloned where I: TrustedRandomAccessNeedsCleanup +{} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsForwardSetup for Cloned where + I: TrustedRandomAccessNeedsForwardSetup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsReverseSetup for Cloned where + I: TrustedRandomAccessNeedsReverseSetup +{ +} + #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, I, T: 'a> TrustedLen for Cloned where diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 0e0407bf3a796..47c77b1fe987a 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,5 +1,8 @@ use crate::iter::traits::trusted_random_access::try_get_unchecked; -use crate::iter::traits::TrustedRandomAccess; +use crate::iter::traits::{ + TrustedRandomAccess, TrustedRandomAccessNeedsCleanup, TrustedRandomAccessNeedsForwardSetup, + TrustedRandomAccessNeedsReverseSetup, +}; use crate::iter::{FusedIterator, TrustedLen}; use crate::ops::Try; @@ -152,14 +155,31 @@ unsafe impl TrustedRandomAccess for Copied where I: TrustedRandomAccess, { - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; - #[inline] fn cleanup(&mut self, num: usize, forward: bool) { self.it.cleanup(num, forward); } } +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsCleanup for Copied where I: TrustedRandomAccessNeedsCleanup +{} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsForwardSetup for Copied where + I: TrustedRandomAccessNeedsForwardSetup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsReverseSetup for Copied where + I: TrustedRandomAccessNeedsReverseSetup +{ +} + #[stable(feature = "iter_copied", since = "1.36.0")] unsafe impl<'a, I, T: 'a> TrustedLen for Copied where diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index a2c1501807667..e26b1355f8d4d 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -1,6 +1,9 @@ use crate::iter::adapters::SourceIter; use crate::iter::traits::trusted_random_access::try_get_unchecked; -use crate::iter::traits::TrustedRandomAccess; +use crate::iter::traits::{ + TrustedRandomAccess, TrustedRandomAccessNeedsCleanup, TrustedRandomAccessNeedsForwardSetup, + TrustedRandomAccessNeedsReverseSetup, +}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::Try; @@ -236,14 +239,33 @@ unsafe impl TrustedRandomAccess for Enumerate where I: TrustedRandomAccess, { - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; - #[inline] fn cleanup(&mut self, num: usize, forward: bool) { self.iter.cleanup(num, forward); } } +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsCleanup for Enumerate where + I: TrustedRandomAccessNeedsCleanup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsForwardSetup for Enumerate where + I: TrustedRandomAccessNeedsForwardSetup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsReverseSetup for Enumerate where + I: TrustedRandomAccessNeedsReverseSetup +{ +} + #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Enumerate where I: FusedIterator {} diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 47d8fb5b8bd10..2835a50337f11 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -2,6 +2,8 @@ use crate::intrinsics; use crate::iter::traits::trusted_random_access::try_get_unchecked; use crate::iter::{ DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, + TrustedRandomAccessNeedsCleanup, TrustedRandomAccessNeedsForwardSetup, + TrustedRandomAccessNeedsReverseSetup, }; use crate::ops::Try; @@ -225,8 +227,6 @@ unsafe impl TrustedRandomAccess for Fuse where I: TrustedRandomAccess, { - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; - #[inline] fn cleanup(&mut self, num: usize, forward: bool) { if let Some(iter) = self.iter.as_mut() { @@ -235,6 +235,24 @@ where } } +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsCleanup for Fuse where I: TrustedRandomAccessNeedsCleanup {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsForwardSetup for Fuse where + I: TrustedRandomAccessNeedsForwardSetup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsReverseSetup for Fuse where + I: TrustedRandomAccessNeedsReverseSetup +{ +} + /// Fuse specialization trait /// /// We only need to worry about `&mut self` methods, which diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index c6a5c2ca2f063..742fe1b3c23e4 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -1,7 +1,10 @@ use crate::fmt; use crate::iter::adapters::SourceIter; use crate::iter::traits::trusted_random_access::try_get_unchecked; -use crate::iter::traits::TrustedRandomAccess; +use crate::iter::traits::{ + TrustedRandomAccess, TrustedRandomAccessNeedsCleanup, TrustedRandomAccessNeedsForwardSetup, + TrustedRandomAccessNeedsReverseSetup, +}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::Try; @@ -194,14 +197,33 @@ unsafe impl TrustedRandomAccess for Map where I: TrustedRandomAccess, { - const NEEDS_CLEANUP: bool = I::NEEDS_CLEANUP; - #[inline] fn cleanup(&mut self, num: usize, forward: bool) { self.iter.cleanup(num, forward); } } +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsCleanup for Map where + I: TrustedRandomAccessNeedsCleanup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsForwardSetup for Map where + I: TrustedRandomAccessNeedsForwardSetup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsReverseSetup for Map where + I: TrustedRandomAccessNeedsReverseSetup +{ +} + #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl SourceIter for Map where diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 9ed29699b4fa2..13de9fd823a76 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -2,7 +2,10 @@ use crate::cmp; use crate::fmt::{self, Debug}; use crate::iter::traits::trusted_random_access::try_get_unchecked; use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; -use crate::iter::{InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess}; +use crate::iter::{ + InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNeedsCleanup, + TrustedRandomAccessNeedsForwardSetup, TrustedRandomAccessNeedsReverseSetup, +}; use crate::ops::Try; /// An iterator that iterates two other iterators simultaneously. @@ -259,14 +262,63 @@ where A: TrustedRandomAccess, B: TrustedRandomAccess, { - const NEEDS_CLEANUP: bool = A::NEEDS_CLEANUP || B::NEEDS_CLEANUP; - fn cleanup(&mut self, num: usize, forward: bool) { self.a.cleanup(num, forward); self.b.cleanup(num, forward); } } +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsCleanup for Zip where + A: TrustedRandomAccessNeedsCleanup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsCleanup for Zip where + B: TrustedRandomAccessNeedsCleanup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsCleanup for Zip +where + A: TrustedRandomAccessNeedsCleanup, + B: TrustedRandomAccessNeedsCleanup, +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsForwardSetup for Zip where + A: TrustedRandomAccessNeedsForwardSetup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsForwardSetup for Zip where + B: TrustedRandomAccessNeedsForwardSetup +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsForwardSetup for Zip +where + A: TrustedRandomAccessNeedsForwardSetup, + B: TrustedRandomAccessNeedsForwardSetup, +{ +} + + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNeedsReverseSetup for Zip where Self: TrustedRandomAccess {} + #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Zip where diff --git a/library/core/src/iter/loop_desugar.rs b/library/core/src/iter/loop_desugar.rs index 52c16404515e2..76d39368748cf 100644 --- a/library/core/src/iter/loop_desugar.rs +++ b/library/core/src/iter/loop_desugar.rs @@ -1,5 +1,7 @@ use crate::iter::IntoIterator; -use crate::iter::TrustedRandomAccess; +use crate::iter::{ + TrustedRandomAccess, TrustedRandomAccessNeedsCleanup, TrustedRandomAccessNeedsForwardSetup, +}; #[derive(Debug)] #[doc(hidden)] @@ -34,39 +36,32 @@ unsafe impl<#[may_dangle] I: Iterator> Drop for ForLoopDesugar { } } -trait DesugarSpec { - fn setup(&mut self); - +trait DesugarNext { fn next_spec(&mut self) -> Option; +} + +trait DesugarSetup { + fn setup(&mut self); +} +trait DesugarCleanup { fn cleanup(&mut self); } -impl DesugarSpec for ForLoopDesugar +impl DesugarNext for ForLoopDesugar where I: Iterator, { - #[inline] - default fn setup(&mut self) {} - #[inline] default fn next_spec(&mut self) -> Option { self.iter.next() } - - #[inline] - default fn cleanup(&mut self) {} } -impl DesugarSpec for ForLoopDesugar +impl DesugarNext for ForLoopDesugar where I: TrustedRandomAccess + Iterator, { - #[inline] - fn setup(&mut self) { - let _ = self.iter.advance_by(0); - } - #[inline] fn next_spec(&mut self) -> Option { let idx = self.idx; @@ -81,11 +76,40 @@ where None } } +} +impl DesugarSetup for ForLoopDesugar +where + I: Iterator, +{ + #[inline] + default fn setup(&mut self) {} +} + +impl DesugarSetup for ForLoopDesugar +where + I: Iterator + TrustedRandomAccess + TrustedRandomAccessNeedsForwardSetup, +{ + #[inline] + fn setup(&mut self) { + let _ = self.iter.advance_by(0); + } +} + +impl DesugarCleanup for ForLoopDesugar +where + I: Iterator, +{ + #[inline] + default fn cleanup(&mut self) {} +} + +impl DesugarCleanup for ForLoopDesugar +where + I: Iterator + TrustedRandomAccessNeedsCleanup + TrustedRandomAccess, +{ #[inline] fn cleanup(&mut self) { - if I::NEEDS_CLEANUP { - self.iter.cleanup(self.idx, true); - } + self.iter.cleanup(self.idx, true); } } diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 3e4f1fb3cdf2b..410f6e00fe90f 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -383,14 +383,17 @@ pub use self::traits::FusedIterator; pub use self::traits::InPlaceIterable; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; -#[unstable(feature = "trusted_random_access", issue = "none")] -pub use self::traits::TrustedRandomAccess; #[unstable(feature = "trusted_step", issue = "85731")] pub use self::traits::TrustedStep; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, }; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::traits::{ + TrustedRandomAccess, TrustedRandomAccessNeedsCleanup, TrustedRandomAccessNeedsForwardSetup, + TrustedRandomAccessNeedsReverseSetup, +}; #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::adapters::zip; diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 11b98340545a8..dcf330827a72a 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -504,8 +504,6 @@ macro_rules! unsafe_range_trusted_random_access_impl { let _ = self.advance_back_by(num); } } - - const NEEDS_CLEANUP: bool = false; } )*) } diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index 26aa66bb45ba7..9ed50fdb2f885 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -21,4 +21,7 @@ pub use self::marker::InPlaceIterable; #[unstable(feature = "trusted_step", issue = "85731")] pub use self::marker::TrustedStep; #[unstable(feature = "trusted_random_access", issue = "none")] -pub use self::trusted_random_access::TrustedRandomAccess; +pub use self::trusted_random_access::{ + TrustedRandomAccess, TrustedRandomAccessNeedsCleanup, TrustedRandomAccessNeedsForwardSetup, + TrustedRandomAccessNeedsReverseSetup, +}; diff --git a/library/core/src/iter/traits/trusted_random_access.rs b/library/core/src/iter/traits/trusted_random_access.rs index 6c0fafde0160a..a33a08c1f20e9 100644 --- a/library/core/src/iter/traits/trusted_random_access.rs +++ b/library/core/src/iter/traits/trusted_random_access.rs @@ -55,11 +55,34 @@ pub unsafe trait TrustedRandomAccess: Sized { self.size_hint().0 } - const NEEDS_CLEANUP: bool; - fn cleanup(&mut self, num: usize, forward: bool); } +// The following marker traits exist because specializing on them currently is the only way to avoid +// emitting dead IR. Associated constants do not work because we currently don't have post-monomorphization +// DCE. +// +// Pulling in the setup and cleanup methods on every specialized `for _ in` loop leads to 10% IR bloat +// and LLVM won't eliminate it in debug mode. + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +#[rustc_specialization_trait] +#[marker] +pub unsafe trait TrustedRandomAccessNeedsCleanup {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +#[rustc_specialization_trait] +#[marker] +pub unsafe trait TrustedRandomAccessNeedsForwardSetup {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +#[rustc_specialization_trait] +#[marker] +pub unsafe trait TrustedRandomAccessNeedsReverseSetup {} + /// Like `Iterator::__iterator_get_unchecked`, but doesn't require the compiler to /// know that `U: TrustedRandomAccess`. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index daf3458ba51d8..b0a2063001672 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -186,6 +186,7 @@ #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] +#![feature(marker_trait_attr)] #![feature(min_specialization)] #![feature(mixed_integer_ops)] #![feature(must_not_suspend)] diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 58780c54382d1..b1da5826834f0 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1371,8 +1371,6 @@ impl FusedIterator for Windows<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { if forward { self.v = &self.v[num..]; @@ -1559,8 +1557,6 @@ impl FusedIterator for Chunks<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { if forward { let len = self.v.len(); @@ -1735,8 +1731,6 @@ impl FusedIterator for ChunksMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { let len = self.len(); let v = mem::replace(&mut self.v, &mut []); @@ -1904,8 +1898,6 @@ impl FusedIterator for ChunksExact<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { if forward { let start = self.chunk_size * num; @@ -2067,8 +2059,6 @@ impl FusedIterator for ChunksExactMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { let v = mem::replace(&mut self.v, &mut []); if forward { @@ -2319,8 +2309,6 @@ impl FusedIterator for ArrayChunks<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { self.iter.cleanup(num, forward); } @@ -2438,8 +2426,6 @@ impl FusedIterator for ArrayChunksMut<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { self.iter.cleanup(num, forward); } @@ -2612,8 +2598,6 @@ impl FusedIterator for RChunks<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { if forward { let end = self.v.len().saturating_sub(self.chunk_size * num); @@ -2791,8 +2775,6 @@ impl FusedIterator for RChunksMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { let len = self.len(); let v = mem::replace(&mut self.v, &mut []); @@ -2964,8 +2946,6 @@ impl FusedIterator for RChunksExact<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { if forward { let end = self.v.len() - (self.chunk_size * num); @@ -3131,8 +3111,6 @@ impl FusedIterator for RChunksExactMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { - const NEEDS_CLEANUP: bool = false; - fn cleanup(&mut self, num: usize, forward: bool) { let v = mem::replace(&mut self.v, &mut []); if forward { @@ -3148,8 +3126,6 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { - const NEEDS_CLEANUP: bool = false; - #[inline] fn cleanup(&mut self, num: usize, forward: bool) { if forward { @@ -3163,8 +3139,6 @@ unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { - const NEEDS_CLEANUP: bool = false; - #[inline] fn cleanup(&mut self, num: usize, forward: bool) { if forward { diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 214a93d4f5e1c..cb01bab909af6 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -348,8 +348,6 @@ unsafe impl TrustedLen for Bytes<'_> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for Bytes<'_> { - const NEEDS_CLEANUP: bool = false; - #[inline] fn cleanup(&mut self, num: usize, forward: bool) { self.0.cleanup(num, forward); From ffff1941ba0d6cc71a17a7f233f7bc2ff4a0ec07 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 20 Apr 2022 15:08:57 +0200 Subject: [PATCH 13/13] use separate methods for forward and backward cleanup This reduces the amount of IR generated when post-loop cleanup is needed --- .../alloc/src/collections/vec_deque/iter.rs | 12 +- .../src/collections/vec_deque/iter_mut.rs | 12 +- library/alloc/src/vec/into_iter.rs | 38 ++-- library/core/src/iter/adapters/cloned.rs | 9 +- library/core/src/iter/adapters/copied.rs | 9 +- library/core/src/iter/adapters/enumerate.rs | 9 +- library/core/src/iter/adapters/fuse.rs | 11 +- library/core/src/iter/adapters/map.rs | 9 +- library/core/src/iter/adapters/zip.rs | 16 +- library/core/src/iter/loop_desugar.rs | 2 +- library/core/src/iter/range.rs | 13 +- .../src/iter/traits/trusted_random_access.rs | 4 +- library/core/src/slice/iter.rs | 196 ++++++++++-------- library/core/src/str/iter.rs | 9 +- 14 files changed, 201 insertions(+), 148 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index 7f7d7e668a20f..efa0d3ea9a651 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -206,11 +206,11 @@ unsafe impl TrustedLen for Iter<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for Iter<'_, T> { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let _ = self.advance_by(num); - } else { - let _ = self.advance_back_by(num); - } + fn cleanup_front(&mut self, num: usize) { + let _ = self.advance_by(num); + } + + fn cleanup_back(&mut self, num: usize) { + let _ = self.advance_back_by(num); } } diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 09a75fc9b20ce..9de8d1643335e 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -155,11 +155,11 @@ unsafe impl TrustedLen for IterMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for IterMut<'_, T> { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let _ = self.advance_by(num); - } else { - let _ = self.advance_back_by(num); - } + fn cleanup_front(&mut self, num: usize) { + let _ = self.advance_by(num); + } + + fn cleanup_back(&mut self, num: usize) { + let _ = self.advance_back_by(num); } } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 6ca973761add7..82ccfeb4eebfd 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -289,27 +289,27 @@ unsafe impl TrustedRandomAccess for IntoIter where T: NonDrop, { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - if mem::size_of::() == 0 { - // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound - // effectively results in unsigned pointers representing positions 0..usize::MAX, - // which is valid for ZSTs. - self.ptr = unsafe { arith_offset(self.ptr as *const i8, num as isize) as *mut T } - } else { - // SAFETY: the caller must guarantee that `num` is in bounds - self.ptr = unsafe { self.ptr.add(num) }; - } + fn cleanup_front(&mut self, num: usize) { + if mem::size_of::() == 0 { + // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound + // effectively results in unsigned pointers representing positions 0..usize::MAX, + // which is valid for ZSTs. + self.ptr = unsafe { arith_offset(self.ptr as *const i8, num as isize) as *mut T } } else { - if mem::size_of::() == 0 { - // SAFETY: same as above - self.end = unsafe { - arith_offset(self.end as *const i8, num.wrapping_neg() as isize) as *mut T - } - } else { - // SAFETY: same as above - self.end = unsafe { self.end.offset(num.wrapping_neg() as isize) }; + // SAFETY: the caller must guarantee that `num` is in bounds + self.ptr = unsafe { self.ptr.add(num) }; + } + } + + fn cleanup_back(&mut self, num: usize) { + if mem::size_of::() == 0 { + // SAFETY: same as above + self.end = unsafe { + arith_offset(self.end as *const i8, num.wrapping_neg() as isize) as *mut T } + } else { + // SAFETY: same as above + self.end = unsafe { self.end.offset(num.wrapping_neg() as isize) }; } } } diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 15b3245ce62eb..b0c46b7eb5182 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -130,8 +130,13 @@ where I: TrustedRandomAccess, { #[inline] - fn cleanup(&mut self, num: usize, forward: bool) { - self.it.cleanup(num, forward); + fn cleanup_front(&mut self, num: usize) { + self.it.cleanup_front(num); + } + + #[inline] + fn cleanup_back(&mut self, num: usize) { + self.it.cleanup_back(num); } } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 47c77b1fe987a..49cb150bd6642 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -156,8 +156,13 @@ where I: TrustedRandomAccess, { #[inline] - fn cleanup(&mut self, num: usize, forward: bool) { - self.it.cleanup(num, forward); + fn cleanup_front(&mut self, num: usize) { + self.it.cleanup_front(num); + } + + #[inline] + fn cleanup_back(&mut self, num: usize) { + self.it.cleanup_back(num); } } diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index e26b1355f8d4d..5f0e3b968e829 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -240,8 +240,13 @@ where I: TrustedRandomAccess, { #[inline] - fn cleanup(&mut self, num: usize, forward: bool) { - self.iter.cleanup(num, forward); + fn cleanup_front(&mut self, num: usize) { + self.iter.cleanup_front(num); + } + + #[inline] + fn cleanup_back(&mut self, num: usize) { + self.iter.cleanup_back(num); } } diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 2835a50337f11..4d48937273e65 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -228,9 +228,16 @@ where I: TrustedRandomAccess, { #[inline] - fn cleanup(&mut self, num: usize, forward: bool) { + fn cleanup_front(&mut self, num: usize) { if let Some(iter) = self.iter.as_mut() { - iter.cleanup(num, forward); + iter.cleanup_front(num); + } + } + + #[inline] + fn cleanup_back(&mut self, num: usize) { + if let Some(iter) = self.iter.as_mut() { + iter.cleanup_back(num); } } } diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 742fe1b3c23e4..883afd1ee65a2 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -198,8 +198,13 @@ where I: TrustedRandomAccess, { #[inline] - fn cleanup(&mut self, num: usize, forward: bool) { - self.iter.cleanup(num, forward); + fn cleanup_front(&mut self, num: usize) { + self.iter.cleanup_front(num); + } + + #[inline] + fn cleanup_back(&mut self, num: usize) { + self.iter.cleanup_back(num); } } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 13de9fd823a76..de34cd2f2e3d5 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -217,7 +217,7 @@ where accum = f(accum, x); } // FIXME drop-guard or use ForLoopDesugar - self.cleanup(len, true); + self.cleanup_front(len); accum } @@ -236,7 +236,7 @@ where accum = f(accum, x)?; } // FIXME drop-guard or use ForLoopDesugar - self.cleanup(len, true); + self.cleanup_front(len); try { accum } } @@ -262,9 +262,14 @@ where A: TrustedRandomAccess, B: TrustedRandomAccess, { - fn cleanup(&mut self, num: usize, forward: bool) { - self.a.cleanup(num, forward); - self.b.cleanup(num, forward); + fn cleanup_front(&mut self, num: usize) { + self.a.cleanup_front(num); + self.b.cleanup_front(num); + } + + fn cleanup_back(&mut self, num: usize) { + self.a.cleanup_back(num); + self.b.cleanup_back(num); } } @@ -314,7 +319,6 @@ where { } - #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccessNeedsReverseSetup for Zip where Self: TrustedRandomAccess {} diff --git a/library/core/src/iter/loop_desugar.rs b/library/core/src/iter/loop_desugar.rs index 76d39368748cf..dd3c0ec649381 100644 --- a/library/core/src/iter/loop_desugar.rs +++ b/library/core/src/iter/loop_desugar.rs @@ -110,6 +110,6 @@ where { #[inline] fn cleanup(&mut self) { - self.iter.cleanup(self.idx, true); + self.iter.cleanup_front(self.idx); } } diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index dcf330827a72a..7afadb74cd50d 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -497,13 +497,14 @@ macro_rules! unsafe_range_trusted_random_access_impl { #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for ops::Range<$t> { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let _ = self.advance_by(num); - } else { - let _ = self.advance_back_by(num); - } + fn cleanup_front(&mut self, num: usize) { + let _ = self.advance_by(num); + } + + fn cleanup_back(&mut self, num: usize) { + let _ = self.advance_back_by(num); } + } )*) } diff --git a/library/core/src/iter/traits/trusted_random_access.rs b/library/core/src/iter/traits/trusted_random_access.rs index a33a08c1f20e9..eda1c5ff9392a 100644 --- a/library/core/src/iter/traits/trusted_random_access.rs +++ b/library/core/src/iter/traits/trusted_random_access.rs @@ -55,7 +55,9 @@ pub unsafe trait TrustedRandomAccess: Sized { self.size_hint().0 } - fn cleanup(&mut self, num: usize, forward: bool); + fn cleanup_front(&mut self, num: usize); + + fn cleanup_back(&mut self, num: usize); } // The following marker traits exist because specializing on them currently is the only way to avoid diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index b1da5826834f0..21d07479b03f6 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1371,12 +1371,12 @@ impl FusedIterator for Windows<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - self.v = &self.v[num..]; - } else { - self.v = &self.v[..self.v.len() - num]; - } + fn cleanup_front(&mut self, num: usize) { + self.v = &self.v[num..]; + } + + fn cleanup_back(&mut self, num: usize) { + self.v = &self.v[..self.v.len() - num]; } } @@ -1557,16 +1557,16 @@ impl FusedIterator for Chunks<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let len = self.v.len(); - let start = cmp::min(len, self.chunk_size * num); - self.v = &self.v[start..]; - } else { - let remaining = self.len() - num; - let end = remaining * self.chunk_size; - self.v = &self.v[..end]; - } + fn cleanup_front(&mut self, num: usize) { + let len = self.v.len(); + let start = cmp::min(len, self.chunk_size * num); + self.v = &self.v[start..]; + } + + fn cleanup_back(&mut self, num: usize) { + let remaining = self.len() - num; + let end = remaining * self.chunk_size; + self.v = &self.v[..end]; } } @@ -1731,17 +1731,18 @@ impl FusedIterator for ChunksMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { + fn cleanup_front(&mut self, num: usize) { + let v = mem::replace(&mut self.v, &mut []); + let start = self.chunk_size * num; + self.v = &mut v[start..]; + } + + fn cleanup_back(&mut self, num: usize) { let len = self.len(); let v = mem::replace(&mut self.v, &mut []); - if forward { - let start = self.chunk_size * num; - self.v = &mut v[start..]; - } else { - let remaining = len - num; - let end = remaining * self.chunk_size; - self.v = &mut v[..end]; - } + let remaining = len - num; + let end = remaining * self.chunk_size; + self.v = &mut v[..end]; } } @@ -1898,14 +1899,14 @@ impl FusedIterator for ChunksExact<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let start = self.chunk_size * num; - self.v = &self.v[start..]; - } else { - let end = self.v.len() - (self.chunk_size * num); - self.v = &self.v[..end]; - } + fn cleanup_front(&mut self, num: usize) { + let start = self.chunk_size * num; + self.v = &self.v[start..]; + } + + fn cleanup_back(&mut self, num: usize) { + let end = self.v.len() - (self.chunk_size * num); + self.v = &self.v[..end]; } } @@ -2059,15 +2060,16 @@ impl FusedIterator for ChunksExactMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { + fn cleanup_front(&mut self, num: usize) { let v = mem::replace(&mut self.v, &mut []); - if forward { - let start = self.chunk_size * num; - self.v = &mut v[start..]; - } else { - let end = v.len() - (self.chunk_size * num); - self.v = &mut v[..end]; - } + let start = self.chunk_size * num; + self.v = &mut v[start..]; + } + + fn cleanup_back(&mut self, num: usize) { + let v = mem::replace(&mut self.v, &mut []); + let end = v.len() - (self.chunk_size * num); + self.v = &mut v[..end]; } } @@ -2309,8 +2311,12 @@ impl FusedIterator for ArrayChunks<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { - fn cleanup(&mut self, num: usize, forward: bool) { - self.iter.cleanup(num, forward); + fn cleanup_front(&mut self, num: usize) { + self.iter.cleanup_front(num); + } + + fn cleanup_back(&mut self, num: usize) { + self.iter.cleanup_back(num); } } @@ -2426,8 +2432,12 @@ impl FusedIterator for ArrayChunksMut<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { - fn cleanup(&mut self, num: usize, forward: bool) { - self.iter.cleanup(num, forward); + fn cleanup_front(&mut self, num: usize) { + self.iter.cleanup_front(num); + } + + fn cleanup_back(&mut self, num: usize) { + self.iter.cleanup_back(num); } } @@ -2598,15 +2608,15 @@ impl FusedIterator for RChunks<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let end = self.v.len().saturating_sub(self.chunk_size * num); - self.v = &self.v[..end]; - } else { - let remainder = self.len() - num; - let start = self.v.len() - remainder * self.chunk_size; - self.v = &self.v[start..]; - } + fn cleanup_front(&mut self, num: usize) { + let end = self.v.len().saturating_sub(self.chunk_size * num); + self.v = &self.v[..end]; + } + + fn cleanup_back(&mut self, num: usize) { + let remainder = self.len() - num; + let start = self.v.len() - remainder * self.chunk_size; + self.v = &self.v[start..]; } } @@ -2775,17 +2785,18 @@ impl FusedIterator for RChunksMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { + fn cleanup_front(&mut self, num: usize) { + let v = mem::replace(&mut self.v, &mut []); + let end = v.len().saturating_sub(self.chunk_size * num); + self.v = &mut v[..end]; + } + + fn cleanup_back(&mut self, num: usize) { let len = self.len(); let v = mem::replace(&mut self.v, &mut []); - self.v = if forward { - let end = v.len().saturating_sub(self.chunk_size * num); - &mut v[..end] - } else { - let remainder = len - num; - let start = v.len() - remainder * self.chunk_size; - &mut v[start..] - }; + let remainder = len - num; + let start = v.len() - remainder * self.chunk_size; + self.v = &mut v[start..] } } @@ -2946,14 +2957,14 @@ impl FusedIterator for RChunksExact<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let end = self.v.len() - (self.chunk_size * num); - self.v = &self.v[..end]; - } else { - let start = self.chunk_size * num; - self.v = &self.v[start..]; - } + fn cleanup_front(&mut self, num: usize) { + let end = self.v.len() - (self.chunk_size * num); + self.v = &self.v[..end]; + } + + fn cleanup_back(&mut self, num: usize) { + let start = self.chunk_size * num; + self.v = &self.v[start..]; } } @@ -3111,15 +3122,16 @@ impl FusedIterator for RChunksExactMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { - fn cleanup(&mut self, num: usize, forward: bool) { + fn cleanup_front(&mut self, num: usize) { let v = mem::replace(&mut self.v, &mut []); - if forward { - let end = v.len() - (self.chunk_size * num); - self.v = &mut v[..end]; - } else { - let start = self.chunk_size * num; - self.v = &mut v[start..]; - } + let end = v.len() - (self.chunk_size * num); + self.v = &mut v[..end]; + } + + fn cleanup_back(&mut self, num: usize) { + let v = mem::replace(&mut self.v, &mut []); + let start = self.chunk_size * num; + self.v = &mut v[start..]; } } @@ -3127,12 +3139,13 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { #[inline] - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let _ = self.advance_by(num); - } else { - let _ = self.advance_back_by(num); - } + fn cleanup_front(&mut self, num: usize) { + let _ = self.advance_by(num); + } + + #[inline] + fn cleanup_back(&mut self, num: usize) { + let _ = self.advance_back_by(num); } } @@ -3140,12 +3153,13 @@ unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { #[inline] - fn cleanup(&mut self, num: usize, forward: bool) { - if forward { - let _ = self.advance_by(num); - } else { - let _ = self.advance_back_by(num); - } + fn cleanup_front(&mut self, num: usize) { + let _ = self.advance_by(num); + } + + #[inline] + fn cleanup_back(&mut self, num: usize) { + let _ = self.advance_back_by(num); } } diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index cb01bab909af6..39a45f630d029 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -349,8 +349,13 @@ unsafe impl TrustedLen for Bytes<'_> {} #[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for Bytes<'_> { #[inline] - fn cleanup(&mut self, num: usize, forward: bool) { - self.0.cleanup(num, forward); + fn cleanup_front(&mut self, num: usize) { + self.0.cleanup_front(num); + } + + #[inline] + fn cleanup_back(&mut self, num: usize) { + self.0.cleanup_back(num); } }