diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-06-15 17:52:35 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-06-15 17:52:35 +0200 |
| commit | f530016f50799aba1a39df2fb881324e6e9193aa (patch) | |
| tree | 58e9b92529ff3ecc2491630730dad51483ef8b9d | |
| parent | 4996b56ba9647d149265d03dcbd9ab837af3a1bb (diff) | |
| parent | 211376927d02a032987d61a445648e7c1e6cc4ca (diff) | |
Rollup merge of #111212 - nicklimmm:issue-107896-fix, r=pnkfelix
Add casting suggestion when assigning negative 2's complement bin or hex literal to a size compatible signed integer Fixes #107896 The issue stated the case for `iX::MIN` variants. This PR extends the cases for other negative values (in the 2's complement). Leveraged sign bits to detect such cases. Example cases: - <img width="845" alt="image" src="https://user-images.githubusercontent.com/65026286/236289682-19859f59-a9c5-48c5-b15f-78a935fbfcec.png"> - <img width="831" alt="image" src="https://user-images.githubusercontent.com/65026286/236289805-5b16488d-9138-4363-a1b6-a5c027c50aba.png"> - <img width="912" alt="image" src="https://user-images.githubusercontent.com/65026286/236290065-685a9777-034b-4def-83a8-cc4e20b1ed0c.png">
| -rw-r--r-- | compiler/rustc_lint/messages.ftl | 1 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lints.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/types.rs | 49 | ||||
| -rw-r--r-- | tests/ui/lint/type-overflow.stderr | 28 |
4 files changed, 89 insertions, 6 deletions
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 5e13ee7b8a4..c66fcdec716 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -425,6 +425,7 @@ lint_overflowing_bin_hex = literal out of range for `{$ty}` .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` .positive_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` .suggestion = consider using the type `{$suggestion_ty}` instead + .sign_bit_suggestion = to use as a negative number (decimal `{$negative_val}`), consider using the type `{$uint_ty}` for the literal and cast it to `{$int_ty}` .help = consider using the type `{$suggestion_ty}` instead lint_overflowing_int = literal out of range for `{$ty}` diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index e990c771bdf..89fa5713b73 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1342,6 +1342,8 @@ pub struct OverflowingBinHex<'a> { pub sign: OverflowingBinHexSign, #[subdiagnostic] pub sub: Option<OverflowingBinHexSub<'a>>, + #[subdiagnostic] + pub sign_bit_sub: Option<OverflowingBinHexSignBitSub<'a>>, } pub enum OverflowingBinHexSign { @@ -1386,6 +1388,21 @@ pub enum OverflowingBinHexSub<'a> { Help { suggestion_ty: &'a str }, } +#[derive(Subdiagnostic)] +#[suggestion( + lint_sign_bit_suggestion, + code = "{lit_no_suffix}{uint_ty} as {int_ty}", + applicability = "maybe-incorrect" +)] +pub struct OverflowingBinHexSignBitSub<'a> { + #[primary_span] + pub span: Span, + pub lit_no_suffix: &'a str, + pub negative_val: String, + pub uint_ty: &'a str, + pub int_ty: &'a str, +} + #[derive(LintDiagnostic)] #[diag(lint_overflowing_int)] #[note] diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 264a59c5585..ec9e7c7fdae 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -3,9 +3,10 @@ use crate::{ lints::{ AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion, - OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSub, - OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, - RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange, VariantSizeDifferencesDiag, + OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub, + OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, + OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange, + VariantSizeDifferencesDiag, }, }; use crate::{LateContext, LateLintPass, LintContext}; @@ -297,10 +298,50 @@ fn report_bin_hex_error( } }, ); + let sign_bit_sub = (!negative) + .then(|| { + let ty::Int(int_ty) = cx.typeck_results().node_type(expr.hir_id).kind() else { + return None; + }; + + let Some(bit_width) = int_ty.bit_width() else { + return None; // isize case + }; + + // Skip if sign bit is not set + if (val & (1 << (bit_width - 1))) == 0 { + return None; + } + + let lit_no_suffix = + if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { + repr_str.split_at(pos).0 + } else { + &repr_str + }; + + Some(OverflowingBinHexSignBitSub { + span: expr.span, + lit_no_suffix, + negative_val: actually.clone(), + int_ty: int_ty.name_str(), + uint_ty: int_ty.to_unsigned().name_str(), + }) + }) + .flatten(); + cx.emit_spanned_lint( OVERFLOWING_LITERALS, expr.span, - OverflowingBinHex { ty: t, lit: repr_str.clone(), dec: val, actually, sign, sub }, + OverflowingBinHex { + ty: t, + lit: repr_str.clone(), + dec: val, + actually, + sign, + sub, + sign_bit_sub, + }, ) } diff --git a/tests/ui/lint/type-overflow.stderr b/tests/ui/lint/type-overflow.stderr index 62cb1f7f4aa..e7c90dcc81b 100644 --- a/tests/ui/lint/type-overflow.stderr +++ b/tests/ui/lint/type-overflow.stderr @@ -16,17 +16,33 @@ warning: literal out of range for `i8` --> $DIR/type-overflow.rs:10:16 | LL | let fail = 0b1000_0001i8; - | ^^^^^^^^^^^^^ help: consider using the type `u8` instead: `0b1000_0001u8` + | ^^^^^^^^^^^^^ | = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into the type `i8` and will become `-127i8` +help: consider using the type `u8` instead + | +LL | let fail = 0b1000_0001u8; + | ~~~~~~~~~~~~~ +help: to use as a negative number (decimal `-127`), consider using the type `u8` for the literal and cast it to `i8` + | +LL | let fail = 0b1000_0001u8 as i8; + | ~~~~~~~~~~~~~~~~~~~ warning: literal out of range for `i64` --> $DIR/type-overflow.rs:12:16 | LL | let fail = 0x8000_0000_0000_0000i64; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the type `u64` instead: `0x8000_0000_0000_0000u64` + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into the type `i64` and will become `-9223372036854775808i64` +help: consider using the type `u64` instead + | +LL | let fail = 0x8000_0000_0000_0000u64; + | ~~~~~~~~~~~~~~~~~~~~~~~~ +help: to use as a negative number (decimal `-9223372036854775808`), consider using the type `u64` for the literal and cast it to `i64` + | +LL | let fail = 0x8000_0000_0000_0000u64 as i64; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ warning: literal out of range for `u32` --> $DIR/type-overflow.rs:14:16 @@ -44,6 +60,10 @@ LL | let fail: i128 = 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 `i128` and will become `-170141183460469231731687303715884105728i128` = help: consider using the type `u128` instead +help: to use as a negative number (decimal `-170141183460469231731687303715884105728`), consider using the type `u128` for the literal and cast it to `i128` + | +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 @@ -53,6 +73,10 @@ 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: 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 |
