Skip to content

Commit 8cbffc5

Browse files
committedJun 5, 2016
Auto merge of #33905 - eddyb:mir-overflow, r=nikomatsakis
[MIR] Implement overflow checking The initial set of changes is from @Aatch's #33255 PR, rebased on master, plus: Added an `Assert` terminator to MIR, to simplify working with overflow and bounds checks. With this terminator, error cases can be accounted for directly, instead of looking for lang item calls. It also keeps the MIR slimmer, with no extra explicit blocks for the actual panic calls. Warnings can be produced when the `Assert` is known to always panic at runtime, e.g.: ```rust warning: index out of bounds: the len is 1 but the index is 3 --> <anon>:1:14 1 |> fn main() { &[std::io::stdout()][3]; } |> ^^^^^^^^^^^^^^^^^^^^^^ ``` Generalized the `OperandValue::FatPtr` optimization to any aggregate pair of immediates. This allows us to generate the same IR for overflow checks as old trans, not something worse. For example, addition on `i16` calls `llvm.sadd.with.overflow.i16`, which returns `{i16, i1}`. However, the Rust type `(i16, bool)`, has to be `{i16, i8}`, only an immediate `bool` is `i1`. But if we split the pair into an `i16` and an `i1`, we can pass them around as such for free. The latest addition is a rebase of #34054, updated to work for pairs too. Closes #34054, fixes #33873. Last but not least, the `#[rustc_inherit_overflow_checks]` attribute was introduced to control the overflow checking behavior of generic or `#[inline]` functions, when translated in another crate. It is **not** intended to be used by crates other than `libcore`, which is in the unusual position of being distributed as only an optimized build with no checks, even when used from debug mode. Before MIR-based translation, this worked out fine, as the decision for overflow was made at translation time, in the crate being compiled, but MIR stored in `rlib` has to contain the checks. To avoid always generating the checks and slowing everything down, a decision was made to use an attribute in the few spots of `libcore` that need it (see #33255 for previous discussion): * `core::ops::{Add, Sub, Mul, Neg, Shl, Shr}` implementations for integers, which have `#[inline]` methods and can be used in generic abstractions from other crates * `core::ops::{Add, Sub, Mul, Neg, Shl, Shr}Assign` same as above, for augmented assignment * `pow` and `abs` methods on integers, which intentionally piggy-back on built-in multiplication and negation, respectively, to get overflow checks * `core::iter::{Iterator, Chain, Peek}::count` and `core::iter::Enumerate::{next, nth}`, also documented as panicking on overflow, from addition, counting elements of an iterator in an `usize`
2 parents 22b36c7 + cee244d commit 8cbffc5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1363
-431
lines changed
 

‎src/libcore/iter/iterator.rs

+1
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ pub trait Iterator {
172172
/// assert_eq!(a.iter().count(), 5);
173173
/// ```
174174
#[inline]
175+
#[rustc_inherit_overflow_checks]
175176
#[stable(feature = "rust1", since = "1.0.0")]
176177
fn count(self) -> usize where Self: Sized {
177178
// Might overflow.

‎src/libcore/iter/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ impl<A, B> Iterator for Chain<A, B> where
510510
}
511511

512512
#[inline]
513+
#[rustc_inherit_overflow_checks]
513514
fn count(self) -> usize {
514515
match self.state {
515516
ChainState::Both => self.a.count() + self.b.count(),
@@ -932,6 +933,7 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
932933
///
933934
/// Might panic if the index of the element overflows a `usize`.
934935
#[inline]
936+
#[rustc_inherit_overflow_checks]
935937
fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
936938
self.iter.next().map(|a| {
937939
let ret = (self.count, a);
@@ -947,6 +949,7 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
947949
}
948950

949951
#[inline]
952+
#[rustc_inherit_overflow_checks]
950953
fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> {
951954
self.iter.nth(n).map(|a| {
952955
let i = self.count + n;
@@ -1008,6 +1011,7 @@ impl<I: Iterator> Iterator for Peekable<I> {
10081011
}
10091012

10101013
#[inline]
1014+
#[rustc_inherit_overflow_checks]
10111015
fn count(self) -> usize {
10121016
(if self.peeked.is_some() { 1 } else { 0 }) + self.iter.count()
10131017
}

0 commit comments

Comments
 (0)