Rollup merge of #106622 - estebank:issue-68972, r=davidtwco
Detect out of bounds range pattern value Fix #68972.
This commit is contained in:
commit
88765b0f59
5 changed files with 115 additions and 6 deletions
|
@ -206,6 +206,10 @@ mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
|
||||||
.label = lower bound larger than upper bound
|
.label = lower bound larger than upper bound
|
||||||
.teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
|
.teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
|
||||||
|
|
||||||
|
mir_build_literal_in_range_out_of_bounds =
|
||||||
|
literal out of range for `{$ty}`
|
||||||
|
.label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`
|
||||||
|
|
||||||
mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
|
mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
|
||||||
|
|
||||||
mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
|
mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
|
||||||
|
|
|
@ -493,6 +493,16 @@ pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
|
||||||
pub teach: Option<()>,
|
pub teach: Option<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(mir_build_literal_in_range_out_of_bounds)]
|
||||||
|
pub struct LiteralOutOfRange<'tcx> {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
pub ty: Ty<'tcx>,
|
||||||
|
pub max: u128,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")]
|
#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")]
|
||||||
pub struct LowerRangeBoundMustBeLessThanUpper {
|
pub struct LowerRangeBoundMustBeLessThanUpper {
|
||||||
|
|
|
@ -129,10 +129,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
hi: mir::ConstantKind<'tcx>,
|
hi: mir::ConstantKind<'tcx>,
|
||||||
end: RangeEnd,
|
end: RangeEnd,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
lo_expr: Option<&hir::Expr<'tcx>>,
|
||||||
|
hi_expr: Option<&hir::Expr<'tcx>>,
|
||||||
) -> PatKind<'tcx> {
|
) -> PatKind<'tcx> {
|
||||||
assert_eq!(lo.ty(), ty);
|
assert_eq!(lo.ty(), ty);
|
||||||
assert_eq!(hi.ty(), ty);
|
assert_eq!(hi.ty(), ty);
|
||||||
let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env);
|
let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env);
|
||||||
|
let max = || {
|
||||||
|
self.tcx
|
||||||
|
.layout_of(self.param_env.with_reveal_all_normalized(self.tcx).and(ty))
|
||||||
|
.ok()
|
||||||
|
.unwrap()
|
||||||
|
.size
|
||||||
|
.unsigned_int_max()
|
||||||
|
};
|
||||||
match (end, cmp) {
|
match (end, cmp) {
|
||||||
// `x..y` where `x < y`.
|
// `x..y` where `x < y`.
|
||||||
// Non-empty because the range includes at least `x`.
|
// Non-empty because the range includes at least `x`.
|
||||||
|
@ -141,7 +151,27 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
// `x..y` where `x >= y`. The range is empty => error.
|
// `x..y` where `x >= y`. The range is empty => error.
|
||||||
(RangeEnd::Excluded, _) => {
|
(RangeEnd::Excluded, _) => {
|
||||||
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
|
let mut lower_overflow = false;
|
||||||
|
let mut higher_overflow = false;
|
||||||
|
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
|
||||||
|
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||||
|
{
|
||||||
|
if lo.eval_bits(self.tcx, self.param_env, ty) != val {
|
||||||
|
lower_overflow = true;
|
||||||
|
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
|
||||||
|
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||||
|
{
|
||||||
|
if hi.eval_bits(self.tcx, self.param_env, ty) != val {
|
||||||
|
higher_overflow = true;
|
||||||
|
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !lower_overflow && !higher_overflow {
|
||||||
|
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
|
||||||
|
}
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
}
|
}
|
||||||
// `x..=y` where `x == y`.
|
// `x..=y` where `x == y`.
|
||||||
|
@ -152,10 +182,34 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
// `x..=y` where `x > y` hence the range is empty => error.
|
// `x..=y` where `x > y` hence the range is empty => error.
|
||||||
(RangeEnd::Included, _) => {
|
(RangeEnd::Included, _) => {
|
||||||
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
|
let mut lower_overflow = false;
|
||||||
span,
|
let mut higher_overflow = false;
|
||||||
teach: if self.tcx.sess.teach(&error_code!(E0030)) { Some(()) } else { None },
|
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
|
||||||
});
|
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||||
|
{
|
||||||
|
if lo.eval_bits(self.tcx, self.param_env, ty) != val {
|
||||||
|
lower_overflow = true;
|
||||||
|
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
|
||||||
|
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||||
|
{
|
||||||
|
if hi.eval_bits(self.tcx, self.param_env, ty) != val {
|
||||||
|
higher_overflow = true;
|
||||||
|
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !lower_overflow && !higher_overflow {
|
||||||
|
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
|
||||||
|
span,
|
||||||
|
teach: if self.tcx.sess.teach(&error_code!(E0030)) {
|
||||||
|
Some(())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,7 +255,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
let (lp, hp) = (lo.as_ref().map(|(x, _)| x), hi.as_ref().map(|(x, _)| x));
|
let (lp, hp) = (lo.as_ref().map(|(x, _)| x), hi.as_ref().map(|(x, _)| x));
|
||||||
let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) {
|
let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) {
|
||||||
Some((lc, hc)) => self.lower_pattern_range(ty, lc, hc, end, lo_span),
|
Some((lc, hc)) => {
|
||||||
|
self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr)
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
let msg = &format!(
|
let msg = &format!(
|
||||||
"found bad range pattern `{:?}` outside of error recovery",
|
"found bad range pattern `{:?}` outside of error recovery",
|
||||||
|
|
13
tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs
Normal file
13
tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#![feature(exclusive_range_pattern)]
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
fn main() {
|
||||||
|
match 0u8 {
|
||||||
|
251..257 => {}
|
||||||
|
//~^ ERROR literal out of range
|
||||||
|
//~| ERROR literal out of range
|
||||||
|
251..=256 => {}
|
||||||
|
//~^ ERROR literal out of range
|
||||||
|
//~| ERROR literal out of range
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
error: literal out of range for `u8`
|
||||||
|
--> $DIR/range-pattern-out-of-bounds-issue-68972.rs:5:14
|
||||||
|
|
|
||||||
|
LL | 251..257 => {}
|
||||||
|
| ^^^ this value doesn't fit in `u8` whose maximum value is `255`
|
||||||
|
|
||||||
|
error: literal out of range for `u8`
|
||||||
|
--> $DIR/range-pattern-out-of-bounds-issue-68972.rs:8:15
|
||||||
|
|
|
||||||
|
LL | 251..=256 => {}
|
||||||
|
| ^^^ this value doesn't fit in `u8` whose maximum value is `255`
|
||||||
|
|
||||||
|
error: literal out of range for `u8`
|
||||||
|
--> $DIR/range-pattern-out-of-bounds-issue-68972.rs:5:14
|
||||||
|
|
|
||||||
|
LL | 251..257 => {}
|
||||||
|
| ^^^ this value doesn't fit in `u8` whose maximum value is `255`
|
||||||
|
|
||||||
|
error: literal out of range for `u8`
|
||||||
|
--> $DIR/range-pattern-out-of-bounds-issue-68972.rs:8:15
|
||||||
|
|
|
||||||
|
LL | 251..=256 => {}
|
||||||
|
| ^^^ this value doesn't fit in `u8` whose maximum value is `255`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
Loading…
Add table
Reference in a new issue