Rollup merge of #135249 - s-cerevisiae:fix-overflowing-literals-help, r=chenyukang
Fix overflows in the implementation of `overflowing_literals` lint's help This PR fixes two overflow problems that cause the `overflowing_literals` lint to behave incorrectly in some edge cases. 1. When an integer literal is between `i128::MAX` and `u128::MAX`, an overflowing `as` cast can cause the suggested type to be overly small. It's fixed by using checked type conversion and returning `u128` when it's the only choice. (Fixes #135248) 2. When an integer literal is `i128::MIN` but is of a smaller type, an overflowing negation cause the compiler to panic in debug build. Fixed by checking the number size beforehand and `wrapping_neg`. (Fixes #131849) Edit: extracted the type conversion part into a standalone function to separate the concern of overflowing.
This commit is contained in:
commit
8f9ccc5d1b
3 changed files with 94 additions and 16 deletions
|
@ -204,20 +204,35 @@ fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static
|
|||
match t.kind() {
|
||||
ty::Uint(ty::UintTy::Usize) | ty::Int(ty::IntTy::Isize) => None,
|
||||
ty::Uint(_) => Some(Integer::fit_unsigned(val).uint_ty_str()),
|
||||
ty::Int(_) if negative => Some(Integer::fit_signed(-(val as i128)).int_ty_str()),
|
||||
ty::Int(int) => {
|
||||
let signed = Integer::fit_signed(val as i128);
|
||||
let unsigned = Integer::fit_unsigned(val);
|
||||
Some(if Some(unsigned.size().bits()) == int.bit_width() {
|
||||
unsigned.uint_ty_str()
|
||||
ty::Int(_) => {
|
||||
let signed = literal_to_i128(val, negative).map(Integer::fit_signed);
|
||||
if negative {
|
||||
signed.map(Integer::int_ty_str)
|
||||
} else {
|
||||
signed.int_ty_str()
|
||||
})
|
||||
let unsigned = Integer::fit_unsigned(val);
|
||||
Some(if let Some(signed) = signed {
|
||||
if unsigned.size() < signed.size() {
|
||||
unsigned.uint_ty_str()
|
||||
} else {
|
||||
signed.int_ty_str()
|
||||
}
|
||||
} else {
|
||||
unsigned.uint_ty_str()
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn literal_to_i128(val: u128, negative: bool) -> Option<i128> {
|
||||
if negative {
|
||||
(val <= i128::MAX as u128 + 1).then(|| val.wrapping_neg() as i128)
|
||||
} else {
|
||||
val.try_into().ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_int_literal<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
type_limits: &TypeLimits,
|
||||
|
|
|
@ -3,20 +3,46 @@
|
|||
|
||||
fn main() {
|
||||
let error = 255i8; //~WARNING literal out of range for `i8`
|
||||
//~^ HELP consider using the type `u8` instead
|
||||
|
||||
let ok = 0b1000_0001; // should be ok -> i32
|
||||
let ok = 0b0111_1111i8; // should be ok -> 127i8
|
||||
|
||||
let fail = 0b1000_0001i8; //~WARNING literal out of range for `i8`
|
||||
//~^ HELP consider using the type `u8` instead
|
||||
//~| HELP consider using the type `u8` for the literal and cast it to `i8`
|
||||
|
||||
let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for `i64`
|
||||
//~^ HELP consider using the type `u64` instead
|
||||
//~| HELP consider using the type `u64` for the literal and cast it to `i64`
|
||||
|
||||
let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for `u32`
|
||||
//~^ HELP consider using the type `u64` instead
|
||||
|
||||
let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
|
||||
//~^ WARNING literal out of range for `i128`
|
||||
//~| HELP consider using the type `u128` instead
|
||||
//~| HELP consider using the type `u128` for the literal and cast it to `i128`
|
||||
|
||||
let fail = 0x8000_0000_0000_0000_0000_0000_0000_0000;
|
||||
//~^ WARNING literal out of range for `i32`
|
||||
//~| HELP consider using the type `u128` instead
|
||||
|
||||
let fail = -0x8000_0000_0000_0000_0000_0000_0000_0000; // issue #131849
|
||||
//~^ WARNING literal out of range for `i32`
|
||||
//~| HELP consider using the type `i128` instead
|
||||
|
||||
let fail = -0x8000_0000_0000_0000_0000_0000_0000_0001i128;
|
||||
//~^ WARNING literal out of range for `i128`
|
||||
|
||||
let fail = 340282366920938463463374607431768211455i8;
|
||||
//~^ WARNING literal out of range for `i8`
|
||||
//~| HELP consider using the type `u128` instead
|
||||
|
||||
let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for `i32`
|
||||
//~| HELP consider using the type `u64` instead
|
||||
//~| HELP
|
||||
|
||||
let fail = -0b1111_1111i8; //~WARNING literal out of range for `i8`
|
||||
//~| HELP consider using the type `i16` instead
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ LL | #![warn(overflowing_literals)]
|
|||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: literal out of range for `i8`
|
||||
--> $DIR/type-overflow.rs:10:16
|
||||
--> $DIR/type-overflow.rs:11:16
|
||||
|
|
||||
LL | let fail = 0b1000_0001i8;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
@ -29,7 +29,7 @@ LL | let fail = 0b1000_0001u8 as i8;
|
|||
| ~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
warning: literal out of range for `i64`
|
||||
--> $DIR/type-overflow.rs:12:16
|
||||
--> $DIR/type-overflow.rs:15:16
|
||||
|
|
||||
LL | let fail = 0x8000_0000_0000_0000i64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -45,7 +45,7 @@ LL | let fail = 0x8000_0000_0000_0000u64 as i64;
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
warning: literal out of range for `u32`
|
||||
--> $DIR/type-overflow.rs:14:16
|
||||
--> $DIR/type-overflow.rs:19:16
|
||||
|
|
||||
LL | let fail = 0x1_FFFF_FFFFu32;
|
||||
| ^^^^^^^^^^^^^^^^ help: consider using the type `u64` instead: `0x1_FFFF_FFFFu64`
|
||||
|
@ -53,7 +53,7 @@ LL | let fail = 0x1_FFFF_FFFFu32;
|
|||
= note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into the type `u32` and will become `4294967295u32`
|
||||
|
||||
warning: literal out of range for `i128`
|
||||
--> $DIR/type-overflow.rs:16:22
|
||||
--> $DIR/type-overflow.rs:22:22
|
||||
|
|
||||
LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -66,20 +66,57 @@ LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000u128 as i128;
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
warning: literal out of range for `i32`
|
||||
--> $DIR/type-overflow.rs:19:16
|
||||
--> $DIR/type-overflow.rs:27:16
|
||||
|
|
||||
LL | let fail = 0x8000_0000_0000_0000_0000_0000_0000_0000;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i32` and will become `0i32`
|
||||
= help: consider using the type `u128` instead
|
||||
|
||||
warning: literal out of range for `i32`
|
||||
--> $DIR/type-overflow.rs:31:17
|
||||
|
|
||||
LL | let fail = -0x8000_0000_0000_0000_0000_0000_0000_0000; // issue #131849
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i32`
|
||||
= note: and the value `-0x8000_0000_0000_0000_0000_0000_0000_0000` will become `0i32`
|
||||
= help: consider using the type `i128` instead
|
||||
|
||||
warning: literal out of range for `i128`
|
||||
--> $DIR/type-overflow.rs:35:17
|
||||
|
|
||||
LL | let fail = -0x8000_0000_0000_0000_0000_0000_0000_0001i128;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0001i128` (decimal `170141183460469231731687303715884105729`) does not fit into the type `i128`
|
||||
= note: and the value `-0x8000_0000_0000_0000_0000_0000_0000_0001i128` will become `170141183460469231731687303715884105727i128`
|
||||
|
||||
warning: literal out of range for `i8`
|
||||
--> $DIR/type-overflow.rs:38:16
|
||||
|
|
||||
LL | let fail = 340282366920938463463374607431768211455i8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `340282366920938463463374607431768211455i8` does not fit into the type `i8` whose range is `-128..=127`
|
||||
= help: consider using the type `u128` instead
|
||||
|
||||
warning: literal out of range for `i32`
|
||||
--> $DIR/type-overflow.rs:42:16
|
||||
|
|
||||
LL | let fail = 0x8FFF_FFFF_FFFF_FFFE;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into the type `i32` and will become `-2i32`
|
||||
= help: consider using the type `i128` instead
|
||||
= help: consider using the type `u64` instead
|
||||
help: to use as a negative number (decimal `-2`), consider using the type `u32` for the literal and cast it to `i32`
|
||||
|
|
||||
LL | let fail = 0x8FFF_FFFF_FFFF_FFFEu32 as i32;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
warning: literal out of range for `i8`
|
||||
--> $DIR/type-overflow.rs:21:17
|
||||
--> $DIR/type-overflow.rs:46:17
|
||||
|
|
||||
LL | let fail = -0b1111_1111i8;
|
||||
| ^^^^^^^^^^^^^ help: consider using the type `i16` instead: `0b1111_1111i16`
|
||||
|
@ -87,5 +124,5 @@ LL | let fail = -0b1111_1111i8;
|
|||
= note: the literal `0b1111_1111i8` (decimal `255`) does not fit into the type `i8`
|
||||
= note: and the value `-0b1111_1111i8` will become `1i8`
|
||||
|
||||
warning: 7 warnings emitted
|
||||
warning: 11 warnings emitted
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue