From 91a3db95a1a5939054d72d2ce69c5647c3cfb93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 29 Aug 2019 16:06:44 -0700 Subject: [PATCH 01/10] Add check for overlapping ranges to unreachable patterns lint --- src/libcore/ascii.rs | 2 + src/librustc_mir/hair/pattern/_match.rs | 230 +++++++++++++----- src/librustc_mir/hair/pattern/check_match.rs | 20 +- src/test/ui/check_match/issue-43253.rs | 17 +- src/test/ui/check_match/issue-43253.stderr | 42 +++- src/test/ui/exhaustive_integer_patterns.rs | 8 +- .../ui/exhaustive_integer_patterns.stderr | 32 ++- .../ui/match/match-range-fail-dominate.rs | 24 +- .../ui/match/match-range-fail-dominate.stderr | 40 +-- src/test/ui/precise_pointer_size_matching.rs | 4 +- .../ui/precise_pointer_size_matching.stderr | 24 +- 11 files changed, 325 insertions(+), 118 deletions(-) diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 4087333e2cf6d..0492fbd55faf2 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -100,6 +100,8 @@ pub fn escape_default(c: u8) -> EscapeDefault { b'\\' => ([b'\\', b'\\', 0, 0], 2), b'\'' => ([b'\\', b'\'', 0, 0], 2), b'"' => ([b'\\', b'"', 0, 0], 2), + // The three arms above are in the following range + #[allow(unreachable_patterns)] b'\x20' ..= b'\x7e' => ([c, 0, 0, 0], 1), _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), }; diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 3ea5805287724..542f0ba5c9ca1 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -167,13 +167,14 @@ use super::{FieldPat, Pat, PatKind, PatRange}; use super::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; -use rustc::hir::RangeEnd; +use rustc::hir::{RangeEnd, HirId}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const}; use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size}; use rustc::mir::Field; use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer}; use rustc::util::common::ErrorReported; +use rustc::lint; use syntax::attr::{SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; @@ -418,7 +419,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] enum Constructor<'tcx> { /// The constructor of all patterns that don't vary by constructor, /// e.g., struct patterns and fixed-length arrays. @@ -426,13 +427,30 @@ enum Constructor<'tcx> { /// Enum variants. Variant(DefId), /// Literal values. - ConstantValue(&'tcx ty::Const<'tcx>), + ConstantValue(&'tcx ty::Const<'tcx>, Span), /// Ranges of literal values (`2..=5` and `2..5`). - ConstantRange(u128, u128, Ty<'tcx>, RangeEnd), + ConstantRange(u128, u128, Ty<'tcx>, RangeEnd, Span), /// Array patterns of length n. Slice(u64), } +// Ignore spans when comparing, they don't carry semantic information as they are only for lints. +impl<'tcx> std::cmp::PartialEq for Constructor<'tcx> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Constructor::Single, Constructor::Single) => true, + (Constructor::Variant(a), Constructor::Variant(b)) => a == b, + (Constructor::ConstantValue(a, _), Constructor::ConstantValue(b, _)) => a == b, + ( + Constructor::ConstantRange(a_start, a_end, a_ty, a_range_end, _), + Constructor::ConstantRange(b_start, b_end, b_ty, b_range_end, _), + ) => a_start == b_start && a_end == b_end && a_ty == b_ty && a_range_end == b_range_end, + (Constructor::Slice(a), Constructor::Slice(b)) => a == b, + _ => false, + } + } +} + impl<'tcx> Constructor<'tcx> { fn is_slice(&self) -> bool { match self { @@ -447,15 +465,36 @@ impl<'tcx> Constructor<'tcx> { adt: &'tcx ty::AdtDef, ) -> VariantIdx { match self { - &Variant(id) => adt.variant_index_with_id(id), - &Single => { + Variant(id) => adt.variant_index_with_id(*id), + Single => { assert!(!adt.is_enum()); VariantIdx::new(0) } - &ConstantValue(c) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c), + ConstantValue(c, _) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c), _ => bug!("bad constructor {:?} for adt {:?}", self, adt) } } + + fn display(&self, tcx: TyCtxt<'tcx>) -> String { + match self { + Constructor::ConstantValue(val, _) => format!("{}", val), + Constructor::ConstantRange(lo, hi, ty, range_end, _) => { + // Get the right sign on the output: + let ty = ty::ParamEnv::empty().and(*ty); + format!( + "{}..{}{}", + ty::Const::from_bits(tcx, *lo, ty), + match range_end { + RangeEnd::Included => "=", + RangeEnd::Excluded => "", + }, + ty::Const::from_bits(tcx, *hi, ty), + ) + } + Constructor::Slice(val) => format!("[{}]", val), + _ => bug!("bad constructor being displayed: `{:?}", self), + } + } } #[derive(Clone, Debug)] @@ -484,6 +523,7 @@ pub enum WitnessPreference { struct PatCtxt<'tcx> { ty: Ty<'tcx>, max_slice_length: u64, + span: Span, } /// A witness of non-exhaustiveness for error reporting, represented @@ -610,8 +650,8 @@ impl<'tcx> Witness<'tcx> { _ => { match *ctor { - ConstantValue(value) => PatKind::Constant { value }, - ConstantRange(lo, hi, ty, end) => PatKind::Range(PatRange { + ConstantValue(value, _) => PatKind::Constant { value }, + ConstantRange(lo, hi, ty, end, _) => PatKind::Range(PatRange { lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)), hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)), end, @@ -647,7 +687,7 @@ fn all_constructors<'a, 'tcx>( let ctors = match pcx.ty.kind { ty::Bool => { [true, false].iter().map(|&b| { - ConstantValue(ty::Const::from_bool(cx.tcx, b)) + ConstantValue(ty::Const::from_bool(cx.tcx, b), pcx.span) }).collect() } ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { @@ -679,15 +719,19 @@ fn all_constructors<'a, 'tcx>( ty::Char => { vec![ // The valid Unicode Scalar Value ranges. - ConstantRange('\u{0000}' as u128, - '\u{D7FF}' as u128, - cx.tcx.types.char, - RangeEnd::Included + ConstantRange( + '\u{0000}' as u128, + '\u{D7FF}' as u128, + cx.tcx.types.char, + RangeEnd::Included, + pcx.span, ), - ConstantRange('\u{E000}' as u128, - '\u{10FFFF}' as u128, - cx.tcx.types.char, - RangeEnd::Included + ConstantRange( + '\u{E000}' as u128, + '\u{10FFFF}' as u128, + cx.tcx.types.char, + RangeEnd::Included, + pcx.span, ), ] } @@ -695,12 +739,12 @@ fn all_constructors<'a, 'tcx>( let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128; let min = 1u128 << (bits - 1); let max = min - 1; - vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included)] + vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included, pcx.span)] } ty::Uint(uty) => { let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); let max = truncate(u128::max_value(), size); - vec![ConstantRange(0, max, pcx.ty, RangeEnd::Included)] + vec![ConstantRange(0, max, pcx.ty, RangeEnd::Included, pcx.span)] } _ => { if cx.is_uninhabited(pcx.ty) { @@ -827,10 +871,11 @@ where /// /// `IntRange` is never used to encode an empty range or a "range" that wraps /// around the (offset) space: i.e., `range.lo <= range.hi`. -#[derive(Clone)] +#[derive(Clone, Debug)] struct IntRange<'tcx> { pub range: RangeInclusive, pub ty: Ty<'tcx>, + pub span: Span, } impl<'tcx> IntRange<'tcx> { @@ -860,6 +905,7 @@ impl<'tcx> IntRange<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, value: &Const<'tcx>, + span: Span, ) -> Option> { if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) { let ty = value.ty; @@ -877,7 +923,7 @@ impl<'tcx> IntRange<'tcx> { return None }; let val = val ^ bias; - Some(IntRange { range: val..=val, ty }) + Some(IntRange { range: val..=val, ty, span }) } else { None } @@ -890,6 +936,7 @@ impl<'tcx> IntRange<'tcx> { hi: u128, ty: Ty<'tcx>, end: &RangeEnd, + span: Span, ) -> Option> { if Self::is_integral(ty) { // Perform a shift if the underlying types are signed, @@ -901,7 +948,7 @@ impl<'tcx> IntRange<'tcx> { None } else { let offset = (*end == RangeEnd::Excluded) as u128; - Some(IntRange { range: lo..=(hi - offset), ty }) + Some(IntRange { range: lo..=(hi - offset), ty, span }) } } else { None @@ -916,8 +963,8 @@ impl<'tcx> IntRange<'tcx> { // Floating-point ranges are permitted and we don't want // to consider them when constructing integer ranges. match ctor { - ConstantRange(lo, hi, ty, end) => Self::from_range(tcx, *lo, *hi, ty, end), - ConstantValue(val) => Self::from_const(tcx, param_env, val), + ConstantRange(lo, hi, ty, end, span) => Self::from_range(tcx, *lo, *hi, ty, end, *span), + ConstantValue(val, span) => Self::from_const(tcx, param_env, val, *span), _ => None, } } @@ -930,7 +977,7 @@ impl<'tcx> IntRange<'tcx> { loop { match pat.kind { box PatKind::Constant { value } => { - return Self::from_const(tcx, param_env, value); + return Self::from_const(tcx, param_env, value, pat.span); } box PatKind::Range(PatRange { lo, hi, end }) => { return Self::from_range( @@ -939,6 +986,7 @@ impl<'tcx> IntRange<'tcx> { hi.eval_bits(tcx, param_env, hi.ty), &lo.ty, &end, + pat.span, ); } box PatKind::AscribeUserType { ref subpattern, .. } => { @@ -965,14 +1013,15 @@ impl<'tcx> IntRange<'tcx> { tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, r: RangeInclusive, + span: Span, ) -> Constructor<'tcx> { let bias = IntRange::signed_bias(tcx, ty); let (lo, hi) = r.into_inner(); if lo == hi { let ty = ty::ParamEnv::empty().and(ty); - ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty)) + ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty), span) } else { - ConstantRange(lo ^ bias, hi ^ bias, ty, RangeEnd::Included) + ConstantRange(lo ^ bias, hi ^ bias, ty, RangeEnd::Included, span) } } @@ -995,17 +1044,23 @@ impl<'tcx> IntRange<'tcx> { if lo > subrange_hi || subrange_lo > hi { // The pattern doesn't intersect with the subrange at all, // so the subrange remains untouched. - remaining_ranges.push(Self::range_to_ctor(tcx, ty, subrange_lo..=subrange_hi)); + remaining_ranges.push( + Self::range_to_ctor(tcx, ty, subrange_lo..=subrange_hi, self.span), + ); } else { if lo > subrange_lo { // The pattern intersects an upper section of the // subrange, so a lower section will remain. - remaining_ranges.push(Self::range_to_ctor(tcx, ty, subrange_lo..=(lo - 1))); + remaining_ranges.push( + Self::range_to_ctor(tcx, ty, subrange_lo..=(lo - 1), self.span), + ); } if hi < subrange_hi { // The pattern intersects a lower section of the // subrange, so an upper section will remain. - remaining_ranges.push(Self::range_to_ctor(tcx, ty, (hi + 1)..=subrange_hi)); + remaining_ranges.push( + Self::range_to_ctor(tcx, ty, (hi + 1)..=subrange_hi, self.span), + ); } } } @@ -1017,7 +1072,8 @@ impl<'tcx> IntRange<'tcx> { let (lo, hi) = (*self.range.start(), *self.range.end()); let (other_lo, other_hi) = (*other.range.start(), *other.range.end()); if lo <= other_hi && other_lo <= hi { - Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty }) + let span = other.span; + Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty, span }) } else { None } @@ -1127,6 +1183,7 @@ pub fn is_useful<'p, 'a, 'tcx>( matrix: &Matrix<'p, 'tcx>, v: &[&Pat<'tcx>], witness: WitnessPreference, + hir_id: HirId, ) -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; debug!("is_useful({:#?}, {:#?})", matrix, v); @@ -1149,6 +1206,10 @@ pub fn is_useful<'p, 'a, 'tcx>( assert!(rows.iter().all(|r| r.len() == v.len())); + let (ty, span) = rows.iter() + .map(|r| (r[0].ty, r[0].span)) + .find(|(ty, _)| !ty.references_error()) + .unwrap_or((v[0].ty, v[0].span)); let pcx = PatCtxt { // TyErr is used to represent the type of wildcard patterns matching // against inaccessible (private) fields of structs, so that we won't @@ -1169,8 +1230,9 @@ pub fn is_useful<'p, 'a, 'tcx>( // FIXME: this might lead to "unstable" behavior with macro hygiene // introducing uninhabited patterns for inaccessible fields. We // need to figure out how to model that. - ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error()).unwrap_or(v[0].ty), - max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))) + ty, + max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))), + span, }; debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); @@ -1184,9 +1246,9 @@ pub fn is_useful<'p, 'a, 'tcx>( Useful } else { split_grouped_constructors( - cx.tcx, cx.param_env, constructors, matrix, pcx.ty, + cx.tcx, cx.param_env, constructors, matrix, pcx.ty, pcx.span, Some(hir_id), ).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) + is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id) ).find(|result| result.is_useful()).unwrap_or(NotUseful) } } else { @@ -1239,8 +1301,11 @@ pub fn is_useful<'p, 'a, 'tcx>( (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching); if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive { - split_grouped_constructors(cx.tcx, cx.param_env, all_ctors, matrix, pcx.ty) - .into_iter().map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness)) + split_grouped_constructors( + cx.tcx, cx.param_env, all_ctors, matrix, pcx.ty, DUMMY_SP, None, + ) + .into_iter() + .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id)) .find(|result| result.is_useful()) .unwrap_or(NotUseful) } else { @@ -1251,7 +1316,7 @@ pub fn is_useful<'p, 'a, 'tcx>( None } }).collect(); - match is_useful(cx, &matrix, &v[1..], witness) { + match is_useful(cx, &matrix, &v[1..], witness, hir_id) { UsefulWithWitness(pats) => { let cx = &*cx; // In this case, there's at least one "free" @@ -1344,6 +1409,7 @@ fn is_useful_specialized<'p, 'a, 'tcx>( ctor: Constructor<'tcx>, lty: Ty<'tcx>, witness: WitnessPreference, + hir_id: HirId, ) -> Usefulness<'tcx> { debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty); @@ -1361,7 +1427,7 @@ fn is_useful_specialized<'p, 'a, 'tcx>( .collect() ); match specialize(cx, v, &ctor, &wild_patterns) { - Some(v) => match is_useful(cx, &matrix, &v, witness) { + Some(v) => match is_useful(cx, &matrix, &v, witness, hir_id) { UsefulWithWitness(witnesses) => UsefulWithWitness( witnesses.into_iter() .map(|witness| witness.apply_constructor(cx, &ctor, lty)) @@ -1381,11 +1447,11 @@ fn is_useful_specialized<'p, 'a, 'tcx>( /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. /// /// Returns `None` in case of a catch-all, which can't be specialized. -fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, - pat: &Pat<'tcx>, - pcx: PatCtxt<'tcx>) - -> Option>> -{ +fn pat_constructors<'tcx>( + cx: &mut MatchCheckCtxt<'_, 'tcx>, + pat: &Pat<'tcx>, + pcx: PatCtxt<'tcx>, +) -> Option>> { match *pat.kind { PatKind::AscribeUserType { ref subpattern, .. } => pat_constructors(cx, subpattern, pcx), @@ -1394,13 +1460,14 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, PatKind::Variant { adt_def, variant_index, .. } => { Some(vec![Variant(adt_def.variants[variant_index].def_id)]) } - PatKind::Constant { value } => Some(vec![ConstantValue(value)]), + PatKind::Constant { value } => Some(vec![ConstantValue(value, pat.span)]), PatKind::Range(PatRange { lo, hi, end }) => Some(vec![ConstantRange( lo.eval_bits(cx.tcx, cx.param_env, lo.ty), hi.eval_bits(cx.tcx, cx.param_env, hi.ty), lo.ty, end, + pat.span, )]), PatKind::Array { .. } => match pcx.ty.kind { ty::Array(_, length) => Some(vec![ @@ -1433,7 +1500,7 @@ fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty ty::Tuple(ref fs) => fs.len() as u64, ty::Slice(..) | ty::Array(..) => match *ctor { Slice(length) => length, - ConstantValue(_) => 0, + ConstantValue(..) => 0, _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) } ty::Ref(..) => 1, @@ -1458,7 +1525,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( ty::Tuple(ref fs) => fs.into_iter().map(|t| t.expect_ty()).collect(), ty::Slice(ty) | ty::Array(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), - ConstantValue(_) => vec![], + ConstantValue(..) => vec![], _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) } ty::Ref(_, rty, _) => vec![rty], @@ -1556,8 +1623,8 @@ fn slice_pat_covered_by_const<'tcx>( // constructor is a range or constant with an integer type. fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>) -> bool { let ty = match ctor { - ConstantValue(value) => value.ty, - ConstantRange(_, _, ty, _) => ty, + ConstantValue(value, _) => value.ty, + ConstantRange(_, _, ty, _, _) => ty, _ => return false, }; if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.kind { @@ -1599,12 +1666,17 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>) /// boundaries for each interval range, sort them, then create constructors for each new interval /// between every pair of boundary points. (This essentially sums up to performing the intuitive /// merging operation depicted above.) +/// +/// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in +/// ranges that case. fn split_grouped_constructors<'p, 'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ctors: Vec>, &Matrix(ref m): &Matrix<'p, 'tcx>, ty: Ty<'tcx>, + span: Span, + hir_id: Option, ) -> Vec> { let mut split_ctors = Vec::with_capacity(ctors.len()); @@ -1621,7 +1693,7 @@ fn split_grouped_constructors<'p, 'tcx>( /// Represents a border between 2 integers. Because the intervals spanning borders /// must be able to cover every integer, we need to be able to represent /// 2^128 + 1 such borders. - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] enum Border { JustBefore(u128), AfterMax, @@ -1638,16 +1710,54 @@ fn split_grouped_constructors<'p, 'tcx>( vec![from, to].into_iter() } + // Collect the span and range of all the intersecting ranges to lint on likely + // incorrect range patterns. (#63987) + let mut overlaps = vec![]; // `borders` is the set of borders between equivalence classes: each equivalence // class lies between 2 borders. let row_borders = m.iter() - .flat_map(|row| IntRange::from_pat(tcx, param_env, row[0])) - .flat_map(|range| ctor_range.intersection(&range)) + .flat_map(|row| { + IntRange::from_pat(tcx, param_env, row[0]).map(|r| (r, row.len())) + }) + .flat_map(|(range, row_len)| { + let intersection = ctor_range.intersection(&range); + if let (Some(range), 1) = (&intersection, row_len) { + // FIXME: for now, only check for overlapping ranges on simple range + // patterns. Otherwise with the current logic the following is detected + // as overlapping: + // match (10u8, true) { + // (0 ..= 125, false) => {} + // (126 ..= 255, false) => {} + // (0 ..= 255, true) => {} + // } + overlaps.push(range.clone()); + } + intersection + }) .flat_map(|range| range_borders(range)); let ctor_borders = range_borders(ctor_range.clone()); let mut borders: Vec<_> = row_borders.chain(ctor_borders).collect(); borders.sort_unstable(); + if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { + let mut err = tcx.struct_span_lint_hir( + lint::builtin::UNREACHABLE_PATTERNS, + hir_id, + ctor_range.span, + "multiple patterns covering the same range", + ); + err.span_label(ctor_range.span, "overlapping patterns"); + for int_range in overlaps { + // Use the real type for user display of the ranges: + err.span_label(int_range.span, &format!( + "this range overlaps on `{}`", + IntRange::range_to_ctor(tcx, ty, int_range.range, DUMMY_SP) + .display(tcx), + )); + } + err.emit(); + } + // We're going to iterate through every pair of borders, making sure that each // represents an interval of nonnegative length, and convert each such interval // into a constructor. @@ -1655,18 +1765,18 @@ fn split_grouped_constructors<'p, 'tcx>( match (window[0], window[1]) { (Border::JustBefore(n), Border::JustBefore(m)) => { if n < m { - Some(IntRange { range: n..=(m - 1), ty }) + Some(IntRange { range: n..=(m - 1), ty, span }) } else { None } } (Border::JustBefore(n), Border::AfterMax) => { - Some(IntRange { range: n..=u128::MAX, ty }) + Some(IntRange { range: n..=u128::MAX, ty, span }) } (Border::AfterMax, _) => None, } }) { - split_ctors.push(IntRange::range_to_ctor(tcx, ty, range)); + split_ctors.push(IntRange::range_to_ctor(tcx, ty, range, span)); } } // Any other constructor can be used unchanged. @@ -1701,13 +1811,13 @@ fn constructor_covered_by_range<'tcx>( }; } match *ctor { - ConstantValue(value) => { + ConstantValue(value, _) => { let to = some_or_ok!(cmp_to(value)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(value)) && end) }, - ConstantRange(from, to, ty, RangeEnd::Included) => { + ConstantRange(from, to, ty, RangeEnd::Included, _) => { let to = some_or_ok!(cmp_to(ty::Const::from_bits( tcx, to, @@ -1721,7 +1831,7 @@ fn constructor_covered_by_range<'tcx>( ty::ParamEnv::empty().and(ty), ))) && end) }, - ConstantRange(from, to, ty, RangeEnd::Excluded) => { + ConstantRange(from, to, ty, RangeEnd::Excluded, _) => { let to = some_or_ok!(cmp_to(ty::Const::from_bits( tcx, to, @@ -1915,7 +2025,7 @@ fn specialize<'p, 'a: 'p, 'tcx>( None } } - ConstantValue(cv) => { + ConstantValue(cv, _) => { match slice_pat_covered_by_const( cx.tcx, pat.span, cv, prefix, slice, suffix, cx.param_env, ) { diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 9bed4fb66ea9d..fe57e12bcfcc8 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -10,6 +10,7 @@ use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::lint; use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc::hir::HirId; use rustc::hir::def::*; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -239,7 +240,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { .map(|pat| smallvec![pat.0]) .collect(); let scrut_ty = self.tables.node_type(scrut.hir_id); - check_exhaustive(cx, scrut_ty, scrut.span, &matrix); + check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id); }) } @@ -256,7 +257,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { expand_pattern(cx, pattern) ]].into_iter().collect(); - let witnesses = match check_not_useful(cx, pattern_ty, &pats) { + let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) { Ok(_) => return, Err(err) => err, }; @@ -389,7 +390,7 @@ fn check_arms<'tcx>( for &(pat, hir_pat) in pats { let v = smallvec![pat]; - match is_useful(cx, &seen, &v, LeaveOutWitness) { + match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) { NotUseful => { match source { hir::MatchSource::IfDesugar { .. } | @@ -428,6 +429,13 @@ fn check_arms<'tcx>( hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { + match pat.kind { + box PatternKind::Range(..) => { + // Covered in `is_useful() with more context` + break; + } + _ => {} + } let mut err = cx.tcx.struct_span_lint_hir( lint::builtin::UNREACHABLE_PATTERNS, hir_pat.hir_id, @@ -465,9 +473,10 @@ fn check_not_useful( cx: &mut MatchCheckCtxt<'_, 'tcx>, ty: Ty<'tcx>, matrix: &Matrix<'_, 'tcx>, + hir_id: HirId, ) -> Result<(), Vec>> { let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild }; - match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) { + match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness, hir_id) { NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable. UsefulWithWitness(pats) => Err(if pats.is_empty() { vec![wild_pattern] @@ -483,8 +492,9 @@ fn check_exhaustive<'tcx>( scrut_ty: Ty<'tcx>, sp: Span, matrix: &Matrix<'_, 'tcx>, + hir_id: HirId, ) { - let witnesses = match check_not_useful(cx, scrut_ty, matrix) { + let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) { Ok(_) => return, Err(err) => err, }; diff --git a/src/test/ui/check_match/issue-43253.rs b/src/test/ui/check_match/issue-43253.rs index a4d6e9b777f02..548300da03405 100644 --- a/src/test/ui/check_match/issue-43253.rs +++ b/src/test/ui/check_match/issue-43253.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![feature(exclusive_range_pattern)] #![warn(unreachable_patterns)] @@ -13,7 +13,7 @@ fn main() { match 10 { 1..10 => {}, - 9..=10 => {}, + 9..=10 => {}, //~ WARNING multiple patterns covering the same range _ => {}, } @@ -23,22 +23,25 @@ fn main() { _ => {}, } - // These cases should generate an "unreachable pattern" warning. + // These cases should generate "unreachable pattern" warnings. match 10 { 1..10 => {}, - 9 => {}, + 9 => {}, //~ WARNING unreachable pattern _ => {}, } match 10 { 1..10 => {}, - 8..=9 => {}, + 8..=9 => {}, //~ WARNING multiple patterns covering the same range _ => {}, } match 10 { - 1..10 => {}, - 9..=9 => {}, + 5..7 => {}, + 6 => {}, //~ WARNING unreachable pattern + 1..10 => {}, //~ WARNING multiple patterns covering the same range + 9..=9 => {}, //~ WARNING unreachable pattern + 6 => {}, //~ WARNING unreachable pattern _ => {}, } } diff --git a/src/test/ui/check_match/issue-43253.stderr b/src/test/ui/check_match/issue-43253.stderr index d961f623e1fa7..24dfa52beb687 100644 --- a/src/test/ui/check_match/issue-43253.stderr +++ b/src/test/ui/check_match/issue-43253.stderr @@ -1,8 +1,10 @@ -warning: unreachable pattern - --> $DIR/issue-43253.rs:29:9 +warning: multiple patterns covering the same range + --> $DIR/issue-43253.rs:16:9 | -LL | 9 => {}, - | ^ +LL | 1..10 => {}, + | ----- this range overlaps on `9i32` +LL | 9..=10 => {}, + | ^^^^^^ overlapping patterns | note: lint level defined here --> $DIR/issue-43253.rs:4:9 @@ -11,14 +13,44 @@ LL | #![warn(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ warning: unreachable pattern + --> $DIR/issue-43253.rs:29:9 + | +LL | 9 => {}, + | ^ + +warning: multiple patterns covering the same range --> $DIR/issue-43253.rs:35:9 | +LL | 1..10 => {}, + | ----- this range overlaps on `8i32..=9i32` LL | 8..=9 => {}, - | ^^^^^ + | ^^^^^ overlapping patterns warning: unreachable pattern --> $DIR/issue-43253.rs:41:9 | +LL | 6 => {}, + | ^ + +warning: multiple patterns covering the same range + --> $DIR/issue-43253.rs:42:9 + | +LL | 5..7 => {}, + | ---- this range overlaps on `5i32..=6i32` +LL | 6 => {}, + | - this range overlaps on `6i32` +LL | 1..10 => {}, + | ^^^^^ overlapping patterns + +warning: unreachable pattern + --> $DIR/issue-43253.rs:43:9 + | LL | 9..=9 => {}, | ^^^^^ +warning: unreachable pattern + --> $DIR/issue-43253.rs:44:9 + | +LL | 6 => {}, + | ^ + diff --git a/src/test/ui/exhaustive_integer_patterns.rs b/src/test/ui/exhaustive_integer_patterns.rs index 2570bc8a56078..ce2b44b8ef167 100644 --- a/src/test/ui/exhaustive_integer_patterns.rs +++ b/src/test/ui/exhaustive_integer_patterns.rs @@ -19,7 +19,7 @@ fn main() { 0 ..= 32 => {} 33 => {} 34 .. 128 => {} - 100 ..= 200 => {} + 100 ..= 200 => {} //~ ERROR multiple patterns covering the same range 200 => {} //~ ERROR unreachable pattern 201 ..= 255 => {} } @@ -41,7 +41,7 @@ fn main() { match x { //~ ERROR non-exhaustive patterns -7 => {} -5..=120 => {} - -2..=20 => {} //~ ERROR unreachable pattern + -2..=20 => {} //~ ERROR multiple patterns covering the same range 125 => {} } @@ -135,9 +135,9 @@ fn main() { (125 .. 128, false) => {} } - match 0u8 { // ok + match 0u8 { 0 .. 2 => {} - 1 ..= 2 => {} + 1 ..= 2 => {} //~ ERROR multiple patterns covering the same range _ => {} } diff --git a/src/test/ui/exhaustive_integer_patterns.stderr b/src/test/ui/exhaustive_integer_patterns.stderr index 6c4b7b0cc0352..ef3faceaa7e10 100644 --- a/src/test/ui/exhaustive_integer_patterns.stderr +++ b/src/test/ui/exhaustive_integer_patterns.stderr @@ -1,8 +1,10 @@ -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:23:9 +error: multiple patterns covering the same range + --> $DIR/exhaustive_integer_patterns.rs:22:9 | -LL | 200 => {} - | ^^^ +LL | 34 .. 128 => {} + | --------- this range overlaps on `100u8..=127u8` +LL | 100 ..= 200 => {} + | ^^^^^^^^^^^ overlapping patterns | note: lint level defined here --> $DIR/exhaustive_integer_patterns.rs:4:9 @@ -10,6 +12,12 @@ note: lint level defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ +error: unreachable pattern + --> $DIR/exhaustive_integer_patterns.rs:23:9 + | +LL | 200 => {} + | ^^^ + error[E0004]: non-exhaustive patterns: `128u8..=std::u8::MAX` not covered --> $DIR/exhaustive_integer_patterns.rs:28:11 | @@ -26,11 +34,13 @@ LL | match x { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: unreachable pattern +error: multiple patterns covering the same range --> $DIR/exhaustive_integer_patterns.rs:44:9 | +LL | -5..=120 => {} + | -------- this range overlaps on `-2i8..=20i8` LL | -2..=20 => {} - | ^^^^^^^ + | ^^^^^^^ overlapping patterns error[E0004]: non-exhaustive patterns: `std::i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered --> $DIR/exhaustive_integer_patterns.rs:41:11 @@ -80,6 +90,14 @@ LL | match (0u8, true) { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms +error: multiple patterns covering the same range + --> $DIR/exhaustive_integer_patterns.rs:140:9 + | +LL | 0 .. 2 => {} + | ------ this range overlaps on `1u8` +LL | 1 ..= 2 => {} + | ^^^^^^^ overlapping patterns + error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered --> $DIR/exhaustive_integer_patterns.rs:145:11 | @@ -104,6 +122,6 @@ LL | match 0u128 { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/match/match-range-fail-dominate.rs b/src/test/ui/match/match-range-fail-dominate.rs index a0cc773d20edd..4c0f57ffbeedd 100644 --- a/src/test/ui/match/match-range-fail-dominate.rs +++ b/src/test/ui/match/match-range-fail-dominate.rs @@ -1,39 +1,41 @@ -//error-pattern: unreachable -//error-pattern: unreachable -//error-pattern: unreachable -//error-pattern: unreachable -//error-pattern: unreachable - #![deny(unreachable_patterns)] fn main() { match 5 { 1 ..= 10 => { } - 5 ..= 6 => { } + 5 ..= 6 => { } //~ ERROR multiple patterns covering the same range _ => {} }; match 5 { 3 ..= 6 => { } - 4 ..= 6 => { } + 4 ..= 6 => { } //~ ERROR multiple patterns covering the same range _ => {} }; match 5 { 4 ..= 6 => { } - 4 ..= 6 => { } + 4 ..= 6 => { } //~ ERROR multiple patterns covering the same range _ => {} }; match 'c' { 'A' ..= 'z' => {} - 'a' ..= 'z' => {} + 'a' ..= 'z' => {} //~ ERROR multiple patterns covering the same range _ => {} }; match 1.0f64 { 0.01f64 ..= 6.5f64 => {} - 0.02f64 => {} + //~^ WARNING floating-point types cannot be used in patterns + //~| WARNING floating-point types cannot be used in patterns + //~| WARNING floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler + //~| WARNING this was previously accepted by the compiler + //~| WARNING this was previously accepted by the compiler + 0.02f64 => {} //~ ERROR unreachable pattern + //~^ WARNING floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler _ => {} }; } diff --git a/src/test/ui/match/match-range-fail-dominate.stderr b/src/test/ui/match/match-range-fail-dominate.stderr index d0ff4930a4519..af667be317de5 100644 --- a/src/test/ui/match/match-range-fail-dominate.stderr +++ b/src/test/ui/match/match-range-fail-dominate.stderr @@ -1,35 +1,43 @@ -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:12:7 +error: multiple patterns covering the same range + --> $DIR/match-range-fail-dominate.rs:6:7 | +LL | 1 ..= 10 => { } + | -------- this range overlaps on `5i32..=6i32` LL | 5 ..= 6 => { } - | ^^^^^^^ + | ^^^^^^^ overlapping patterns | note: lint level defined here - --> $DIR/match-range-fail-dominate.rs:7:9 + --> $DIR/match-range-fail-dominate.rs:1:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:18:7 +error: multiple patterns covering the same range + --> $DIR/match-range-fail-dominate.rs:12:7 | +LL | 3 ..= 6 => { } + | ------- this range overlaps on `4i32..=6i32` LL | 4 ..= 6 => { } - | ^^^^^^^ + | ^^^^^^^ overlapping patterns -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:24:7 +error: multiple patterns covering the same range + --> $DIR/match-range-fail-dominate.rs:18:7 | LL | 4 ..= 6 => { } - | ^^^^^^^ + | ------- this range overlaps on `4i32..=6i32` +LL | 4 ..= 6 => { } + | ^^^^^^^ overlapping patterns -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:30:7 +error: multiple patterns covering the same range + --> $DIR/match-range-fail-dominate.rs:24:7 | +LL | 'A' ..= 'z' => {} + | ----------- this range overlaps on `'a'..='z'` LL | 'a' ..= 'z' => {} - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ overlapping patterns warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:35:7 + --> $DIR/match-range-fail-dominate.rs:29:7 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^^ @@ -39,7 +47,7 @@ LL | 0.01f64 ..= 6.5f64 => {} = note: for more information, see issue #41620 warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:35:19 + --> $DIR/match-range-fail-dominate.rs:29:19 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^ @@ -63,7 +71,7 @@ LL | 0.02f64 => {} | ^^^^^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:35:7 + --> $DIR/match-range-fail-dominate.rs:29:7 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^^ diff --git a/src/test/ui/precise_pointer_size_matching.rs b/src/test/ui/precise_pointer_size_matching.rs index 759b63b188b35..239197af2ca1d 100644 --- a/src/test/ui/precise_pointer_size_matching.rs +++ b/src/test/ui/precise_pointer_size_matching.rs @@ -23,11 +23,11 @@ fn main() { match 0isize { //~ ERROR non-exhaustive patterns 1 ..= 8 => {} - -5 ..= 20 => {} + -5 ..= 20 => {} //~ ERROR multiple patterns covering the same range } match 0usize { //~ ERROR non-exhaustive patterns 1 ..= 8 => {} - 5 ..= 20 => {} + 5 ..= 20 => {} //~ ERROR multiple patterns covering the same range } } diff --git a/src/test/ui/precise_pointer_size_matching.stderr b/src/test/ui/precise_pointer_size_matching.stderr index 2c2c2aa04c233..06b0e73c5a3b7 100644 --- a/src/test/ui/precise_pointer_size_matching.stderr +++ b/src/test/ui/precise_pointer_size_matching.stderr @@ -1,3 +1,17 @@ +error: multiple patterns covering the same range + --> $DIR/precise_pointer_size_matching.rs:26:9 + | +LL | 1 ..= 8 => {} + | ------- this range overlaps on `1isize..=8isize` +LL | -5 ..= 20 => {} + | ^^^^^^^^^ overlapping patterns + | +note: lint level defined here + --> $DIR/precise_pointer_size_matching.rs:11:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + error[E0004]: non-exhaustive patterns: `std::isize::MIN..=-6isize` and `21isize..=std::isize::MAX` not covered --> $DIR/precise_pointer_size_matching.rs:24:11 | @@ -6,6 +20,14 @@ LL | match 0isize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms +error: multiple patterns covering the same range + --> $DIR/precise_pointer_size_matching.rs:31:9 + | +LL | 1 ..= 8 => {} + | ------- this range overlaps on `5usize..=8usize` +LL | 5 ..= 20 => {} + | ^^^^^^^^ overlapping patterns + error[E0004]: non-exhaustive patterns: `0usize` and `21usize..=std::usize::MAX` not covered --> $DIR/precise_pointer_size_matching.rs:29:11 | @@ -14,6 +36,6 @@ LL | match 0usize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0004`. From 220b9b29c26953ff14eb94be70e9741365783aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 29 Aug 2019 17:16:39 -0700 Subject: [PATCH 02/10] Move overlapping patterns to its own lint --- src/libcore/ascii.rs | 2 +- src/librustc/lint/builtin.rs | 7 +++++++ src/librustc_lint/lib.rs | 1 + src/librustc_mir/hair/pattern/_match.rs | 2 +- src/test/ui/check_match/issue-43253.rs | 2 +- src/test/ui/check_match/issue-43253.stderr | 8 +++++++- src/test/ui/exhaustive_integer_patterns.rs | 2 +- src/test/ui/exhaustive_integer_patterns.stderr | 8 +++++++- src/test/ui/match/match-range-fail-dominate.rs | 2 +- src/test/ui/match/match-range-fail-dominate.stderr | 12 +++++++++--- src/test/ui/precise_pointer_size_matching.rs | 2 +- src/test/ui/precise_pointer_size_matching.stderr | 6 +++--- 12 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 0492fbd55faf2..04aefd57ca2ea 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -101,7 +101,7 @@ pub fn escape_default(c: u8) -> EscapeDefault { b'\'' => ([b'\\', b'\'', 0, 0], 2), b'"' => ([b'\\', b'"', 0, 0], 2), // The three arms above are in the following range - #[allow(unreachable_patterns)] + #[allow(overlapping_patterns)] b'\x20' ..= b'\x7e' => ([c, 0, 0, 0], 1), _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), }; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 983e3a9922ec2..4c28f6372fe2c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -80,6 +80,12 @@ declare_lint! { "detects unreachable patterns" } +declare_lint! { + pub OVERLAPPING_PATTERNS, + Warn, + "detects overlapping patterns" +} + declare_lint! { pub UNUSED_MACROS, Warn, @@ -423,6 +429,7 @@ declare_lint_pass! { DEAD_CODE, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, + OVERLAPPING_PATTERNS, UNUSED_MACROS, WARNINGS, UNUSED_FEATURES, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 0e054013cd779..e3860e229d6b5 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -255,6 +255,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UNUSED_MUT, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, + OVERLAPPING_PATTERNS, UNUSED_MUST_USE, UNUSED_UNSAFE, PATH_STATEMENTS, diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 542f0ba5c9ca1..1b3c824458e73 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1741,7 +1741,7 @@ fn split_grouped_constructors<'p, 'tcx>( if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { let mut err = tcx.struct_span_lint_hir( - lint::builtin::UNREACHABLE_PATTERNS, + lint::builtin::OVERLAPPING_PATTERNS, hir_id, ctor_range.span, "multiple patterns covering the same range", diff --git a/src/test/ui/check_match/issue-43253.rs b/src/test/ui/check_match/issue-43253.rs index 548300da03405..5c6834459f0d4 100644 --- a/src/test/ui/check_match/issue-43253.rs +++ b/src/test/ui/check_match/issue-43253.rs @@ -1,7 +1,7 @@ // check-pass - #![feature(exclusive_range_pattern)] #![warn(unreachable_patterns)] +#![warn(overlapping_patterns)] fn main() { // These cases should generate no warning. diff --git a/src/test/ui/check_match/issue-43253.stderr b/src/test/ui/check_match/issue-43253.stderr index 24dfa52beb687..2f6888c0118aa 100644 --- a/src/test/ui/check_match/issue-43253.stderr +++ b/src/test/ui/check_match/issue-43253.stderr @@ -9,7 +9,7 @@ LL | 9..=10 => {}, note: lint level defined here --> $DIR/issue-43253.rs:4:9 | -LL | #![warn(unreachable_patterns)] +LL | #![warn(overlapping_patterns)] | ^^^^^^^^^^^^^^^^^^^^ warning: unreachable pattern @@ -17,6 +17,12 @@ warning: unreachable pattern | LL | 9 => {}, | ^ + | +note: lint level defined here + --> $DIR/issue-43253.rs:3:9 + | +LL | #![warn(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ warning: multiple patterns covering the same range --> $DIR/issue-43253.rs:35:9 diff --git a/src/test/ui/exhaustive_integer_patterns.rs b/src/test/ui/exhaustive_integer_patterns.rs index ce2b44b8ef167..ef88ce94aa6a2 100644 --- a/src/test/ui/exhaustive_integer_patterns.rs +++ b/src/test/ui/exhaustive_integer_patterns.rs @@ -1,7 +1,7 @@ #![feature(precise_pointer_size_matching)] #![feature(exclusive_range_pattern)] - #![deny(unreachable_patterns)] +#![deny(overlapping_patterns)] use std::{char, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128}; diff --git a/src/test/ui/exhaustive_integer_patterns.stderr b/src/test/ui/exhaustive_integer_patterns.stderr index ef3faceaa7e10..59cd3fffa8df5 100644 --- a/src/test/ui/exhaustive_integer_patterns.stderr +++ b/src/test/ui/exhaustive_integer_patterns.stderr @@ -9,7 +9,7 @@ LL | 100 ..= 200 => {} note: lint level defined here --> $DIR/exhaustive_integer_patterns.rs:4:9 | -LL | #![deny(unreachable_patterns)] +LL | #![deny(overlapping_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern @@ -17,6 +17,12 @@ error: unreachable pattern | LL | 200 => {} | ^^^ + | +note: lint level defined here + --> $DIR/exhaustive_integer_patterns.rs:3:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ error[E0004]: non-exhaustive patterns: `128u8..=std::u8::MAX` not covered --> $DIR/exhaustive_integer_patterns.rs:28:11 diff --git a/src/test/ui/match/match-range-fail-dominate.rs b/src/test/ui/match/match-range-fail-dominate.rs index 4c0f57ffbeedd..bdbb1f050a7a3 100644 --- a/src/test/ui/match/match-range-fail-dominate.rs +++ b/src/test/ui/match/match-range-fail-dominate.rs @@ -1,4 +1,4 @@ -#![deny(unreachable_patterns)] +#![deny(unreachable_patterns, overlapping_patterns)] fn main() { match 5 { diff --git a/src/test/ui/match/match-range-fail-dominate.stderr b/src/test/ui/match/match-range-fail-dominate.stderr index af667be317de5..b14e9b5008d9d 100644 --- a/src/test/ui/match/match-range-fail-dominate.stderr +++ b/src/test/ui/match/match-range-fail-dominate.stderr @@ -7,10 +7,10 @@ LL | 5 ..= 6 => { } | ^^^^^^^ overlapping patterns | note: lint level defined here - --> $DIR/match-range-fail-dominate.rs:1:9 + --> $DIR/match-range-fail-dominate.rs:1:31 | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(unreachable_patterns, overlapping_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ error: multiple patterns covering the same range --> $DIR/match-range-fail-dominate.rs:12:7 @@ -69,6 +69,12 @@ error: unreachable pattern | LL | 0.02f64 => {} | ^^^^^^^ + | +note: lint level defined here + --> $DIR/match-range-fail-dominate.rs:1:9 + | +LL | #![deny(unreachable_patterns, overlapping_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ warning: floating-point types cannot be used in patterns --> $DIR/match-range-fail-dominate.rs:29:7 diff --git a/src/test/ui/precise_pointer_size_matching.rs b/src/test/ui/precise_pointer_size_matching.rs index 239197af2ca1d..be2a140ddc3dd 100644 --- a/src/test/ui/precise_pointer_size_matching.rs +++ b/src/test/ui/precise_pointer_size_matching.rs @@ -8,7 +8,7 @@ #![feature(precise_pointer_size_matching)] #![feature(exclusive_range_pattern)] -#![deny(unreachable_patterns)] +#![deny(unreachable_patterns, overlapping_patterns)] use std::{usize, isize}; diff --git a/src/test/ui/precise_pointer_size_matching.stderr b/src/test/ui/precise_pointer_size_matching.stderr index 06b0e73c5a3b7..4930047fc1e9a 100644 --- a/src/test/ui/precise_pointer_size_matching.stderr +++ b/src/test/ui/precise_pointer_size_matching.stderr @@ -7,10 +7,10 @@ LL | -5 ..= 20 => {} | ^^^^^^^^^ overlapping patterns | note: lint level defined here - --> $DIR/precise_pointer_size_matching.rs:11:9 + --> $DIR/precise_pointer_size_matching.rs:11:31 | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(unreachable_patterns, overlapping_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ error[E0004]: non-exhaustive patterns: `std::isize::MIN..=-6isize` and `21isize..=std::isize::MAX` not covered --> $DIR/precise_pointer_size_matching.rs:24:11 From 916936c77488d0a75cc254b5bdc9a787c8ed8768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 29 Aug 2019 17:20:20 -0700 Subject: [PATCH 03/10] Silence lint in `fit_signed` and `fit_unsigned` --- src/librustc_target/abi/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index fde5c5bed4d91..2feee73847dfb 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -488,6 +488,7 @@ impl Integer { /// Finds the smallest Integer type which can represent the signed value. pub fn fit_signed(x: i128) -> Integer { + #[cfg_attr(not(stage0), allow(overlapping_patterns))] match x { -0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8, -0x0000_0000_0000_8000..=0x0000_0000_0000_7fff => I16, @@ -499,6 +500,7 @@ impl Integer { /// Finds the smallest Integer type which can represent the unsigned value. pub fn fit_unsigned(x: u128) -> Integer { + #[cfg_attr(not(stage0), allow(overlapping_patterns))] match x { 0..=0x0000_0000_0000_00ff => I8, 0..=0x0000_0000_0000_ffff => I16, From d2cb5a8c35cd40909f097bdbbc59fc870f0a8e91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 29 Aug 2019 17:41:25 -0700 Subject: [PATCH 04/10] Move lint emitter to its own method --- src/librustc_mir/hair/pattern/_match.rs | 45 +++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 1b3c824458e73..48ff7fff5edfe 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1739,24 +1739,7 @@ fn split_grouped_constructors<'p, 'tcx>( let mut borders: Vec<_> = row_borders.chain(ctor_borders).collect(); borders.sort_unstable(); - if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { - let mut err = tcx.struct_span_lint_hir( - lint::builtin::OVERLAPPING_PATTERNS, - hir_id, - ctor_range.span, - "multiple patterns covering the same range", - ); - err.span_label(ctor_range.span, "overlapping patterns"); - for int_range in overlaps { - // Use the real type for user display of the ranges: - err.span_label(int_range.span, &format!( - "this range overlaps on `{}`", - IntRange::range_to_ctor(tcx, ty, int_range.range, DUMMY_SP) - .display(tcx), - )); - } - err.emit(); - } + lint_unreachable_patterns(tcx, hir_id, ctor_range, ty, overlaps); // We're going to iterate through every pair of borders, making sure that each // represents an interval of nonnegative length, and convert each such interval @@ -1787,6 +1770,32 @@ fn split_grouped_constructors<'p, 'tcx>( split_ctors } +fn lint_unreachable_patterns( + tcx: TyCtxt<'tcx>, + hir_id: Option, + ctor_range: IntRange<'tcx>, + ty: Ty<'tcx>, + overlaps: Vec>, +) { + if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { + let mut err = tcx.struct_span_lint_hir( + lint::builtin::OVERLAPPING_PATTERNS, + hir_id, + ctor_range.span, + "multiple patterns covering the same range", + ); + err.span_label(ctor_range.span, "overlapping patterns"); + for int_range in overlaps { + // Use the real type for user display of the ranges: + err.span_label(int_range.span, &format!( + "this range overlaps on `{}`", + IntRange::range_to_ctor(tcx, ty, int_range.range, DUMMY_SP).display(tcx), + )); + } + err.emit(); + } +} + fn constructor_covered_by_range<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, From be9e6af65e5cd4811725c6f29fe99b7bf6e6611d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 29 Aug 2019 17:41:41 -0700 Subject: [PATCH 05/10] review comments: use if let --- src/librustc_mir/hair/pattern/check_match.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index fe57e12bcfcc8..d6ec155c96303 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -429,12 +429,9 @@ fn check_arms<'tcx>( hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - match pat.kind { - box PatternKind::Range(..) => { - // Covered in `is_useful() with more context` - break; - } - _ => {} + if let box PatternKind::Range(..) = pat.kind { + // Covered by `overlapping_patterns` with more context + break; } let mut err = cx.tcx.struct_span_lint_hir( lint::builtin::UNREACHABLE_PATTERNS, From 1ec60730fecfc72eb7454f2b8d37f7de7068cd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 29 Aug 2019 17:42:45 -0700 Subject: [PATCH 06/10] Deduplicate code for formatting `RangeEnd` --- src/librustc/hir/mod.rs | 9 +++++++++ src/librustc_mir/hair/pattern/_match.rs | 7 ++----- src/librustc_mir/hair/pattern/mod.rs | 5 +---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 7350f89018be2..02b391615b621 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -989,6 +989,15 @@ pub enum RangeEnd { Excluded, } +impl fmt::Display for RangeEnd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + RangeEnd::Included => "..=", + RangeEnd::Excluded => "..", + }) + } +} + #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum PatKind { /// Represents a wildcard pattern (i.e., `_`). diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 48ff7fff5edfe..636bb2ed6179c 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -482,12 +482,9 @@ impl<'tcx> Constructor<'tcx> { // Get the right sign on the output: let ty = ty::ParamEnv::empty().and(*ty); format!( - "{}..{}{}", + "{}{}{}", ty::Const::from_bits(tcx, *lo, ty), - match range_end { - RangeEnd::Included => "=", - RangeEnd::Excluded => "", - }, + range_end, ty::Const::from_bits(tcx, *hi, ty), ) } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 58d741b9295a3..7e17162dfb3ef 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -312,10 +312,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } PatKind::Range(PatRange { lo, hi, end }) => { write!(f, "{}", lo)?; - match end { - RangeEnd::Included => write!(f, "..=")?, - RangeEnd::Excluded => write!(f, "..")?, - } + write!(f, "{}", end)?; write!(f, "{}", hi) } PatKind::Slice { ref prefix, ref slice, ref suffix } | From 6832da85c2241c9d75d01f1779f54cd9054d7a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 29 Aug 2019 18:00:29 -0700 Subject: [PATCH 07/10] rename method --- src/librustc_mir/hair/pattern/_match.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 636bb2ed6179c..04a42d85aff6e 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1736,7 +1736,7 @@ fn split_grouped_constructors<'p, 'tcx>( let mut borders: Vec<_> = row_borders.chain(ctor_borders).collect(); borders.sort_unstable(); - lint_unreachable_patterns(tcx, hir_id, ctor_range, ty, overlaps); + lint_overlapping_patterns(tcx, hir_id, ctor_range, ty, overlaps); // We're going to iterate through every pair of borders, making sure that each // represents an interval of nonnegative length, and convert each such interval @@ -1767,7 +1767,7 @@ fn split_grouped_constructors<'p, 'tcx>( split_ctors } -fn lint_unreachable_patterns( +fn lint_overlapping_patterns( tcx: TyCtxt<'tcx>, hir_id: Option, ctor_range: IntRange<'tcx>, From 89b19ccfdc6117f4df4d8c765464d6d929d483e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 30 Aug 2019 13:37:59 -0700 Subject: [PATCH 08/10] Continue to emit unreachable pattern on cases caught by overlapping patterns --- src/librustc_mir/hair/pattern/check_match.rs | 4 -- src/test/ui/check_match/issue-43253.stderr | 6 +++ src/test/ui/exhaustive_integer_patterns.rs | 4 +- .../ui/exhaustive_integer_patterns.stderr | 26 +++++---- .../ui/match/match-range-fail-dominate.rs | 16 ++++-- .../ui/match/match-range-fail-dominate.stderr | 54 +++++++++++++------ 6 files changed, 76 insertions(+), 34 deletions(-) diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index d6ec155c96303..7bc4bf291ee48 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -429,10 +429,6 @@ fn check_arms<'tcx>( hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - if let box PatternKind::Range(..) = pat.kind { - // Covered by `overlapping_patterns` with more context - break; - } let mut err = cx.tcx.struct_span_lint_hir( lint::builtin::UNREACHABLE_PATTERNS, hir_pat.hir_id, diff --git a/src/test/ui/check_match/issue-43253.stderr b/src/test/ui/check_match/issue-43253.stderr index 2f6888c0118aa..ca4cd89732276 100644 --- a/src/test/ui/check_match/issue-43253.stderr +++ b/src/test/ui/check_match/issue-43253.stderr @@ -32,6 +32,12 @@ LL | 1..10 => {}, LL | 8..=9 => {}, | ^^^^^ overlapping patterns +warning: unreachable pattern + --> $DIR/issue-43253.rs:35:9 + | +LL | 8..=9 => {}, + | ^^^^^ + warning: unreachable pattern --> $DIR/issue-43253.rs:41:9 | diff --git a/src/test/ui/exhaustive_integer_patterns.rs b/src/test/ui/exhaustive_integer_patterns.rs index ef88ce94aa6a2..a0c1b013f390a 100644 --- a/src/test/ui/exhaustive_integer_patterns.rs +++ b/src/test/ui/exhaustive_integer_patterns.rs @@ -41,7 +41,9 @@ fn main() { match x { //~ ERROR non-exhaustive patterns -7 => {} -5..=120 => {} - -2..=20 => {} //~ ERROR multiple patterns covering the same range + -2..=20 => {} + //~^ ERROR unreachable pattern + //~| ERROR multiple patterns covering the same range 125 => {} } diff --git a/src/test/ui/exhaustive_integer_patterns.stderr b/src/test/ui/exhaustive_integer_patterns.stderr index 59cd3fffa8df5..44fbc96922571 100644 --- a/src/test/ui/exhaustive_integer_patterns.stderr +++ b/src/test/ui/exhaustive_integer_patterns.stderr @@ -48,6 +48,12 @@ LL | -5..=120 => {} LL | -2..=20 => {} | ^^^^^^^ overlapping patterns +error: unreachable pattern + --> $DIR/exhaustive_integer_patterns.rs:44:9 + | +LL | -2..=20 => {} + | ^^^^^^^ + error[E0004]: non-exhaustive patterns: `std::i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered --> $DIR/exhaustive_integer_patterns.rs:41:11 | @@ -57,7 +63,7 @@ LL | match x { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `std::i8::MIN` not covered - --> $DIR/exhaustive_integer_patterns.rs:82:11 + --> $DIR/exhaustive_integer_patterns.rs:84:11 | LL | match 0i8 { | ^^^ pattern `std::i8::MIN` not covered @@ -65,7 +71,7 @@ LL | match 0i8 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `0i16` not covered - --> $DIR/exhaustive_integer_patterns.rs:90:11 + --> $DIR/exhaustive_integer_patterns.rs:92:11 | LL | match 0i16 { | ^^^^ pattern `0i16` not covered @@ -73,7 +79,7 @@ LL | match 0i16 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `128u8..=std::u8::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:108:11 + --> $DIR/exhaustive_integer_patterns.rs:110:11 | LL | match 0u8 { | ^^^ pattern `128u8..=std::u8::MAX` not covered @@ -81,7 +87,7 @@ LL | match 0u8 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=std::u8::MAX, Some(_))` not covered - --> $DIR/exhaustive_integer_patterns.rs:120:11 + --> $DIR/exhaustive_integer_patterns.rs:122:11 | LL | match (0u8, Some(())) { | ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=std::u8::MAX, Some(_))` not covered @@ -89,7 +95,7 @@ LL | match (0u8, Some(())) { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(126u8..=127u8, false)` not covered - --> $DIR/exhaustive_integer_patterns.rs:125:11 + --> $DIR/exhaustive_integer_patterns.rs:127:11 | LL | match (0u8, true) { | ^^^^^^^^^^^ pattern `(126u8..=127u8, false)` not covered @@ -97,7 +103,7 @@ LL | match (0u8, true) { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: multiple patterns covering the same range - --> $DIR/exhaustive_integer_patterns.rs:140:9 + --> $DIR/exhaustive_integer_patterns.rs:142:9 | LL | 0 .. 2 => {} | ------ this range overlaps on `1u8` @@ -105,7 +111,7 @@ LL | 1 ..= 2 => {} | ^^^^^^^ overlapping patterns error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:145:11 + --> $DIR/exhaustive_integer_patterns.rs:147:11 | LL | match 0u128 { | ^^^^^ pattern `std::u128::MAX` not covered @@ -113,7 +119,7 @@ LL | match 0u128 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `5u128..=std::u128::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:149:11 + --> $DIR/exhaustive_integer_patterns.rs:151:11 | LL | match 0u128 { | ^^^^^ pattern `5u128..=std::u128::MAX` not covered @@ -121,13 +127,13 @@ LL | match 0u128 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `0u128..=3u128` not covered - --> $DIR/exhaustive_integer_patterns.rs:153:11 + --> $DIR/exhaustive_integer_patterns.rs:155:11 | LL | match 0u128 { | ^^^^^ pattern `0u128..=3u128` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: aborting due to 15 previous errors +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/match/match-range-fail-dominate.rs b/src/test/ui/match/match-range-fail-dominate.rs index bdbb1f050a7a3..b6a89b8910c49 100644 --- a/src/test/ui/match/match-range-fail-dominate.rs +++ b/src/test/ui/match/match-range-fail-dominate.rs @@ -3,25 +3,33 @@ fn main() { match 5 { 1 ..= 10 => { } - 5 ..= 6 => { } //~ ERROR multiple patterns covering the same range + 5 ..= 6 => { } + //~^ ERROR unreachable pattern + //~| ERROR multiple patterns covering the same range _ => {} }; match 5 { 3 ..= 6 => { } - 4 ..= 6 => { } //~ ERROR multiple patterns covering the same range + 4 ..= 6 => { } + //~^ ERROR unreachable pattern + //~| ERROR multiple patterns covering the same range _ => {} }; match 5 { 4 ..= 6 => { } - 4 ..= 6 => { } //~ ERROR multiple patterns covering the same range + 4 ..= 6 => { } + //~^ ERROR unreachable pattern + //~| ERROR multiple patterns covering the same range _ => {} }; match 'c' { 'A' ..= 'z' => {} - 'a' ..= 'z' => {} //~ ERROR multiple patterns covering the same range + 'a' ..= 'z' => {} + //~^ ERROR unreachable pattern + //~| ERROR multiple patterns covering the same range _ => {} }; diff --git a/src/test/ui/match/match-range-fail-dominate.stderr b/src/test/ui/match/match-range-fail-dominate.stderr index b14e9b5008d9d..4a76e05fab53e 100644 --- a/src/test/ui/match/match-range-fail-dominate.stderr +++ b/src/test/ui/match/match-range-fail-dominate.stderr @@ -12,32 +12,62 @@ note: lint level defined here LL | #![deny(unreachable_patterns, overlapping_patterns)] | ^^^^^^^^^^^^^^^^^^^^ +error: unreachable pattern + --> $DIR/match-range-fail-dominate.rs:6:7 + | +LL | 5 ..= 6 => { } + | ^^^^^^^ + | +note: lint level defined here + --> $DIR/match-range-fail-dominate.rs:1:9 + | +LL | #![deny(unreachable_patterns, overlapping_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + error: multiple patterns covering the same range - --> $DIR/match-range-fail-dominate.rs:12:7 + --> $DIR/match-range-fail-dominate.rs:14:7 | LL | 3 ..= 6 => { } | ------- this range overlaps on `4i32..=6i32` LL | 4 ..= 6 => { } | ^^^^^^^ overlapping patterns +error: unreachable pattern + --> $DIR/match-range-fail-dominate.rs:14:7 + | +LL | 4 ..= 6 => { } + | ^^^^^^^ + error: multiple patterns covering the same range - --> $DIR/match-range-fail-dominate.rs:18:7 + --> $DIR/match-range-fail-dominate.rs:22:7 | LL | 4 ..= 6 => { } | ------- this range overlaps on `4i32..=6i32` LL | 4 ..= 6 => { } | ^^^^^^^ overlapping patterns +error: unreachable pattern + --> $DIR/match-range-fail-dominate.rs:22:7 + | +LL | 4 ..= 6 => { } + | ^^^^^^^ + error: multiple patterns covering the same range - --> $DIR/match-range-fail-dominate.rs:24:7 + --> $DIR/match-range-fail-dominate.rs:30:7 | LL | 'A' ..= 'z' => {} | ----------- this range overlaps on `'a'..='z'` LL | 'a' ..= 'z' => {} | ^^^^^^^^^^^ overlapping patterns +error: unreachable pattern + --> $DIR/match-range-fail-dominate.rs:30:7 + | +LL | 'a' ..= 'z' => {} + | ^^^^^^^^^^^ + warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:29:7 + --> $DIR/match-range-fail-dominate.rs:37:7 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^^ @@ -47,7 +77,7 @@ LL | 0.01f64 ..= 6.5f64 => {} = note: for more information, see issue #41620 warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:29:19 + --> $DIR/match-range-fail-dominate.rs:37:19 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^ @@ -56,7 +86,7 @@ LL | 0.01f64 ..= 6.5f64 => {} = note: for more information, see issue #41620 warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:36:7 + --> $DIR/match-range-fail-dominate.rs:44:7 | LL | 0.02f64 => {} | ^^^^^^^ @@ -65,19 +95,13 @@ LL | 0.02f64 => {} = note: for more information, see issue #41620 error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:36:7 + --> $DIR/match-range-fail-dominate.rs:44:7 | LL | 0.02f64 => {} | ^^^^^^^ - | -note: lint level defined here - --> $DIR/match-range-fail-dominate.rs:1:9 - | -LL | #![deny(unreachable_patterns, overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:29:7 + --> $DIR/match-range-fail-dominate.rs:37:7 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^^ @@ -85,5 +109,5 @@ LL | 0.01f64 ..= 6.5f64 => {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 -error: aborting due to 5 previous errors +error: aborting due to 9 previous errors From 73d6efc43e0629b2028e7d031306088f44f84782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 6 Oct 2019 21:47:01 -0700 Subject: [PATCH 09/10] Only emit overlapping patterns lint if the overlap is partial --- src/libcore/ascii.rs | 2 - src/librustc_mir/hair/pattern/_match.rs | 35 +++++++++++- src/librustc_target/abi/mod.rs | 2 - src/test/ui/check_match/issue-43253.stderr | 18 ------ src/test/ui/exhaustive_integer_patterns.rs | 1 - .../ui/exhaustive_integer_patterns.stderr | 28 ++++------ src/test/ui/issues/issue-13867.rs | 1 + src/test/ui/issues/issue-21475.rs | 2 +- src/test/ui/issues/issue-26251.rs | 2 + .../ui/match/match-range-fail-dominate.rs | 4 -- .../ui/match/match-range-fail-dominate.stderr | 56 +++---------------- src/test/ui/precise_pointer_size_matching.rs | 2 +- .../ui/precise_pointer_size_matching.stderr | 22 +++----- .../rfc-2005-default-binding-mode/range.rs | 2 +- 14 files changed, 66 insertions(+), 111 deletions(-) diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 04aefd57ca2ea..4087333e2cf6d 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -100,8 +100,6 @@ pub fn escape_default(c: u8) -> EscapeDefault { b'\\' => ([b'\\', b'\\', 0, 0], 2), b'\'' => ([b'\\', b'\'', 0, 0], 2), b'"' => ([b'\\', b'"', 0, 0], 2), - // The three arms above are in the following range - #[allow(overlapping_patterns)] b'\x20' ..= b'\x7e' => ([c, 0, 0, 0], 1), _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), }; diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 04a42d85aff6e..580ded50b05c6 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1075,6 +1075,38 @@ impl<'tcx> IntRange<'tcx> { None } } + + fn suspicious_intersection(&self, other: &Self) -> bool { + let (lo, hi) = (*self.range.start(), *self.range.end()); + let (other_lo, other_hi) = (*other.range.start(), *other.range.end()); + + // `false` in the following cases: + // 1 ---- + // 2 ---------- + // + // 1 ---------- + // 2 ---- + // + // 1 ---- + // 2 ---- + // + // 1 ---- + // 2 ---- + + // `true` in the following cases: + // 1 --------- + // 2 ---------- + lo < other_lo && hi > other_lo && hi < other_hi || + // 1 --------- + // 2 ---------- + lo > other_lo && lo < other_hi && hi > other_hi || + // 1 ---- + // 2 ---- + lo == other_hi && other_lo < lo || + // 1 ---- + // 2 ----- + hi == other_lo && lo < other_lo + } } // A request for missing constructor data in terms of either: @@ -1718,7 +1750,8 @@ fn split_grouped_constructors<'p, 'tcx>( }) .flat_map(|(range, row_len)| { let intersection = ctor_range.intersection(&range); - if let (Some(range), 1) = (&intersection, row_len) { + let should_lint = ctor_range.suspicious_intersection(&range); + if let (Some(range), 1, true) = (&intersection, row_len, should_lint) { // FIXME: for now, only check for overlapping ranges on simple range // patterns. Otherwise with the current logic the following is detected // as overlapping: diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 2feee73847dfb..fde5c5bed4d91 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -488,7 +488,6 @@ impl Integer { /// Finds the smallest Integer type which can represent the signed value. pub fn fit_signed(x: i128) -> Integer { - #[cfg_attr(not(stage0), allow(overlapping_patterns))] match x { -0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8, -0x0000_0000_0000_8000..=0x0000_0000_0000_7fff => I16, @@ -500,7 +499,6 @@ impl Integer { /// Finds the smallest Integer type which can represent the unsigned value. pub fn fit_unsigned(x: u128) -> Integer { - #[cfg_attr(not(stage0), allow(overlapping_patterns))] match x { 0..=0x0000_0000_0000_00ff => I8, 0..=0x0000_0000_0000_ffff => I16, diff --git a/src/test/ui/check_match/issue-43253.stderr b/src/test/ui/check_match/issue-43253.stderr index ca4cd89732276..cb4a0486eef9a 100644 --- a/src/test/ui/check_match/issue-43253.stderr +++ b/src/test/ui/check_match/issue-43253.stderr @@ -24,14 +24,6 @@ note: lint level defined here LL | #![warn(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -warning: multiple patterns covering the same range - --> $DIR/issue-43253.rs:35:9 - | -LL | 1..10 => {}, - | ----- this range overlaps on `8i32..=9i32` -LL | 8..=9 => {}, - | ^^^^^ overlapping patterns - warning: unreachable pattern --> $DIR/issue-43253.rs:35:9 | @@ -44,16 +36,6 @@ warning: unreachable pattern LL | 6 => {}, | ^ -warning: multiple patterns covering the same range - --> $DIR/issue-43253.rs:42:9 - | -LL | 5..7 => {}, - | ---- this range overlaps on `5i32..=6i32` -LL | 6 => {}, - | - this range overlaps on `6i32` -LL | 1..10 => {}, - | ^^^^^ overlapping patterns - warning: unreachable pattern --> $DIR/issue-43253.rs:43:9 | diff --git a/src/test/ui/exhaustive_integer_patterns.rs b/src/test/ui/exhaustive_integer_patterns.rs index a0c1b013f390a..442b2f772572c 100644 --- a/src/test/ui/exhaustive_integer_patterns.rs +++ b/src/test/ui/exhaustive_integer_patterns.rs @@ -43,7 +43,6 @@ fn main() { -5..=120 => {} -2..=20 => {} //~^ ERROR unreachable pattern - //~| ERROR multiple patterns covering the same range 125 => {} } diff --git a/src/test/ui/exhaustive_integer_patterns.stderr b/src/test/ui/exhaustive_integer_patterns.stderr index 44fbc96922571..4c5806f9606f8 100644 --- a/src/test/ui/exhaustive_integer_patterns.stderr +++ b/src/test/ui/exhaustive_integer_patterns.stderr @@ -40,14 +40,6 @@ LL | match x { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: multiple patterns covering the same range - --> $DIR/exhaustive_integer_patterns.rs:44:9 - | -LL | -5..=120 => {} - | -------- this range overlaps on `-2i8..=20i8` -LL | -2..=20 => {} - | ^^^^^^^ overlapping patterns - error: unreachable pattern --> $DIR/exhaustive_integer_patterns.rs:44:9 | @@ -63,7 +55,7 @@ LL | match x { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `std::i8::MIN` not covered - --> $DIR/exhaustive_integer_patterns.rs:84:11 + --> $DIR/exhaustive_integer_patterns.rs:83:11 | LL | match 0i8 { | ^^^ pattern `std::i8::MIN` not covered @@ -71,7 +63,7 @@ LL | match 0i8 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `0i16` not covered - --> $DIR/exhaustive_integer_patterns.rs:92:11 + --> $DIR/exhaustive_integer_patterns.rs:91:11 | LL | match 0i16 { | ^^^^ pattern `0i16` not covered @@ -79,7 +71,7 @@ LL | match 0i16 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `128u8..=std::u8::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:110:11 + --> $DIR/exhaustive_integer_patterns.rs:109:11 | LL | match 0u8 { | ^^^ pattern `128u8..=std::u8::MAX` not covered @@ -87,7 +79,7 @@ LL | match 0u8 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=std::u8::MAX, Some(_))` not covered - --> $DIR/exhaustive_integer_patterns.rs:122:11 + --> $DIR/exhaustive_integer_patterns.rs:121:11 | LL | match (0u8, Some(())) { | ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=std::u8::MAX, Some(_))` not covered @@ -95,7 +87,7 @@ LL | match (0u8, Some(())) { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(126u8..=127u8, false)` not covered - --> $DIR/exhaustive_integer_patterns.rs:127:11 + --> $DIR/exhaustive_integer_patterns.rs:126:11 | LL | match (0u8, true) { | ^^^^^^^^^^^ pattern `(126u8..=127u8, false)` not covered @@ -103,7 +95,7 @@ LL | match (0u8, true) { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: multiple patterns covering the same range - --> $DIR/exhaustive_integer_patterns.rs:142:9 + --> $DIR/exhaustive_integer_patterns.rs:141:9 | LL | 0 .. 2 => {} | ------ this range overlaps on `1u8` @@ -111,7 +103,7 @@ LL | 1 ..= 2 => {} | ^^^^^^^ overlapping patterns error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:147:11 + --> $DIR/exhaustive_integer_patterns.rs:146:11 | LL | match 0u128 { | ^^^^^ pattern `std::u128::MAX` not covered @@ -119,7 +111,7 @@ LL | match 0u128 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `5u128..=std::u128::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:151:11 + --> $DIR/exhaustive_integer_patterns.rs:150:11 | LL | match 0u128 { | ^^^^^ pattern `5u128..=std::u128::MAX` not covered @@ -127,13 +119,13 @@ LL | match 0u128 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `0u128..=3u128` not covered - --> $DIR/exhaustive_integer_patterns.rs:155:11 + --> $DIR/exhaustive_integer_patterns.rs:154:11 | LL | match 0u128 { | ^^^^^ pattern `0u128..=3u128` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: aborting due to 16 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-13867.rs b/src/test/ui/issues/issue-13867.rs index e66368f9ba8fa..809205685634e 100644 --- a/src/test/ui/issues/issue-13867.rs +++ b/src/test/ui/issues/issue-13867.rs @@ -1,6 +1,7 @@ // run-pass // Test that codegen works correctly when there are multiple refutable // patterns in match expression. +#![allow(overlapping_patterns)] enum Foo { diff --git a/src/test/ui/issues/issue-21475.rs b/src/test/ui/issues/issue-21475.rs index 16d003aba7cab..ab0a18869632a 100644 --- a/src/test/ui/issues/issue-21475.rs +++ b/src/test/ui/issues/issue-21475.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(unused_imports)] +#![allow(unused_imports, overlapping_patterns)] // pretty-expanded FIXME #23616 use m::{START, END}; diff --git a/src/test/ui/issues/issue-26251.rs b/src/test/ui/issues/issue-26251.rs index 0434ef9e5a958..edb06fea8ad53 100644 --- a/src/test/ui/issues/issue-26251.rs +++ b/src/test/ui/issues/issue-26251.rs @@ -1,4 +1,6 @@ // run-pass +#![allow(overlapping_patterns)] + fn main() { let x = 'a'; diff --git a/src/test/ui/match/match-range-fail-dominate.rs b/src/test/ui/match/match-range-fail-dominate.rs index b6a89b8910c49..7de7b7e79be44 100644 --- a/src/test/ui/match/match-range-fail-dominate.rs +++ b/src/test/ui/match/match-range-fail-dominate.rs @@ -5,7 +5,6 @@ fn main() { 1 ..= 10 => { } 5 ..= 6 => { } //~^ ERROR unreachable pattern - //~| ERROR multiple patterns covering the same range _ => {} }; @@ -13,7 +12,6 @@ fn main() { 3 ..= 6 => { } 4 ..= 6 => { } //~^ ERROR unreachable pattern - //~| ERROR multiple patterns covering the same range _ => {} }; @@ -21,7 +19,6 @@ fn main() { 4 ..= 6 => { } 4 ..= 6 => { } //~^ ERROR unreachable pattern - //~| ERROR multiple patterns covering the same range _ => {} }; @@ -29,7 +26,6 @@ fn main() { 'A' ..= 'z' => {} 'a' ..= 'z' => {} //~^ ERROR unreachable pattern - //~| ERROR multiple patterns covering the same range _ => {} }; diff --git a/src/test/ui/match/match-range-fail-dominate.stderr b/src/test/ui/match/match-range-fail-dominate.stderr index 4a76e05fab53e..c15186d2558f2 100644 --- a/src/test/ui/match/match-range-fail-dominate.stderr +++ b/src/test/ui/match/match-range-fail-dominate.stderr @@ -1,17 +1,3 @@ -error: multiple patterns covering the same range - --> $DIR/match-range-fail-dominate.rs:6:7 - | -LL | 1 ..= 10 => { } - | -------- this range overlaps on `5i32..=6i32` -LL | 5 ..= 6 => { } - | ^^^^^^^ overlapping patterns - | -note: lint level defined here - --> $DIR/match-range-fail-dominate.rs:1:31 - | -LL | #![deny(unreachable_patterns, overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - error: unreachable pattern --> $DIR/match-range-fail-dominate.rs:6:7 | @@ -24,50 +10,26 @@ note: lint level defined here LL | #![deny(unreachable_patterns, overlapping_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: multiple patterns covering the same range - --> $DIR/match-range-fail-dominate.rs:14:7 - | -LL | 3 ..= 6 => { } - | ------- this range overlaps on `4i32..=6i32` -LL | 4 ..= 6 => { } - | ^^^^^^^ overlapping patterns - error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:14:7 + --> $DIR/match-range-fail-dominate.rs:13:7 | LL | 4 ..= 6 => { } | ^^^^^^^ -error: multiple patterns covering the same range - --> $DIR/match-range-fail-dominate.rs:22:7 - | -LL | 4 ..= 6 => { } - | ------- this range overlaps on `4i32..=6i32` -LL | 4 ..= 6 => { } - | ^^^^^^^ overlapping patterns - error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:22:7 + --> $DIR/match-range-fail-dominate.rs:20:7 | LL | 4 ..= 6 => { } | ^^^^^^^ -error: multiple patterns covering the same range - --> $DIR/match-range-fail-dominate.rs:30:7 - | -LL | 'A' ..= 'z' => {} - | ----------- this range overlaps on `'a'..='z'` -LL | 'a' ..= 'z' => {} - | ^^^^^^^^^^^ overlapping patterns - error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:30:7 + --> $DIR/match-range-fail-dominate.rs:27:7 | LL | 'a' ..= 'z' => {} | ^^^^^^^^^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:37:7 + --> $DIR/match-range-fail-dominate.rs:33:7 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^^ @@ -77,7 +39,7 @@ LL | 0.01f64 ..= 6.5f64 => {} = note: for more information, see issue #41620 warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:37:19 + --> $DIR/match-range-fail-dominate.rs:33:19 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^ @@ -86,7 +48,7 @@ LL | 0.01f64 ..= 6.5f64 => {} = note: for more information, see issue #41620 warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:44:7 + --> $DIR/match-range-fail-dominate.rs:40:7 | LL | 0.02f64 => {} | ^^^^^^^ @@ -95,13 +57,13 @@ LL | 0.02f64 => {} = note: for more information, see issue #41620 error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:44:7 + --> $DIR/match-range-fail-dominate.rs:40:7 | LL | 0.02f64 => {} | ^^^^^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:37:7 + --> $DIR/match-range-fail-dominate.rs:33:7 | LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^^ @@ -109,5 +71,5 @@ LL | 0.01f64 ..= 6.5f64 => {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 -error: aborting due to 9 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/precise_pointer_size_matching.rs b/src/test/ui/precise_pointer_size_matching.rs index be2a140ddc3dd..ee91088c0c36a 100644 --- a/src/test/ui/precise_pointer_size_matching.rs +++ b/src/test/ui/precise_pointer_size_matching.rs @@ -23,7 +23,7 @@ fn main() { match 0isize { //~ ERROR non-exhaustive patterns 1 ..= 8 => {} - -5 ..= 20 => {} //~ ERROR multiple patterns covering the same range + -5 ..= 20 => {} } match 0usize { //~ ERROR non-exhaustive patterns diff --git a/src/test/ui/precise_pointer_size_matching.stderr b/src/test/ui/precise_pointer_size_matching.stderr index 4930047fc1e9a..98d347e06b609 100644 --- a/src/test/ui/precise_pointer_size_matching.stderr +++ b/src/test/ui/precise_pointer_size_matching.stderr @@ -1,17 +1,3 @@ -error: multiple patterns covering the same range - --> $DIR/precise_pointer_size_matching.rs:26:9 - | -LL | 1 ..= 8 => {} - | ------- this range overlaps on `1isize..=8isize` -LL | -5 ..= 20 => {} - | ^^^^^^^^^ overlapping patterns - | -note: lint level defined here - --> $DIR/precise_pointer_size_matching.rs:11:31 - | -LL | #![deny(unreachable_patterns, overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - error[E0004]: non-exhaustive patterns: `std::isize::MIN..=-6isize` and `21isize..=std::isize::MAX` not covered --> $DIR/precise_pointer_size_matching.rs:24:11 | @@ -27,6 +13,12 @@ LL | 1 ..= 8 => {} | ------- this range overlaps on `5usize..=8usize` LL | 5 ..= 20 => {} | ^^^^^^^^ overlapping patterns + | +note: lint level defined here + --> $DIR/precise_pointer_size_matching.rs:11:31 + | +LL | #![deny(unreachable_patterns, overlapping_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ error[E0004]: non-exhaustive patterns: `0usize` and `21usize..=std::usize::MAX` not covered --> $DIR/precise_pointer_size_matching.rs:29:11 @@ -36,6 +28,6 @@ LL | match 0usize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs index 580e67513b396..f8abd1b96d80e 100644 --- a/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs @@ -3,7 +3,7 @@ pub fn main() { let i = 5; match &&&&i { 1 ..= 3 => panic!(), - 3 ..= 8 => {}, + 4 ..= 8 => {}, _ => panic!(), } } From 593cdcccf28361df155c37916dcfcbe1bf19d9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 16 Oct 2019 12:22:23 -0700 Subject: [PATCH 10/10] Lint only on single element overlap --- src/librustc_mir/hair/pattern/_match.rs | 35 ++++++------------- src/test/ui/exhaustive_integer_patterns.rs | 2 +- .../ui/exhaustive_integer_patterns.stderr | 22 ++++-------- src/test/ui/issues/issue-13867.rs | 2 -- src/test/ui/precise_pointer_size_matching.rs | 2 +- .../ui/precise_pointer_size_matching.stderr | 16 +-------- 6 files changed, 20 insertions(+), 59 deletions(-) diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 580ded50b05c6..1d83b104177e2 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1077,35 +1077,20 @@ impl<'tcx> IntRange<'tcx> { } fn suspicious_intersection(&self, other: &Self) -> bool { - let (lo, hi) = (*self.range.start(), *self.range.end()); - let (other_lo, other_hi) = (*other.range.start(), *other.range.end()); - // `false` in the following cases: - // 1 ---- - // 2 ---------- - // - // 1 ---------- - // 2 ---- + // 1 ---- // 1 ---------- // 1 ---- // 1 ---- + // 2 ---------- // 2 ---- // 2 ---- // 2 ---- // - // 1 ---- - // 2 ---- + // The following are currently `false`, but could be `true` in the future (#64007): + // 1 --------- // 1 --------- + // 2 ---------- // 2 ---------- // - // 1 ---- - // 2 ---- - // `true` in the following cases: - // 1 --------- - // 2 ---------- - lo < other_lo && hi > other_lo && hi < other_hi || - // 1 --------- - // 2 ---------- - lo > other_lo && lo < other_hi && hi > other_hi || - // 1 ---- - // 2 ---- - lo == other_hi && other_lo < lo || - // 1 ---- - // 2 ----- - hi == other_lo && lo < other_lo + // 1 ------- // 1 ------- + // 2 -------- // 2 ------- + let (lo, hi) = (*self.range.start(), *self.range.end()); + let (other_lo, other_hi) = (*other.range.start(), *other.range.end()); + (lo == other_hi || hi == other_lo) } } diff --git a/src/test/ui/exhaustive_integer_patterns.rs b/src/test/ui/exhaustive_integer_patterns.rs index 442b2f772572c..59f749198971b 100644 --- a/src/test/ui/exhaustive_integer_patterns.rs +++ b/src/test/ui/exhaustive_integer_patterns.rs @@ -19,7 +19,7 @@ fn main() { 0 ..= 32 => {} 33 => {} 34 .. 128 => {} - 100 ..= 200 => {} //~ ERROR multiple patterns covering the same range + 100 ..= 200 => {} 200 => {} //~ ERROR unreachable pattern 201 ..= 255 => {} } diff --git a/src/test/ui/exhaustive_integer_patterns.stderr b/src/test/ui/exhaustive_integer_patterns.stderr index 4c5806f9606f8..7a3a36a820c65 100644 --- a/src/test/ui/exhaustive_integer_patterns.stderr +++ b/src/test/ui/exhaustive_integer_patterns.stderr @@ -1,17 +1,3 @@ -error: multiple patterns covering the same range - --> $DIR/exhaustive_integer_patterns.rs:22:9 - | -LL | 34 .. 128 => {} - | --------- this range overlaps on `100u8..=127u8` -LL | 100 ..= 200 => {} - | ^^^^^^^^^^^ overlapping patterns - | -note: lint level defined here - --> $DIR/exhaustive_integer_patterns.rs:4:9 - | -LL | #![deny(overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - error: unreachable pattern --> $DIR/exhaustive_integer_patterns.rs:23:9 | @@ -101,6 +87,12 @@ LL | 0 .. 2 => {} | ------ this range overlaps on `1u8` LL | 1 ..= 2 => {} | ^^^^^^^ overlapping patterns + | +note: lint level defined here + --> $DIR/exhaustive_integer_patterns.rs:4:9 + | +LL | #![deny(overlapping_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered --> $DIR/exhaustive_integer_patterns.rs:146:11 @@ -126,6 +118,6 @@ LL | match 0u128 { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-13867.rs b/src/test/ui/issues/issue-13867.rs index 809205685634e..9510aae775341 100644 --- a/src/test/ui/issues/issue-13867.rs +++ b/src/test/ui/issues/issue-13867.rs @@ -1,8 +1,6 @@ // run-pass // Test that codegen works correctly when there are multiple refutable // patterns in match expression. -#![allow(overlapping_patterns)] - enum Foo { FooUint(usize), diff --git a/src/test/ui/precise_pointer_size_matching.rs b/src/test/ui/precise_pointer_size_matching.rs index ee91088c0c36a..54aeb8616d959 100644 --- a/src/test/ui/precise_pointer_size_matching.rs +++ b/src/test/ui/precise_pointer_size_matching.rs @@ -28,6 +28,6 @@ fn main() { match 0usize { //~ ERROR non-exhaustive patterns 1 ..= 8 => {} - 5 ..= 20 => {} //~ ERROR multiple patterns covering the same range + 5 ..= 20 => {} } } diff --git a/src/test/ui/precise_pointer_size_matching.stderr b/src/test/ui/precise_pointer_size_matching.stderr index 98d347e06b609..2c2c2aa04c233 100644 --- a/src/test/ui/precise_pointer_size_matching.stderr +++ b/src/test/ui/precise_pointer_size_matching.stderr @@ -6,20 +6,6 @@ LL | match 0isize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: multiple patterns covering the same range - --> $DIR/precise_pointer_size_matching.rs:31:9 - | -LL | 1 ..= 8 => {} - | ------- this range overlaps on `5usize..=8usize` -LL | 5 ..= 20 => {} - | ^^^^^^^^ overlapping patterns - | -note: lint level defined here - --> $DIR/precise_pointer_size_matching.rs:11:31 - | -LL | #![deny(unreachable_patterns, overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - error[E0004]: non-exhaustive patterns: `0usize` and `21usize..=std::usize::MAX` not covered --> $DIR/precise_pointer_size_matching.rs:29:11 | @@ -28,6 +14,6 @@ LL | match 0usize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0004`.