diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 44cf1591c7d4a..d252f651c78cc 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -140,13 +140,15 @@ declare_lint! { pub struct TypeLimits { /// Id of the last visited negated expression negated_expr_id: Option<hir::HirId>, + /// Span of the last visited negated expression + negated_expr_span: Option<Span>, } impl_lint_pass!(TypeLimits => [UNUSED_COMPARISONS, OVERFLOWING_LITERALS, INVALID_NAN_COMPARISONS]); impl TypeLimits { pub fn new() -> TypeLimits { - TypeLimits { negated_expr_id: None } + TypeLimits { negated_expr_id: None, negated_expr_span: None } } } @@ -426,17 +428,15 @@ fn lint_int_literal<'tcx>( return; } - let lit = cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .expect("must get snippet from literal"); + let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span }; + let lit = + cx.sess().source_map().span_to_snippet(span).expect("must get snippet from literal"); let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); cx.emit_spanned_lint( OVERFLOWING_LITERALS, - e.span, + span, OverflowingInt { ty: t.name_str(), lit, min, max, help }, ); } @@ -622,9 +622,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) { match e.kind { hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => { - // propagate negation, if the negation itself isn't negated + // Propagate negation, if the negation itself isn't negated if self.negated_expr_id != Some(e.hir_id) { self.negated_expr_id = Some(expr.hir_id); + self.negated_expr_span = Some(e.span); } } hir::ExprKind::Binary(binop, ref l, ref r) => { diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index ce021923f647f..db3886b32beb4 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -173,7 +173,7 @@ mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count -> 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}` + .label = this value does not fit into the type `{$ty}` whose range is `{$min}..={$max}` mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = lower range bound must be less than or equal to upper diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index bee5ac550ddce..4f98932a88d4b 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -551,6 +551,7 @@ pub struct LiteralOutOfRange<'tcx> { #[label] pub span: Span, pub ty: Ty<'tcx>, + pub min: i128, pub max: u128, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index fe47a1cd78c49..25726c5a8725e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -20,15 +20,15 @@ use rustc_index::Idx; use rustc_middle::mir::interpret::{ ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar, }; -use rustc_middle::mir::{self, Const, UserTypeProjection}; -use rustc_middle::mir::{BorrowKind, Mutability}; +use rustc_middle::mir::{self, BorrowKind, Const, Mutability, UserTypeProjection}; use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange}; -use rustc_middle::ty::CanonicalUserTypeAnnotation; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, AdtDef, Region, Ty, TyCtxt, UserType}; -use rustc_middle::ty::{GenericArg, GenericArgsRef}; -use rustc_span::{Span, Symbol}; -use rustc_target::abi::FieldIdx; +use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::ty::{ + self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt, + TypeVisitableExt, UserType, +}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_target::abi::{FieldIdx, Integer}; use std::cmp::Ordering; @@ -85,127 +85,159 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ) } - fn lower_range_expr( + fn lower_pattern_range_endpoint( &mut self, - expr: &'tcx hir::Expr<'tcx>, - ) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) { - match self.lower_lit(expr) { - PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { - (kind, Some(ascription)) + expr: Option<&'tcx hir::Expr<'tcx>>, + ) -> Result<(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>), ErrorGuaranteed> { + match expr { + None => Ok((None, None)), + Some(expr) => { + let (kind, ascr) = match self.lower_lit(expr) { + PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { + (kind, Some(ascription)) + } + kind => (kind, None), + }; + let value = if let PatKind::Constant { value } = kind { + value + } else { + let msg = format!( + "found bad range pattern endpoint `{expr:?}` outside of error recovery" + ); + return Err(self.tcx.sess.delay_span_bug(expr.span, msg)); + }; + Ok((Some(value), ascr)) } - kind => (kind, None), } } + /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we + /// encounter a range pattern like `-130i8..2`: if we believe `eval_bits`, this looks like a + /// range where the endpoints are in the wrong order. To avoid a confusing error message, we + /// check for overflow then. + /// This is only called when the range is already known to be malformed. + fn error_on_literal_overflow( + &self, + expr: Option<&'tcx hir::Expr<'tcx>>, + ty: Ty<'tcx>, + ) -> Result<(), ErrorGuaranteed> { + use hir::{ExprKind, UnOp}; + use rustc_ast::ast::LitKind; + + let Some(mut expr) = expr else { + return Ok(()); + }; + let span = expr.span; + + // We need to inspect the original expression, because if we only inspect the output of + // `eval_bits`, an overflowed value has already been wrapped around. + // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint. + let mut negated = false; + if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind { + negated = true; + expr = sub_expr; + } + let ExprKind::Lit(lit) = expr.kind else { + return Ok(()); + }; + let LitKind::Int(lit_val, _) = lit.node else { + return Ok(()); + }; + let (min, max): (i128, u128) = match ty.kind() { + ty::Int(ity) => { + let size = Integer::from_int_ty(&self.tcx, *ity).size(); + (size.signed_int_min(), size.signed_int_max() as u128) + } + ty::Uint(uty) => { + let size = Integer::from_uint_ty(&self.tcx, *uty).size(); + (0, size.unsigned_int_max()) + } + _ => { + return Ok(()); + } + }; + // Detect literal value out of range `[min, max]` inclusive, avoiding use of `-min` to + // prevent overflow/panic. + if (negated && lit_val > max + 1) || (!negated && lit_val > max) { + return Err(self.tcx.sess.emit_err(LiteralOutOfRange { span, ty, min, max })); + } + Ok(()) + } + fn lower_pattern_range( &mut self, - ty: Ty<'tcx>, - lo: mir::Const<'tcx>, - hi: mir::Const<'tcx>, + lo_expr: Option<&'tcx hir::Expr<'tcx>>, + hi_expr: Option<&'tcx hir::Expr<'tcx>>, end: RangeEnd, + ty: Ty<'tcx>, span: Span, - lo_expr: Option<&hir::Expr<'tcx>>, - hi_expr: Option<&hir::Expr<'tcx>>, - ) -> PatKind<'tcx> { + ) -> Result<PatKind<'tcx>, ErrorGuaranteed> { + if lo_expr.is_none() && hi_expr.is_none() { + let msg = format!("found twice-open range pattern (`..`) outside of error recovery"); + return Err(self.tcx.sess.delay_span_bug(span, msg)); + } + + let (lo, lo_ascr) = self.lower_pattern_range_endpoint(lo_expr)?; + let (hi, hi_ascr) = self.lower_pattern_range_endpoint(hi_expr)?; + + let lo = lo.unwrap_or_else(|| { + // Unwrap is ok because the type is known to be numeric. + let lo = ty.numeric_min_val(self.tcx).unwrap(); + mir::Const::from_ty_const(lo, self.tcx) + }); + let hi = hi.unwrap_or_else(|| { + // Unwrap is ok because the type is known to be numeric. + let hi = ty.numeric_max_val(self.tcx).unwrap(); + mir::Const::from_ty_const(hi, self.tcx) + }); assert_eq!(lo.ty(), ty); assert_eq!(hi.ty(), ty); + 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) { + let mut kind = match (end, cmp) { // `x..y` where `x < y`. // Non-empty because the range includes at least `x`. (RangeEnd::Excluded, Some(Ordering::Less)) => { PatKind::Range(Box::new(PatRange { lo, hi, end })) } - // `x..y` where `x >= y`. The range is empty => error. - (RangeEnd::Excluded, _) => { - 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) != 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) != 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 - } // `x..=y` where `x == y`. (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo }, // `x..=y` where `x < y`. (RangeEnd::Included, Some(Ordering::Less)) => { PatKind::Range(Box::new(PatRange { lo, hi, end })) } - // `x..=y` where `x > y` hence the range is empty => error. - (RangeEnd::Included, _) => { - 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) != val { - lower_overflow = true; - self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); + // `x..y` where `x >= y`, or `x..=y` where `x > y`. The range is empty => error. + _ => { + // Emit a more appropriate message if there was overflow. + self.error_on_literal_overflow(lo_expr, ty)?; + self.error_on_literal_overflow(hi_expr, ty)?; + let e = match end { + RangeEnd::Included => { + self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { + span, + teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), + }) } - } - 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) != val { - higher_overflow = true; - self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); + RangeEnd::Excluded => { + self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span }) } - } - if !lower_overflow && !higher_overflow { - self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { - span, - teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), - }); - } - PatKind::Wild + }; + return Err(e); } - } - } + }; - fn normalize_range_pattern_ends( - &self, - ty: Ty<'tcx>, - lo: Option<&PatKind<'tcx>>, - hi: Option<&PatKind<'tcx>>, - ) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> { - match (lo, hi) { - (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => { - Some((*lo, *hi)) - } - (Some(PatKind::Constant { value: lo }), None) => { - let hi = ty.numeric_max_val(self.tcx)?; - Some((*lo, mir::Const::from_ty_const(hi, self.tcx))) - } - (None, Some(PatKind::Constant { value: hi })) => { - let lo = ty.numeric_min_val(self.tcx)?; - Some((mir::Const::from_ty_const(lo, self.tcx), *hi)) + // If we are handling a range with associated constants (e.g. + // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated + // constants somewhere. Have them on the range pattern. + for ascr in [lo_ascr, hi_ascr] { + if let Some(ascription) = ascr { + kind = PatKind::AscribeUserType { + ascription, + subpattern: Box::new(Pat { span, ty, kind }), + }; } - _ => None, } + Ok(kind) } #[instrument(skip(self), level = "debug")] @@ -220,37 +252,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); - let lo_span = lo_expr.map_or(pat.span, |e| e.span); - let lo = lo_expr.map(|e| self.lower_range_expr(e)); - let hi = hi_expr.map(|e| self.lower_range_expr(e)); - - 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) { - Some((lc, hc)) => { - self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr) - } - None => { - let msg = format!( - "found bad range pattern `{:?}` outside of error recovery", - (&lo, &hi), - ); - self.tcx.sess.delay_span_bug(pat.span, msg); - PatKind::Wild - } - }; - - // If we are handling a range with associated constants (e.g. - // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated - // constants somewhere. Have them on the range pattern. - for end in &[lo, hi] { - if let Some((_, Some(ascription))) = end { - let subpattern = Box::new(Pat { span: pat.span, ty, kind }); - kind = - PatKind::AscribeUserType { ascription: ascription.clone(), subpattern }; - } - } - - kind + // FIXME?: returning `_` can cause inaccurate "unreachable" warnings. This can be + // fixed by returning `PatKind::Const(ConstKind::Error(...))` if #115937 gets + // merged. + self.lower_pattern_range(lo_expr, hi_expr, end, ty, span).unwrap_or(PatKind::Wild) } hir::PatKind::Path(ref qpath) => { diff --git a/tests/ui/error-codes/E0030-teach.stderr b/tests/ui/error-codes/E0030-teach.stderr index 3f1ad4af3a94e..9435cb204bdd6 100644 --- a/tests/ui/error-codes/E0030-teach.stderr +++ b/tests/ui/error-codes/E0030-teach.stderr @@ -2,7 +2,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/E0030-teach.rs:5:9 | LL | 1000 ..= 5 => {} - | ^^^^ lower bound larger than upper bound + | ^^^^^^^^^^ lower bound larger than upper bound | = 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. diff --git a/tests/ui/error-codes/E0030.stderr b/tests/ui/error-codes/E0030.stderr index db8161d8fd5d8..1aeca29167875 100644 --- a/tests/ui/error-codes/E0030.stderr +++ b/tests/ui/error-codes/E0030.stderr @@ -2,7 +2,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/E0030.rs:3:9 | LL | 1000 ..= 5 => {} - | ^^^^ lower bound larger than upper bound + | ^^^^^^^^^^ lower bound larger than upper bound error: aborting due to previous error diff --git a/tests/ui/lint/lint-type-overflow.stderr b/tests/ui/lint/lint-type-overflow.stderr index 48d8228b802ac..971c3eb9b2e3b 100644 --- a/tests/ui/lint/lint-type-overflow.stderr +++ b/tests/ui/lint/lint-type-overflow.stderr @@ -29,21 +29,21 @@ LL | let x1: i8 = 128; = help: consider using the type `u8` instead error: literal out of range for `i8` - --> $DIR/lint-type-overflow.rs:18:19 + --> $DIR/lint-type-overflow.rs:18:18 | LL | let x3: i8 = -129; - | ^^^ + | ^^^^ | - = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `-129` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `i16` instead error: literal out of range for `i8` - --> $DIR/lint-type-overflow.rs:19:19 + --> $DIR/lint-type-overflow.rs:19:18 | LL | let x3: i8 = -(129); - | ^^^^^ + | ^^^^^^ | - = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `-(129)` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `i16` instead error: literal out of range for `i8` @@ -74,12 +74,12 @@ LL | let x = 128_i8; = help: consider using the type `u8` instead error: literal out of range for `i8` - --> $DIR/lint-type-overflow.rs:28:14 + --> $DIR/lint-type-overflow.rs:28:13 | LL | let x = -129_i8; - | ^^^^^^ + | ^^^^^^^ | - = note: the literal `129_i8` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `-129_i8` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `i16` instead error: literal out of range for `i32` @@ -101,21 +101,21 @@ LL | let x = 2147483648_i32; = help: consider using the type `u32` instead error: literal out of range for `i32` - --> $DIR/lint-type-overflow.rs:36:19 + --> $DIR/lint-type-overflow.rs:36:18 | LL | let x: i32 = -2147483649; - | ^^^^^^^^^^ + | ^^^^^^^^^^^ | - = note: the literal `2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = note: the literal `-2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647` = help: consider using the type `i64` instead error: literal out of range for `i32` - --> $DIR/lint-type-overflow.rs:37:14 + --> $DIR/lint-type-overflow.rs:37:13 | LL | let x = -2147483649_i32; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | - = note: the literal `2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = note: the literal `-2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` = help: consider using the type `i64` instead error: literal out of range for `i32` @@ -146,21 +146,21 @@ LL | let x = 18446744073709551615_i64; = help: consider using the type `u64` instead error: literal out of range for `i64` - --> $DIR/lint-type-overflow.rs:43:19 + --> $DIR/lint-type-overflow.rs:43:18 | LL | let x: i64 = -9223372036854775809; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = note: the literal `-9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` = help: consider using the type `i128` instead error: literal out of range for `i64` - --> $DIR/lint-type-overflow.rs:44:14 + --> $DIR/lint-type-overflow.rs:44:13 | LL | let x = -9223372036854775809_i64; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = note: the literal `-9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` = help: consider using the type `i128` instead error: aborting due to 18 previous errors diff --git a/tests/ui/match/match-range-fail-2.stderr b/tests/ui/match/match-range-fail-2.stderr index 52a2bf2b34aa6..089fa851f97c2 100644 --- a/tests/ui/match/match-range-fail-2.stderr +++ b/tests/ui/match/match-range-fail-2.stderr @@ -2,19 +2,19 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/match-range-fail-2.rs:5:9 | LL | 6 ..= 1 => { } - | ^ lower bound larger than upper bound + | ^^^^^^^ lower bound larger than upper bound error[E0579]: lower range bound must be less than upper --> $DIR/match-range-fail-2.rs:11:9 | LL | 0 .. 0 => { } - | ^ + | ^^^^^^ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/match-range-fail-2.rs:17:9 | LL | 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } - | ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound error: aborting due to 3 previous errors diff --git a/tests/ui/match/validate-range-endpoints.rs b/tests/ui/match/validate-range-endpoints.rs new file mode 100644 index 0000000000000..1d1737f8b82f4 --- /dev/null +++ b/tests/ui/match/validate-range-endpoints.rs @@ -0,0 +1,59 @@ +#![feature(exclusive_range_pattern)] +#![feature(inline_const_pat)] +#![allow(incomplete_features)] +#![allow(overlapping_range_endpoints)] + +fn main() { + const TOO_BIG: u8 = 256; + match 0u8 { + 1..257 => {} + //~^ ERROR literal out of range + 1..=256 => {} + //~^ ERROR literal out of range + + // overflow is detected in a later pass for these + 0..257 => {} + 0..=256 => {} + 256..=100 => {} + + // There isn't really a way to detect these + 1..=TOO_BIG => {} + //~^ ERROR lower range bound must be less than or equal to upper + 1..=const { 256 } => {} + //~^ ERROR lower range bound must be less than or equal to upper + _ => {} + } + + match 0u64 { + 10000000000000000000..=99999999999999999999 => {} + //~^ ERROR literal out of range + _ => {} + } + + match 0i8 { + 0..129 => {} + //~^ ERROR literal out of range + 0..=128 => {} + //~^ ERROR literal out of range + -129..0 => {} + //~^ ERROR literal out of range + -10000..=-20 => {} + //~^ ERROR literal out of range + + // overflow is detected in a later pass for these + 128..=0 => {} + 0..-129 => {} + -10000..=0 => {} + _ => {} + } + + // FIXME: error message is confusing + match 0i8 { + //~^ ERROR `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered + -10000..=0 => {} + } + match 0i8 { + //~^ ERROR `i8::MIN..=-17_i8` not covered + -10000.. => {} + } +} diff --git a/tests/ui/match/validate-range-endpoints.stderr b/tests/ui/match/validate-range-endpoints.stderr new file mode 100644 index 0000000000000..0813fccff5187 --- /dev/null +++ b/tests/ui/match/validate-range-endpoints.stderr @@ -0,0 +1,84 @@ +error: literal out of range for `u8` + --> $DIR/validate-range-endpoints.rs:9:12 + | +LL | 1..257 => {} + | ^^^ this value does not fit into the type `u8` whose range is `0..=255` + +error: literal out of range for `u8` + --> $DIR/validate-range-endpoints.rs:11:13 + | +LL | 1..=256 => {} + | ^^^ this value does not fit into the type `u8` whose range is `0..=255` + +error[E0030]: lower range bound must be less than or equal to upper + --> $DIR/validate-range-endpoints.rs:20:9 + | +LL | 1..=TOO_BIG => {} + | ^^^^^^^^^^^ lower bound larger than upper bound + +error[E0030]: lower range bound must be less than or equal to upper + --> $DIR/validate-range-endpoints.rs:22:9 + | +LL | 1..=const { 256 } => {} + | ^^^^^^^^^^^^^^^^^ lower bound larger than upper bound + +error: literal out of range for `u64` + --> $DIR/validate-range-endpoints.rs:28:32 + | +LL | 10000000000000000000..=99999999999999999999 => {} + | ^^^^^^^^^^^^^^^^^^^^ this value does not fit into the type `u64` whose range is `0..=18446744073709551615` + +error: literal out of range for `i8` + --> $DIR/validate-range-endpoints.rs:34:12 + | +LL | 0..129 => {} + | ^^^ this value does not fit into the type `i8` whose range is `-128..=127` + +error: literal out of range for `i8` + --> $DIR/validate-range-endpoints.rs:36:13 + | +LL | 0..=128 => {} + | ^^^ this value does not fit into the type `i8` whose range is `-128..=127` + +error: literal out of range for `i8` + --> $DIR/validate-range-endpoints.rs:38:9 + | +LL | -129..0 => {} + | ^^^^ this value does not fit into the type `i8` whose range is `-128..=127` + +error: literal out of range for `i8` + --> $DIR/validate-range-endpoints.rs:40:9 + | +LL | -10000..=-20 => {} + | ^^^^^^ this value does not fit into the type `i8` whose range is `-128..=127` + +error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered + --> $DIR/validate-range-endpoints.rs:51:11 + | +LL | match 0i8 { + | ^^^ patterns `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered + | + = note: the matched value is of type `i8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ -10000..=0 => {}, +LL + i8::MIN..=-17_i8 | 1_i8..=i8::MAX => todo!() + | + +error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` not covered + --> $DIR/validate-range-endpoints.rs:55:11 + | +LL | match 0i8 { + | ^^^ pattern `i8::MIN..=-17_i8` not covered + | + = note: the matched value is of type `i8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ -10000.. => {}, +LL + i8::MIN..=-17_i8 => todo!() + | + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0004, E0030. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr index 4f3f9d1eb3a76..21f1fdba886c5 100644 --- a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr +++ b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr @@ -2,13 +2,13 @@ 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` + | ^^^ this value does not fit into the type `u8` whose range is `0..=255` error: literal out of range for `u8` --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:7:15 | LL | 251..=256 => {} - | ^^^ this value doesn't fit in `u8` whose maximum value is `255` + | ^^^ this value does not fit into the type `u8` whose range is `0..=255` error: aborting due to 2 previous errors