Skip to content

Commit f530016

Browse files
authored
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">
2 parents 4996b56 + 2113769 commit f530016

File tree

4 files changed

+89
-6
lines changed

4 files changed

+89
-6
lines changed

compiler/rustc_lint/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ lint_overflowing_bin_hex = literal out of range for `{$ty}`
425425
.negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}`
426426
.positive_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}`
427427
.suggestion = consider using the type `{$suggestion_ty}` instead
428+
.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}`
428429
.help = consider using the type `{$suggestion_ty}` instead
429430
430431
lint_overflowing_int = literal out of range for `{$ty}`

compiler/rustc_lint/src/lints.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,8 @@ pub struct OverflowingBinHex<'a> {
13421342
pub sign: OverflowingBinHexSign,
13431343
#[subdiagnostic]
13441344
pub sub: Option<OverflowingBinHexSub<'a>>,
1345+
#[subdiagnostic]
1346+
pub sign_bit_sub: Option<OverflowingBinHexSignBitSub<'a>>,
13451347
}
13461348

13471349
pub enum OverflowingBinHexSign {
@@ -1386,6 +1388,21 @@ pub enum OverflowingBinHexSub<'a> {
13861388
Help { suggestion_ty: &'a str },
13871389
}
13881390

1391+
#[derive(Subdiagnostic)]
1392+
#[suggestion(
1393+
lint_sign_bit_suggestion,
1394+
code = "{lit_no_suffix}{uint_ty} as {int_ty}",
1395+
applicability = "maybe-incorrect"
1396+
)]
1397+
pub struct OverflowingBinHexSignBitSub<'a> {
1398+
#[primary_span]
1399+
pub span: Span,
1400+
pub lit_no_suffix: &'a str,
1401+
pub negative_val: String,
1402+
pub uint_ty: &'a str,
1403+
pub int_ty: &'a str,
1404+
}
1405+
13891406
#[derive(LintDiagnostic)]
13901407
#[diag(lint_overflowing_int)]
13911408
#[note]

compiler/rustc_lint/src/types.rs

+45-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use crate::{
33
lints::{
44
AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
55
InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion,
6-
OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSub,
7-
OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt,
8-
RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange, VariantSizeDifferencesDiag,
6+
OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub,
7+
OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral,
8+
OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange,
9+
VariantSizeDifferencesDiag,
910
},
1011
};
1112
use crate::{LateContext, LateLintPass, LintContext};
@@ -297,10 +298,50 @@ fn report_bin_hex_error(
297298
}
298299
},
299300
);
301+
let sign_bit_sub = (!negative)
302+
.then(|| {
303+
let ty::Int(int_ty) = cx.typeck_results().node_type(expr.hir_id).kind() else {
304+
return None;
305+
};
306+
307+
let Some(bit_width) = int_ty.bit_width() else {
308+
return None; // isize case
309+
};
310+
311+
// Skip if sign bit is not set
312+
if (val & (1 << (bit_width - 1))) == 0 {
313+
return None;
314+
}
315+
316+
let lit_no_suffix =
317+
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
318+
repr_str.split_at(pos).0
319+
} else {
320+
&repr_str
321+
};
322+
323+
Some(OverflowingBinHexSignBitSub {
324+
span: expr.span,
325+
lit_no_suffix,
326+
negative_val: actually.clone(),
327+
int_ty: int_ty.name_str(),
328+
uint_ty: int_ty.to_unsigned().name_str(),
329+
})
330+
})
331+
.flatten();
332+
300333
cx.emit_spanned_lint(
301334
OVERFLOWING_LITERALS,
302335
expr.span,
303-
OverflowingBinHex { ty: t, lit: repr_str.clone(), dec: val, actually, sign, sub },
336+
OverflowingBinHex {
337+
ty: t,
338+
lit: repr_str.clone(),
339+
dec: val,
340+
actually,
341+
sign,
342+
sub,
343+
sign_bit_sub,
344+
},
304345
)
305346
}
306347

tests/ui/lint/type-overflow.stderr

+26-2
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,33 @@ warning: literal out of range for `i8`
1616
--> $DIR/type-overflow.rs:10:16
1717
|
1818
LL | let fail = 0b1000_0001i8;
19-
| ^^^^^^^^^^^^^ help: consider using the type `u8` instead: `0b1000_0001u8`
19+
| ^^^^^^^^^^^^^
2020
|
2121
= note: the literal `0b1000_0001i8` (decimal `129`) does not fit into the type `i8` and will become `-127i8`
22+
help: consider using the type `u8` instead
23+
|
24+
LL | let fail = 0b1000_0001u8;
25+
| ~~~~~~~~~~~~~
26+
help: to use as a negative number (decimal `-127`), consider using the type `u8` for the literal and cast it to `i8`
27+
|
28+
LL | let fail = 0b1000_0001u8 as i8;
29+
| ~~~~~~~~~~~~~~~~~~~
2230

2331
warning: literal out of range for `i64`
2432
--> $DIR/type-overflow.rs:12:16
2533
|
2634
LL | let fail = 0x8000_0000_0000_0000i64;
27-
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the type `u64` instead: `0x8000_0000_0000_0000u64`
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^
2836
|
2937
= note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into the type `i64` and will become `-9223372036854775808i64`
38+
help: consider using the type `u64` instead
39+
|
40+
LL | let fail = 0x8000_0000_0000_0000u64;
41+
| ~~~~~~~~~~~~~~~~~~~~~~~~
42+
help: to use as a negative number (decimal `-9223372036854775808`), consider using the type `u64` for the literal and cast it to `i64`
43+
|
44+
LL | let fail = 0x8000_0000_0000_0000u64 as i64;
45+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3046

3147
warning: literal out of range for `u32`
3248
--> $DIR/type-overflow.rs:14:16
@@ -44,6 +60,10 @@ LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
4460
|
4561
= note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i128` and will become `-170141183460469231731687303715884105728i128`
4662
= help: consider using the type `u128` instead
63+
help: to use as a negative number (decimal `-170141183460469231731687303715884105728`), consider using the type `u128` for the literal and cast it to `i128`
64+
|
65+
LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000u128 as i128;
66+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4767

4868
warning: literal out of range for `i32`
4969
--> $DIR/type-overflow.rs:19:16
@@ -53,6 +73,10 @@ LL | let fail = 0x8FFF_FFFF_FFFF_FFFE;
5373
|
5474
= note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into the type `i32` and will become `-2i32`
5575
= help: consider using the type `i128` instead
76+
help: to use as a negative number (decimal `-2`), consider using the type `u32` for the literal and cast it to `i32`
77+
|
78+
LL | let fail = 0x8FFF_FFFF_FFFF_FFFEu32 as i32;
79+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5680

5781
warning: literal out of range for `i8`
5882
--> $DIR/type-overflow.rs:21:17

0 commit comments

Comments
 (0)