Error when using signed integer minimum value
I tried this code:
fn main() {
let x: i8 = -128_i8;
}
I expected to see this happen: Code should compile as the i8 has the range [-128..127]
Instead, this happened: gcc-test.rs:2:18: error: integer overflows the respective type ‘i8’ 2 | let x: i8 = -128_i8;
Meta
- What version of Rust GCC were you using, git sha if possible. c0f11672d760513256997f325da678016d13f677
Note that this is technically an overflow in Rust, that much is right: -128_i8 is the negation of the integer literal 128_i8, and 128_i8 is out of range for type i8. -128_i8 is not a literal in its own right. However, Rust has special handling to deal with this and not regard it as an error. The way this works in Rust is that:
- Out of range literals are at the core level valid. Literals are parsed as
u128constants and then converted as if by a numeric cast to the requested type. The cast is specified to truncate. This means that the value of128_i8is128, converted toi8, which results in -128. (Ref: https://doc.rust-lang.org/stable/reference/expressions/literal-expr.html#integer-literal-expressions) - Negation of literals is treated as a special case. Negation is one of the operations that can result in an overflow error in debug mode, but negation of literals is a special case where overflow is always allowed. The negation of an
i8value of-128would ordinarily overflow and result in an error in debug builds, but the negation of a literal with a value of-128leaves the value unchanged, it produces a constant that still has the same value-128. (Ref: https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#overflow) - There is a lint rule
overflowing_literals, optional but enabled by default, to flag out-of-range literals. However, despite the name, it does not actually check for literals. This lint rule too has a special case to deal with this: if a literal is negated, rather than checking that the literal's value is in range, it checks that the negation of the literal's value is in range (or, in other words, it checks thatvalue <= type::MAX + 1rather thanvalue <= type::MAX).
You can see this if you look closely: with the rustc compiler, if you change the code to
fn main() {
let x: i8 = -200_i8;
}
the resulting note points out that 200 is out of range, not that -200 is out of range.