about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-11-26 00:14:14 +0000
committerbors <bors@rust-lang.org>2023-11-26 00:14:14 +0000
commitee80c8d0a8bc63b69f68216c5d37f9ab837eedd0 (patch)
treefc3220f40b1319bb8b71a79027c2d19bf7d6fc72 /tests
parentf5dc2653fdd8b5d177b2ccbd84057954340a89fc (diff)
parent273cbb73047436927a680da5d1636d87be9aafe3 (diff)
downloadrust-ee80c8d0a8bc63b69f68216c5d37f9ab837eedd0.tar.gz
rust-ee80c8d0a8bc63b69f68216c5d37f9ab837eedd0.zip
Auto merge of #117611 - Nadrieril:linear-pass-take-4, r=cjgillot
Rewrite exhaustiveness in one pass

This is at least my 4th attempt at this in as many years x) Previous attempts were all too complicated or too slow. But we're finally here!

The previous version of the exhaustiveness algorithm computed reachability for each arm then exhaustiveness of the whole match. Since each of these steps does roughly the same things, this rewrites the algorithm to do them all in one go. I also think this makes things much simpler.

I also rewrote the documentation of the algorithm in depth. Hopefully it's up-to-date and easier to follow now. Plz comment if anything's unclear.

r? `@oli-obk` I think you're one of the rare other people to understand the exhaustiveness algorithm?

cc `@varkor` I know you're not active anymore, but if you feel like having a look you might enjoy this :D

Fixes https://github.com/rust-lang/rust/issues/79307
Diffstat (limited to 'tests')
-rw-r--r--tests/ui/or-patterns/exhaustiveness-pass.rs11
-rw-r--r--tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs10
-rw-r--r--tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr72
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr2
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr51
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs33
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/reachability.rs5
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/reachability.stderr56
-rw-r--r--tests/ui/pattern/usefulness/issue-3601.rs2
-rw-r--r--tests/ui/pattern/usefulness/issue-3601.stderr6
-rw-r--r--tests/ui/pattern/usefulness/match-non-exhaustive.stderr10
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs4
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr42
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs77
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr138
15 files changed, 281 insertions, 238 deletions
diff --git a/tests/ui/or-patterns/exhaustiveness-pass.rs b/tests/ui/or-patterns/exhaustiveness-pass.rs
index 428b9a19fe6..a52e08c507d 100644
--- a/tests/ui/or-patterns/exhaustiveness-pass.rs
+++ b/tests/ui/or-patterns/exhaustiveness-pass.rs
@@ -35,6 +35,17 @@ fn main() {
         ((0, 0) | (1, 0),) => {}
         _ => {}
     }
+    match ((0, 0),) {
+        // Note how the second one would be redundant without the guard.
+        ((x, y) | (y, x),) if x == 0 => {}
+        _ => {}
+    }
+    match 0 {
+        // We don't warn the second one as redundant in general because of cases like the one above.
+        // We could technically do it if there are no bindings.
+        0 | 0 if 0 == 0 => {}
+        _ => {}
+    }
 
     // This one caused ICE https://github.com/rust-lang/rust/issues/117378
     match (0u8, 0) {
diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
index 8429799cabf..20a8d754996 100644
--- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
+++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
@@ -1,6 +1,7 @@
 #![deny(unreachable_patterns)]
 
 // We wrap patterns in a tuple because top-level or-patterns were special-cased.
+#[rustfmt::skip]
 fn main() {
     match (0u8,) {
         (1 | 2,) => {}
@@ -73,6 +74,11 @@ fn main() {
             | 0] => {} //~ ERROR unreachable
         _ => {}
     }
+    match (true, 0) {
+        (true, 0 | 0) => {} //~ ERROR unreachable
+        (_, 0 | 0) => {} //~ ERROR unreachable
+        _ => {}
+    }
     match &[][..] {
         [0] => {}
         [0, _] => {}
@@ -149,4 +155,8 @@ fn main() {
             | true, //~ ERROR unreachable
             false | true) => {}
     }
+    match (true, true) {
+        (x, y)
+            | (y, x) => {} //~ ERROR unreachable
+    }
 }
diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
index 3f7d47dcb8c..3616dda9981 100644
--- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
+++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:7:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:8:9
    |
 LL |         (1,) => {}
    |         ^^^^
@@ -11,128 +11,140 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:12:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:13:9
    |
 LL |         (2,) => {}
    |         ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:18:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:19:9
    |
 LL |         (1 | 2,) => {}
    |         ^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:23:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
    |
 LL |         (1, 3) => {}
    |         ^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
    |
 LL |         (1, 4) => {}
    |         ^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
    |
 LL |         (2, 4) => {}
    |         ^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
    |
 LL |         (2 | 1, 4) => {}
    |         ^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:28:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:29:9
    |
 LL |         (1, 4 | 5) => {}
    |         ^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:36:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
    |
 LL |         (Some(1),) => {}
    |         ^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:38:9
    |
 LL |         (None,) => {}
    |         ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
    |
 LL |         ((1..=4,),) => {}
    |         ^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:47:14
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:48:14
    |
 LL |         (1 | 1,) => {}
    |              ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:51:19
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:52:19
    |
 LL |         (0 | 1) | 1 => {}
    |                   ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:57:14
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
    |
 LL |         0 | (0 | 0) => {}
    |              ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:57:18
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:58:18
    |
 LL |         0 | (0 | 0) => {}
    |                  ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:65:13
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:66:13
    |
 LL | /             Some(
 LL | |                 0 | 0) => {}
    | |______________________^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:71:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
    |
 LL |             | 0
    |               ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:73:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
    |
 LL |             | 0] => {}
    |               ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:81:10
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:78:20
+   |
+LL |         (true, 0 | 0) => {}
+   |                    ^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:79:17
+   |
+LL |         (_, 0 | 0) => {}
+   |                 ^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:87:10
    |
 LL |         [1
    |          ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:93:10
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:99:10
    |
 LL |         [true
    |          ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:100:36
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:106:36
    |
 LL |         (true | false, None | Some(true
    |                                    ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:105:14
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:111:14
    |
 LL |             (true
    |              ^^^^
@@ -143,28 +155,34 @@ LL |         (true | false, None | Some(t_or_f!())) => {}
    = note: this error originates in the macro `t_or_f` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:116:14
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:122:14
    |
 LL |         Some(0
    |              ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:135:19
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:141:19
    |
 LL |                 | false) => {}
    |                   ^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:143:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
    |
 LL |             | true) => {}
    |               ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:155:15
    |
 LL |             | true,
    |               ^^^^
 
-error: aborting due to 26 previous errors
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:160:15
+   |
+LL |             | (y, x) => {}
+   |               ^^^^^^
+
+error: aborting due to 29 previous errors
 
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
index 9e35960bcda..ebbbccc5d58 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/pointer-sized-int.rs:54:11
+  --> $DIR/pointer-sized-int.rs:59:11
    |
 LL |     match 7usize {}
    |           ^^^^^^
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
index d16ec5412db..2949081039a 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
@@ -9,7 +9,7 @@ LL |     match 0usize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 ~         0 ..= usize::MAX => {},
+LL ~         0..=usize::MAX => {},
 LL +         usize::MAX.. => todo!()
    |
 
@@ -24,12 +24,12 @@ LL |     match 0isize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 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 ~         isize::MIN ..= isize::MAX => {},
+LL ~         isize::MIN..=isize::MAX => {},
 LL +         ..isize::MIN | isize::MAX.. => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
-  --> $DIR/pointer-sized-int.rs:25:8
+  --> $DIR/pointer-sized-int.rs:24:8
    |
 LL |     m!(0usize, 0..=usize::MAX);
    |        ^^^^^^ pattern `usize::MAX..` not covered
@@ -43,7 +43,7 @@ LL |         match $s { $($t)+ => {}, usize::MAX.. => todo!() }
    |                                +++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
-  --> $DIR/pointer-sized-int.rs:27:8
+  --> $DIR/pointer-sized-int.rs:26:8
    |
 LL |     m!(0usize, 0..5 | 5..=usize::MAX);
    |        ^^^^^^ pattern `usize::MAX..` not covered
@@ -57,7 +57,7 @@ LL |         match $s { $($t)+ => {}, usize::MAX.. => todo!() }
    |                                +++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
-  --> $DIR/pointer-sized-int.rs:29:8
+  --> $DIR/pointer-sized-int.rs:28:8
    |
 LL |     m!(0usize, 0..usize::MAX | usize::MAX);
    |        ^^^^^^ pattern `usize::MAX..` not covered
@@ -71,7 +71,7 @@ LL |         match $s { $($t)+ => {}, usize::MAX.. => todo!() }
    |                                +++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `(usize::MAX.., _)` not covered
-  --> $DIR/pointer-sized-int.rs:31:8
+  --> $DIR/pointer-sized-int.rs:30:8
    |
 LL |     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
    |        ^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered
@@ -85,7 +85,7 @@ LL |         match $s { $($t)+ => {}, (usize::MAX.., _) => todo!() }
    |                                ++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
-  --> $DIR/pointer-sized-int.rs:36:8
+  --> $DIR/pointer-sized-int.rs:39:8
    |
 LL |     m!(0isize, isize::MIN..=isize::MAX);
    |        ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
@@ -99,7 +99,7 @@ LL |         match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
    |                                ++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
-  --> $DIR/pointer-sized-int.rs:38:8
+  --> $DIR/pointer-sized-int.rs:41:8
    |
 LL |     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
    |        ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
@@ -113,9 +113,9 @@ LL |         match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
    |                                ++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
-  --> $DIR/pointer-sized-int.rs:40:8
+  --> $DIR/pointer-sized-int.rs:43:8
    |
-LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+LL |     m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX);
    |        ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
    = note: the matched value is of type `isize`
@@ -126,37 +126,36 @@ help: ensure that all possible cases are being handled by adding a match arm wit
 LL |         match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
    |                                ++++++++++++++++++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
-  --> $DIR/pointer-sized-int.rs:42:8
+error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
+  --> $DIR/pointer-sized-int.rs:45:8
    |
-LL |     m!((0isize, true), (isize::MIN..5, true)
-   |        ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
+LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+   |        ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
-   = note: the matched value is of type `(isize, bool)`
+   = note: the matched value is of type `isize`
    = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 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 |         match $s { $($t)+ => {}, (..isize::MIN, _) | (isize::MAX.., _) => todo!() }
-   |                                ++++++++++++++++++++++++++++++++++++++++++++++++++
+LL |         match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
-  --> $DIR/pointer-sized-int.rs:47:11
+error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
+  --> $DIR/pointer-sized-int.rs:48:9
    |
-LL |     match 0isize {
-   |           ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
+LL |         (0isize, true),
+   |         ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
    |
-   = note: the matched value is of type `isize`
+   = note: the matched value is of type `(isize, bool)`
    = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 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 ~         1 ..= isize::MAX => {},
-LL +         ..isize::MIN | isize::MAX.. => todo!()
-   |
+LL |         match $s { $($t)+ => {}, (..isize::MIN, _) | (isize::MAX.., _) => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/pointer-sized-int.rs:54:11
+  --> $DIR/pointer-sized-int.rs:59:11
    |
 LL |     match 7usize {}
    |           ^^^^^^
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
index 20a3cbe127f..cf137dca5aa 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
@@ -13,15 +13,14 @@ macro_rules! m {
 fn main() {
     match 0usize {
         //[deny]~^ ERROR non-exhaustive patterns
-        0 ..= usize::MAX => {}
+        0..=usize::MAX => {}
     }
 
     match 0isize {
         //[deny]~^ ERROR non-exhaustive patterns
-        isize::MIN ..= isize::MAX => {}
+        isize::MIN..=isize::MAX => {}
     }
 
-    m!(0usize, 0..);
     m!(0usize, 0..=usize::MAX);
     //[deny]~^ ERROR non-exhaustive patterns
     m!(0usize, 0..5 | 5..=usize::MAX);
@@ -30,26 +29,32 @@ fn main() {
     //[deny]~^ ERROR non-exhaustive patterns
     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
     //[deny]~^ ERROR non-exhaustive patterns
+
+    m!(0usize, 0..);
+    m!(0usize, 0..5 | 5..);
+    m!(0usize, ..5 | 5..);
+    m!((0usize, true), (0..5, true) | (5.., true) | (0.., false));
     m!(0usize, 0..=usize::MAX | usize::MAX..);
 
-    m!(0isize, ..0 | 0..);
     m!(0isize, isize::MIN..=isize::MAX);
     //[deny]~^ ERROR non-exhaustive patterns
     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
     //[deny]~^ ERROR non-exhaustive patterns
+    m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
     //[deny]~^ ERROR non-exhaustive patterns
-    m!((0isize, true), (isize::MIN..5, true)
-        | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
-    //[deny]~^^ ERROR non-exhaustive patterns
-    m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..);
+    m!(
+        (0isize, true),
+        (isize::MIN..5, true) | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false)
+    );
+    //[deny]~^^^ ERROR non-exhaustive patterns
 
-    match 0isize {
-        //[deny]~^ ERROR non-exhaustive patterns
-        isize::MIN ..= -1 => {}
-        0 => {}
-        1 ..= isize::MAX => {}
-    }
+    m!(0isize, ..0 | 0..);
+    m!(0isize, ..5 | 5..);
+    m!((0isize, true), (..5, true)
+        | (5.., true) | (..0 | 0.., false));
+    m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..);
 
     match 7usize {}
     //~^ ERROR non-exhaustive patterns
diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.rs b/tests/ui/pattern/usefulness/integer-ranges/reachability.rs
index fb4d59b0578..247fdd91572 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/reachability.rs
+++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.rs
@@ -9,9 +9,10 @@ macro_rules! m {
             $t2 => {}
             _ => {}
         }
-    }
+    };
 }
 
+#[rustfmt::skip]
 fn main() {
     m!(0u8, 42, 41);
     m!(0u8, 42, 42); //~ ERROR unreachable pattern
@@ -85,7 +86,7 @@ fn main() {
     match 'a' {
         '\u{0}'..='\u{D7FF}' => {},
         '\u{E000}'..='\u{10_FFFF}' => {},
-        '\u{D7FF}'..='\u{E000}' => {}, // FIXME should be unreachable
+        '\u{D7FF}'..='\u{E000}' => {}, //~ ERROR unreachable pattern
     }
 
     match (0u8, true) {
diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr
index 0ffb0ffd82a..c5b028d2038 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/reachability.rs:17:17
+  --> $DIR/reachability.rs:18:17
    |
 LL |     m!(0u8, 42, 42);
    |                 ^^
@@ -11,127 +11,127 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:21:22
+  --> $DIR/reachability.rs:22:22
    |
 LL |     m!(0u8, 20..=30, 20);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:22:22
+  --> $DIR/reachability.rs:23:22
    |
 LL |     m!(0u8, 20..=30, 21);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:23:22
+  --> $DIR/reachability.rs:24:22
    |
 LL |     m!(0u8, 20..=30, 25);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:24:22
+  --> $DIR/reachability.rs:25:22
    |
 LL |     m!(0u8, 20..=30, 29);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:25:22
+  --> $DIR/reachability.rs:26:22
    |
 LL |     m!(0u8, 20..=30, 30);
    |                      ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:28:21
+  --> $DIR/reachability.rs:29:21
    |
 LL |     m!(0u8, 20..30, 20);
    |                     ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:29:21
+  --> $DIR/reachability.rs:30:21
    |
 LL |     m!(0u8, 20..30, 21);
    |                     ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:30:21
+  --> $DIR/reachability.rs:31:21
    |
 LL |     m!(0u8, 20..30, 25);
    |                     ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:31:21
+  --> $DIR/reachability.rs:32:21
    |
 LL |     m!(0u8, 20..30, 29);
    |                     ^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:35:22
+  --> $DIR/reachability.rs:36:22
    |
 LL |     m!(0u8, 20..=30, 20..=30);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:36:22
+  --> $DIR/reachability.rs:37:22
    |
 LL |     m!(0u8, 20.. 30, 20.. 30);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:37:22
+  --> $DIR/reachability.rs:38:22
    |
 LL |     m!(0u8, 20..=30, 20.. 30);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:39:22
+  --> $DIR/reachability.rs:40:22
    |
 LL |     m!(0u8, 20..=30, 21..=30);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:40:22
+  --> $DIR/reachability.rs:41:22
    |
 LL |     m!(0u8, 20..=30, 20..=29);
    |                      ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:42:24
+  --> $DIR/reachability.rs:43:24
    |
 LL |     m!('a', 'A'..='z', 'a'..='z');
    |                        ^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:49:9
+  --> $DIR/reachability.rs:50:9
    |
 LL |         5..=8 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:55:9
+  --> $DIR/reachability.rs:56:9
    |
 LL |         5..15 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:62:9
+  --> $DIR/reachability.rs:63:9
    |
 LL |         5..25 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:70:9
+  --> $DIR/reachability.rs:71:9
    |
 LL |         5..25 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:76:9
+  --> $DIR/reachability.rs:77:9
    |
 LL |         5..15 => {},
    |         ^^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:83:9
+  --> $DIR/reachability.rs:84:9
    |
 LL |         _ => {},
    |         - matches any value
@@ -139,16 +139,22 @@ LL |         '\u{D7FF}'..='\u{E000}' => {},
    |         ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:104:9
+  --> $DIR/reachability.rs:89:9
+   |
+LL |         '\u{D7FF}'..='\u{E000}' => {},
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/reachability.rs:105:9
    |
 LL |         &FOO => {}
    |         ^^^^
 
 error: unreachable pattern
-  --> $DIR/reachability.rs:105:9
+  --> $DIR/reachability.rs:106:9
    |
 LL |         BAR => {}
    |         ^^^
 
-error: aborting due to 24 previous errors
+error: aborting due to 25 previous errors
 
diff --git a/tests/ui/pattern/usefulness/issue-3601.rs b/tests/ui/pattern/usefulness/issue-3601.rs
index a6d2b11f4ee..868e8c71027 100644
--- a/tests/ui/pattern/usefulness/issue-3601.rs
+++ b/tests/ui/pattern/usefulness/issue-3601.rs
@@ -31,7 +31,7 @@ fn main() {
             //~^ ERROR non-exhaustive patterns
             //~| NOTE the matched value is of type
             //~| NOTE match arms with guards don't count towards exhaustivity
-            //~| NOTE pattern `box _` not covered
+            //~| NOTE pattern `box ElementKind::HTMLImageElement(_)` not covered
             //~| NOTE `Box<ElementKind>` defined here
             box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => true,
         },
diff --git a/tests/ui/pattern/usefulness/issue-3601.stderr b/tests/ui/pattern/usefulness/issue-3601.stderr
index ce18b736c10..a3fcaa79b06 100644
--- a/tests/ui/pattern/usefulness/issue-3601.stderr
+++ b/tests/ui/pattern/usefulness/issue-3601.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `box _` not covered
+error[E0004]: non-exhaustive patterns: `box ElementKind::HTMLImageElement(_)` not covered
   --> $DIR/issue-3601.rs:30:44
    |
 LL |         box NodeKind::Element(ed) => match ed.kind {
-   |                                            ^^^^^^^ pattern `box _` not covered
+   |                                            ^^^^^^^ pattern `box ElementKind::HTMLImageElement(_)` not covered
    |
 note: `Box<ElementKind>` defined here
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
@@ -11,7 +11,7 @@ note: `Box<ElementKind>` defined here
 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 ~             box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => true,
-LL ~             box _ => todo!(),
+LL ~             box ElementKind::HTMLImageElement(_) => todo!(),
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr
index 4fa3a729212..1a0cc58f35d 100644
--- a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr
+++ b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr
@@ -10,18 +10,18 @@ help: ensure that all possible cases are being handled by adding a match arm wit
 LL |     match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() }
    |                      ++++++++++++++++++++++++++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/match-non-exhaustive.rs:3:11
    |
 LL |     match 0 { 0 if false => () }
-   |           ^ pattern `_` not covered
+   |           ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
    |
    = note: the matched value is of type `i32`
    = 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
+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 |     match 0 { 0 if false => (), _ => todo!() }
-   |                               ++++++++++++++
+LL |     match 0 { 0 if false => (), i32::MIN..=-1_i32 | 1_i32..=i32::MAX => todo!() }
+   |                               +++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs
index 46e0da5be9b..97ded70fc92 100644
--- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs
+++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs
@@ -44,6 +44,10 @@ fn main() {
         [] => {}
     }
     match s {
+        //~^ ERROR `&[]` and `&[_, ..]` not covered
+        [..] if false => {}
+    }
+    match s {
         //~^ ERROR `&[_, _, ..]` not covered
         [] => {}
         [_] => {}
diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
index fb6ecda3c4d..a8786d02414 100644
--- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
+++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
@@ -89,10 +89,24 @@ LL ~         [] => {},
 LL +         &[_, ..] => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
+error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:46:11
    |
 LL |     match s {
+   |           ^ patterns `&[]` and `&[_, ..]` not covered
+   |
+   = note: the matched value is of type `&[bool]`
+   = 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, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         [..] if false => {},
+LL +         &[] | &[_, ..] => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:50:11
+   |
+LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
    |
    = note: the matched value is of type `&[bool]`
@@ -103,7 +117,7 @@ LL +         &[_, _, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:51:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:55:11
    |
 LL |     match s {
    |           ^ pattern `&[false, ..]` not covered
@@ -116,7 +130,7 @@ LL +         &[false, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:56:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:60:11
    |
 LL |     match s {
    |           ^ pattern `&[false, _, ..]` not covered
@@ -129,7 +143,7 @@ LL +         &[false, _, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:62:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:66:11
    |
 LL |     match s {
    |           ^ pattern `&[_, .., false]` not covered
@@ -142,7 +156,7 @@ LL +         &[_, .., false] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:69:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:73:11
    |
 LL |     match s {
    |           ^ pattern `&[_, _, .., true]` not covered
@@ -155,7 +169,7 @@ LL +         &[_, _, .., true] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:76:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:80:11
    |
 LL |     match s {
    |           ^ pattern `&[true, _, .., _]` not covered
@@ -168,7 +182,7 @@ LL +         &[true, _, .., _] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:85:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:89:11
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
@@ -181,7 +195,7 @@ LL +         &[] | &[_, _, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:89:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:93:11
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
@@ -194,7 +208,7 @@ LL +         &[] | &[_, _, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:93:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:97:11
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
@@ -207,7 +221,7 @@ LL +         &[] | &[_, _, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:98:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:102:11
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
@@ -220,7 +234,7 @@ LL +         &[] | &[_, _, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:103:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:107:11
    |
 LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
@@ -233,7 +247,7 @@ LL +         &[_, _, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[false]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:108:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:112:11
    |
 LL |     match s {
    |           ^ pattern `&[false]` not covered
@@ -246,7 +260,7 @@ LL +         &[false] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[false]` not covered
-  --> $DIR/slice-patterns-exhaustiveness.rs:121:11
+  --> $DIR/slice-patterns-exhaustiveness.rs:125:11
    |
 LL |     match s1 {
    |           ^^ pattern `&[false]` not covered
@@ -258,6 +272,6 @@ LL ~         CONST1 => {},
 LL +         &[false] => todo!()
    |
 
-error: aborting due to 20 previous errors
+error: aborting due to 21 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs
index e0a6051a81f..a6c1dc53f8b 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs
@@ -1,6 +1,7 @@
 // Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly.
 
 #![feature(non_exhaustive_omitted_patterns_lint, unstable_test_feature)]
+#![deny(unreachable_patterns)]
 
 // aux-build:enums.rs
 extern crate enums;
@@ -31,11 +32,21 @@ pub enum Bar {
     C,
 }
 
+fn no_lint() {
+    let non_enum = NonExhaustiveEnum::Unit;
+    // Ok: without the attribute
+    match non_enum {
+        NonExhaustiveEnum::Unit => {}
+        NonExhaustiveEnum::Tuple(_) => {}
+        _ => {}
+    }
+}
+
+#[deny(non_exhaustive_omitted_patterns)]
 fn main() {
     let enumeration = Bar::A;
 
     // Ok: this is a crate local non_exhaustive enum
-    #[deny(non_exhaustive_omitted_patterns)]
     match enumeration {
         Bar::A => {}
         Bar::B => {}
@@ -44,14 +55,13 @@ fn main() {
 
     let non_enum = NonExhaustiveEnum::Unit;
 
-    // Ok: without the attribute
+    #[allow(non_exhaustive_omitted_patterns)]
     match non_enum {
         NonExhaustiveEnum::Unit => {}
         NonExhaustiveEnum::Tuple(_) => {}
         _ => {}
     }
 
-    #[deny(non_exhaustive_omitted_patterns)]
     match non_enum {
         //~^ some variants are not matched explicitly
         NonExhaustiveEnum::Unit => {}
@@ -59,7 +69,6 @@ fn main() {
         _ => {}
     }
 
-    #[deny(non_exhaustive_omitted_patterns)]
     match non_enum {
         //~^ some variants are not matched explicitly
         NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {}
@@ -68,7 +77,6 @@ fn main() {
 
     let x = 5;
     // We ignore the guard.
-    #[deny(non_exhaustive_omitted_patterns)]
     match non_enum {
         NonExhaustiveEnum::Unit if x > 10 => {}
         NonExhaustiveEnum::Tuple(_) => {}
@@ -76,14 +84,12 @@ fn main() {
         _ => {}
     }
 
-    #[deny(non_exhaustive_omitted_patterns)]
     match (non_enum, true) {
         (NonExhaustiveEnum::Unit, true) => {}
         (NonExhaustiveEnum::Tuple(_), false) => {}
         (NonExhaustiveEnum::Struct { .. }, false) => {}
         _ => {}
     }
-    #[deny(non_exhaustive_omitted_patterns)]
     match (non_enum, true) {
         //~^ some variants are not matched explicitly
         (NonExhaustiveEnum::Unit, true) => {}
@@ -91,14 +97,12 @@ fn main() {
         _ => {}
     }
 
-    #[deny(non_exhaustive_omitted_patterns)]
     match (true, non_enum) {
         (true, NonExhaustiveEnum::Unit) => {}
         (false, NonExhaustiveEnum::Tuple(_)) => {}
         (false, NonExhaustiveEnum::Struct { .. }) => {}
         _ => {}
     }
-    #[deny(non_exhaustive_omitted_patterns)]
     match (true, non_enum) {
         //~^ some variants are not matched explicitly
         (true, NonExhaustiveEnum::Unit) => {}
@@ -106,7 +110,6 @@ fn main() {
         _ => {}
     }
 
-    #[deny(non_exhaustive_omitted_patterns)]
     match Some(non_enum) {
         //~^ some variants are not matched explicitly
         Some(NonExhaustiveEnum::Unit) => {}
@@ -116,7 +119,6 @@ fn main() {
 
     // Ok: all covered and not `unreachable-patterns`
     #[deny(unreachable_patterns)]
-    #[deny(non_exhaustive_omitted_patterns)]
     match non_enum {
         NonExhaustiveEnum::Unit => {}
         NonExhaustiveEnum::Tuple(_) => {}
@@ -124,7 +126,6 @@ fn main() {
         _ => {}
     }
 
-    #[deny(non_exhaustive_omitted_patterns)]
     match NestedNonExhaustive::B {
         //~^ some variants are not matched explicitly
         NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {}
@@ -133,54 +134,53 @@ fn main() {
         _ => {}
     }
 
-    #[warn(non_exhaustive_omitted_patterns)]
     match VariantNonExhaustive::Baz(1, 2) {
         VariantNonExhaustive::Baz(_, _) => {}
         VariantNonExhaustive::Bar { x, .. } => {}
     }
     //~^^ some fields are not explicitly listed
 
-    #[warn(non_exhaustive_omitted_patterns)]
     let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default();
     //~^ some fields are not explicitly listed
 
     // Ok: this is local
-    #[warn(non_exhaustive_omitted_patterns)]
     let Foo { a, b, .. } = Foo::default();
 
-    #[warn(non_exhaustive_omitted_patterns)]
     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
     //~^ some fields are not explicitly listed
     //~^^ some fields are not explicitly listed
 
     // Ok: this tests https://github.com/rust-lang/rust/issues/89382
-    #[warn(non_exhaustive_omitted_patterns)]
     let MixedVisFields { a, b, .. } = MixedVisFields::default();
 
     // Ok: this only has 1 variant
-    #[deny(non_exhaustive_omitted_patterns)]
     match NonExhaustiveSingleVariant::A(true) {
         NonExhaustiveSingleVariant::A(true) => {}
         _ => {}
     }
 
     // We can't catch the case below, so for consistency we don't catch this one either.
-    #[deny(non_exhaustive_omitted_patterns)]
     match NonExhaustiveSingleVariant::A(true) {
         _ => {}
     }
     // We can't catch this case, because this would require digging fully through all the values of
     // any type we encounter. We need to be able to only consider present constructors.
-    #[deny(non_exhaustive_omitted_patterns)]
     match &NonExhaustiveSingleVariant::A(true) {
         _ => {}
     }
 
+    match Some(NonExhaustiveSingleVariant::A(true)) {
+        Some(_) => {}
+        None => {}
+    }
+    match Some(&NonExhaustiveSingleVariant::A(true)) {
+        Some(_) => {}
+        None => {}
+    }
+
     // Ok: we don't lint on `if let` expressions
-    #[deny(non_exhaustive_omitted_patterns)]
     if let NonExhaustiveEnum::Tuple(_) = non_enum {}
 
-    #[deny(non_exhaustive_omitted_patterns)]
     match UnstableEnum::Stable {
         //~^ some variants are not matched explicitly
         UnstableEnum::Stable => {}
@@ -189,7 +189,6 @@ fn main() {
     }
 
     // Ok: the feature is on and all variants are matched
-    #[deny(non_exhaustive_omitted_patterns)]
     match UnstableEnum::Stable {
         UnstableEnum::Stable => {}
         UnstableEnum::Stable2 => {}
@@ -198,52 +197,66 @@ fn main() {
     }
 
     // Ok: the feature is on and both variants are matched
-    #[deny(non_exhaustive_omitted_patterns)]
     match OnlyUnstableEnum::Unstable {
         OnlyUnstableEnum::Unstable => {}
         OnlyUnstableEnum::Unstable2 => {}
         _ => {}
     }
 
-    #[deny(non_exhaustive_omitted_patterns)]
     match OnlyUnstableEnum::Unstable {
         //~^ some variants are not matched explicitly
         OnlyUnstableEnum::Unstable => {}
         _ => {}
     }
 
-    #[warn(non_exhaustive_omitted_patterns)]
     let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
     //~^ some fields are not explicitly listed
 
     // OK: both unstable fields are matched with feature on
-    #[warn(non_exhaustive_omitted_patterns)]
     let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new();
 
-    #[warn(non_exhaustive_omitted_patterns)]
     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
     //~^ some fields are not explicitly listed
 
     // OK: both unstable and stable fields are matched with feature on
-    #[warn(non_exhaustive_omitted_patterns)]
     let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default();
 
     // Ok: local bindings are allowed
-    #[deny(non_exhaustive_omitted_patterns)]
     let local = NonExhaustiveEnum::Unit;
 
     // Ok: missing patterns will be blocked by the pattern being refutable
-    #[deny(non_exhaustive_omitted_patterns)]
     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
     //~^ refutable pattern in local binding
 
-    #[deny(non_exhaustive_omitted_patterns)]
+    // Check that matching on a reference results in a correct diagnostic
     match &non_enum {
         //~^ some variants are not matched explicitly
+        //~| pattern `&NonExhaustiveEnum::Struct { .. }` not covered
         NonExhaustiveEnum::Unit => {}
         NonExhaustiveEnum::Tuple(_) => {}
         _ => {}
     }
+
+    match (true, &non_enum) {
+        //~^ some variants are not matched explicitly
+        //~| patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered
+        (true, NonExhaustiveEnum::Unit) => {}
+        _ => {}
+    }
+
+    match (&non_enum, true) {
+        //~^ some variants are not matched explicitly
+        //~| patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered
+        (NonExhaustiveEnum::Unit, true) => {}
+        _ => {}
+    }
+
+    match Some(&non_enum) {
+        //~^ some variants are not matched explicitly
+        //~| pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered
+        Some(NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_)) => {}
+        _ => {}
+    }
 }
 
 #[deny(non_exhaustive_omitted_patterns)]
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr
index 7db61f1241e..1037033c4b7 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr
@@ -1,4 +1,4 @@
-warning: some fields are not explicitly listed
+error: some fields are not explicitly listed
   --> $DIR/omitted-patterns.rs:139:9
    |
 LL |         VariantNonExhaustive::Bar { x, .. } => {}
@@ -7,41 +7,31 @@ LL |         VariantNonExhaustive::Bar { x, .. } => {}
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:136:12
+  --> $DIR/omitted-patterns.rs:45:8
    |
-LL |     #[warn(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deny(non_exhaustive_omitted_patterns)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:144:9
+error: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:143:9
    |
 LL |     let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed
    |
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:143:12
-   |
-LL |     #[warn(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:152:29
+error: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:149:29
    |
 LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed
    |
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:151:12
-   |
-LL |     #[warn(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:152:9
+error: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:149:9
    |
 LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed
@@ -49,117 +39,77 @@ LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found
 
-warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:216:9
+error: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:212:9
    |
 LL |     let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed
    |
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:215:12
-   |
-LL |     #[warn(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:224:9
+error: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:218:9
    |
 LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed
    |
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:223:12
-   |
-LL |     #[warn(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:55:11
+  --> $DIR/omitted-patterns.rs:65:11
    |
 LL |     match non_enum {
    |           ^^^^^^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:54:12
-   |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:63:11
+  --> $DIR/omitted-patterns.rs:72:11
    |
 LL |     match non_enum {
    |           ^^^^^^^^ pattern `NonExhaustiveEnum::Tuple(_)` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:62:12
-   |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:87:11
+  --> $DIR/omitted-patterns.rs:93:11
    |
 LL |     match (non_enum, true) {
    |           ^^^^^^^^^^^^^^^^ pattern `(NonExhaustiveEnum::Struct { .. }, _)` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `(NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:86:12
-   |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:102:11
+  --> $DIR/omitted-patterns.rs:106:11
    |
 LL |     match (true, non_enum) {
    |           ^^^^^^^^^^^^^^^^ pattern `(_, NonExhaustiveEnum::Struct { .. })` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `(bool, NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:101:12
-   |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:110:11
+  --> $DIR/omitted-patterns.rs:113:11
    |
 LL |     match Some(non_enum) {
    |           ^^^^^^^^^^^^^^ pattern `Some(NonExhaustiveEnum::Struct { .. })` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `Option<NonExhaustiveEnum>` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:109:12
-   |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:128:11
+  --> $DIR/omitted-patterns.rs:129:11
    |
 LL |     match NestedNonExhaustive::B {
    |           ^^^^^^^^^^^^^^^^^^^^^^ patterns `NestedNonExhaustive::C`, `NestedNonExhaustive::A(NonExhaustiveEnum::Tuple(_))` and `NestedNonExhaustive::A(NonExhaustiveEnum::Struct { .. })` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:127:12
-   |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:184:11
@@ -169,28 +119,18 @@ LL |     match UnstableEnum::Stable {
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:183:12
-   |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:209:11
+  --> $DIR/omitted-patterns.rs:206:11
    |
 LL |     match OnlyUnstableEnum::Unstable {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `OnlyUnstableEnum::Unstable2` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:208:12
-   |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/omitted-patterns.rs:237:9
+  --> $DIR/omitted-patterns.rs:228:9
    |
 LL |     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
    |         ^^^^^^^^^^^^^^^ pattern `_` not covered
@@ -204,19 +144,41 @@ LL |     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit
    |                                                                             ++++++++++++++++
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:241:11
+  --> $DIR/omitted-patterns.rs:232:11
    |
 LL |     match &non_enum {
    |           ^^^^^^^^^ pattern `&NonExhaustiveEnum::Struct { .. }` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `&NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
-note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:240:12
+
+error: some variants are not matched explicitly
+  --> $DIR/omitted-patterns.rs:240:11
+   |
+LL |     match (true, &non_enum) {
+   |           ^^^^^^^^^^^^^^^^^ patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered
    |
-LL |     #[deny(non_exhaustive_omitted_patterns)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: ensure that all variants are matched explicitly by adding the suggested match arms
+   = note: the matched value is of type `(bool, &NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found
+
+error: some variants are not matched explicitly
+  --> $DIR/omitted-patterns.rs:247:11
+   |
+LL |     match (&non_enum, true) {
+   |           ^^^^^^^^^^^^^^^^^ patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered
+   |
+   = help: ensure that all variants are matched explicitly by adding the suggested match arms
+   = note: the matched value is of type `(&NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found
+
+error: some variants are not matched explicitly
+  --> $DIR/omitted-patterns.rs:254:11
+   |
+LL |     match Some(&non_enum) {
+   |           ^^^^^^^^^^^^^^^ pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered
+   |
+   = help: ensure that all variants are matched explicitly by adding the suggested match arms
+   = note: the matched value is of type `Option<&NonExhaustiveEnum>` and the `non_exhaustive_omitted_patterns` attribute was found
 
-error: aborting due to 10 previous errors; 6 warnings emitted
+error: aborting due to 19 previous errors
 
 For more information about this error, try `rustc --explain E0005`.