about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2020-12-17 01:25:53 +0000
committerNadrieril <nadrieril+git@gmail.com>2020-12-18 16:21:39 +0000
commit6319d737e07d732aa044864933b69a39fdbeec0a (patch)
treeee12811deeaa0991550d3e786c31db501cbdffb5
parent2d71a0b9b9871966dd1f63b4113eeecc2d6e2f6f (diff)
downloadrust-6319d737e07d732aa044864933b69a39fdbeec0a.tar.gz
rust-6319d737e07d732aa044864933b69a39fdbeec0a.zip
Merge unreachable subpatterns correctly
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs31
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs4
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr20
3 files changed, 36 insertions, 19 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 02b5e0eb3b2..c07d4c9b8f7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -788,13 +788,32 @@ impl<'tcx> Usefulness<'tcx> {
     /// When trying several branches and each returns a `Usefulness`, we need to combine the
     /// results together.
     fn merge_split_constructors(usefulnesses: impl Iterator<Item = Self>) -> Self {
+        // If we have detected some unreachable sub-branches, we only want to keep them when they
+        // were unreachable in _all_ branches. So we take a big intersection.
+
+        // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the
+        // sets are only non-empty in the diagnostic path.
+        let mut unreachables: Option<SpanSet> = None;
         // Witnesses of usefulness, if any.
         let mut witnesses = Vec::new();
 
         for u in usefulnesses {
             match u {
-                Useful(..) => {
-                    return u;
+                Useful(spans) if spans.is_empty() => {
+                    // Once we reach the empty set, more intersections won't change the result.
+                    return Useful(SpanSet::new());
+                }
+                Useful(spans) => {
+                    if let Some(unreachables) = &mut unreachables {
+                        if !unreachables.is_empty() {
+                            unreachables.intersection_mut(&spans);
+                        }
+                        if unreachables.is_empty() {
+                            return Useful(SpanSet::new());
+                        }
+                    } else {
+                        unreachables = Some(spans);
+                    }
                 }
                 NotUseful => {}
                 UsefulWithWitness(wits) => {
@@ -803,7 +822,13 @@ impl<'tcx> Usefulness<'tcx> {
             }
         }
 
-        if !witnesses.is_empty() { UsefulWithWitness(witnesses) } else { NotUseful }
+        if !witnesses.is_empty() {
+            UsefulWithWitness(witnesses)
+        } else if let Some(unreachables) = unreachables {
+            Useful(unreachables)
+        } else {
+            NotUseful
+        }
     }
 
     fn apply_constructor<'p>(
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
index 3e242a797a2..184ffa85c40 100644
--- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
@@ -64,11 +64,9 @@ fn main() {
             | 2, ..] => {}
         _ => {}
     }
-    // FIXME: incorrect
     match &[][..] {
         [true] => {}
-        [true //~ ERROR unreachable
-            | false, ..] => {}
+        [true | false, ..] => {}
         _ => {}
     }
     match &[][..] {
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
index ac0b34c2bd5..8b1003b5514 100644
--- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
@@ -95,46 +95,40 @@ LL |         [1
    |          ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:70:10
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:75:10
    |
 LL |         [true
    |          ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:77:10
-   |
-LL |         [true
-   |          ^^^^
-
-error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:84:36
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:82:36
    |
 LL |         (true | false, None | Some(true
    |                                    ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:100:14
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:98:14
    |
 LL |         Some(0
    |              ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:119:19
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:117:19
    |
 LL |                 | false) => {}
    |                   ^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:127:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:125:15
    |
 LL |             | true) => {}
    |               ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:133:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:131:15
    |
 LL |             | true,
    |               ^^^^
 
-error: aborting due to 22 previous errors
+error: aborting due to 21 previous errors