about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-12 22:58:42 +0000
committerbors <bors@rust-lang.org>2021-01-12 22:58:42 +0000
commit058a71016553f267ae80b90276ef79956457d51a (patch)
tree9cd990416b0821aaa898a16bca44205fd92a4bba /src/test
parent7a9b552cb1621c9c57898d147228aab32b65a7c3 (diff)
parente608d8f4e5e8e33b5d480323596d2aeabd129e4f (diff)
Auto merge of #79670 - Nadrieril:uninhabited-query, r=estebank
Turn type inhabitedness into a query to fix `exhaustive_patterns` perf

We measured in https://github.com/rust-lang/rust/pull/79394 that enabling the [`exhaustive_patterns` feature](https://github.com/rust-lang/rust/issues/51085) causes significant perf degradation. It was conjectured that the culprit is type inhabitedness checking, and [I hypothesized](https://github.com/rust-lang/rust/pull/79394#issuecomment-733861149) that turning this computation into a query would solve most of the problem.

This PR turns `tcx.is_ty_uninhabited_from` into a query, and I measured a 25% perf gain on the benchmark that stress-tests `exhaustiveness_patterns`. This more than compensates for the 30% perf hit I measured [when creating it](https://github.com/rust-lang/rustc-perf/pull/801). We'll have to measure enabling the feature again, but I suspect this fixes the perf regression entirely.
I'd like a perf run on this PR obviously.
I made small atomic commits to help reviewing. The first one is just me discovering the "revisions" feature of the testing framework.

I believe there's a push to move things out of `rustc_middle` because it's huge. I guess `inhabitedness/mod.rs` could be moved out, but it's quite small. `DefIdForest` might be movable somewhere too. I don't know what the policy is for that.

Ping `@camelid` since you were interested in following along
`@rustbot` modify labels: +A-exhaustiveness-checking
Diffstat (limited to 'src/test')
-rw-r--r--src/test/ui/pattern/usefulness/auxiliary/empty.rs8
-rw-r--r--src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr (renamed from src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr)160
-rw-r--r--src/test/ui/pattern/usefulness/empty-match.normal.stderr (renamed from src/test/ui/pattern/usefulness/match-empty.stderr)152
-rw-r--r--src/test/ui/pattern/usefulness/empty-match.rs95
-rw-r--r--src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs48
-rw-r--r--src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr (renamed from src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr)2
-rw-r--r--src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr (renamed from src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr)24
-rw-r--r--src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs (renamed from src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs)14
-rw-r--r--src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs118
-rw-r--r--src/test/ui/pattern/usefulness/match-empty.rs118
-rw-r--r--src/test/ui/pattern/usefulness/uninhabited.rs143
11 files changed, 434 insertions, 448 deletions
diff --git a/src/test/ui/pattern/usefulness/auxiliary/empty.rs b/src/test/ui/pattern/usefulness/auxiliary/empty.rs
index 0b0719f48ee..29a03c9e8b5 100644
--- a/src/test/ui/pattern/usefulness/auxiliary/empty.rs
+++ b/src/test/ui/pattern/usefulness/auxiliary/empty.rs
@@ -1,2 +1,10 @@
 #![crate_type = "rlib"]
 pub enum EmptyForeignEnum {}
+
+pub struct VisiblyUninhabitedForeignStruct {
+    pub field: EmptyForeignEnum,
+}
+
+pub struct SecretlyUninhabitedForeignStruct {
+    _priv: EmptyForeignEnum,
+}
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
index 9d8b5f38e8c..b99386e7402 100644
--- a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr
+++ b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
@@ -1,94 +1,94 @@
 error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:52:9
+  --> $DIR/empty-match.rs:37:9
    |
 LL |         _ => {},
    |         ^
    |
 note: the lint level is defined here
-  --> $DIR/match-empty-exhaustive_patterns.rs:5:9
+  --> $DIR/empty-match.rs:8:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:55:9
+  --> $DIR/empty-match.rs:40:9
    |
 LL |         _ if false => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:62:9
+  --> $DIR/empty-match.rs:47:9
    |
 LL |         _ => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:65:9
+  --> $DIR/empty-match.rs:50:9
    |
 LL |         _ if false => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:72:9
+  --> $DIR/empty-match.rs:57:9
    |
 LL |         _ => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:75:9
+  --> $DIR/empty-match.rs:60:9
    |
 LL |         _ if false => {},
    |         ^
 
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:82:9
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+  --> $DIR/empty-match.rs:78:20
    |
-LL |         Some(_) => {}
-   |         ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:86:9
+LL |     match_no_arms!(0u8);
+   |                    ^^^
    |
-LL |         Some(_) => {}
-   |         ^^^^^^^
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/match-empty-exhaustive_patterns.rs:89:18
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
+  --> $DIR/empty-match.rs:79:20
    |
-LL |     match_empty!(0u8);
-   |                  ^^^
+LL | struct NonEmptyStruct1;
+   | ----------------------- `NonEmptyStruct1` defined here
+...
+LL |     match_no_arms!(NonEmptyStruct1);
+   |                    ^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `u8`
+   = note: the matched value is of type `NonEmptyStruct1`
 
-error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
-  --> $DIR/match-empty-exhaustive_patterns.rs:91:18
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
+  --> $DIR/empty-match.rs:80:20
    |
-LL | struct NonEmptyStruct(bool);
-   | ---------------------------- `NonEmptyStruct` defined here
+LL | struct NonEmptyStruct2(bool);
+   | ----------------------------- `NonEmptyStruct2` defined here
 ...
-LL |     match_empty!(NonEmptyStruct(true));
-   |                  ^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!(NonEmptyStruct2(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyStruct`
+   = note: the matched value is of type `NonEmptyStruct2`
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/match-empty-exhaustive_patterns.rs:93:18
+  --> $DIR/empty-match.rs:81:20
    |
 LL | / union NonEmptyUnion1 {
 LL | |     foo: (),
 LL | | }
    | |_- `NonEmptyUnion1` defined here
 ...
-LL |       match_empty!((NonEmptyUnion1 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       match_no_arms!((NonEmptyUnion1 { foo: () }));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyUnion1`
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/match-empty-exhaustive_patterns.rs:95:18
+  --> $DIR/empty-match.rs:82:20
    |
 LL | / union NonEmptyUnion2 {
 LL | |     foo: (),
@@ -96,101 +96,107 @@ LL | |     bar: (),
 LL | | }
    | |_- `NonEmptyUnion2` defined here
 ...
-LL |       match_empty!((NonEmptyUnion2 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       match_no_arms!((NonEmptyUnion2 { foo: () }));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyUnion2`
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:97:18
+  --> $DIR/empty-match.rs:83:20
    |
 LL | / enum NonEmptyEnum1 {
 LL | |     Foo(bool),
    | |     --- not covered
-LL | |
-LL | |
 LL | | }
    | |_- `NonEmptyEnum1` defined here
 ...
-LL |       match_empty!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |       match_no_arms!(NonEmptyEnum1::Foo(true));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum1`
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:99:18
+  --> $DIR/empty-match.rs:84:20
    |
 LL | / enum NonEmptyEnum2 {
 LL | |     Foo(bool),
    | |     --- not covered
-LL | |
-LL | |
 LL | |     Bar,
    | |     --- not covered
-LL | |
-LL | |
 LL | | }
    | |_- `NonEmptyEnum2` defined here
 ...
-LL |       match_empty!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+LL |       match_no_arms!(NonEmptyEnum2::Foo(true));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum2`
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:101:18
+  --> $DIR/empty-match.rs:85:20
    |
 LL | / enum NonEmptyEnum5 {
 LL | |     V1, V2, V3, V4, V5,
 LL | | }
    | |_- `NonEmptyEnum5` defined here
 ...
-LL |       match_empty!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |       match_no_arms!(NonEmptyEnum5::V1);
+   |                      ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum5`
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:104:18
+  --> $DIR/empty-match.rs:87:24
    |
-LL |     match_false!(0u8);
-   |                  ^^^ pattern `_` not covered
+LL |     match_guarded_arm!(0u8);
+   |                        ^^^ pattern `_` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:106:18
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
+  --> $DIR/empty-match.rs:88:24
+   |
+LL | struct NonEmptyStruct1;
+   | ----------------------- `NonEmptyStruct1` defined here
+...
+LL |     match_guarded_arm!(NonEmptyStruct1);
+   |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct1`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
+  --> $DIR/empty-match.rs:89:24
    |
-LL | struct NonEmptyStruct(bool);
-   | ---------------------------- `NonEmptyStruct` defined here
+LL | struct NonEmptyStruct2(bool);
+   | ----------------------------- `NonEmptyStruct2` defined here
 ...
-LL |     match_false!(NonEmptyStruct(true));
-   |                  ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
+LL |     match_guarded_arm!(NonEmptyStruct2(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyStruct`
+   = note: the matched value is of type `NonEmptyStruct2`
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:108:18
+  --> $DIR/empty-match.rs:90:24
    |
 LL | / union NonEmptyUnion1 {
 LL | |     foo: (),
 LL | | }
    | |_- `NonEmptyUnion1` defined here
 ...
-LL |       match_false!((NonEmptyUnion1 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL |       match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyUnion1`
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:110:18
+  --> $DIR/empty-match.rs:91:24
    |
 LL | / union NonEmptyUnion2 {
 LL | |     foo: (),
@@ -198,60 +204,54 @@ LL | |     bar: (),
 LL | | }
    | |_- `NonEmptyUnion2` defined here
 ...
-LL |       match_false!((NonEmptyUnion2 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL |       match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyUnion2`
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:112:18
+  --> $DIR/empty-match.rs:92:24
    |
 LL | / enum NonEmptyEnum1 {
 LL | |     Foo(bool),
    | |     --- not covered
-LL | |
-LL | |
 LL | | }
    | |_- `NonEmptyEnum1` defined here
 ...
-LL |       match_false!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |       match_guarded_arm!(NonEmptyEnum1::Foo(true));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum1`
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:114:18
+  --> $DIR/empty-match.rs:93:24
    |
 LL | / enum NonEmptyEnum2 {
 LL | |     Foo(bool),
    | |     --- not covered
-LL | |
-LL | |
 LL | |     Bar,
    | |     --- not covered
-LL | |
-LL | |
 LL | | }
    | |_- `NonEmptyEnum2` defined here
 ...
-LL |       match_false!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+LL |       match_guarded_arm!(NonEmptyEnum2::Foo(true));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum2`
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:116:18
+  --> $DIR/empty-match.rs:94:24
    |
 LL | / enum NonEmptyEnum5 {
 LL | |     V1, V2, V3, V4, V5,
 LL | | }
    | |_- `NonEmptyEnum5` defined here
 ...
-LL |       match_false!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |       match_guarded_arm!(NonEmptyEnum5::V1);
+   |                          ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum5`
diff --git a/src/test/ui/pattern/usefulness/match-empty.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr
index 6065c552390..b99386e7402 100644
--- a/src/test/ui/pattern/usefulness/match-empty.stderr
+++ b/src/test/ui/pattern/usefulness/empty-match.normal.stderr
@@ -1,82 +1,94 @@
 error: unreachable pattern
-  --> $DIR/match-empty.rs:51:9
+  --> $DIR/empty-match.rs:37:9
    |
 LL |         _ => {},
    |         ^
    |
 note: the lint level is defined here
-  --> $DIR/match-empty.rs:4:9
+  --> $DIR/empty-match.rs:8:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/match-empty.rs:54:9
+  --> $DIR/empty-match.rs:40:9
    |
 LL |         _ if false => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/match-empty.rs:61:9
+  --> $DIR/empty-match.rs:47:9
    |
 LL |         _ => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/match-empty.rs:64:9
+  --> $DIR/empty-match.rs:50:9
    |
 LL |         _ if false => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/match-empty.rs:71:9
+  --> $DIR/empty-match.rs:57:9
    |
 LL |         _ => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/match-empty.rs:74:9
+  --> $DIR/empty-match.rs:60:9
    |
 LL |         _ if false => {},
    |         ^
 
 error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/match-empty.rs:89:18
+  --> $DIR/empty-match.rs:78:20
    |
-LL |     match_empty!(0u8);
-   |                  ^^^
+LL |     match_no_arms!(0u8);
+   |                    ^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
-  --> $DIR/match-empty.rs:91:18
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
+  --> $DIR/empty-match.rs:79:20
    |
-LL | struct NonEmptyStruct(bool);
-   | ---------------------------- `NonEmptyStruct` defined here
+LL | struct NonEmptyStruct1;
+   | ----------------------- `NonEmptyStruct1` defined here
 ...
-LL |     match_empty!(NonEmptyStruct(true));
-   |                  ^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!(NonEmptyStruct1);
+   |                    ^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyStruct`
+   = note: the matched value is of type `NonEmptyStruct1`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
+  --> $DIR/empty-match.rs:80:20
+   |
+LL | struct NonEmptyStruct2(bool);
+   | ----------------------------- `NonEmptyStruct2` defined here
+...
+LL |     match_no_arms!(NonEmptyStruct2(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct2`
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/match-empty.rs:93:18
+  --> $DIR/empty-match.rs:81:20
    |
 LL | / union NonEmptyUnion1 {
 LL | |     foo: (),
 LL | | }
    | |_- `NonEmptyUnion1` defined here
 ...
-LL |       match_empty!((NonEmptyUnion1 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       match_no_arms!((NonEmptyUnion1 { foo: () }));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyUnion1`
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/match-empty.rs:95:18
+  --> $DIR/empty-match.rs:82:20
    |
 LL | / union NonEmptyUnion2 {
 LL | |     foo: (),
@@ -84,101 +96,107 @@ LL | |     bar: (),
 LL | | }
    | |_- `NonEmptyUnion2` defined here
 ...
-LL |       match_empty!((NonEmptyUnion2 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       match_no_arms!((NonEmptyUnion2 { foo: () }));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyUnion2`
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
-  --> $DIR/match-empty.rs:97:18
+  --> $DIR/empty-match.rs:83:20
    |
 LL | / enum NonEmptyEnum1 {
 LL | |     Foo(bool),
    | |     --- not covered
-LL | |
-LL | |
 LL | | }
    | |_- `NonEmptyEnum1` defined here
 ...
-LL |       match_empty!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |       match_no_arms!(NonEmptyEnum1::Foo(true));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum1`
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
-  --> $DIR/match-empty.rs:99:18
+  --> $DIR/empty-match.rs:84:20
    |
 LL | / enum NonEmptyEnum2 {
 LL | |     Foo(bool),
    | |     --- not covered
-LL | |
-LL | |
 LL | |     Bar,
    | |     --- not covered
-LL | |
-LL | |
 LL | | }
    | |_- `NonEmptyEnum2` defined here
 ...
-LL |       match_empty!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+LL |       match_no_arms!(NonEmptyEnum2::Foo(true));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum2`
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
-  --> $DIR/match-empty.rs:101:18
+  --> $DIR/empty-match.rs:85:20
    |
 LL | / enum NonEmptyEnum5 {
 LL | |     V1, V2, V3, V4, V5,
 LL | | }
    | |_- `NonEmptyEnum5` defined here
 ...
-LL |       match_empty!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |       match_no_arms!(NonEmptyEnum5::V1);
+   |                      ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum5`
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/match-empty.rs:104:18
+  --> $DIR/empty-match.rs:87:24
    |
-LL |     match_false!(0u8);
-   |                  ^^^ pattern `_` not covered
+LL |     match_guarded_arm!(0u8);
+   |                        ^^^ pattern `_` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
-  --> $DIR/match-empty.rs:106:18
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
+  --> $DIR/empty-match.rs:88:24
+   |
+LL | struct NonEmptyStruct1;
+   | ----------------------- `NonEmptyStruct1` defined here
+...
+LL |     match_guarded_arm!(NonEmptyStruct1);
+   |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct1`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
+  --> $DIR/empty-match.rs:89:24
    |
-LL | struct NonEmptyStruct(bool);
-   | ---------------------------- `NonEmptyStruct` defined here
+LL | struct NonEmptyStruct2(bool);
+   | ----------------------------- `NonEmptyStruct2` defined here
 ...
-LL |     match_false!(NonEmptyStruct(true));
-   |                  ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
+LL |     match_guarded_arm!(NonEmptyStruct2(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyStruct`
+   = note: the matched value is of type `NonEmptyStruct2`
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/match-empty.rs:108:18
+  --> $DIR/empty-match.rs:90:24
    |
 LL | / union NonEmptyUnion1 {
 LL | |     foo: (),
 LL | | }
    | |_- `NonEmptyUnion1` defined here
 ...
-LL |       match_false!((NonEmptyUnion1 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL |       match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyUnion1`
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/match-empty.rs:110:18
+  --> $DIR/empty-match.rs:91:24
    |
 LL | / union NonEmptyUnion2 {
 LL | |     foo: (),
@@ -186,64 +204,58 @@ LL | |     bar: (),
 LL | | }
    | |_- `NonEmptyUnion2` defined here
 ...
-LL |       match_false!((NonEmptyUnion2 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL |       match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyUnion2`
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
-  --> $DIR/match-empty.rs:112:18
+  --> $DIR/empty-match.rs:92:24
    |
 LL | / enum NonEmptyEnum1 {
 LL | |     Foo(bool),
    | |     --- not covered
-LL | |
-LL | |
 LL | | }
    | |_- `NonEmptyEnum1` defined here
 ...
-LL |       match_false!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |       match_guarded_arm!(NonEmptyEnum1::Foo(true));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum1`
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
-  --> $DIR/match-empty.rs:114:18
+  --> $DIR/empty-match.rs:93:24
    |
 LL | / enum NonEmptyEnum2 {
 LL | |     Foo(bool),
    | |     --- not covered
-LL | |
-LL | |
 LL | |     Bar,
    | |     --- not covered
-LL | |
-LL | |
 LL | | }
    | |_- `NonEmptyEnum2` defined here
 ...
-LL |       match_false!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+LL |       match_guarded_arm!(NonEmptyEnum2::Foo(true));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum2`
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
-  --> $DIR/match-empty.rs:116:18
+  --> $DIR/empty-match.rs:94:24
    |
 LL | / enum NonEmptyEnum5 {
 LL | |     V1, V2, V3, V4, V5,
 LL | | }
    | |_- `NonEmptyEnum5` defined here
 ...
-LL |       match_false!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |       match_guarded_arm!(NonEmptyEnum5::V1);
+   |                          ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `NonEmptyEnum5`
 
-error: aborting due to 20 previous errors
+error: aborting due to 22 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/empty-match.rs b/src/test/ui/pattern/usefulness/empty-match.rs
new file mode 100644
index 00000000000..8110ec013d7
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/empty-match.rs
@@ -0,0 +1,95 @@
+// aux-build:empty.rs
+// revisions: normal exhaustive_patterns
+//
+// This tests a match with no arms on various types.
+#![feature(never_type)]
+#![feature(never_type_fallback)]
+#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
+#![deny(unreachable_patterns)]
+
+extern crate empty;
+
+enum EmptyEnum {}
+
+struct NonEmptyStruct1;
+struct NonEmptyStruct2(bool);
+union NonEmptyUnion1 {
+    foo: (),
+}
+union NonEmptyUnion2 {
+    foo: (),
+    bar: (),
+}
+enum NonEmptyEnum1 {
+    Foo(bool),
+}
+enum NonEmptyEnum2 {
+    Foo(bool),
+    Bar,
+}
+enum NonEmptyEnum5 {
+    V1, V2, V3, V4, V5,
+}
+
+fn empty_enum(x: EmptyEnum) {
+    match x {} // ok
+    match x {
+        _ => {}, //~ ERROR unreachable pattern
+    }
+    match x {
+        _ if false => {}, //~ ERROR unreachable pattern
+    }
+}
+
+fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
+    match x {} // ok
+    match x {
+        _ => {}, //~ ERROR unreachable pattern
+    }
+    match x {
+        _ if false => {}, //~ ERROR unreachable pattern
+    }
+}
+
+fn never(x: !) {
+    match x {} // ok
+    match x {
+        _ => {}, //~ ERROR unreachable pattern
+    }
+    match x {
+        _ if false => {}, //~ ERROR unreachable pattern
+    }
+}
+
+macro_rules! match_no_arms {
+    ($e:expr) => {
+        match $e {}
+    };
+}
+macro_rules! match_guarded_arm {
+    ($e:expr) => {
+        match $e {
+            _ if false => {}
+        }
+    };
+}
+
+fn main() {
+    match_no_arms!(0u8); //~ ERROR type `u8` is non-empty
+    match_no_arms!(NonEmptyStruct1); //~ ERROR type `NonEmptyStruct1` is non-empty
+    match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty
+    match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty
+    match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty
+    match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
+    match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
+    match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
+
+    match_guarded_arm!(0u8); //~ ERROR `_` not covered
+    match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered
+    match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered
+    match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered
+    match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered
+    match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
+    match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
+    match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
+}
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs
deleted file mode 100644
index 9292f22e09e..00000000000
--- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-#![feature(exclusive_range_pattern)]
-
-macro_rules! m {
-    ($s:expr, $($t:tt)+) => {
-        match $s { $($t)+ => {} }
-    }
-}
-
-fn main() {
-    match 0usize {
-        //~^ ERROR non-exhaustive patterns
-        0 ..= usize::MAX => {}
-    }
-
-    match 0isize {
-        //~^ ERROR non-exhaustive patterns
-        isize::MIN ..= isize::MAX => {}
-    }
-
-    m!(0usize, 0..=usize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!(0usize, 0..5 | 5..=usize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!(0usize, 0..usize::MAX | usize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
-    //~^ ERROR non-exhaustive patterns
-
-    m!(0isize, isize::MIN..=isize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!(0isize, isize::MIN..5 | 5..=isize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!(0isize, isize::MIN..isize::MAX | isize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!((0isize, true), (isize::MIN..5, true)
-        | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
-    //~^^ ERROR non-exhaustive patterns
-
-    match 0isize {
-        //~^ ERROR non-exhaustive patterns
-        isize::MIN ..= -1 => {}
-        0 => {}
-        1 ..= isize::MAX => {}
-    }
-
-    match 7usize {}
-    //~^ ERROR non-exhaustive patterns
-}
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
index 0b3c65166ee..25632934583 100644
--- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr
+++ b/src/test/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-allow.rs:36:11
+  --> $DIR/pointer-sized-int.rs:48:11
    |
 LL |     match 7usize {}
    |           ^^^^^^
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
index 9d566b0e775..e8ac9f3cfe1 100644
--- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr
+++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:10:11
+  --> $DIR/pointer-sized-int.rs:12:11
    |
 LL |     match 0usize {
    |           ^^^^^^ pattern `_` not covered
@@ -10,7 +10,7 @@ LL |     match 0usize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:15:11
+  --> $DIR/pointer-sized-int.rs:17:11
    |
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
@@ -21,7 +21,7 @@ LL |     match 0isize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:20:8
+  --> $DIR/pointer-sized-int.rs:22:8
    |
 LL |     m!(0usize, 0..=usize::MAX);
    |        ^^^^^^ pattern `_` not covered
@@ -32,7 +32,7 @@ LL |     m!(0usize, 0..=usize::MAX);
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:22:8
+  --> $DIR/pointer-sized-int.rs:24:8
    |
 LL |     m!(0usize, 0..5 | 5..=usize::MAX);
    |        ^^^^^^ pattern `_` not covered
@@ -43,7 +43,7 @@ LL |     m!(0usize, 0..5 | 5..=usize::MAX);
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:24:8
+  --> $DIR/pointer-sized-int.rs:26:8
    |
 LL |     m!(0usize, 0..usize::MAX | usize::MAX);
    |        ^^^^^^ pattern `_` not covered
@@ -54,7 +54,7 @@ LL |     m!(0usize, 0..usize::MAX | usize::MAX);
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 
 error[E0004]: non-exhaustive patterns: `(_, _)` not covered
-  --> $DIR/pointer-sized-int-deny.rs:26:8
+  --> $DIR/pointer-sized-int.rs:28:8
    |
 LL |     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
    |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
@@ -63,7 +63,7 @@ LL |     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::
    = note: the matched value is of type `(usize, bool)`
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:29:8
+  --> $DIR/pointer-sized-int.rs:31:8
    |
 LL |     m!(0isize, isize::MIN..=isize::MAX);
    |        ^^^^^^ pattern `_` not covered
@@ -74,7 +74,7 @@ LL |     m!(0isize, isize::MIN..=isize::MAX);
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:31:8
+  --> $DIR/pointer-sized-int.rs:33:8
    |
 LL |     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
    |        ^^^^^^ pattern `_` not covered
@@ -85,7 +85,7 @@ LL |     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:33:8
+  --> $DIR/pointer-sized-int.rs:35:8
    |
 LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
    |        ^^^^^^ pattern `_` not covered
@@ -96,7 +96,7 @@ LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 
 error[E0004]: non-exhaustive patterns: `(_, _)` not covered
-  --> $DIR/pointer-sized-int-deny.rs:35:8
+  --> $DIR/pointer-sized-int.rs:37:8
    |
 LL |     m!((0isize, true), (isize::MIN..5, true)
    |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
@@ -105,7 +105,7 @@ LL |     m!((0isize, true), (isize::MIN..5, true)
    = note: the matched value is of type `(isize, bool)`
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:39:11
+  --> $DIR/pointer-sized-int.rs:41:11
    |
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
@@ -116,7 +116,7 @@ LL |     match 0isize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/pointer-sized-int-deny.rs:46:11
+  --> $DIR/pointer-sized-int.rs:48:11
    |
 LL |     match 7usize {}
    |           ^^^^^^
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
index 6173053cc4f..1ed18c26763 100644
--- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs
+++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
@@ -1,5 +1,6 @@
-#![feature(precise_pointer_size_matching)]
+// revisions: allow deny
 #![feature(exclusive_range_pattern)]
+#![cfg_attr(allow, feature(precise_pointer_size_matching))]
 
 macro_rules! m {
     ($s:expr, $($t:tt)+) => {
@@ -9,25 +10,36 @@ macro_rules! m {
 
 fn main() {
     match 0usize {
+        //[deny]~^ ERROR non-exhaustive patterns
         0 ..= usize::MAX => {}
     }
 
     match 0isize {
+        //[deny]~^ ERROR non-exhaustive patterns
         isize::MIN ..= isize::MAX => {}
     }
 
     m!(0usize, 0..=usize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
     m!(0usize, 0..5 | 5..=usize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
     m!(0usize, 0..usize::MAX | usize::MAX);
+    //[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!(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..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
 
     match 0isize {
+        //[deny]~^ ERROR non-exhaustive patterns
         isize::MIN ..= -1 => {}
         0 => {}
         1 ..= isize::MAX => {}
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
deleted file mode 100644
index c5c3a214f9a..00000000000
--- a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-// aux-build:empty.rs
-#![feature(never_type)]
-#![feature(never_type_fallback)]
-#![feature(exhaustive_patterns)]
-#![deny(unreachable_patterns)]
-
-extern crate empty;
-
-enum EmptyEnum {}
-
-struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
-union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
-    foo: (),
-}
-union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
-    foo: (),
-    bar: (),
-}
-enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
-    Foo(bool),
-    //~^ not covered
-    //~| not covered
-}
-enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
-    Foo(bool),
-    //~^ not covered
-    //~| not covered
-    Bar,
-    //~^ not covered
-    //~| not covered
-}
-enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
-    V1, V2, V3, V4, V5,
-}
-
-macro_rules! match_empty {
-    ($e:expr) => {
-        match $e {}
-    };
-}
-macro_rules! match_false {
-    ($e:expr) => {
-        match $e {
-            _ if false => {}
-        }
-    };
-}
-
-fn empty_enum(x: EmptyEnum) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn never(x: !) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn main() {
-    match None::<!> {
-        None => {}
-        Some(_) => {} //~ ERROR unreachable pattern
-    }
-    match None::<EmptyEnum> {
-        None => {}
-        Some(_) => {} //~ ERROR unreachable pattern
-    }
-
-    match_empty!(0u8);
-    //~^ ERROR type `u8` is non-empty
-    match_empty!(NonEmptyStruct(true));
-    //~^ ERROR type `NonEmptyStruct` is non-empty
-    match_empty!((NonEmptyUnion1 { foo: () }));
-    //~^ ERROR type `NonEmptyUnion1` is non-empty
-    match_empty!((NonEmptyUnion2 { foo: () }));
-    //~^ ERROR type `NonEmptyUnion2` is non-empty
-    match_empty!(NonEmptyEnum1::Foo(true));
-    //~^ ERROR `Foo(_)` not covered
-    match_empty!(NonEmptyEnum2::Foo(true));
-    //~^ ERROR `Foo(_)` and `Bar` not covered
-    match_empty!(NonEmptyEnum5::V1);
-    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
-
-    match_false!(0u8);
-    //~^ ERROR `_` not covered
-    match_false!(NonEmptyStruct(true));
-    //~^ ERROR `NonEmptyStruct(_)` not covered
-    match_false!((NonEmptyUnion1 { foo: () }));
-    //~^ ERROR `NonEmptyUnion1 { .. }` not covered
-    match_false!((NonEmptyUnion2 { foo: () }));
-    //~^ ERROR `NonEmptyUnion2 { .. }` not covered
-    match_false!(NonEmptyEnum1::Foo(true));
-    //~^ ERROR `Foo(_)` not covered
-    match_false!(NonEmptyEnum2::Foo(true));
-    //~^ ERROR `Foo(_)` and `Bar` not covered
-    match_false!(NonEmptyEnum5::V1);
-    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
-}
diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs
deleted file mode 100644
index 10ea2a10406..00000000000
--- a/src/test/ui/pattern/usefulness/match-empty.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-// aux-build:empty.rs
-#![feature(never_type)]
-#![feature(never_type_fallback)]
-#![deny(unreachable_patterns)]
-
-extern crate empty;
-
-enum EmptyEnum {}
-
-struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
-union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
-    foo: (),
-}
-union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
-    foo: (),
-    bar: (),
-}
-enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
-    Foo(bool),
-    //~^ not covered
-    //~| not covered
-}
-enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
-    Foo(bool),
-    //~^ not covered
-    //~| not covered
-    Bar,
-    //~^ not covered
-    //~| not covered
-}
-enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
-    V1, V2, V3, V4, V5,
-}
-
-macro_rules! match_empty {
-    ($e:expr) => {
-        match $e {}
-    };
-}
-macro_rules! match_false {
-    ($e:expr) => {
-        match $e {
-            _ if false => {}
-        }
-    };
-}
-
-fn empty_enum(x: EmptyEnum) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn never(x: !) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn main() {
-    // `exhaustive_patterns` is not on, so uninhabited branches are not detected as unreachable.
-    match None::<!> {
-        None => {}
-        Some(_) => {}
-    }
-    match None::<EmptyEnum> {
-        None => {}
-        Some(_) => {}
-    }
-
-    match_empty!(0u8);
-    //~^ ERROR type `u8` is non-empty
-    match_empty!(NonEmptyStruct(true));
-    //~^ ERROR type `NonEmptyStruct` is non-empty
-    match_empty!((NonEmptyUnion1 { foo: () }));
-    //~^ ERROR type `NonEmptyUnion1` is non-empty
-    match_empty!((NonEmptyUnion2 { foo: () }));
-    //~^ ERROR type `NonEmptyUnion2` is non-empty
-    match_empty!(NonEmptyEnum1::Foo(true));
-    //~^ ERROR `Foo(_)` not covered
-    match_empty!(NonEmptyEnum2::Foo(true));
-    //~^ ERROR `Foo(_)` and `Bar` not covered
-    match_empty!(NonEmptyEnum5::V1);
-    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
-
-    match_false!(0u8);
-    //~^ ERROR `_` not covered
-    match_false!(NonEmptyStruct(true));
-    //~^ ERROR `NonEmptyStruct(_)` not covered
-    match_false!((NonEmptyUnion1 { foo: () }));
-    //~^ ERROR `NonEmptyUnion1 { .. }` not covered
-    match_false!((NonEmptyUnion2 { foo: () }));
-    //~^ ERROR `NonEmptyUnion2 { .. }` not covered
-    match_false!(NonEmptyEnum1::Foo(true));
-    //~^ ERROR `Foo(_)` not covered
-    match_false!(NonEmptyEnum2::Foo(true));
-    //~^ ERROR `Foo(_)` and `Bar` not covered
-    match_false!(NonEmptyEnum5::V1);
-    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
-}
diff --git a/src/test/ui/pattern/usefulness/uninhabited.rs b/src/test/ui/pattern/usefulness/uninhabited.rs
new file mode 100644
index 00000000000..77cd0f4005e
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/uninhabited.rs
@@ -0,0 +1,143 @@
+// check-pass
+// aux-build:empty.rs
+//
+// This tests plays with matching and uninhabited types. This also serves as a test for the
+// `tcx.is_ty_uninhabited_from()` function.
+#![feature(never_type)]
+#![feature(never_type_fallback)]
+#![feature(exhaustive_patterns)]
+#![deny(unreachable_patterns)]
+
+macro_rules! assert_empty {
+    ($ty:ty) => {
+        const _: () = {
+            fn assert_empty(x: $ty) {
+                match x {}
+                match Some(x) {
+                    None => {}
+                }
+            }
+        };
+    };
+}
+macro_rules! assert_non_empty {
+    ($ty:ty) => {
+        const _: () = {
+            fn assert_non_empty(x: $ty) {
+                match x {
+                    _ => {}
+                }
+                match Some(x) {
+                    None => {}
+                    Some(_) => {}
+                }
+            }
+        };
+    };
+}
+
+extern crate empty;
+assert_empty!(empty::EmptyForeignEnum);
+assert_empty!(empty::VisiblyUninhabitedForeignStruct);
+assert_non_empty!(empty::SecretlyUninhabitedForeignStruct);
+
+enum Void {}
+assert_empty!(Void);
+
+enum Enum2 {
+    Foo(Void),
+    Bar(!),
+}
+assert_empty!(Enum2);
+
+enum Enum3 {
+    Foo(Void),
+    Bar {
+        x: u64,
+        y: !,
+    },
+}
+assert_empty!(Enum3);
+
+enum Enum4 {
+    Foo(u64),
+    Bar(!),
+}
+assert_non_empty!(Enum4);
+
+struct Struct1(empty::EmptyForeignEnum);
+assert_empty!(Struct1);
+
+struct Struct2 {
+    x: u64,
+    y: !,
+}
+assert_empty!(Struct2);
+
+union Union {
+    foo: !,
+}
+assert_non_empty!(Union);
+
+assert_empty!((!, String));
+
+assert_non_empty!(&'static !);
+assert_non_empty!(&'static Struct1);
+assert_non_empty!(&'static &'static &'static !);
+
+assert_empty!([!; 1]);
+assert_empty!([Void; 2]);
+assert_non_empty!([!; 0]);
+assert_non_empty!(&'static [!]);
+
+mod visibility {
+    /// This struct can only be seen to be inhabited in modules `b`, `c` or `d`, because otherwise
+    /// the uninhabitedness of both `SecretlyUninhabited` structs is hidden.
+    struct SometimesEmptyStruct {
+        x: a::b::SecretlyUninhabited,
+        y: c::AlsoSecretlyUninhabited,
+    }
+
+    /// This enum can only be seen to be inhabited in module `d`.
+    enum SometimesEmptyEnum {
+        X(c::AlsoSecretlyUninhabited),
+        Y(c::d::VerySecretlyUninhabited),
+    }
+
+    mod a {
+        use super::*;
+        pub mod b {
+            use super::*;
+            pub struct SecretlyUninhabited {
+                _priv: !,
+            }
+            assert_empty!(SometimesEmptyStruct);
+        }
+
+        assert_non_empty!(SometimesEmptyStruct);
+        assert_non_empty!(SometimesEmptyEnum);
+    }
+
+    mod c {
+        use super::*;
+        pub struct AlsoSecretlyUninhabited {
+            _priv: ::Struct1,
+        }
+        assert_empty!(SometimesEmptyStruct);
+        assert_non_empty!(SometimesEmptyEnum);
+
+        pub mod d {
+            use super::*;
+            pub struct VerySecretlyUninhabited {
+                _priv: !,
+            }
+            assert_empty!(SometimesEmptyStruct);
+            assert_empty!(SometimesEmptyEnum);
+        }
+    }
+
+    assert_non_empty!(SometimesEmptyStruct);
+    assert_non_empty!(SometimesEmptyEnum);
+}
+
+fn main() {}