diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 94f8bbe2437f8..f2560b35aa2e1 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -67,6 +67,7 @@ declare_lint_pass! { MISSING_FRAGMENT_SPECIFIER, MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, + NON_CONTIGUOUS_RANGE_ENDPOINTS, NON_EXHAUSTIVE_OMITTED_PATTERNS, ORDER_DEPENDENT_TRAIT_OBJECTS, OVERLAPPING_RANGE_ENDPOINTS, @@ -812,6 +813,36 @@ declare_lint! { "detects range patterns with overlapping endpoints" } +declare_lint! { + /// The `non_contiguous_range_endpoints` lint detects likely off-by-one errors when using + /// exclusive [range patterns]. + /// + /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns + /// + /// ### Example + /// + /// ```rust + /// # #![feature(exclusive_range_pattern)] + /// let x = 123u32; + /// match x { + /// 0..100 => { println!("small"); } + /// 101..1000 => { println!("large"); } + /// _ => { println!("larger"); } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is likely a mistake to have range patterns in a match expression that miss out a single + /// number. Check that the beginning and end values are what you expect, and keep in mind that + /// with `..=` the right bound is inclusive, and with `..` it is exclusive. + pub NON_CONTIGUOUS_RANGE_ENDPOINTS, + Warn, + "detects off-by-one errors with exclusive range patterns" +} + declare_lint! { /// The `bindings_with_variant_name` lint detects pattern bindings with /// the same name as one of the matched variants. diff --git a/compiler/rustc_pattern_analysis/messages.ftl b/compiler/rustc_pattern_analysis/messages.ftl index 827928f97d7cb..41a1d958f1094 100644 --- a/compiler/rustc_pattern_analysis/messages.ftl +++ b/compiler/rustc_pattern_analysis/messages.ftl @@ -1,3 +1,11 @@ +pattern_analysis_excluside_range_missing_gap = multiple ranges are one apart + .label = this range doesn't match `{$gap}` because `..` is an exclusive range + .suggestion = use an inclusive range instead + +pattern_analysis_excluside_range_missing_max = exclusive range missing `{$max}` + .label = this range doesn't match `{$max}` because `..` is an exclusive range + .suggestion = use an inclusive range instead + pattern_analysis_non_exhaustive_omitted_pattern = some variants are not matched explicitly .help = ensure that all variants are matched explicitly by adding the suggested match arms .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 767227619b04b..69e294e47a561 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -192,7 +192,7 @@ impl fmt::Display for RangeEnd { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum MaybeInfiniteInt { NegInfinity, - /// Encoded value. DO NOT CONSTRUCT BY HAND; use `new_finite`. + /// Encoded value. DO NOT CONSTRUCT BY HAND; use `new_finite_{int,uint}`. #[non_exhaustive] Finite(u128), /// The integer after `u128::MAX`. We need it to represent `x..=u128::MAX` as an exclusive range. @@ -229,25 +229,22 @@ impl MaybeInfiniteInt { } /// Note: this will not turn a finite value into an infinite one or vice-versa. - pub fn minus_one(self) -> Self { + pub fn minus_one(self) -> Option { match self { - Finite(n) => match n.checked_sub(1) { - Some(m) => Finite(m), - None => panic!("Called `MaybeInfiniteInt::minus_one` on 0"), - }, - JustAfterMax => Finite(u128::MAX), - x => x, + Finite(n) => n.checked_sub(1).map(Finite), + JustAfterMax => Some(Finite(u128::MAX)), + x => Some(x), } } /// Note: this will not turn a finite value into an infinite one or vice-versa. - pub fn plus_one(self) -> Self { + pub fn plus_one(self) -> Option { match self { Finite(n) => match n.checked_add(1) { - Some(m) => Finite(m), - None => JustAfterMax, + Some(m) => Some(Finite(m)), + None => Some(JustAfterMax), }, - JustAfterMax => panic!("Called `MaybeInfiniteInt::plus_one` on u128::MAX+1"), - x => x, + JustAfterMax => None, + x => Some(x), } } } @@ -268,18 +265,24 @@ impl IntRange { pub fn is_singleton(&self) -> bool { // Since `lo` and `hi` can't be the same `Infinity` and `plus_one` never changes from finite // to infinite, this correctly only detects ranges that contain exacly one `Finite(x)`. - self.lo.plus_one() == self.hi + self.lo.plus_one() == Some(self.hi) } + /// Construct a singleton range. + /// `x` must be a `Finite(_)` value. #[inline] pub fn from_singleton(x: MaybeInfiniteInt) -> IntRange { - IntRange { lo: x, hi: x.plus_one() } + // `unwrap()` is ok on a finite value + IntRange { lo: x, hi: x.plus_one().unwrap() } } + /// Construct a range with these boundaries. + /// `lo` must not be `PosInfinity` or `JustAfterMax`. `hi` must not be `NegInfinity`. + /// If `end` is `Included`, `hi` must also not be `JustAfterMax`. #[inline] pub fn from_range(lo: MaybeInfiniteInt, mut hi: MaybeInfiniteInt, end: RangeEnd) -> IntRange { if end == RangeEnd::Included { - hi = hi.plus_one(); + hi = hi.plus_one().unwrap(); } if lo >= hi { // This should have been caught earlier by E0030. diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index d0f56f0268dfa..e471b8abd7357 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -76,6 +76,57 @@ impl<'tcx> AddToDiagnostic for Overlap<'tcx> { } } +#[derive(LintDiagnostic)] +#[diag(pattern_analysis_excluside_range_missing_max)] +pub struct ExclusiveRangeMissingMax<'tcx> { + #[label] + #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")] + /// This is an exclusive range that looks like `lo..max` (i.e. doesn't match `max`). + pub first_range: Span, + /// Suggest `lo..=max` instead. + pub suggestion: String, + pub max: Pat<'tcx>, +} + +#[derive(LintDiagnostic)] +#[diag(pattern_analysis_excluside_range_missing_gap)] +pub struct ExclusiveRangeMissingGap<'tcx> { + #[label] + #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")] + /// This is an exclusive range that looks like `lo..gap` (i.e. doesn't match `gap`). + pub first_range: Span, + pub gap: Pat<'tcx>, + /// Suggest `lo..=gap` instead. + pub suggestion: String, + #[subdiagnostic] + /// All these ranges skipped over `gap` which we think is probably a mistake. + pub gap_with: Vec>, +} + +pub struct GappedRange<'tcx> { + pub span: Span, + pub gap: Pat<'tcx>, + pub first_range: Pat<'tcx>, +} + +impl<'tcx> AddToDiagnostic for GappedRange<'tcx> { + fn add_to_diagnostic_with>( + self, + diag: &mut Diag<'_, G>, + _: F, + ) { + let GappedRange { span, gap, first_range } = self; + + // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` + // does not support `#[subdiagnostic(eager)]`... + let message = format!( + "this could appear to continue range `{first_range}`, but `{gap}` isn't matched by \ + either of them" + ); + diag.span_label(span, message); + } +} + #[derive(LintDiagnostic)] #[diag(pattern_analysis_non_exhaustive_omitted_pattern)] #[help] diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 4b0955699fc39..f632eaf7ea4f6 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -70,14 +70,8 @@ use rustc_middle::ty::Ty; use rustc_span::ErrorGuaranteed; use crate::constructor::{Constructor, ConstructorSet, IntRange}; -#[cfg(feature = "rustc")] -use crate::lints::lint_nonexhaustive_missing_variants; use crate::pat::DeconstructedPat; use crate::pat_column::PatternColumn; -#[cfg(feature = "rustc")] -use crate::rustc::RustcMatchCheckCtxt; -#[cfg(feature = "rustc")] -use crate::usefulness::{compute_match_usefulness, ValidityConstraint}; pub trait Captures<'a> {} impl<'a, T: ?Sized> Captures<'a> for T {} @@ -145,6 +139,18 @@ pub trait TypeCx: Sized + fmt::Debug { /// The maximum pattern complexity limit was reached. fn complexity_exceeded(&self) -> Result<(), Self::Error>; + + /// Lint that there is a gap `gap` between `pat` and all of `gapped_with` such that the gap is + /// not matched by another range. If `gapped_with` is empty, then `gap` is `T::MAX`. We only + /// detect singleton gaps. + /// The default implementation does nothing. + fn lint_non_contiguous_range_endpoints( + &self, + _pat: &DeconstructedPat, + _gap: IntRange, + _gapped_with: &[&DeconstructedPat], + ) { + } } /// The arm of a match expression. @@ -167,11 +173,14 @@ impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {} /// useful, and runs some lints. #[cfg(feature = "rustc")] pub fn analyze_match<'p, 'tcx>( - tycx: &RustcMatchCheckCtxt<'p, 'tcx>, + tycx: &rustc::RustcMatchCheckCtxt<'p, 'tcx>, arms: &[rustc::MatchArm<'p, 'tcx>], scrut_ty: Ty<'tcx>, pattern_complexity_limit: Option, ) -> Result, ErrorGuaranteed> { + use lints::lint_nonexhaustive_missing_variants; + use usefulness::{compute_match_usefulness, ValidityConstraint}; + let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee); let report = diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 5f5bfa7154a74..0085f0ab6566b 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -8,7 +8,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::middle::stability::EvalResult; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::{self, Const}; -use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary}; +use rustc_middle::thir::{self, FieldPat, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, FieldDef, OpaqueTypeKey, Ty, TyCtxt, TypeVisitableExt, VariantDef}; use rustc_session::lint; @@ -718,12 +718,12 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> { let value = mir::Const::from_ty_const(c, cx.tcx); lo = PatRangeBoundary::Finite(value); } - let hi = if matches!(range.hi, Finite(0)) { + let hi = if let Some(hi) = range.hi.minus_one() { + hi + } else { // The range encodes `..ty::MIN`, so we can't convert it to an inclusive range. end = rustc_hir::RangeEnd::Excluded; range.hi - } else { - range.hi.minus_one() }; let hi = cx.hoist_pat_range_bdy(hi, ty); PatKind::Range(Box::new(PatRange { lo, hi, end, ty: ty.inner() })) @@ -900,6 +900,70 @@ impl<'p, 'tcx: 'p> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { let span = self.whole_match_span.unwrap_or(self.scrut_span); Err(self.tcx.dcx().span_err(span, "reached pattern complexity limit")) } + + fn lint_non_contiguous_range_endpoints( + &self, + pat: &crate::pat::DeconstructedPat, + gap: IntRange, + gapped_with: &[&crate::pat::DeconstructedPat], + ) { + let Some(&thir_pat) = pat.data() else { return }; + let thir::PatKind::Range(range) = &thir_pat.kind else { return }; + // Only lint when the left range is an exclusive range. + if range.end != rustc_hir::RangeEnd::Excluded { + return; + } + // `pat` is an exclusive range like `lo..gap`. `gapped_with` contains ranges that start with + // `gap+1`. + let suggested_range: thir::Pat<'_> = { + // Suggest `lo..=gap` instead. + let mut suggested_range = thir_pat.clone(); + let thir::PatKind::Range(range) = &mut suggested_range.kind else { unreachable!() }; + range.end = rustc_hir::RangeEnd::Included; + suggested_range + }; + let gap_as_pat = self.hoist_pat_range(&gap, *pat.ty()); + if gapped_with.is_empty() { + // If `gapped_with` is empty, `gap == T::MAX`. + self.tcx.emit_node_span_lint( + lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS, + self.match_lint_level, + thir_pat.span, + errors::ExclusiveRangeMissingMax { + // Point at this range. + first_range: thir_pat.span, + // That's the gap that isn't covered. + max: gap_as_pat.clone(), + // Suggest `lo..=max` instead. + suggestion: suggested_range.to_string(), + }, + ); + } else { + self.tcx.emit_node_span_lint( + lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS, + self.match_lint_level, + thir_pat.span, + errors::ExclusiveRangeMissingGap { + // Point at this range. + first_range: thir_pat.span, + // That's the gap that isn't covered. + gap: gap_as_pat.clone(), + // Suggest `lo..=gap` instead. + suggestion: suggested_range.to_string(), + // All these ranges skipped over `gap` which we think is probably a + // mistake. + gap_with: gapped_with + .iter() + .map(|pat| errors::GappedRange { + span: pat.data().unwrap().span, + gap: gap_as_pat.clone(), + first_range: thir_pat.clone(), + }) + .collect(), + }, + ); + } + } } /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index c518844cc5e52..a067bf1f0c23e 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -1489,7 +1489,7 @@ impl WitnessMatrix { /// We can however get false negatives because exhaustiveness does not explore all cases. See the /// section on relevancy at the top of the file. fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( - mcx: &mut UsefulnessCtxt<'_, Cx>, + cx: &Cx, overlap_range: IntRange, matrix: &Matrix<'p, Cx>, specialized_matrix: &Matrix<'p, Cx>, @@ -1522,11 +1522,11 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( .map(|&(_, pat)| pat) .collect(); if !overlaps_with.is_empty() { - mcx.tycx.lint_overlapping_range_endpoints(pat, overlap_range, &overlaps_with); + cx.lint_overlapping_range_endpoints(pat, overlap_range, &overlaps_with); } } suffixes.push((child_row_id, pat)) - } else if this_range.hi == overlap.plus_one() { + } else if Some(this_range.hi) == overlap.plus_one() { // `this_range` looks like `this_range.lo..=overlap`; it overlaps with any // ranges that look like `overlap..=hi`. if !suffixes.is_empty() { @@ -1538,7 +1538,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( .map(|&(_, pat)| pat) .collect(); if !overlaps_with.is_empty() { - mcx.tycx.lint_overlapping_range_endpoints(pat, overlap_range, &overlaps_with); + cx.lint_overlapping_range_endpoints(pat, overlap_range, &overlaps_with); } } prefixes.push((child_row_id, pat)) @@ -1546,6 +1546,33 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( } } +/// Collect ranges that have a singleton gap between them. +fn collect_non_contiguous_range_endpoints<'p, Cx: TypeCx>( + cx: &Cx, + gap_range: &IntRange, + matrix: &Matrix<'p, Cx>, +) { + let gap = gap_range.lo; + // Ranges that look like `lo..gap`. + let mut onebefore: SmallVec<[_; 1]> = Default::default(); + // Ranges that start on `gap+1` or singletons `gap+1`. + let mut oneafter: SmallVec<[_; 1]> = Default::default(); + // Look through the column for ranges near the gap. + for pat in matrix.heads() { + let PatOrWild::Pat(pat) = pat else { continue }; + let Constructor::IntRange(this_range) = pat.ctor() else { continue }; + if gap == this_range.hi { + onebefore.push(pat) + } else if gap.plus_one() == Some(this_range.lo) { + oneafter.push(pat) + } + } + + for pat_before in onebefore { + cx.lint_non_contiguous_range_endpoints(pat_before, *gap_range, oneafter.as_slice()); + } +} + /// The core of the algorithm. /// /// This recursively computes witnesses of the non-exhaustiveness of `matrix` (if any). Also tracks @@ -1626,13 +1653,24 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( && spec_matrix.rows.len() >= 2 && spec_matrix.rows.iter().any(|row| !row.intersects.is_empty()) { - collect_overlapping_range_endpoints(mcx, overlap_range, matrix, &spec_matrix); + collect_overlapping_range_endpoints(mcx.tycx, overlap_range, matrix, &spec_matrix); } } matrix.unspecialize(spec_matrix); } + // Detect singleton gaps between ranges. + if missing_ctors.iter().any(|c| matches!(c, Constructor::IntRange(..))) { + for missing in &missing_ctors { + if let Constructor::IntRange(gap) = missing { + if gap.is_singleton() { + collect_non_contiguous_range_endpoints(mcx.tycx, gap, matrix); + } + } + } + } + // Record usefulness in the patterns. for row in matrix.rows() { if row.useful { diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.fixed b/src/tools/clippy/tests/ui/manual_range_patterns.fixed index b348d7071f6e9..e9f6fbcc3fc8c 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.fixed +++ b/src/tools/clippy/tests/ui/manual_range_patterns.fixed @@ -1,4 +1,5 @@ #![allow(unused)] +#![allow(non_contiguous_range_endpoints)] #![warn(clippy::manual_range_patterns)] #![feature(exclusive_range_pattern)] diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.rs b/src/tools/clippy/tests/ui/manual_range_patterns.rs index a0750f54b73f1..d525aaa24ad1b 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.rs +++ b/src/tools/clippy/tests/ui/manual_range_patterns.rs @@ -1,4 +1,5 @@ #![allow(unused)] +#![allow(non_contiguous_range_endpoints)] #![warn(clippy::manual_range_patterns)] #![feature(exclusive_range_pattern)] diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.stderr b/src/tools/clippy/tests/ui/manual_range_patterns.stderr index 7c19fdd475f19..af9256aeea390 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.stderr +++ b/src/tools/clippy/tests/ui/manual_range_patterns.stderr @@ -1,5 +1,5 @@ error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:8:25 + --> tests/ui/manual_range_patterns.rs:9:25 | LL | let _ = matches!(f, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` @@ -8,109 +8,109 @@ LL | let _ = matches!(f, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); = help: to override `-D warnings` add `#[allow(clippy::manual_range_patterns)]` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:9:25 + --> tests/ui/manual_range_patterns.rs:10:25 | LL | let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 7 | 8 | 10); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:16:25 + --> tests/ui/manual_range_patterns.rs:17:25 | LL | let _ = matches!(f, 1 | (2..=4)); | ^^^^^^^^^^^ help: try: `1..=4` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:17:25 + --> tests/ui/manual_range_patterns.rs:18:25 | LL | let _ = matches!(f, 1 | (2..4)); | ^^^^^^^^^^ help: try: `1..4` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:18:25 + --> tests/ui/manual_range_patterns.rs:19:25 | LL | let _ = matches!(f, (1..=10) | (2..=13) | (14..=48324728) | 48324729); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=48324729` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:19:25 + --> tests/ui/manual_range_patterns.rs:20:25 | LL | let _ = matches!(f, 0 | (1..=10) | 48324730 | (2..=13) | (14..=48324728) | 48324729); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0..=48324730` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:20:25 + --> tests/ui/manual_range_patterns.rs:21:25 | LL | let _ = matches!(f, 0..=1 | 0..=2 | 0..=3); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `0..=3` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:23:9 + --> tests/ui/manual_range_patterns.rs:24:9 | LL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:26:25 + --> tests/ui/manual_range_patterns.rs:27:25 | LL | let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-5..=3` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:28:25 + --> tests/ui/manual_range_patterns.rs:29:25 | LL | let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-1_000_001..=1_000_001` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:31:17 + --> tests/ui/manual_range_patterns.rs:32:17 | LL | matches!(f, 0x00 | 0x01 | 0x02 | 0x03); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0x00..=0x03` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:32:17 + --> tests/ui/manual_range_patterns.rs:33:17 | LL | matches!(f, 0x00..=0x05 | 0x06 | 0x07); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0x00..=0x07` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:33:17 + --> tests/ui/manual_range_patterns.rs:34:17 | LL | matches!(f, -0x09 | -0x08 | -0x07..=0x00); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-0x09..=0x00` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:35:17 + --> tests/ui/manual_range_patterns.rs:36:17 | LL | matches!(f, 0..5 | 5); | ^^^^^^^^ help: try: `0..=5` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:36:17 + --> tests/ui/manual_range_patterns.rs:37:17 | LL | matches!(f, 0 | 1..5); | ^^^^^^^^ help: try: `0..5` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:38:17 + --> tests/ui/manual_range_patterns.rs:39:17 | LL | matches!(f, 0..=5 | 6..10); | ^^^^^^^^^^^^^ help: try: `0..10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:39:17 + --> tests/ui/manual_range_patterns.rs:40:17 | LL | matches!(f, 0..5 | 5..=10); | ^^^^^^^^^^^^^ help: try: `0..=10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:40:17 + --> tests/ui/manual_range_patterns.rs:41:17 | LL | matches!(f, 5..=10 | 0..5); | ^^^^^^^^^^^^^ help: try: `0..=10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:44:26 + --> tests/ui/manual_range_patterns.rs:45:26 | LL | matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs index 33b99259dfec9..9d067229b6de8 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs @@ -1,6 +1,7 @@ // Test various non-exhaustive matches for `X..`, `..=X` and `..X` ranges. #![feature(exclusive_range_pattern)] +#![allow(non_contiguous_range_endpoints)] fn main() {} diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr index 1e68235303b2e..6b20a820b7302 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:14:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8 | LL | m!(0f32, f32::NEG_INFINITY..); | ^^^^ pattern `_` not covered @@ -11,7 +11,7 @@ LL | match $s { $($t)+ => {}, _ => todo!() } | ++++++++++++++ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:8 | LL | m!(0f32, ..f32::INFINITY); | ^^^^ pattern `_` not covered @@ -23,7 +23,7 @@ LL | match $s { $($t)+ => {}, _ => todo!() } | ++++++++++++++ error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:24:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8 | LL | m!('a', ..core::char::MAX); | ^^^ pattern `'\u{10ffff}'` not covered @@ -35,7 +35,7 @@ LL | match $s { $($t)+ => {}, '\u{10ffff}' => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8 | LL | m!('a', ..ALMOST_MAX); | ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered @@ -47,7 +47,7 @@ LL | match $s { $($t)+ => {}, '\u{10fffe}'..='\u{10ffff}' => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `'\0'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8 | LL | m!('a', ALMOST_MIN..); | ^^^ pattern `'\0'` not covered @@ -59,7 +59,7 @@ LL | match $s { $($t)+ => {}, '\0' => todo!() } | +++++++++++++++++ error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8 | LL | m!('a', ..=ALMOST_MAX); | ^^^ pattern `'\u{10ffff}'` not covered @@ -71,7 +71,7 @@ LL | match $s { $($t)+ => {}, '\u{10ffff}' => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `'b'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8 | LL | m!('a', ..=VAL | VAL_2..); | ^^^ pattern `'b'` not covered @@ -83,7 +83,7 @@ LL | match $s { $($t)+ => {}, 'b' => todo!() } | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `'b'` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8 | LL | m!('a', ..VAL_1 | VAL_2..); | ^^^ pattern `'b'` not covered @@ -95,7 +95,7 @@ LL | match $s { $($t)+ => {}, 'b' => todo!() } | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:39:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12 | LL | m!(0, ..u8::MAX); | ^ pattern `u8::MAX` not covered @@ -107,7 +107,7 @@ LL | match $s { $($t)+ => {}, u8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `254_u8..=u8::MAX` not covered @@ -119,7 +119,7 @@ LL | match $s { $($t)+ => {}, 254_u8..=u8::MAX => todo!() } | +++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u8` not covered @@ -131,7 +131,7 @@ LL | match $s { $($t)+ => {}, 0_u8 => todo!() } | +++++++++++++++++ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u8::MAX` not covered @@ -143,7 +143,7 @@ LL | match $s { $($t)+ => {}, u8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u8` not covered @@ -155,7 +155,7 @@ LL | match $s { $($t)+ => {}, 43_u8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u8` not covered @@ -167,7 +167,7 @@ LL | match $s { $($t)+ => {}, 43_u8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:52:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12 | LL | m!(0, ..u16::MAX); | ^ pattern `u16::MAX` not covered @@ -179,7 +179,7 @@ LL | match $s { $($t)+ => {}, u16::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `65534_u16..=u16::MAX` not covered @@ -191,7 +191,7 @@ LL | match $s { $($t)+ => {}, 65534_u16..=u16::MAX => todo!() } | +++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u16` not covered @@ -203,7 +203,7 @@ LL | match $s { $($t)+ => {}, 0_u16 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u16::MAX` not covered @@ -215,7 +215,7 @@ LL | match $s { $($t)+ => {}, u16::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u16` not covered @@ -227,7 +227,7 @@ LL | match $s { $($t)+ => {}, 43_u16 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u16` not covered @@ -239,7 +239,7 @@ LL | match $s { $($t)+ => {}, 43_u16 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:65:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12 | LL | m!(0, ..u32::MAX); | ^ pattern `u32::MAX` not covered @@ -251,7 +251,7 @@ LL | match $s { $($t)+ => {}, u32::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `4294967294_u32..=u32::MAX` not covered @@ -263,7 +263,7 @@ LL | match $s { $($t)+ => {}, 4294967294_u32..=u32::MAX => todo!() } | ++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u32` not covered @@ -275,7 +275,7 @@ LL | match $s { $($t)+ => {}, 0_u32 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u32::MAX` not covered @@ -287,7 +287,7 @@ LL | match $s { $($t)+ => {}, u32::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u32` not covered @@ -299,7 +299,7 @@ LL | match $s { $($t)+ => {}, 43_u32 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u32` not covered @@ -311,7 +311,7 @@ LL | match $s { $($t)+ => {}, 43_u32 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:78:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12 | LL | m!(0, ..u64::MAX); | ^ pattern `u64::MAX` not covered @@ -323,7 +323,7 @@ LL | match $s { $($t)+ => {}, u64::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `18446744073709551614_u64..=u64::MAX` not covered @@ -335,7 +335,7 @@ LL | match $s { $($t)+ => {}, 18446744073709551614_u64..=u64::MAX => tod | ++++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u64` not covered @@ -347,7 +347,7 @@ LL | match $s { $($t)+ => {}, 0_u64 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u64::MAX` not covered @@ -359,7 +359,7 @@ LL | match $s { $($t)+ => {}, u64::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u64` not covered @@ -371,7 +371,7 @@ LL | match $s { $($t)+ => {}, 43_u64 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u64` not covered @@ -383,7 +383,7 @@ LL | match $s { $($t)+ => {}, 43_u64 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:91:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12 | LL | m!(0, ..u128::MAX); | ^ pattern `u128::MAX` not covered @@ -395,7 +395,7 @@ LL | match $s { $($t)+ => {}, u128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered @@ -407,7 +407,7 @@ LL | match $s { $($t)+ => {}, 340282366920938463463374607431768211454_u1 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `0_u128` not covered @@ -419,7 +419,7 @@ LL | match $s { $($t)+ => {}, 0_u128 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `u128::MAX` not covered @@ -431,7 +431,7 @@ LL | match $s { $($t)+ => {}, u128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_u128` not covered @@ -443,7 +443,7 @@ LL | match $s { $($t)+ => {}, 43_u128 => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_u128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_u128` not covered @@ -455,7 +455,7 @@ LL | match $s { $($t)+ => {}, 43_u128 => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:107:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12 | LL | m!(0, ..i8::MAX); | ^ pattern `i8::MAX` not covered @@ -467,7 +467,7 @@ LL | match $s { $($t)+ => {}, i8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `126_i8..=i8::MAX` not covered @@ -479,7 +479,7 @@ LL | match $s { $($t)+ => {}, 126_i8..=i8::MAX => todo!() } | +++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i8::MIN` not covered @@ -491,7 +491,7 @@ LL | match $s { $($t)+ => {}, i8::MIN => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i8::MAX` not covered @@ -503,7 +503,7 @@ LL | match $s { $($t)+ => {}, i8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i8` not covered @@ -515,7 +515,7 @@ LL | match $s { $($t)+ => {}, 43_i8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i8` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i8` not covered @@ -527,7 +527,7 @@ LL | match $s { $($t)+ => {}, 43_i8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:120:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12 | LL | m!(0, ..i16::MAX); | ^ pattern `i16::MAX` not covered @@ -539,7 +539,7 @@ LL | match $s { $($t)+ => {}, i16::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `32766_i16..=i16::MAX` not covered @@ -551,7 +551,7 @@ LL | match $s { $($t)+ => {}, 32766_i16..=i16::MAX => todo!() } | +++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i16::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i16::MIN` not covered @@ -563,7 +563,7 @@ LL | match $s { $($t)+ => {}, i16::MIN => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i16::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i16::MAX` not covered @@ -575,7 +575,7 @@ LL | match $s { $($t)+ => {}, i16::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i16` not covered @@ -587,7 +587,7 @@ LL | match $s { $($t)+ => {}, 43_i16 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i16` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i16` not covered @@ -599,7 +599,7 @@ LL | match $s { $($t)+ => {}, 43_i16 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:133:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12 | LL | m!(0, ..i32::MAX); | ^ pattern `i32::MAX` not covered @@ -611,7 +611,7 @@ LL | match $s { $($t)+ => {}, i32::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `2147483646_i32..=i32::MAX` not covered @@ -623,7 +623,7 @@ LL | match $s { $($t)+ => {}, 2147483646_i32..=i32::MAX => todo!() } | ++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i32::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i32::MIN` not covered @@ -635,7 +635,7 @@ LL | match $s { $($t)+ => {}, i32::MIN => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i32::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i32::MAX` not covered @@ -647,7 +647,7 @@ LL | match $s { $($t)+ => {}, i32::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i32` not covered @@ -659,7 +659,7 @@ LL | match $s { $($t)+ => {}, 43_i32 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i32` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i32` not covered @@ -671,7 +671,7 @@ LL | match $s { $($t)+ => {}, 43_i32 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:146:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12 | LL | m!(0, ..i64::MAX); | ^ pattern `i64::MAX` not covered @@ -683,7 +683,7 @@ LL | match $s { $($t)+ => {}, i64::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `9223372036854775806_i64..=i64::MAX` not covered @@ -695,7 +695,7 @@ LL | match $s { $($t)+ => {}, 9223372036854775806_i64..=i64::MAX => todo | +++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i64::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i64::MIN` not covered @@ -707,7 +707,7 @@ LL | match $s { $($t)+ => {}, i64::MIN => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i64::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i64::MAX` not covered @@ -719,7 +719,7 @@ LL | match $s { $($t)+ => {}, i64::MAX => todo!() } | +++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i64` not covered @@ -731,7 +731,7 @@ LL | match $s { $($t)+ => {}, 43_i64 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i64` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i64` not covered @@ -743,7 +743,7 @@ LL | match $s { $($t)+ => {}, 43_i64 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:159:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12 | LL | m!(0, ..i128::MAX); | ^ pattern `i128::MAX` not covered @@ -755,7 +755,7 @@ LL | match $s { $($t)+ => {}, i128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12 | LL | m!(0, ..ALMOST_MAX); | ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered @@ -767,7 +767,7 @@ LL | match $s { $($t)+ => {}, 170141183460469231731687303715884105726_i1 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i128::MIN` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12 | LL | m!(0, ALMOST_MIN..); | ^ pattern `i128::MIN` not covered @@ -779,7 +779,7 @@ LL | match $s { $($t)+ => {}, i128::MIN => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i128::MAX` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12 | LL | m!(0, ..=ALMOST_MAX); | ^ pattern `i128::MAX` not covered @@ -791,7 +791,7 @@ LL | match $s { $($t)+ => {}, i128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12 | LL | m!(0, ..=VAL | VAL_2..); | ^ pattern `43_i128` not covered @@ -803,7 +803,7 @@ LL | match $s { $($t)+ => {}, 43_i128 => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `43_i128` not covered - --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12 + --> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12 | LL | m!(0, ..VAL_1 | VAL_2..); | ^ pattern `43_i128` not covered diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions0.rs b/tests/ui/half-open-range-patterns/range_pat_interactions0.rs index 7a82f9ce89a86..53b6b89ed1662 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions0.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions0.rs @@ -1,4 +1,5 @@ //@ run-pass +#![allow(non_contiguous_range_endpoints)] #![feature(exclusive_range_pattern)] #![feature(inline_const_pat)] diff --git a/tests/ui/match/issue-18060.rs b/tests/ui/match/issue-18060.rs index daba393a3fa3d..9d480ba6b8bbb 100644 --- a/tests/ui/match/issue-18060.rs +++ b/tests/ui/match/issue-18060.rs @@ -1,6 +1,7 @@ //@ run-pass // Regression test for #18060: match arms were matching in the wrong order. +#[allow(non_contiguous_range_endpoints)] fn main() { assert_eq!(2, match (1, 3) { (0, 2..=5) => 1, (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 }); assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 }); diff --git a/tests/ui/mir/mir_match_test.rs b/tests/ui/mir/mir_match_test.rs index 925e1e6ab3d47..0da8522f2181a 100644 --- a/tests/ui/mir/mir_match_test.rs +++ b/tests/ui/mir/mir_match_test.rs @@ -1,5 +1,6 @@ #![feature(exclusive_range_pattern)] #![allow(overlapping_range_endpoints)] +#![allow(non_contiguous_range_endpoints)] //@ run-pass diff --git a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs index 0f5f49c4ca473..07156d9a08a34 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs +++ b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs @@ -1,5 +1,6 @@ #![feature(exclusive_range_pattern)] #![allow(overlapping_range_endpoints)] +#![allow(non_contiguous_range_endpoints)] #![deny(unreachable_patterns)] macro_rules! m { diff --git a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr index b585de2062913..90d0fd7483a99 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered - --> $DIR/exhaustiveness.rs:47:8 + --> $DIR/exhaustiveness.rs:48:8 | LL | m!(0u8, 0..255); | ^^^ pattern `u8::MAX` not covered @@ -11,7 +11,7 @@ LL | match $s { $($t)+ => {}, u8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered - --> $DIR/exhaustiveness.rs:48:8 + --> $DIR/exhaustiveness.rs:49:8 | LL | m!(0u8, 0..=254); | ^^^ pattern `u8::MAX` not covered @@ -23,7 +23,7 @@ LL | match $s { $($t)+ => {}, u8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u8` not covered - --> $DIR/exhaustiveness.rs:49:8 + --> $DIR/exhaustiveness.rs:50:8 | LL | m!(0u8, 1..=255); | ^^^ pattern `0_u8` not covered @@ -35,7 +35,7 @@ LL | match $s { $($t)+ => {}, 0_u8 => todo!() } | +++++++++++++++++ error[E0004]: non-exhaustive patterns: `42_u8` not covered - --> $DIR/exhaustiveness.rs:50:8 + --> $DIR/exhaustiveness.rs:51:8 | LL | m!(0u8, 0..42 | 43..=255); | ^^^ pattern `42_u8` not covered @@ -47,7 +47,7 @@ LL | match $s { $($t)+ => {}, 42_u8 => todo!() } | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered - --> $DIR/exhaustiveness.rs:51:8 + --> $DIR/exhaustiveness.rs:52:8 | LL | m!(0i8, -128..127); | ^^^ pattern `i8::MAX` not covered @@ -59,7 +59,7 @@ LL | match $s { $($t)+ => {}, i8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered - --> $DIR/exhaustiveness.rs:52:8 + --> $DIR/exhaustiveness.rs:53:8 | LL | m!(0i8, -128..=126); | ^^^ pattern `i8::MAX` not covered @@ -71,7 +71,7 @@ LL | match $s { $($t)+ => {}, i8::MAX => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `i8::MIN` not covered - --> $DIR/exhaustiveness.rs:53:8 + --> $DIR/exhaustiveness.rs:54:8 | LL | m!(0i8, -127..=127); | ^^^ pattern `i8::MIN` not covered @@ -83,7 +83,7 @@ LL | match $s { $($t)+ => {}, i8::MIN => todo!() } | ++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_i8` not covered - --> $DIR/exhaustiveness.rs:54:11 + --> $DIR/exhaustiveness.rs:55:11 | LL | match 0i8 { | ^^^ pattern `0_i8` not covered @@ -96,7 +96,7 @@ LL + 0_i8 => todo!() | error[E0004]: non-exhaustive patterns: `u128::MAX` not covered - --> $DIR/exhaustiveness.rs:59:8 + --> $DIR/exhaustiveness.rs:60:8 | LL | m!(0u128, 0..=ALMOST_MAX); | ^^^^^ pattern `u128::MAX` not covered @@ -108,7 +108,7 @@ LL | match $s { $($t)+ => {}, u128::MAX => todo!() } | ++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered - --> $DIR/exhaustiveness.rs:60:8 + --> $DIR/exhaustiveness.rs:61:8 | LL | m!(0u128, 0..=4); | ^^^^^ pattern `5_u128..=u128::MAX` not covered @@ -120,7 +120,7 @@ LL | match $s { $($t)+ => {}, 5_u128..=u128::MAX => todo!() } | +++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `0_u128` not covered - --> $DIR/exhaustiveness.rs:61:8 + --> $DIR/exhaustiveness.rs:62:8 | LL | m!(0u128, 1..=u128::MAX); | ^^^^^ pattern `0_u128` not covered @@ -132,7 +132,7 @@ LL | match $s { $($t)+ => {}, 0_u128 => todo!() } | +++++++++++++++++++ error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered - --> $DIR/exhaustiveness.rs:69:11 + --> $DIR/exhaustiveness.rs:70:11 | LL | match (0u8, true) { | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered diff --git a/tests/ui/pattern/usefulness/integer-ranges/gap_between_ranges.rs b/tests/ui/pattern/usefulness/integer-ranges/gap_between_ranges.rs new file mode 100644 index 0000000000000..78849d7e14325 --- /dev/null +++ b/tests/ui/pattern/usefulness/integer-ranges/gap_between_ranges.rs @@ -0,0 +1,117 @@ +#![feature(exclusive_range_pattern)] +#![deny(non_contiguous_range_endpoints)] + +macro_rules! m { + ($s:expr, $t1:pat, $t2:pat) => { + match $s { + $t1 => {} + $t2 => {} + _ => {} + } + }; +} + +fn main() { + match 0u8 { + 20..30 => {} //~ ERROR multiple ranges are one apart + 31..=40 => {} + _ => {} + } + match 0u8 { + 20..30 => {} //~ ERROR multiple ranges are one apart + 31 => {} + _ => {} + } + + m!(0u8, 20..30, 31..=40); //~ ERROR multiple ranges are one apart + m!(0u8, 31..=40, 20..30); //~ ERROR multiple ranges are one apart + m!(0u8, 20..30, 29..=40); //~ WARN multiple patterns overlap on their endpoints + m!(0u8, 20..30, 30..=40); + m!(0u8, 20..30, 31..=40); //~ ERROR multiple ranges are one apart + m!(0u8, 20..30, 32..=40); + m!(0u8, 20..30, 31..=32); //~ ERROR multiple ranges are one apart + // Don't lint two singletons. + m!(0u8, 30, 32); + // Don't lint on the equivalent inclusive range + m!(0u8, 20..=29, 31..=40); + // Don't lint if the lower one is a singleton. + m!(0u8, 30, 32..=40); + + // Catch the `lo..MAX` case. + match 0u8 { + 0..255 => {} //~ ERROR exclusive range missing `u8::MAX` + _ => {} + } + // Except for `usize`, since `0..=usize::MAX` isn't exhaustive either. + match 0usize { + 0..usize::MAX => {} + _ => {} + } + + // Don't lint if the gap is caught by another range. + match 0u8 { + 0..10 => {} + 11..20 => {} + 10 => {} + _ => {} + } + match 0u8 { + 0..10 => {} + 11..20 => {} + 5..15 => {} + _ => {} + } + match 0u8 { + 0..255 => {} + 255 => {} + } + + // Test multiple at once + match 0u8 { + 0..10 => {} //~ ERROR multiple ranges are one apart + 11..20 => {} + 11..30 => {} + _ => {} + } + match 0u8 { + 0..10 => {} //~ ERROR multiple ranges are one apart + 11..20 => {} //~ ERROR multiple ranges are one apart + 21..30 => {} + _ => {} + } + match 0u8 { + 00..20 => {} //~ ERROR multiple ranges are one apart + 10..20 => {} //~ ERROR multiple ranges are one apart + 21..30 => {} + 21..40 => {} + _ => {} + } + + // Test nested + match (0u8, true) { + (0..10, true) => {} //~ ERROR multiple ranges are one apart + (11..20, true) => {} + _ => {} + } + match (true, 0u8) { + (true, 0..10) => {} //~ ERROR multiple ranges are one apart + (true, 11..20) => {} + _ => {} + } + // Asymmetry due to how exhaustiveness is computed. + match (0u8, true) { + (0..10, true) => {} //~ ERROR multiple ranges are one apart + (11..20, false) => {} + _ => {} + } + match (true, 0u8) { + (true, 0..10) => {} + (false, 11..20) => {} + _ => {} + } + match Some(0u8) { + Some(0..10) => {} //~ ERROR multiple ranges are one apart + Some(11..20) => {} + _ => {} + } +} diff --git a/tests/ui/pattern/usefulness/integer-ranges/gap_between_ranges.stderr b/tests/ui/pattern/usefulness/integer-ranges/gap_between_ranges.stderr new file mode 100644 index 0000000000000..e5c2d788ba4ef --- /dev/null +++ b/tests/ui/pattern/usefulness/integer-ranges/gap_between_ranges.stderr @@ -0,0 +1,193 @@ +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:16:9 + | +LL | 20..30 => {} + | ^^^^^^ + | | + | this range doesn't match `30_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `20_u8..=30_u8` +LL | 31..=40 => {} + | ------- this could appear to continue range `20_u8..30_u8`, but `30_u8` isn't matched by either of them + | +note: the lint level is defined here + --> $DIR/gap_between_ranges.rs:2:9 + | +LL | #![deny(non_contiguous_range_endpoints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:21:9 + | +LL | 20..30 => {} + | ^^^^^^ + | | + | this range doesn't match `30_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `20_u8..=30_u8` +LL | 31 => {} + | -- this could appear to continue range `20_u8..30_u8`, but `30_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:26:13 + | +LL | m!(0u8, 20..30, 31..=40); + | ^^^^^^ ------- this could appear to continue range `20_u8..30_u8`, but `30_u8` isn't matched by either of them + | | + | this range doesn't match `30_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `20_u8..=30_u8` + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:27:22 + | +LL | m!(0u8, 31..=40, 20..30); + | ------- ^^^^^^ + | | | + | | this range doesn't match `30_u8` because `..` is an exclusive range + | | help: use an inclusive range instead: `20_u8..=30_u8` + | this could appear to continue range `20_u8..30_u8`, but `30_u8` isn't matched by either of them + +warning: multiple patterns overlap on their endpoints + --> $DIR/gap_between_ranges.rs:28:21 + | +LL | m!(0u8, 20..30, 29..=40); + | ------ ^^^^^^^ ... with this range + | | + | this range overlaps on `29_u8`... + | + = note: you likely meant to write mutually exclusive ranges + = note: `#[warn(overlapping_range_endpoints)]` on by default + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:30:13 + | +LL | m!(0u8, 20..30, 31..=40); + | ^^^^^^ ------- this could appear to continue range `20_u8..30_u8`, but `30_u8` isn't matched by either of them + | | + | this range doesn't match `30_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `20_u8..=30_u8` + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:32:13 + | +LL | m!(0u8, 20..30, 31..=32); + | ^^^^^^ ------- this could appear to continue range `20_u8..30_u8`, but `30_u8` isn't matched by either of them + | | + | this range doesn't match `30_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `20_u8..=30_u8` + +error: exclusive range missing `u8::MAX` + --> $DIR/gap_between_ranges.rs:42:9 + | +LL | 0..255 => {} + | ^^^^^^ + | | + | this range doesn't match `u8::MAX` because `..` is an exclusive range + | help: use an inclusive range instead: `0_u8..=u8::MAX` + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:71:9 + | +LL | 0..10 => {} + | ^^^^^ + | | + | this range doesn't match `10_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `0_u8..=10_u8` +LL | 11..20 => {} + | ------ this could appear to continue range `0_u8..10_u8`, but `10_u8` isn't matched by either of them +LL | 11..30 => {} + | ------ this could appear to continue range `0_u8..10_u8`, but `10_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:77:9 + | +LL | 0..10 => {} + | ^^^^^ + | | + | this range doesn't match `10_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `0_u8..=10_u8` +LL | 11..20 => {} + | ------ this could appear to continue range `0_u8..10_u8`, but `10_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:78:9 + | +LL | 11..20 => {} + | ^^^^^^ + | | + | this range doesn't match `20_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `11_u8..=20_u8` +LL | 21..30 => {} + | ------ this could appear to continue range `11_u8..20_u8`, but `20_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:83:9 + | +LL | 00..20 => {} + | ^^^^^^ + | | + | this range doesn't match `20_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `0_u8..=20_u8` +LL | 10..20 => {} +LL | 21..30 => {} + | ------ this could appear to continue range `0_u8..20_u8`, but `20_u8` isn't matched by either of them +LL | 21..40 => {} + | ------ this could appear to continue range `0_u8..20_u8`, but `20_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:84:9 + | +LL | 10..20 => {} + | ^^^^^^ + | | + | this range doesn't match `20_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `10_u8..=20_u8` +LL | 21..30 => {} + | ------ this could appear to continue range `10_u8..20_u8`, but `20_u8` isn't matched by either of them +LL | 21..40 => {} + | ------ this could appear to continue range `10_u8..20_u8`, but `20_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:92:10 + | +LL | (0..10, true) => {} + | ^^^^^ + | | + | this range doesn't match `10_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `0_u8..=10_u8` +LL | (11..20, true) => {} + | ------ this could appear to continue range `0_u8..10_u8`, but `10_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:97:16 + | +LL | (true, 0..10) => {} + | ^^^^^ + | | + | this range doesn't match `10_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `0_u8..=10_u8` +LL | (true, 11..20) => {} + | ------ this could appear to continue range `0_u8..10_u8`, but `10_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:103:10 + | +LL | (0..10, true) => {} + | ^^^^^ + | | + | this range doesn't match `10_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `0_u8..=10_u8` +LL | (11..20, false) => {} + | ------ this could appear to continue range `0_u8..10_u8`, but `10_u8` isn't matched by either of them + +error: multiple ranges are one apart + --> $DIR/gap_between_ranges.rs:113:14 + | +LL | Some(0..10) => {} + | ^^^^^ + | | + | this range doesn't match `10_u8` because `..` is an exclusive range + | help: use an inclusive range instead: `0_u8..=10_u8` +LL | Some(11..20) => {} + | ------ this could appear to continue range `0_u8..10_u8`, but `10_u8` isn't matched by either of them + +error: aborting due to 16 previous errors; 1 warning emitted + diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.rs b/tests/ui/pattern/usefulness/integer-ranges/reachability.rs index 247fdd91572cd..13b84e2c44bc1 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/reachability.rs +++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.rs @@ -1,5 +1,6 @@ #![feature(exclusive_range_pattern)] #![allow(overlapping_range_endpoints)] +#![allow(non_contiguous_range_endpoints)] #![deny(unreachable_patterns)] macro_rules! m { diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr index c5b028d2038c3..0f52dfd83b9cb 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr @@ -1,137 +1,137 @@ error: unreachable pattern - --> $DIR/reachability.rs:18:17 + --> $DIR/reachability.rs:19:17 | LL | m!(0u8, 42, 42); | ^^ | note: the lint level is defined here - --> $DIR/reachability.rs:3:9 + --> $DIR/reachability.rs:4:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:22:22 + --> $DIR/reachability.rs:23:22 | LL | m!(0u8, 20..=30, 20); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:23:22 + --> $DIR/reachability.rs:24:22 | LL | m!(0u8, 20..=30, 21); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:24:22 + --> $DIR/reachability.rs:25:22 | LL | m!(0u8, 20..=30, 25); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:25:22 + --> $DIR/reachability.rs:26:22 | LL | m!(0u8, 20..=30, 29); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:26:22 + --> $DIR/reachability.rs:27:22 | LL | m!(0u8, 20..=30, 30); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:29:21 + --> $DIR/reachability.rs:30:21 | LL | m!(0u8, 20..30, 20); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:30:21 + --> $DIR/reachability.rs:31:21 | LL | m!(0u8, 20..30, 21); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:31:21 + --> $DIR/reachability.rs:32:21 | LL | m!(0u8, 20..30, 25); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:32:21 + --> $DIR/reachability.rs:33:21 | LL | m!(0u8, 20..30, 29); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:36:22 + --> $DIR/reachability.rs:37:22 | LL | m!(0u8, 20..=30, 20..=30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:37:22 + --> $DIR/reachability.rs:38:22 | LL | m!(0u8, 20.. 30, 20.. 30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:38:22 + --> $DIR/reachability.rs:39:22 | LL | m!(0u8, 20..=30, 20.. 30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:40:22 + --> $DIR/reachability.rs:41:22 | LL | m!(0u8, 20..=30, 21..=30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:41:22 + --> $DIR/reachability.rs:42:22 | LL | m!(0u8, 20..=30, 20..=29); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:43:24 + --> $DIR/reachability.rs:44:24 | LL | m!('a', 'A'..='z', 'a'..='z'); | ^^^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:50:9 + --> $DIR/reachability.rs:51:9 | LL | 5..=8 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:56:9 + --> $DIR/reachability.rs:57:9 | LL | 5..15 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:63:9 + --> $DIR/reachability.rs:64:9 | LL | 5..25 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:71:9 + --> $DIR/reachability.rs:72:9 | LL | 5..25 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:77:9 + --> $DIR/reachability.rs:78:9 | LL | 5..15 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:84:9 + --> $DIR/reachability.rs:85:9 | LL | _ => {}, | - matches any value @@ -139,19 +139,19 @@ LL | '\u{D7FF}'..='\u{E000}' => {}, | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern error: unreachable pattern - --> $DIR/reachability.rs:89:9 + --> $DIR/reachability.rs:90:9 | LL | '\u{D7FF}'..='\u{E000}' => {}, | ^^^^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:105:9 + --> $DIR/reachability.rs:106:9 | LL | &FOO => {} | ^^^^ error: unreachable pattern - --> $DIR/reachability.rs:106:9 + --> $DIR/reachability.rs:107:9 | LL | BAR => {} | ^^^