mirror of https://github.com/rust-lang/rust.git
Rollup merge of #109554 - MU001999:master, r=WaffleLapkin
Suggest ..= when someone tries to create an overflowing range Fixes #109529
This commit is contained in:
commit
83573a3776
|
@ -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}`
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue