summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir/pattern/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src/thir/pattern/mod.rs')
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs99
1 files changed, 69 insertions, 30 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 48a231a6c..3a6ef87c9 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -2,14 +2,16 @@
mod check_match;
mod const_to_pat;
-mod deconstruct_pat;
+pub(crate) mod deconstruct_pat;
mod usefulness;
pub(crate) use self::check_match::check_match;
+pub(crate) use self::usefulness::MatchCheckCtxt;
+use crate::errors::*;
use crate::thir::util::UserAnnotatedTyHelpers;
-use rustc_errors::struct_span_err;
+use rustc_errors::error_code;
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
@@ -127,10 +129,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
hi: mir::ConstantKind<'tcx>,
end: RangeEnd,
span: Span,
+ lo_expr: Option<&hir::Expr<'tcx>>,
+ hi_expr: Option<&hir::Expr<'tcx>>,
) -> PatKind<'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) {
// `x..y` where `x < y`.
// Non-empty because the range includes at least `x`.
@@ -139,13 +151,27 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
// `x..y` where `x >= y`. The range is empty => error.
(RangeEnd::Excluded, _) => {
- struct_span_err!(
- self.tcx.sess,
- span,
- E0579,
- "lower range bound must be less than upper"
- )
- .emit();
+ 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
}
// `x..=y` where `x == y`.
@@ -156,23 +182,34 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
// `x..=y` where `x > y` hence the range is empty => error.
(RangeEnd::Included, _) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0030,
- "lower range bound must be less than or equal to upper"
- );
- err.span_label(span, "lower bound larger than upper bound");
- if self.tcx.sess.teach(&err.get_code().unwrap()) {
- err.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.",
- );
+ 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(LowerRangeBoundMustBeLessThanOrEqualToUpper {
+ span,
+ teach: if self.tcx.sess.teach(&error_code!(E0030)) {
+ Some(())
+ } else {
+ None
+ },
+ });
}
- err.emit();
PatKind::Wild
}
}
@@ -218,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 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 => {
let msg = &format!(
"found bad range pattern `{:?}` outside of error recovery",
@@ -501,7 +540,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
Err(_) => {
- self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+ self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
return pat_from_kind(PatKind::Wild);
}
};
@@ -548,11 +587,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
Err(ErrorHandled::TooGeneric) => {
// While `Reported | Linted` cases will have diagnostics emitted already
// it is not true for TooGeneric case, so we need to give user more information.
- self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+ self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
pat_from_kind(PatKind::Wild)
}
Err(_) => {
- self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+ self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
pat_from_kind(PatKind::Wild)
}
}
@@ -584,7 +623,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
mir::ConstantKind::Unevaluated(..) => {
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
- self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+ self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
return PatKind::Wild;
}
}