Skip to content

Add check for overlapping ranges to unreachable patterns lint #64007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Oct 19, 2019
Prev Previous commit
Next Next commit
Only emit overlapping patterns lint if the overlap is partial
  • Loading branch information
estebank committed Oct 16, 2019
commit 73d6efc43e0629b2028e7d031306088f44f84782
2 changes: 0 additions & 2 deletions src/libcore/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};
Expand Down
35 changes: 34 additions & 1 deletion src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 0 additions & 2 deletions src/librustc_target/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
18 changes: 0 additions & 18 deletions src/test/ui/check_match/issue-43253.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand All @@ -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
|
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/exhaustive_integer_patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ fn main() {
-5..=120 => {}
-2..=20 => {}
//~^ ERROR unreachable pattern
//~| ERROR multiple patterns covering the same range
125 => {}
}

Expand Down
28 changes: 10 additions & 18 deletions src/test/ui/exhaustive_integer_patterns.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand All @@ -63,77 +55,77 @@ 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
|
= 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
|
= 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
|
= 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
|
= 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
|
= 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`
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
|
= 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
|
= 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`.
1 change: 1 addition & 0 deletions src/test/ui/issues/issue-13867.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-21475.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-pass
#![allow(unused_imports)]
#![allow(unused_imports, overlapping_patterns)]
// pretty-expanded FIXME #23616

use m::{START, END};
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/issues/issue-26251.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// run-pass
#![allow(overlapping_patterns)]

fn main() {
let x = 'a';

Expand Down
4 changes: 0 additions & 4 deletions src/test/ui/match/match-range-fail-dominate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,27 @@ fn main() {
1 ..= 10 => { }
5 ..= 6 => { }
//~^ ERROR unreachable pattern
//~| ERROR multiple patterns covering the same range
_ => {}
};

match 5 {
3 ..= 6 => { }
4 ..= 6 => { }
//~^ ERROR unreachable pattern
//~| ERROR multiple patterns covering the same range
_ => {}
};

match 5 {
4 ..= 6 => { }
4 ..= 6 => { }
//~^ ERROR unreachable pattern
//~| ERROR multiple patterns covering the same range
_ => {}
};

match 'c' {
'A' ..= 'z' => {}
'a' ..= 'z' => {}
//~^ ERROR unreachable pattern
//~| ERROR multiple patterns covering the same range
_ => {}
};

Expand Down
56 changes: 9 additions & 47 deletions src/test/ui/match/match-range-fail-dominate.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand All @@ -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 => {}
| ^^^^^^^
Expand All @@ -77,7 +39,7 @@ LL | 0.01f64 ..= 6.5f64 => {}
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/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 => {}
| ^^^^^^
Expand All @@ -86,7 +48,7 @@ LL | 0.01f64 ..= 6.5f64 => {}
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/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 => {}
| ^^^^^^^
Expand All @@ -95,19 +57,19 @@ LL | 0.02f64 => {}
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/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 => {}
| ^^^^^^^
|
= 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 <https://github.com/rust-lang/rust/issues/41620>

error: aborting due to 9 previous errors
error: aborting due to 5 previous errors

2 changes: 1 addition & 1 deletion src/test/ui/precise_pointer_size_matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading