Rollup merge of #109554 - MU001999:master, r=WaffleLapkin

Suggest ..= when someone tries to create an overflowing range

Fixes #109529
This commit is contained in:
Matthias Krüger 2023-03-29 21:19:48 +02:00 committed by GitHub
commit 83573a3776
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 94 additions and 15 deletions

View File

@ -197,7 +197,9 @@ lint_drop_glue =
types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped
lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}` lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}`
.suggestion = use an inclusive range instead
lint_range_use_inclusive_range = use an inclusive range instead
lint_overflowing_bin_hex = literal out of range for `{$ty}` lint_overflowing_bin_hex = literal out of range for `{$ty}`
.negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`

View File

@ -1210,11 +1210,33 @@ impl<'a> DecorateLint<'a, ()> for DropGlue<'_> {
#[diag(lint_range_endpoint_out_of_range)] #[diag(lint_range_endpoint_out_of_range)]
pub struct RangeEndpointOutOfRange<'a> { pub struct RangeEndpointOutOfRange<'a> {
pub ty: &'a str, pub ty: &'a str,
#[suggestion(code = "{start}..={literal}{suffix}", applicability = "machine-applicable")] #[subdiagnostic]
pub suggestion: Span, pub sub: UseInclusiveRange<'a>,
pub start: String, }
pub literal: u128,
pub suffix: &'a str, #[derive(Subdiagnostic)]
pub enum UseInclusiveRange<'a> {
#[suggestion(
lint_range_use_inclusive_range,
code = "{start}..={literal}{suffix}",
applicability = "machine-applicable"
)]
WithoutParen {
#[primary_span]
sugg: Span,
start: String,
literal: u128,
suffix: &'a str,
},
#[multipart_suggestion(lint_range_use_inclusive_range, applicability = "machine-applicable")]
WithParen {
#[suggestion_part(code = "=")]
eq_sugg: Span,
#[suggestion_part(code = "{literal}{suffix}")]
lit_sugg: Span,
literal: u128,
suffix: &'a str,
},
} }
#[derive(LintDiagnostic)] #[derive(LintDiagnostic)]

View File

@ -4,7 +4,8 @@ use crate::{
AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign,
OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral,
OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag, OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange,
VariantSizeDifferencesDiag,
}, },
}; };
use crate::{LateContext, LateLintPass, LintContext}; use crate::{LateContext, LateLintPass, LintContext};
@ -136,6 +137,14 @@ fn lint_overflowing_range_endpoint<'tcx>(
expr: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>,
ty: &str, ty: &str,
) -> bool { ) -> bool {
// Look past casts to support cases like `0..256 as u8`
let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.hir().get(cx.tcx.hir().parent_id(expr.hir_id))
&& let ExprKind::Cast(_, _) = par_expr.kind {
(par_expr, expr.span)
} else {
(expr, expr.span)
};
// We only want to handle exclusive (`..`) ranges, // We only want to handle exclusive (`..`) ranges,
// which are represented as `ExprKind::Struct`. // which are represented as `ExprKind::Struct`.
let par_id = cx.tcx.hir().parent_id(expr.hir_id); let par_id = cx.tcx.hir().parent_id(expr.hir_id);
@ -155,7 +164,6 @@ fn lint_overflowing_range_endpoint<'tcx>(
if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) { if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) {
return false; return false;
}; };
let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
use rustc_ast::{LitIntType, LitKind}; use rustc_ast::{LitIntType, LitKind};
let suffix = match lit.node { let suffix = match lit.node {
@ -164,16 +172,28 @@ fn lint_overflowing_range_endpoint<'tcx>(
LitKind::Int(_, LitIntType::Unsuffixed) => "", LitKind::Int(_, LitIntType::Unsuffixed) => "",
_ => bug!(), _ => bug!(),
}; };
cx.emit_spanned_lint(
OVERFLOWING_LITERALS, let sub_sugg = if expr.span.lo() == lit_span.lo() {
struct_expr.span, let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
RangeEndpointOutOfRange { UseInclusiveRange::WithoutParen {
ty, sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
suggestion: struct_expr.span,
start, start,
literal: lit_val - 1, literal: lit_val - 1,
suffix, suffix,
}, }
} else {
UseInclusiveRange::WithParen {
eq_sugg: expr.span.shrink_to_lo(),
lit_sugg: lit_span,
literal: lit_val - 1,
suffix,
}
};
cx.emit_spanned_lint(
OVERFLOWING_LITERALS,
struct_expr.span,
RangeEndpointOutOfRange { ty, sub: sub_sugg },
); );
// We've just emitted a lint, special cased for `(...)..MAX+1` ranges, // We've just emitted a lint, special cased for `(...)..MAX+1` ranges,

View File

@ -0,0 +1,6 @@
// run-rustfix
fn main() {
for _ in 0..=255 as u8 {} //~ ERROR range endpoint is out of range
for _ in 0..=(255 as u8) {} //~ ERROR range endpoint is out of range
}

View File

@ -0,0 +1,6 @@
// run-rustfix
fn main() {
for _ in 0..256 as u8 {} //~ ERROR range endpoint is out of range
for _ in 0..(256 as u8) {} //~ ERROR range endpoint is out of range
}

View File

@ -0,0 +1,23 @@
error: range endpoint is out of range for `u8`
--> $DIR/issue-109529.rs:4:14
|
LL | for _ in 0..256 as u8 {}
| ------^^^^^^
| |
| help: use an inclusive range instead: `0..=255`
|
= note: `#[deny(overflowing_literals)]` on by default
error: range endpoint is out of range for `u8`
--> $DIR/issue-109529.rs:5:14
|
LL | for _ in 0..(256 as u8) {}
| ^^^^^^^^^^^^^^
|
help: use an inclusive range instead
|
LL | for _ in 0..=(255 as u8) {}
| + ~~~
error: aborting due to 2 previous errors