about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-05-10 20:31:06 +0200
committerGitHub <noreply@github.com>2019-05-10 20:31:06 +0200
commitd94cb9f2ea86a088a970c6cf741efaef6fb6ed16 (patch)
tree7d5b594335fc716277a8514376971a6f84ef651d /src/test
parentcff1bdbd77d29a28a94ff9f5bf1e1c84e5bb6259 (diff)
parent1f0fb0391caf232dacabdf73fbbb84f2452b25c1 (diff)
downloadrust-d94cb9f2ea86a088a970c6cf741efaef6fb6ed16.tar.gz
rust-d94cb9f2ea86a088a970c6cf741efaef6fb6ed16.zip
Rollup merge of #60529 - davidtwco:rfc-2008-uninhabited, r=petrochenkov
RFC 2008: Uninhabitedness fixes for enum variants and tests

Part of #44109.

At the request of @Centril, this PR adds tests asserting that uninhabited non-exhaustive types are considered inhabited in extern crates. In adding these tests, I fixed an oversight in the implementation of RFC 2008 on enum variants that resulted in non-exhaustive enum variants being considered uninhabited in extern crates.

Before this PR, these lines would error:

```rust
// extern crate
pub enum UninhabitedVariants {
    #[non_exhaustive] Tuple(!),
    #[non_exhaustive] Struct { x: ! }
}

pub enum PartiallyInhabitedVariants {
    Tuple(u8),
    #[non_exhaustive] Struct { x: ! }
}

// current crate
match uninhabited_variant() /* fn() -> Option<UninhabitedVariants> */ {
    Some(_x) => (), //~ ERROR unreachable pattern
    None => (),
}

while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() /* fn() -> PartiallyInhabitedVariants */ {
    //~^ ERROR unreachable pattern
}
```

cc @Centril
r? @petrochenkov
Diffstat (limited to 'src/test')
-rw-r--r--src/test/ui/pattern/const-pat-ice.stderr2
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs33
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs38
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr47
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs46
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr47
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs36
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs52
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr59
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs40
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs58
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs34
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs42
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr49
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs37
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs48
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs59
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs71
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr38
23 files changed, 975 insertions, 1 deletions
diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr
index 261e95229a7..260c2e04d74 100644
--- a/src/test/ui/pattern/const-pat-ice.stderr
+++ b/src/test/ui/pattern/const-pat-ice.stderr
@@ -1,4 +1,4 @@
-thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1071:5
+thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1083:5
 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 error: internal compiler error: unexpected panic
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
new file mode 100644
index 00000000000..8cb9a8cf1f6
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
@@ -0,0 +1,33 @@
+#![crate_type = "rlib"]
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub enum PartiallyInhabitedVariants {
+    Tuple(u8),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+
+pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+
+pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+
+pub struct IndirectUninhabitedVariants(UninhabitedVariants);
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs
new file mode 100644
index 00000000000..80b9dc4c1c3
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs
@@ -0,0 +1,38 @@
+// aux-build:uninhabited.rs
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    UninhabitedEnum,
+    UninhabitedStruct,
+    UninhabitedTupleStruct,
+    UninhabitedVariants,
+};
+
+// This test checks that uninhabited non-exhaustive types cannot coerce to any type, as the never
+// type can.
+
+struct A;
+
+fn can_coerce_never_type_to_anything(x: !) -> A {
+    x
+}
+
+fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr
new file mode 100644
index 00000000000..d05ee1d39ec
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr
@@ -0,0 +1,47 @@
+error[E0308]: mismatched types
+  --> $DIR/coercions.rs:23:5
+   |
+LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+   |                                                                - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found enum `uninhabited::UninhabitedEnum`
+   |
+   = note: expected type `A`
+              found type `uninhabited::UninhabitedEnum`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions.rs:27:5
+   |
+LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+   |                                                                               - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found struct `uninhabited::UninhabitedTupleStruct`
+   |
+   = note: expected type `A`
+              found type `uninhabited::UninhabitedTupleStruct`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions.rs:31:5
+   |
+LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+   |                                                                    - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found struct `uninhabited::UninhabitedStruct`
+   |
+   = note: expected type `A`
+              found type `uninhabited::UninhabitedStruct`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions.rs:35:5
+   |
+LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
+   |                                                                                  - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found enum `uninhabited::UninhabitedVariants`
+   |
+   = note: expected type `A`
+              found type `uninhabited::UninhabitedVariants`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs
new file mode 100644
index 00000000000..803a542f8aa
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs
@@ -0,0 +1,46 @@
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+struct A;
+
+// This test checks that uninhabited non-exhaustive types defined in the same crate cannot coerce
+// to any type, as the never type can.
+
+fn can_coerce_never_type_to_anything(x: !) -> A {
+    x
+}
+
+fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr
new file mode 100644
index 00000000000..8f6b709bb1f
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr
@@ -0,0 +1,47 @@
+error[E0308]: mismatched types
+  --> $DIR/coercions_same_crate.rs:31:5
+   |
+LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+   |                                                                - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found enum `UninhabitedEnum`
+   |
+   = note: expected type `A`
+              found type `UninhabitedEnum`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions_same_crate.rs:35:5
+   |
+LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+   |                                                                               - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found struct `UninhabitedTupleStruct`
+   |
+   = note: expected type `A`
+              found type `UninhabitedTupleStruct`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions_same_crate.rs:39:5
+   |
+LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+   |                                                                    - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found struct `UninhabitedStruct`
+   |
+   = note: expected type `A`
+              found type `UninhabitedStruct`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions_same_crate.rs:43:5
+   |
+LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
+   |                                                                                  - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found enum `UninhabitedVariants`
+   |
+   = note: expected type `A`
+              found type `UninhabitedVariants`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs
new file mode 100644
index 00000000000..98a7fdbc504
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs
@@ -0,0 +1,36 @@
+// aux-build:uninhabited.rs
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    IndirectUninhabitedEnum,
+    IndirectUninhabitedStruct,
+    IndirectUninhabitedTupleStruct,
+    IndirectUninhabitedVariants,
+};
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type through a level of
+// indirection from an extern crate will not compile.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
+    x: IndirectUninhabitedVariants,
+) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
new file mode 100644
index 00000000000..af82022e1da
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
@@ -0,0 +1,35 @@
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled
+  --> $DIR/indirect_match.rs:19:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `uninhabited::IndirectUninhabitedStruct` is not handled
+  --> $DIR/indirect_match.rs:23:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `uninhabited::IndirectUninhabitedTupleStruct` is not handled
+  --> $DIR/indirect_match.rs:27:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `uninhabited::IndirectUninhabitedVariants` is not handled
+  --> $DIR/indirect_match.rs:33:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
new file mode 100644
index 00000000000..3c8d495e12c
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
@@ -0,0 +1,52 @@
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+
+pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+
+pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+
+pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type through a level of
+// indirection from the defining crate will not compile without `#![feature(exhaustive_patterns)]`.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
+    x: IndirectUninhabitedVariants,
+) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
new file mode 100644
index 00000000000..27b120792d6
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
@@ -0,0 +1,59 @@
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled
+  --> $DIR/indirect_match_same_crate.rs:35:11
+   |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+   | ----------------------------------------------------
+   | |          |
+   | |          variant not covered
+   | `IndirectUninhabitedEnum` defined here
+...
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `IndirectUninhabitedStruct` is not handled
+  --> $DIR/indirect_match_same_crate.rs:39:11
+   |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+   | --------------------------------------------------------
+   | |          |
+   | |          variant not covered
+   | `IndirectUninhabitedStruct` defined here
+...
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `IndirectUninhabitedTupleStruct` is not handled
+  --> $DIR/indirect_match_same_crate.rs:43:11
+   |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+   | ------------------------------------------------------------------
+   | |          |
+   | |          variant not covered
+   | `IndirectUninhabitedTupleStruct` defined here
+...
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `IndirectUninhabitedVariants` is not handled
+  --> $DIR/indirect_match_same_crate.rs:49:11
+   |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+   | ------------------------------------------------------------
+   | |          |
+   | |          variant not covered
+   | `IndirectUninhabitedVariants` defined here
+...
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
new file mode 100644
index 00000000000..be86519ecb1
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
@@ -0,0 +1,40 @@
+// aux-build:uninhabited.rs
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    IndirectUninhabitedEnum,
+    IndirectUninhabitedStruct,
+    IndirectUninhabitedTupleStruct,
+    IndirectUninhabitedVariants,
+};
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type through a level of
+// indirection from an extern crate will not compile. In particular, this enables the
+// `exhaustive_patterns` feature as this can change the branch used in the compiler to determine
+// this.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
+    x: IndirectUninhabitedVariants,
+) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
new file mode 100644
index 00000000000..17a8d010072
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
@@ -0,0 +1,35 @@
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
new file mode 100644
index 00000000000..5dbd38e07df
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
@@ -0,0 +1,58 @@
+// compile-pass
+// skip-codegen
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+
+pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+
+pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+
+pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate
+// will compile. In particular, this enables the `exhaustive_patterns` feature as this can
+// change the branch used in the compiler to determine this.
+// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
+    x: IndirectUninhabitedVariants,
+) -> A {
+    match x {}
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs
new file mode 100644
index 00000000000..e54098d4d48
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs
@@ -0,0 +1,34 @@
+// aux-build:uninhabited.rs
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    UninhabitedEnum,
+    UninhabitedStruct,
+    UninhabitedTupleStruct,
+    UninhabitedVariants,
+};
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate
+// will not compile.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
new file mode 100644
index 00000000000..de39688f45a
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
@@ -0,0 +1,35 @@
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
+  --> $DIR/match.rs:19:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `uninhabited::UninhabitedStruct` is not handled
+  --> $DIR/match.rs:23:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `uninhabited::UninhabitedTupleStruct` is not handled
+  --> $DIR/match.rs:27:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: multiple patterns of type `uninhabited::UninhabitedVariants` are not handled
+  --> $DIR/match.rs:31:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
new file mode 100644
index 00000000000..6405dd3bd65
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
@@ -0,0 +1,42 @@
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate
+// will compile.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
new file mode 100644
index 00000000000..410285a39a9
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
@@ -0,0 +1,49 @@
+error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled
+  --> $DIR/match_same_crate.rs:31:11
+   |
+LL |   pub struct UninhabitedStruct {
+   |   -          ----------------- variant not covered
+   |  _|
+   | |
+LL | |     _priv: !,
+LL | | }
+   | |_- `UninhabitedStruct` defined here
+...
+LL |       match x {}
+   |             ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled
+  --> $DIR/match_same_crate.rs:35:11
+   |
+LL | pub struct UninhabitedTupleStruct(!);
+   | -------------------------------------
+   | |          |
+   | |          variant not covered
+   | `UninhabitedTupleStruct` defined here
+...
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: multiple patterns of type `UninhabitedVariants` are not handled
+  --> $DIR/match_same_crate.rs:39:11
+   |
+LL | / pub enum UninhabitedVariants {
+LL | |     #[non_exhaustive] Tuple(!),
+   | |                       ----- variant not covered
+LL | |     #[non_exhaustive] Struct { x: ! }
+   | |                       ------ variant not covered
+LL | | }
+   | |_- `UninhabitedVariants` defined here
+...
+LL |       match x {}
+   |             ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
new file mode 100644
index 00000000000..900dfff652e
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
@@ -0,0 +1,37 @@
+// aux-build:uninhabited.rs
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    UninhabitedEnum,
+    UninhabitedStruct,
+    UninhabitedTupleStruct,
+    UninhabitedVariants,
+};
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate
+// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can
+// change the branch used in the compiler to determine this.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
new file mode 100644
index 00000000000..48a888bc50b
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -0,0 +1,35 @@
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
+  --> $DIR/match_with_exhaustive_patterns.rs:22:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty
+  --> $DIR/match_with_exhaustive_patterns.rs:26:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty
+  --> $DIR/match_with_exhaustive_patterns.rs:30:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedVariants` is non-empty
+  --> $DIR/match_with_exhaustive_patterns.rs:34:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
new file mode 100644
index 00000000000..74922d4bcb5
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
@@ -0,0 +1,48 @@
+// compile-pass
+// skip-codegen
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate
+// will compile. In particular, this enables the `exhaustive_patterns` feature as this can
+// change the branch used in the compiler to determine this.
+// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {}
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs
new file mode 100644
index 00000000000..97061310d19
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs
@@ -0,0 +1,59 @@
+// aux-build:uninhabited.rs
+// compile-pass
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    PartiallyInhabitedVariants,
+    UninhabitedEnum,
+    UninhabitedStruct,
+    UninhabitedTupleStruct,
+    UninhabitedVariants,
+};
+
+fn uninhabited_enum() -> Option<UninhabitedEnum> {
+    None
+}
+
+fn uninhabited_variant() -> Option<UninhabitedVariants> {
+    None
+}
+
+fn partially_inhabited_variant() -> PartiallyInhabitedVariants {
+    PartiallyInhabitedVariants::Tuple(3)
+}
+
+fn uninhabited_struct() -> Option<UninhabitedStruct> {
+    None
+}
+
+fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> {
+    None
+}
+
+// This test checks that non-exhaustive types that would normally be considered uninhabited within
+// the defining crate are not considered uninhabited from extern crates.
+
+fn main() {
+    match uninhabited_enum() {
+        Some(_x) => (), // This line would normally error.
+        None => (),
+    }
+
+    match uninhabited_variant() {
+        Some(_x) => (), // This line would normally error.
+        None => (),
+    }
+
+    // This line would normally error.
+    while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {
+    }
+
+    while let Some(_x) = uninhabited_struct() { // This line would normally error.
+    }
+
+    while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error.
+    }
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
new file mode 100644
index 00000000000..302a35cab5f
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
@@ -0,0 +1,71 @@
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub enum PartiallyInhabitedVariants {
+    Tuple(u8),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+fn uninhabited_enum() -> Option<UninhabitedEnum> {
+    None
+}
+
+fn uninhabited_variant() -> Option<UninhabitedVariants> {
+    None
+}
+
+fn partially_inhabited_variant() -> PartiallyInhabitedVariants {
+    PartiallyInhabitedVariants::Tuple(3)
+}
+
+fn uninhabited_struct() -> Option<UninhabitedStruct> {
+    None
+}
+
+fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> {
+    None
+}
+
+// This test checks that non-exhaustive types that would normally be considered uninhabited within
+// the defining crate are still considered uninhabited.
+
+fn main() {
+    match uninhabited_enum() {
+        Some(_x) => (), //~ ERROR unreachable pattern
+        None => (),
+    }
+
+    match uninhabited_variant() {
+        Some(_x) => (), //~ ERROR unreachable pattern
+        None => (),
+    }
+
+    while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
+        //~^ ERROR unreachable pattern
+    }
+
+    while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable pattern
+    }
+
+    while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable pattern
+    }
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
new file mode 100644
index 00000000000..72f37d9a60b
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
@@ -0,0 +1,38 @@
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:53:9
+   |
+LL |         Some(_x) => (),
+   |         ^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/patterns_same_crate.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:58:9
+   |
+LL |         Some(_x) => (),
+   |         ^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:62:15
+   |
+LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:66:15
+   |
+LL |     while let Some(_x) = uninhabited_struct() {
+   |               ^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:69:15
+   |
+LL |     while let Some(_x) = uninhabited_tuple_struct() {
+   |               ^^^^^^^^
+
+error: aborting due to 5 previous errors
+