diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index b5a655e4218f1..372cb783f503f 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -276,6 +276,7 @@ use self::Usefulness::*; use self::WitnessPreference::*; use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; use rustc_index::vec::Idx; use super::{compare_const_vals, PatternFoldable, PatternFolder}; @@ -1852,16 +1853,35 @@ crate fn is_useful<'p, 'tcx>( // We need to push the already-seen patterns into the matrix in order to detect redundant // branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns. let mut matrix = matrix.clone(); - let mut unreachable_pats = Vec::new(); + // `Vec` of all the unreachable branches of the current or-pattern. + let mut unreachable_branches = Vec::new(); + // Subpatterns that are unreachable from all branches. E.g. in the following case, the last + // `true` is unreachable only from one branch, so it is overall reachable. + // ``` + // match (true, true) { + // (true, true) => {} + // (false | true, false | true) => {} + // } + // ``` + let mut unreachable_subpats = FxHashSet::default(); + // Whether any branch at all is useful. let mut any_is_useful = false; + for v in vs { let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); match res { Useful(pats) => { - any_is_useful = true; - unreachable_pats.extend(pats); + if !any_is_useful { + any_is_useful = true; + // Initialize with the first set of unreachable subpatterns encountered. + unreachable_subpats = pats.into_iter().collect(); + } else { + // Keep the patterns unreachable from both this and previous branches. + unreachable_subpats = + pats.into_iter().filter(|p| unreachable_subpats.contains(p)).collect(); + } } - NotUseful => unreachable_pats.push(v.head().span), + NotUseful => unreachable_branches.push(v.head().span), UsefulWithWitness(_) => { bug!("Encountered or-pat in `v` during exhaustiveness checking") } @@ -1871,7 +1891,13 @@ crate fn is_useful<'p, 'tcx>( matrix.push(v); } } - return if any_is_useful { Useful(unreachable_pats) } else { NotUseful }; + if any_is_useful { + // Collect all the unreachable patterns. + unreachable_branches.extend(unreachable_subpats); + return Useful(unreachable_branches); + } else { + return NotUseful; + } } // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 44bae282d8857..a1147cb5cfc9c 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -29,6 +29,9 @@ fn main() { (1, 4 | 5) => {} //~ ERROR unreachable pattern _ => {} } + match (true, true) { + (false | true, false | true) => (), + } match (Some(0u8),) { (None | Some(1 | 2),) => {} (Some(1),) => {} //~ ERROR unreachable pattern @@ -67,4 +70,29 @@ fn main() { | 1) => {} _ => {} } + + // A subpattern that is only unreachable in one branch is overall reachable. + match (true, true) { + (true, true) => {} + (false | true, false | true) => {} + } + match (true, true) { + (true, false) => {} + (false, true) => {} + (false | true, false | true) => {} + } + // A subpattern that is unreachable in all branches is overall unreachable. + match (true, true) { + (false, true) => {} + (true, true) => {} + (false | true, false + | true) => {} //~ ERROR unreachable + } + match (true, true) { + (true, false) => {} + (true, true) => {} + (false + | true, //~ ERROR unreachable + false | true) => {} + } } diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index bef6f8270bc54..d92b545a8694f 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -53,52 +53,64 @@ LL | (1, 4 | 5) => {} | ^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:34:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9 | LL | (Some(1),) => {} | ^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:35:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:38:9 | LL | (None,) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:40:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:43:9 | LL | ((1..=4,),) => {} | ^^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:45:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:48:14 | LL | (1 | 1,) => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:52:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:53:15 | -LL | | 0] => {} +LL | | 0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:50:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:55:15 | -LL | | 0 +LL | | 0] => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:60:10 + --> $DIR/exhaustiveness-unreachable-pattern.rs:63:10 | LL | [1 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:66:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:69:14 | LL | Some(0 | ^ -error: aborting due to 16 previous errors +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:89:15 + | +LL | | true) => {} + | ^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:95:15 + | +LL | | true, + | ^^^^ + +error: aborting due to 18 previous errors diff --git a/src/test/ui/or-patterns/search-via-bindings.rs b/src/test/ui/or-patterns/search-via-bindings.rs index eb127b881cd37..067e617373a63 100644 --- a/src/test/ui/or-patterns/search-via-bindings.rs +++ b/src/test/ui/or-patterns/search-via-bindings.rs @@ -3,7 +3,6 @@ // run-pass #![feature(or_patterns)] -#![allow(unreachable_patterns)] // FIXME(or-patterns) this shouldn't trigger fn search(target: (bool, bool, bool)) -> u32 { let x = ((false, true), (false, true), (false, true));