Skip to content

Identify unreachable subpatterns more reliably #80632

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 9 commits into from
Feb 7, 2021
14 changes: 7 additions & 7 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::usefulness::Usefulness::*;
use super::usefulness::{
compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, UsefulnessReport,
compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, Reachability,
UsefulnessReport,
};
use super::{PatCtxt, PatKind, PatternError};

@@ -398,10 +398,11 @@ fn report_arm_reachability<'p, 'tcx>(
report: &UsefulnessReport<'p, 'tcx>,
source: hir::MatchSource,
) {
use Reachability::*;
let mut catchall = None;
for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
match is_useful {
NotUseful => {
Unreachable => {
match source {
hir::MatchSource::WhileDesugar => bug!(),

@@ -430,17 +431,16 @@ fn report_arm_reachability<'p, 'tcx>(
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
}
}
Useful(unreachables) if unreachables.is_empty() => {}
Reachable(unreachables) if unreachables.is_empty() => {}
// The arm is reachable, but contains unreachable subpatterns (from or-patterns).
Useful(unreachables) => {
let mut unreachables: Vec<_> = unreachables.iter().collect();
Reachable(unreachables) => {
let mut unreachables = unreachables.clone();
// Emit lints in the order in which they occur in the file.
unreachables.sort_unstable();
for span in unreachables {
unreachable_pattern(cx.tcx, span, arm.hir_id, None);
}
}
UsefulWithWitness(_) => bug!(),
}
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
catchall = Some(arm.pat.span);
2 changes: 0 additions & 2 deletions compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
Original file line number Diff line number Diff line change
@@ -724,8 +724,6 @@ impl<'tcx> Constructor<'tcx> {
where
'tcx: 'a,
{
debug!("Constructor::split({:#?})", self);

match self {
Wildcard => {
let mut split_wildcard = SplitWildcard::new(pcx);
573 changes: 371 additions & 202 deletions compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

Large diffs are not rendered by default.

23 changes: 21 additions & 2 deletions src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
Original file line number Diff line number Diff line change
@@ -48,6 +48,25 @@ fn main() {
(1 | 1,) => {} //~ ERROR unreachable
_ => {}
}
match 0 {
(0 | 1) | 1 => {} //~ ERROR unreachable
_ => {}
}
match 0 {
// We get two errors because recursive or-pattern expansion means we don't notice the two
// errors span a whole pattern. This could be better but doesn't matter much
0 | (0 | 0) => {}
//~^ ERROR unreachable
//~| ERROR unreachable
_ => {}
}
match None {
// There is only one error that correctly points to the whole subpattern
Some(0) |
Some( //~ ERROR unreachable
0 | 0) => {}
_ => {}
}
match [0; 2] {
[0
| 0 //~ ERROR unreachable
@@ -84,8 +103,8 @@ fn main() {
}
macro_rules! t_or_f {
() => {
(true // FIXME: should be unreachable
| false)
(true //~ ERROR unreachable
| false)
};
}
match (true, None) {
56 changes: 46 additions & 10 deletions src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
Original file line number Diff line number Diff line change
@@ -77,58 +77,94 @@ LL | (1 | 1,) => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:53:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:52:19
|
LL | (0 | 1) | 1 => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
|
LL | 0 | (0 | 0) => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:18
|
LL | 0 | (0 | 0) => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:66:13
|
LL | / Some(
LL | | 0 | 0) => {}
| |______________________^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
|
LL | | 0
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:55:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
|
LL | | 0] => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:63:10
--> $DIR/exhaustiveness-unreachable-pattern.rs:82:10
|
LL | [1
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:75:10
--> $DIR/exhaustiveness-unreachable-pattern.rs:94:10
|
LL | [true
| ^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:82:36
--> $DIR/exhaustiveness-unreachable-pattern.rs:101:36
|
LL | (true | false, None | Some(true
| ^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:98:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:106:14
|
LL | (true
| ^^^^
...
LL | (true | false, None | Some(t_or_f!())) => {}
| --------- in this macro invocation
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:117:14
|
LL | Some(0
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:117:19
--> $DIR/exhaustiveness-unreachable-pattern.rs:136:19
|
LL | | false) => {}
| ^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:125:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:144:15
|
LL | | true) => {}
| ^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:131:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:150:15
|
LL | | true,
| ^^^^

error: aborting due to 21 previous errors
error: aborting due to 26 previous errors

27 changes: 27 additions & 0 deletions src/test/ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// check-pass
#![deny(unreachable_patterns)]
pub enum TypeCtor {
Slice,
Array,
}

pub struct ApplicationTy(TypeCtor);

macro_rules! ty_app {
($ctor:pat) => {
ApplicationTy($ctor)
};
}

fn _foo(ty: ApplicationTy) {
match ty {
ty_app!(TypeCtor::Array) | ty_app!(TypeCtor::Slice) => {}
}

// same as above, with the macro expanded
match ty {
ApplicationTy(TypeCtor::Array) | ApplicationTy(TypeCtor::Slice) => {}
}
}

fn main() {}