Skip to content

Commit

Permalink
Add check for overlapping ranges to unreachable patterns lint
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Oct 16, 2019
1 parent 237d54f commit 91a3db9
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 118 deletions.
2 changes: 2 additions & 0 deletions src/libcore/ascii.rs
Expand Up @@ -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),
};
Expand Down
230 changes: 170 additions & 60 deletions src/librustc_mir/hair/pattern/_match.rs

Large diffs are not rendered by default.

20 changes: 15 additions & 5 deletions src/librustc_mir/hair/pattern/check_match.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
})
}

Expand All @@ -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,
};
Expand Down Expand Up @@ -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 { .. } |
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -465,9 +473,10 @@ fn check_not_useful(
cx: &mut MatchCheckCtxt<'_, 'tcx>,
ty: Ty<'tcx>,
matrix: &Matrix<'_, 'tcx>,
hir_id: HirId,
) -> Result<(), Vec<super::Pat<'tcx>>> {
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]
Expand All @@ -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,
};
Expand Down
17 changes: 10 additions & 7 deletions 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)]
Expand All @@ -13,7 +13,7 @@ fn main() {

match 10 {
1..10 => {},
9..=10 => {},
9..=10 => {}, //~ WARNING multiple patterns covering the same range
_ => {},
}

Expand All @@ -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
_ => {},
}
}
42 changes: 37 additions & 5 deletions 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
Expand All @@ -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 => {},
| ^

8 changes: 4 additions & 4 deletions src/test/ui/exhaustive_integer_patterns.rs
Expand Up @@ -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 => {}
}
Expand All @@ -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 => {}
}

Expand Down Expand Up @@ -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
_ => {}
}

Expand Down
32 changes: 25 additions & 7 deletions src/test/ui/exhaustive_integer_patterns.stderr
@@ -1,15 +1,23 @@
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
|
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
|
Expand All @@ -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
Expand Down Expand Up @@ -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
|
Expand All @@ -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`.
24 changes: 13 additions & 11 deletions 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
_ => {}
};
}

0 comments on commit 91a3db9

Please sign in to comment.