about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2023-11-18 21:39:57 +0100
committerNadrieril <nadrieril+git@gmail.com>2023-12-09 00:44:49 +0100
commitddef5b61f134834c81f8802d07ce3774e46143f6 (patch)
tree1ad87b3669823ad42d537ab03c19dc93a31b4a67
parentf5dbb54648e40f3363321cd5ea6cd903db1af994 (diff)
downloadrust-ddef5b61f134834c81f8802d07ce3774e46143f6.tar.gz
rust-ddef5b61f134834c81f8802d07ce3774e46143f6.zip
Don't warn an empty pattern unreachable if we're not sure the data is valid
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs44
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs85
-rw-r--r--tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr389
-rw-r--r--tests/ui/pattern/usefulness/empty-types.normal.stderr130
-rw-r--r--tests/ui/pattern/usefulness/empty-types.rs128
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.rs6
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.stderr31
-rw-r--r--tests/ui/uninhabited/uninhabited-patterns.rs4
-rw-r--r--tests/ui/uninhabited/uninhabited-patterns.stderr20
9 files changed, 183 insertions, 654 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index f1ad0f25cd2..e66402a7eb3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -787,9 +787,6 @@ pub(super) enum Constructor<'tcx> {
 }
 
 impl<'tcx> Constructor<'tcx> {
-    pub(super) fn is_wildcard(&self) -> bool {
-        matches!(self, Wildcard)
-    }
     pub(super) fn is_non_exhaustive(&self) -> bool {
         matches!(self, NonExhaustive)
     }
@@ -973,15 +970,17 @@ pub(super) enum ConstructorSet {
 /// constructors that exist in the type but are not present in the column.
 ///
 /// More formally, if we discard wildcards from the column, this respects the following constraints:
-/// 1. the union of `present` and `missing` covers the whole type
+/// 1. the union of `present`, `missing` and `missing_empty` covers all the constructors of the type
 /// 2. each constructor in `present` is covered by something in the column
-/// 3. no constructor in `missing` is covered by anything in the column
+/// 3. no constructor in `missing` or `missing_empty` is covered by anything in the column
 /// 4. each constructor in the column is equal to the union of one or more constructors in `present`
 /// 5. `missing` does not contain empty constructors (see discussion about emptiness at the top of
 ///    the file);
-/// 6. constructors in `present` and `missing` are split for the column; in other words, they are
-///    either fully included in or fully disjoint from each constructor in the column. In other
-///    words, there are no non-trivial intersections like between `0..10` and `5..15`.
+/// 6. `missing_empty` contains only empty constructors
+/// 7. constructors in `present`, `missing` and `missing_empty` are split for the column; in other
+///    words, they are either fully included in or fully disjoint from each constructor in the
+///    column. In yet other words, there are no non-trivial intersections like between `0..10` and
+///    `5..15`.
 ///
 /// We must be particularly careful with weird constructors like `Opaque`: they're not formally part
 /// of the `ConstructorSet` for the type, yet if we forgot to include them in `present` we would be
@@ -990,6 +989,7 @@ pub(super) enum ConstructorSet {
 pub(super) struct SplitConstructorSet<'tcx> {
     pub(super) present: SmallVec<[Constructor<'tcx>; 1]>,
     pub(super) missing: Vec<Constructor<'tcx>>,
+    pub(super) missing_empty: Vec<Constructor<'tcx>>,
 }
 
 impl ConstructorSet {
@@ -1132,10 +1132,10 @@ impl ConstructorSet {
         // Constructors in `ctors`, except wildcards and opaques.
         let mut seen = Vec::new();
         for ctor in ctors.cloned() {
-            if let Constructor::Opaque(..) = ctor {
-                present.push(ctor);
-            } else if !ctor.is_wildcard() {
-                seen.push(ctor);
+            match ctor {
+                Opaque(..) => present.push(ctor),
+                Wildcard => {} // discard wildcards
+                _ => seen.push(ctor),
             }
         }
 
@@ -1239,16 +1239,24 @@ impl ConstructorSet {
                 missing.push(NonExhaustive);
             }
             ConstructorSet::NoConstructors => {
-                if !pcx.is_top_level {
-                    missing_empty.push(NonExhaustive);
-                }
+                // In a `MaybeInvalid` place even an empty pattern may be reachable. We therefore
+                // add a dummy empty constructor here, which will be ignored if the place is
+                // `ValidOnly`.
+                missing_empty.push(NonExhaustive);
             }
         }
 
-        if !pcx.cx.tcx.features().exhaustive_patterns {
-            missing.extend(missing_empty);
+        // We have now grouped all the constructors into 3 buckets: present, missing, missing_empty.
+        // In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
+        // types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
+        if !pcx.cx.tcx.features().exhaustive_patterns
+            && !(pcx.is_top_level && matches!(self, Self::NoConstructors))
+        {
+            // Treat all missing constructors as nonempty.
+            missing.extend(missing_empty.drain(..));
         }
-        SplitConstructorSet { present, missing }
+
+        SplitConstructorSet { present, missing, missing_empty }
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index d86147b4699..637cc38be2c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -637,12 +637,18 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
     }
 }
 
-/// In the matrix, tracks whether a given place (aka column) is known to contain a valid value or
-/// not.
+/// Serves two purposes:
+/// - in a wildcard, tracks whether the wildcard matches only valid values (i.e. is a binding `_a`)
+///     or also invalid values (i.e. is a true `_` pattern).
+/// - in the matrix, track whether a given place (aka column) is known to contain a valid value or
+///     not.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub(super) enum ValidityConstraint {
     ValidOnly,
     MaybeInvalid,
+    /// Option for backwards compatibility: the place is not known to be valid but we allow omitting
+    /// `useful && !reachable` arms anyway.
+    MaybeInvalidButAllowOmittingArms,
 }
 
 impl ValidityConstraint {
@@ -650,19 +656,37 @@ impl ValidityConstraint {
         if is_valid_only { ValidOnly } else { MaybeInvalid }
     }
 
+    fn allow_omitting_side_effecting_arms(self) -> Self {
+        match self {
+            MaybeInvalid | MaybeInvalidButAllowOmittingArms => MaybeInvalidButAllowOmittingArms,
+            // There are no side-effecting empty arms here, nothing to do.
+            ValidOnly => ValidOnly,
+        }
+    }
+
+    pub(super) fn is_known_valid(self) -> bool {
+        matches!(self, ValidOnly)
+    }
+    pub(super) fn allows_omitting_empty_arms(self) -> bool {
+        matches!(self, ValidOnly | MaybeInvalidButAllowOmittingArms)
+    }
+
     /// If the place has validity given by `self` and we read that the value at the place has
     /// constructor `ctor`, this computes what we can assume about the validity of the constructor
     /// fields.
     ///
     /// Pending further opsem decisions, the current behavior is: validity is preserved, except
-    /// under `&` where validity is reset to `MaybeInvalid`.
+    /// inside `&` and union fields where validity is reset to `MaybeInvalid`.
     pub(super) fn specialize<'tcx>(
         self,
         pcx: &PatCtxt<'_, '_, 'tcx>,
         ctor: &Constructor<'tcx>,
     ) -> Self {
-        // We preserve validity except when we go under a reference.
-        if matches!(ctor, Constructor::Single) && matches!(pcx.ty.kind(), ty::Ref(..)) {
+        // We preserve validity except when we go inside a reference or a union field.
+        if matches!(ctor, Constructor::Single)
+            && (matches!(pcx.ty.kind(), ty::Ref(..))
+                || matches!(pcx.ty.kind(), ty::Adt(def, ..) if def.is_union()))
+        {
             // Validity of `x: &T` does not imply validity of `*x: T`.
             MaybeInvalid
         } else {
@@ -675,7 +699,7 @@ impl fmt::Display for ValidityConstraint {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let s = match self {
             ValidOnly => "✓",
-            MaybeInvalid => "?",
+            MaybeInvalid | MaybeInvalidButAllowOmittingArms => "?",
         };
         write!(f, "{s}")
     }
@@ -1202,9 +1226,9 @@ fn compute_exhaustiveness_and_usefulness<'p, 'tcx>(
         for row in matrix.rows_mut() {
             // All rows are useful until they're not.
             row.useful = true;
+            // When there's an unguarded row, the match is exhaustive and any subsequent row is not
+            // useful.
             if !row.is_under_guard {
-                // There's an unguarded row, so the match is exhaustive, and any subsequent row is
-                // unreachable.
                 return WitnessMatrix::empty();
             }
         }
@@ -1215,26 +1239,37 @@ fn compute_exhaustiveness_and_usefulness<'p, 'tcx>(
     debug!("ty: {ty:?}");
     let pcx = &PatCtxt { cx, ty, is_top_level };
 
+    // Whether the place/column we are inspecting is known to contain valid data.
+    let place_validity = matrix.place_validity[0];
+    // For backwards compability we allow omitting some empty arms that we ideally shouldn't.
+    let place_validity = place_validity.allow_omitting_side_effecting_arms();
+
     // Analyze the constructors present in this column.
     let ctors = matrix.heads().map(|p| p.ctor());
-    let split_set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, ctors);
-
+    let split_set = ConstructorSet::for_ty(cx, ty).split(pcx, ctors);
     let all_missing = split_set.present.is_empty();
-    let always_report_all = is_top_level && !IntRange::is_integral(pcx.ty);
-    // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
-    let report_individual_missing_ctors = always_report_all || !all_missing;
 
+    // Build the set of constructors we will specialize with. It must cover the whole type.
     let mut split_ctors = split_set.present;
-    let mut only_report_missing = false;
     if !split_set.missing.is_empty() {
         // We need to iterate over a full set of constructors, so we add `Missing` to represent the
         // missing ones. This is explained under "Constructor Splitting" at the top of this file.
         split_ctors.push(Constructor::Missing);
-        // For diagnostic purposes we choose to only report the constructors that are missing. Since
-        // `Missing` matches only the wildcard rows, it matches fewer rows than any normal
-        // constructor and is therefore guaranteed to result in more witnesses. So skipping the
-        // other constructors does not jeopardize correctness.
-        only_report_missing = true;
+    } else if !split_set.missing_empty.is_empty() && !place_validity.is_known_valid() {
+        // The missing empty constructors are reachable if the place can contain invalid data.
+        split_ctors.push(Constructor::Missing);
+    }
+
+    // Decide what constructors to report.
+    let always_report_all = is_top_level && !IntRange::is_integral(pcx.ty);
+    // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
+    let report_individual_missing_ctors = always_report_all || !all_missing;
+    // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
+    // split_ctors.contains(Missing)`. The converse usually holds except in the
+    // `MaybeInvalidButAllowOmittingArms` backwards-compatibility case.
+    let mut missing_ctors = split_set.missing;
+    if !place_validity.allows_omitting_empty_arms() {
+        missing_ctors.extend(split_set.missing_empty);
     }
 
     let mut ret = WitnessMatrix::empty();
@@ -1246,11 +1281,19 @@ fn compute_exhaustiveness_and_usefulness<'p, 'tcx>(
             compute_exhaustiveness_and_usefulness(cx, &mut spec_matrix, false)
         });
 
-        if !only_report_missing || matches!(ctor, Constructor::Missing) {
+        let counts_for_exhaustiveness = match ctor {
+            Constructor::Missing => !missing_ctors.is_empty(),
+            // If there are missing constructors we'll report those instead. Since `Missing` matches
+            // only the wildcard rows, it matches fewer rows than this constructor, and is therefore
+            // guaranteed to result in the same or more witnesses. So skipping this does not
+            // jeopardize correctness.
+            _ => missing_ctors.is_empty(),
+        };
+        if counts_for_exhaustiveness {
             // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
             witnesses.apply_constructor(
                 pcx,
-                &split_set.missing,
+                &missing_ctors,
                 &ctor,
                 report_individual_missing_ctors,
             );
diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
index 9a53b54704e..367aba3bdd6 100644
--- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
@@ -32,12 +32,6 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:62:9
-   |
-LL |         &_ => {}
-   |         ^^
-
-error: unreachable pattern
   --> $DIR/empty-types.rs:69:9
    |
 LL |         (_, _) => {}
@@ -185,42 +179,6 @@ LL |             _ => {}
    |             ^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:158:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:167:13
-   |
-LL |             Some(_) => {}
-   |             ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:171:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:175:13
-   |
-LL |             _a => {}
-   |             ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:180:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:185:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
   --> $DIR/empty-types.rs:204:13
    |
 LL |             _ => {}
@@ -251,48 +209,6 @@ LL |             _ => {}
    |             ^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:234:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:239:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:245:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:251:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:256:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:262:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:268:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
   --> $DIR/empty-types.rs:284:9
    |
 LL |         _ => {}
@@ -316,18 +232,6 @@ error: unreachable pattern
 LL |         Err(_) => {}
    |         ^^^^^^
 
-error: unreachable pattern
-  --> $DIR/empty-types.rs:296:9
-   |
-LL |         &_ => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:299:9
-   |
-LL |         Uninit { value: _ } => {}
-   |         ^^^^^^^^^^^^^^^^^^^
-
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
   --> $DIR/empty-types.rs:323:11
    |
@@ -342,24 +246,6 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error: unreachable pattern
-  --> $DIR/empty-types.rs:331:9
-   |
-LL |         [_] => {}
-   |         ^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:332:9
-   |
-LL |         [_, _, ..] => {}
-   |         ^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:337:9
-   |
-LL |         [_, _, _, ..] => {}
-   |         ^^^^^^^^^^^^^
-
 error[E0004]: non-exhaustive patterns: `&[]` not covered
   --> $DIR/empty-types.rs:334:11
    |
@@ -369,20 +255,9 @@ LL |     match slice_never {
    = note: the matched value is of type `&[!]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |         [_, _, _, ..] => {}, &[] => todo!()
-   |                            ++++++++++++++++
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:341:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:345:9
+LL ~         [_, _, _, ..] => {},
+LL +         &[] => todo!()
    |
-LL |         _x => {}
-   |         ^^
 
 error[E0004]: non-exhaustive patterns: `&[]` not covered
   --> $DIR/empty-types.rs:347:11
@@ -430,18 +305,6 @@ error: unreachable pattern
 LL |         [_, ..] => {}
    |         ^^^^^^^
 
-error: unreachable pattern
-  --> $DIR/empty-types.rs:375:9
-   |
-LL |         &[_, _, _] => {}
-   |         ^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:379:9
-   |
-LL |         &[_x, _, _] => {}
-   |         ^^^^^^^^^^^
-
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
   --> $DIR/empty-types.rs:383:11
    |
@@ -501,186 +364,6 @@ LL |         _a => {}
    |         ^^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:436:9
-   |
-LL |         &_ => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:444:9
-   |
-LL |         &_a => {}
-   |         ^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:453:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:458:9
-   |
-LL |         _a => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:463:9
-   |
-LL |         &_ => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:468:9
-   |
-LL |         &_a => {}
-   |         ^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:475:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:479:9
-   |
-LL |         _a => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:485:9
-   |
-LL |         ref _a => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:494:9
-   |
-LL |         Some(_) => {}
-   |         ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:499:9
-   |
-LL |         Some(_a) => {}
-   |         ^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:504:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:509:9
-   |
-LL |         _a => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:514:14
-   |
-LL |         _a @ Some(_) => {}
-   |              ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:521:9
-   |
-LL |         ref _a => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:526:18
-   |
-LL |         ref _a @ Some(_) => {}
-   |                  ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:531:18
-   |
-LL |         ref _a @ Some(_b) => {}
-   |                  ^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:538:9
-   |
-LL |         Ok(_) => {}
-   |         ^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:542:9
-   |
-LL |         Ok(_) => {}
-   |         ^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:544:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:549:9
-   |
-LL |         Ok(_a) => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:553:9
-   |
-LL |         Ok(_a) => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:555:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:559:9
-   |
-LL |         Ok(_a) => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:561:9
-   |
-LL |         Err(_) => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:569:9
-   |
-LL |         (_, _) => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:573:9
-   |
-LL |         (_x, _) => {}
-   |         ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:577:9
-   |
-LL |         (_, _x) => {}
-   |         ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:581:9
-   |
-LL |         (0, _x) => {}
-   |         ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:583:9
-   |
-LL |         (1.., _) => {}
-   |         ^^^^^^^^
-
-error: unreachable pattern
   --> $DIR/empty-types.rs:598:9
    |
 LL |         _ => {}
@@ -704,73 +387,7 @@ error: unreachable pattern
 LL |         _x if false => {}
    |         ^^
 
-error: unreachable pattern
-  --> $DIR/empty-types.rs:613:9
-   |
-LL |         _ if false => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:615:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:622:9
-   |
-LL |         _a if false => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:624:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:629:9
-   |
-LL |         _a if false => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:634:9
-   |
-LL |         &_a if false => {}
-   |         ^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:641:9
-   |
-LL |         Ok(_x) if false => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:643:9
-   |
-LL |         Ok(_) => {}
-   |         ^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:645:9
-   |
-LL |         Err(_) => {}
-   |         ^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:650:9
-   |
-LL |         (_, _x) if false => {}
-   |         ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:652:9
-   |
-LL |         (_, _) => {}
-   |         ^^^^^^
-
-error: aborting due to 113 previous errors
+error: aborting due to 49 previous errors
 
 Some errors have detailed explanations: E0004, E0005.
 For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr
index b066393a61e..133a95a821b 100644
--- a/tests/ui/pattern/usefulness/empty-types.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr
@@ -234,12 +234,6 @@ LL ~             None => {},
 LL +             Some(_) => todo!()
    |
 
-error: unreachable pattern
-  --> $DIR/empty-types.rs:158:13
-   |
-LL |             _ => {}
-   |             ^
-
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
   --> $DIR/empty-types.rs:161:15
    |
@@ -259,18 +253,6 @@ LL +             Some(_) => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:180:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:185:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
   --> $DIR/empty-types.rs:204:13
    |
 LL |             _ => {}
@@ -301,48 +283,6 @@ LL |             _ => {}
    |             ^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:234:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:239:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:245:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:251:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:256:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:262:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:268:13
-   |
-LL |             _ => {}
-   |             ^
-
-error: unreachable pattern
   --> $DIR/empty-types.rs:284:9
    |
 LL |         _ => {}
@@ -448,8 +388,9 @@ LL |     match slice_never {
    = note: the matched value is of type `&[!]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL |         [_, _, _, ..] => {}, &[] | &[_] | &[_, _] => todo!()
-   |                            +++++++++++++++++++++++++++++++++
+LL ~         [_, _, _, ..] => {},
+LL +         &[] | &[_] | &[_, _] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered
   --> $DIR/empty-types.rs:347:11
@@ -545,24 +486,6 @@ LL ~         &None => {},
 LL +         &Some(_) => todo!()
    |
 
-error: unreachable pattern
-  --> $DIR/empty-types.rs:475:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:479:9
-   |
-LL |         _a => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:485:9
-   |
-LL |         ref _a => {}
-   |         ^^^^^^
-
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
   --> $DIR/empty-types.rs:487:11
    |
@@ -595,8 +518,9 @@ note: `Result<!, !>` defined here
    = note: the matched value is of type `Result<!, !>`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |         Ok(_) => {}, Err(_) => todo!()
-   |                    +++++++++++++++++++
+LL ~         Ok(_) => {},
+LL +         Err(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   --> $DIR/empty-types.rs:546:11
@@ -612,8 +536,9 @@ note: `Result<!, !>` defined here
    = note: the matched value is of type `Result<!, !>`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |         Ok(_a) => {}, Err(_) => todo!()
-   |                     +++++++++++++++++++
+LL ~         Ok(_a) => {},
+LL +         Err(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
   --> $DIR/empty-types.rs:565:11
@@ -653,36 +578,6 @@ error: unreachable pattern
 LL |         _x if false => {}
    |         ^^
 
-error: unreachable pattern
-  --> $DIR/empty-types.rs:613:9
-   |
-LL |         _ if false => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:615:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:622:9
-   |
-LL |         _a if false => {}
-   |         ^^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:624:9
-   |
-LL |         _ => {}
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/empty-types.rs:629:9
-   |
-LL |         _a if false => {}
-   |         ^^
-
 error[E0004]: non-exhaustive patterns: `&_` not covered
   --> $DIR/empty-types.rs:631:11
    |
@@ -694,8 +589,9 @@ LL |     match ref_never {
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |         &_a if false => {}, &_ => todo!()
-   |                           +++++++++++++++
+LL ~         &_a if false => {},
+LL +         &_ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
   --> $DIR/empty-types.rs:659:11
@@ -715,7 +611,7 @@ LL ~         None => {},
 LL +         Some(_) => todo!()
    |
 
-error: aborting due to 66 previous errors
+error: aborting due to 48 previous errors
 
 Some errors have detailed explanations: E0004, E0005.
 For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-types.rs b/tests/ui/pattern/usefulness/empty-types.rs
index fc422298a31..1e1d23e446d 100644
--- a/tests/ui/pattern/usefulness/empty-types.rs
+++ b/tests/ui/pattern/usefulness/empty-types.rs
@@ -59,7 +59,7 @@ fn basic(x: NeverBundle) {
     }
     match ref_never {
         // useful, reachable
-        &_ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &_ => {}
     }
 
     let tuple_half_never: (u32, !) = x.tuple_half_never;
@@ -155,7 +155,7 @@ fn void_same_as_never(x: NeverBundle) {
         let ref_void: &Void = &x.void;
         match *ref_void {}
         match *ref_void {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
         let ref_opt_void: &Option<Void> = &None;
         match *ref_opt_void {
@@ -164,25 +164,25 @@ fn void_same_as_never(x: NeverBundle) {
         }
         match *ref_opt_void {
             None => {}
-            Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+            Some(_) => {}
         }
         match *ref_opt_void {
             None => {}
-            _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+            _ => {}
         }
         match *ref_opt_void {
             None => {}
-            _a => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+            _a => {}
         }
         let union_void = Uninit::<Void>::new();
         match union_void.value {}
         match union_void.value {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
         let ptr_void: *const Void = std::ptr::null();
         match *ptr_void {}
         match *ptr_void {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
     }
 }
@@ -231,41 +231,41 @@ fn invalid_scrutinees(x: NeverBundle) {
         // A pointer may point to a place with an invalid value.
         match *ptr_never {}
         match *ptr_never {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
         // A reference may point to a place with an invalid value.
         match *ref_never {}
         match *ref_never {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
         // This field access is a dereference.
         let ref_x: &NeverBundle = &x;
         match ref_x.never {}
         match ref_x.never {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
         // This nested field access is a dereference.
         let nested_ref_x: &NestedNeverBundle = &nested_x;
         match nested_ref_x.0.never {}
         match nested_ref_x.0.never {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
         // A cast does not load.
         match (*ptr_never as Void) {}
         match (*ptr_never as Void) {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
         // A union field may contain invalid data.
         let union_never = Uninit::<!>::new();
         match union_never.value {}
         match union_never.value {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
         // Indexing is like a field access. This one accesses behind a reference.
         let slice_never: &[!] = &[];
         match slice_never[0] {}
         match slice_never[0] {
-            _ => {} //~ ERROR unreachable pattern
+            _ => {}
         }
     }
 }
@@ -293,10 +293,10 @@ fn nested_validity_tracking(bundle: NeverBundle) {
 
     // These should be considered !known_valid and not warn unreachable.
     match ref_never {
-        &_ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &_ => {}
     }
     match union_never {
-        Uninit { value: _ } => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Uninit { value: _ } => {}
     }
 }
 
@@ -328,21 +328,21 @@ fn arrays_and_slices(x: NeverBundle) {
     }
     match slice_never {
         [] => {}
-        [_] => {}        //[exhaustive_patterns]~ ERROR unreachable pattern
-        [_, _, ..] => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        [_] => {}
+        [_, _, ..] => {}
     }
     match slice_never {
         //[normal]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered
         //[exhaustive_patterns]~^^ ERROR `&[]` not covered
-        [_, _, _, ..] => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        [_, _, _, ..] => {}
     }
     match slice_never {
         [] => {}
-        _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _ => {}
     }
     match slice_never {
         [] => {}
-        _x => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _x => {}
     }
     match slice_never {
         //[normal]~^ ERROR `&[]` and `&[_, ..]` not covered
@@ -372,11 +372,11 @@ fn arrays_and_slices(x: NeverBundle) {
     let ref_array_3_never: &[!; 3] = &array_3_never;
     match ref_array_3_never {
         // useful, reachable
-        &[_, _, _] => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &[_, _, _] => {}
     }
     match ref_array_3_never {
         // useful, !reachable
-        &[_x, _, _] => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &[_x, _, _] => {}
     }
 
     let array_0_never: [!; 0] = [];
@@ -433,7 +433,7 @@ fn bindings(x: NeverBundle) {
     }
     match ref_never {
         // useful, reachable
-        &_ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &_ => {}
     }
     match ref_never {
         // useful, reachable
@@ -441,7 +441,7 @@ fn bindings(x: NeverBundle) {
     }
     match ref_never {
         // useful, !reachable
-        &_a => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &_a => {}
     }
     match ref_opt_never {
         //[normal]~^ ERROR non-exhaustive
@@ -450,39 +450,39 @@ fn bindings(x: NeverBundle) {
     match ref_opt_never {
         &None => {}
         // useful, reachable
-        _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _ => {}
     }
     match ref_opt_never {
         &None => {}
         // useful, reachable
-        _a => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _a => {}
     }
     match ref_opt_never {
         &None => {}
         // useful, reachable
-        &_ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &_ => {}
     }
     match ref_opt_never {
         &None => {}
         // useful, !reachable
-        &_a => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &_a => {}
     }
 
     // On a !known_valid place.
     match *ref_never {}
     match *ref_never {
         // useful, reachable
-        _ => {} //~ ERROR unreachable pattern
+        _ => {}
     }
     match *ref_never {
         // useful, !reachable
-        _a => {} //~ ERROR unreachable pattern
+        _a => {}
     }
     // This is equivalent to `match ref_never { _a => {} }`. In other words, it asserts validity of
     // `ref_never` but says nothing of the data at `*ref_never`.
     match *ref_never {
         // useful, reachable
-        ref _a => {} //~ ERROR unreachable pattern
+        ref _a => {}
     }
     match *ref_opt_never {
         //[normal]~^ ERROR non-exhaustive
@@ -491,74 +491,74 @@ fn bindings(x: NeverBundle) {
     match *ref_opt_never {
         None => {}
         // useful, reachable
-        Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Some(_) => {}
     }
     match *ref_opt_never {
         None => {}
         // useful, !reachable
-        Some(_a) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Some(_a) => {}
     }
     match *ref_opt_never {
         None => {}
         // useful, reachable
-        _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _ => {}
     }
     match *ref_opt_never {
         None => {}
         // useful, !reachable
-        _a => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _a => {}
     }
     match *ref_opt_never {
         None => {}
         // useful, !reachable
-        _a @ Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _a @ Some(_) => {}
     }
     // This is equivalent to `match ref_opt_never { None => {}, _a => {} }`. In other words, it
     // asserts validity of `ref_opt_never` but says nothing of the data at `*ref_opt_never`.
     match *ref_opt_never {
         None => {}
         // useful, reachable
-        ref _a => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        ref _a => {}
     }
     match *ref_opt_never {
         None => {}
         // useful, reachable
-        ref _a @ Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        ref _a @ Some(_) => {}
     }
     match *ref_opt_never {
         None => {}
         // useful, !reachable
-        ref _a @ Some(_b) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        ref _a @ Some(_b) => {}
     }
 
     let ref_res_never: &Result<!, !> = &x.result_never;
     match *ref_res_never {
         //[normal]~^ ERROR non-exhaustive
         // useful, reachable
-        Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Ok(_) => {}
     }
     match *ref_res_never {
         // useful, reachable
-        Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Ok(_) => {}
         // useful, reachable
-        _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _ => {}
     }
     match *ref_res_never {
         //[normal]~^ ERROR non-exhaustive
         // useful, !reachable
-        Ok(_a) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Ok(_a) => {}
     }
     match *ref_res_never {
         // useful, !reachable
-        Ok(_a) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Ok(_a) => {}
         // useful, reachable
-        _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        _ => {}
     }
     match *ref_res_never {
         // useful, !reachable
-        Ok(_a) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Ok(_a) => {}
         // useful, reachable
-        Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Err(_) => {}
     }
 
     let ref_tuple_half_never: &(u32, !) = &x.tuple_half_never;
@@ -566,21 +566,21 @@ fn bindings(x: NeverBundle) {
     //[normal]~^ ERROR non-empty
     match *ref_tuple_half_never {
         // useful, reachable
-        (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        (_, _) => {}
     }
     match *ref_tuple_half_never {
         // useful, reachable
-        (_x, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        (_x, _) => {}
     }
     match *ref_tuple_half_never {
         // useful, !reachable
-        (_, _x) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        (_, _x) => {}
     }
     match *ref_tuple_half_never {
         // useful, !reachable
-        (0, _x) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        (0, _x) => {}
         // useful, reachable
-        (1.., _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        (1.., _) => {}
     }
 }
 
@@ -610,46 +610,46 @@ fn guards_and_validity(x: NeverBundle) {
     // If the pattern under the guard doesn't load, all is normal.
     match *ref_never {
         // useful, reachable
-        _ if false => {} //~ ERROR unreachable pattern
+        _ if false => {}
         // useful, reachable
-        _ => {} //~ ERROR unreachable pattern
+        _ => {}
     }
     // Now the madness commences. The guard caused a load of the value thus asserting validity. So
     // there's no invalid value for `_` to catch. So the second pattern is unreachable despite the
     // guard not being taken.
     match *ref_never {
         // useful, !reachable
-        _a if false => {} //~ ERROR unreachable pattern
+        _a if false => {}
         // !useful, !reachable
-        _ => {} //~ ERROR unreachable pattern
+        _ => {}
     }
     // The above still applies to the implicit `_` pattern used for exhaustiveness.
     match *ref_never {
         // useful, !reachable
-        _a if false => {} //~ ERROR unreachable pattern
+        _a if false => {}
     }
     match ref_never {
         //[normal]~^ ERROR non-exhaustive
         // useful, !reachable
-        &_a if false => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        &_a if false => {}
     }
 
     // Same but with subpatterns.
     let ref_result_never: &Result<!, !> = &x.result_never;
     match *ref_result_never {
         // useful, !reachable
-        Ok(_x) if false => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Ok(_x) if false => {}
         // !useful, !reachable
-        Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Ok(_) => {}
         // useful, !reachable
-        Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        Err(_) => {}
     }
     let ref_tuple_never: &(!, !) = &x.tuple_never;
     match *ref_tuple_never {
         // useful, !reachable
-        (_, _x) if false => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        (_, _x) if false => {}
         // !useful, !reachable
-        (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern
+        (_, _) => {}
     }
 }
 
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.rs b/tests/ui/pattern/usefulness/slice_of_empty.rs
index fe068871195..3cbd0eba57f 100644
--- a/tests/ui/pattern/usefulness/slice_of_empty.rs
+++ b/tests/ui/pattern/usefulness/slice_of_empty.rs
@@ -11,12 +11,12 @@ fn foo(nevers: &[!]) {
 
     match nevers {
         &[] => (),
-        &[_] => (),        //~ ERROR unreachable pattern
-        &[_, _, ..] => (), //~ ERROR unreachable pattern
+        &[_] => (),
+        &[_, _, ..] => (),
     };
 
     match nevers {
         //~^ ERROR non-exhaustive patterns: `&[]` not covered
-        &[_] => (), //~ ERROR unreachable pattern
+        &[_] => (),
     };
 }
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.stderr b/tests/ui/pattern/usefulness/slice_of_empty.stderr
index 07bb6b3a67d..d56360d4cec 100644
--- a/tests/ui/pattern/usefulness/slice_of_empty.stderr
+++ b/tests/ui/pattern/usefulness/slice_of_empty.stderr
@@ -1,27 +1,3 @@
-error: unreachable pattern
-  --> $DIR/slice_of_empty.rs:14:9
-   |
-LL |         &[_] => (),
-   |         ^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/slice_of_empty.rs:3:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/slice_of_empty.rs:15:9
-   |
-LL |         &[_, _, ..] => (),
-   |         ^^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/slice_of_empty.rs:20:9
-   |
-LL |         &[_] => (),
-   |         ^^^^
-
 error[E0004]: non-exhaustive patterns: `&[]` not covered
   --> $DIR/slice_of_empty.rs:18:11
    |
@@ -31,9 +7,10 @@ LL |     match nevers {
    = note: the matched value is of type `&[!]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |         &[_] => (), &[] => todo!(),
-   |                   ++++++++++++++++
+LL ~         &[_] => (),
+LL ~         &[] => todo!(),
+   |
 
-error: aborting due to 4 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/uninhabited/uninhabited-patterns.rs b/tests/ui/uninhabited/uninhabited-patterns.rs
index 43b19e790e2..4e90691e5c8 100644
--- a/tests/ui/uninhabited/uninhabited-patterns.rs
+++ b/tests/ui/uninhabited/uninhabited-patterns.rs
@@ -22,14 +22,14 @@ fn main() {
 
     match x {
         &[] => (),
-        &[..] => (), //~ ERROR unreachable pattern
+        &[..] => (),
     };
 
     let x: Result<Box<NotSoSecretlyEmpty>, &[Result<!, !>]> = Err(&[]);
     match x {
         Ok(box _) => (), //~ ERROR unreachable pattern
         Err(&[]) => (),
-        Err(&[..]) => (), //~ ERROR unreachable pattern
+        Err(&[..]) => (),
     }
 
     let x: Result<foo::SecretlyEmpty, Result<NotSoSecretlyEmpty, u32>> = Err(Err(123));
diff --git a/tests/ui/uninhabited/uninhabited-patterns.stderr b/tests/ui/uninhabited/uninhabited-patterns.stderr
index 19f34a52bdb..a6fda88f032 100644
--- a/tests/ui/uninhabited/uninhabited-patterns.stderr
+++ b/tests/ui/uninhabited/uninhabited-patterns.stderr
@@ -1,8 +1,8 @@
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:25:9
+  --> $DIR/uninhabited-patterns.rs:30:9
    |
-LL |         &[..] => (),
-   |         ^^^^^
+LL |         Ok(box _) => (),
+   |         ^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/uninhabited-patterns.rs:4:9
@@ -11,18 +11,6 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:30:9
-   |
-LL |         Ok(box _) => (),
-   |         ^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:32:9
-   |
-LL |         Err(&[..]) => (),
-   |         ^^^^^^^^^^
-
-error: unreachable pattern
   --> $DIR/uninhabited-patterns.rs:39:9
    |
 LL |         Err(Ok(_y)) => (),
@@ -34,5 +22,5 @@ error: unreachable pattern
 LL |     while let Some(_y) = foo() {
    |               ^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors