Skip to content

Commit 97b7c76

Browse files
committed
Work-around optimiser deficiencies in Range iterator.
The conditional mutation of the previous implementation resulted in poor code, making it unconditional makes `Range` less well behaved as an Iterator (but still legal) but also makes it fast. The intention is that this change will be reverted when rustc/LLVM handle the best-behaved implementation better. cc #24660
1 parent 7397bdc commit 97b7c76

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

src/libcore/iter.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2737,9 +2737,17 @@ impl<A: Step + One> Iterator for ops::Range<A> where
27372737

27382738
#[inline]
27392739
fn next(&mut self) -> Option<A> {
2740-
if self.start < self.end {
2741-
let mut n = &self.start + &A::one();
2742-
mem::swap(&mut n, &mut self.start);
2740+
// FIXME #24660: this may start returning Some after returning
2741+
// None if the + overflows. This is OK per Iterator's
2742+
// definition, but it would be really nice for a core iterator
2743+
// like `x..y` to be as well behaved as
2744+
// possible. Unfortunately, for types like `i32`, LLVM
2745+
// mishandles the version that places the mutation inside the
2746+
// `if`: it seems to optimise the `Option<i32>` in a way that
2747+
// confuses it.
2748+
let mut n = &self.start + &A::one();
2749+
mem::swap(&mut n, &mut self.start);
2750+
if n < self.end {
27432751
Some(n)
27442752
} else {
27452753
None

src/libcoretest/iter.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,3 +932,10 @@ fn bench_max(b: &mut Bencher) {
932932
it.map(scatter).max()
933933
})
934934
}
935+
936+
#[bench]
937+
fn bench_range_constant_fold(b: &mut Bencher) {
938+
// this should be constant-folded to just '1000', and so this
939+
// benchmark should run quickly...
940+
b.iter(|| (0..1000).count())
941+
}

0 commit comments

Comments
 (0)