about summary refs log tree commit diff
path: root/compiler
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 /compiler
parent2d71a0b9b9871966dd1f63b4113eeecc2d6e2f6f (diff)
downloadrust-6319d737e07d732aa044864933b69a39fdbeec0a.tar.gz
rust-6319d737e07d732aa044864933b69a39fdbeec0a.zip
Merge unreachable subpatterns correctly
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs31
1 files changed, 28 insertions, 3 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>(