diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 24ef8a6e01ac2..0ea59a74abd59 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2737,9 +2737,17 @@ impl Iterator for ops::Range where #[inline] fn next(&mut self) -> Option { - if self.start < self.end { - let mut n = &self.start + &A::one(); - mem::swap(&mut n, &mut self.start); + // FIXME #24660: this may start returning Some after returning + // None if the + overflows. This is OK per Iterator's + // definition, but it would be really nice for a core iterator + // like `x..y` to be as well behaved as + // possible. Unfortunately, for types like `i32`, LLVM + // mishandles the version that places the mutation inside the + // `if`: it seems to optimise the `Option` in a way that + // confuses it. + let mut n = &self.start + &A::one(); + mem::swap(&mut n, &mut self.start); + if n < self.end { Some(n) } else { None diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index a56820c61ccbb..9c2a96657a5cc 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -932,3 +932,10 @@ fn bench_max(b: &mut Bencher) { it.map(scatter).max() }) } + +#[bench] +fn bench_range_constant_fold(b: &mut Bencher) { + // this should be constant-folded to just '1000', and so this + // benchmark should run quickly... + b.iter(|| (0..1000).count()) +}