about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-09-03 19:13:24 +0200
committerGitHub <noreply@github.com>2024-09-03 19:13:24 +0200
commite7504ac70407c116d35a4faa38f3b03bc62457a6 (patch)
treec86eabc37c1dbbe0a3a3d78e145d8e0bbdf5c32f
parent51c686f32b937065b22ac416065733980d936f4c (diff)
parent6f6a6bc710e538741aa06d40df6492471e4be8af (diff)
downloadrust-e7504ac70407c116d35a4faa38f3b03bc62457a6.tar.gz
rust-e7504ac70407c116d35a4faa38f3b03bc62457a6.zip
Rollup merge of #128934 - Nadrieril:fix-empty-non-exhaustive, r=compiler-errors
Non-exhaustive structs may be empty

This is a follow-up to a discrepancy noticed in https://github.com/rust-lang/rust/pull/122792: today, the following struct is considered inhabited (non-empty) outside its defining crate:
```rust
#[non_exhaustive]
pub struct UninhabitedStruct {
    pub never: !,
    // other fields
}
```

`#[non_exhaustive]` on a struct should mean that adding fields to it isn't a breaking change. There is no way that adding fields to this struct could make it non-empty since the `never` field must stay and is inconstructible. I suspect this was implemented this way due to confusion with `#[non_exhaustive]` enums, which indeed should be considered non-empty outside their defining crate.

I propose that we consider such a struct uninhabited (empty), just like it would be without the `#[non_exhaustive]` annotation.

Code that doesn't pass today and will pass after this:
```rust
// In a different crate
fn empty_match_on_empty_struct<T>(x: UninhabitedStruct) -> T {
    match x {}
}
```

This is not a breaking change.

r? ``@compiler-errors``
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs4
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs8
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs10
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs9
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr19
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs21
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr66
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs26
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr65
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs21
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs23
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.stderr39
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs5
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr10
16 files changed, 135 insertions, 207 deletions
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 698104b0462..dd00db8635f 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -81,10 +81,6 @@ impl<'tcx> VariantDef {
         adt: ty::AdtDef<'_>,
     ) -> InhabitedPredicate<'tcx> {
         debug_assert!(!adt.is_union());
-        if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
-            // Non-exhaustive variants from other crates are always considered inhabited.
-            return InhabitedPredicate::True;
-        }
         InhabitedPredicate::all(
             tcx,
             self.fields.iter().map(|field| {
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d7885e05a2f..6c09f97bfe7 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -229,17 +229,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     } else {
                         let variant =
                             &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
-
-                        // In the cases of either a `#[non_exhaustive]` field list or a non-public
-                        // field, we skip uninhabited fields in order not to reveal the
-                        // uninhabitedness of the whole variant.
-                        let is_non_exhaustive =
-                            variant.is_field_list_non_exhaustive() && !adt.did().is_local();
                         let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
                             let is_visible =
                                 adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
                             let is_uninhabited = cx.is_uninhabited(*ty);
-                            let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
+                            let skip = is_uninhabited && !is_visible;
                             (ty, PrivateUninhabitedField(skip))
                         });
                         cx.dropless_arena.alloc_from_iter(tys)
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
index a2735d4cbfb..e1799761b69 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
@@ -7,11 +7,17 @@ pub enum UninhabitedEnum {
 
 #[non_exhaustive]
 pub struct UninhabitedStruct {
-    _priv: !,
+    pub never: !,
+    _priv: (),
 }
 
 #[non_exhaustive]
-pub struct UninhabitedTupleStruct(!);
+pub struct PrivatelyUninhabitedStruct {
+    never: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(pub !);
 
 pub enum UninhabitedVariants {
     #[non_exhaustive] Tuple(!),
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
index 66e93291c72..f332e6deeb8 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
@@ -5,7 +5,7 @@ LL |     match x {}
    |           ^
    |
 note: `IndirectUninhabitedEnum` defined here
-  --> $DIR/auxiliary/uninhabited.rs:26:1
+  --> $DIR/auxiliary/uninhabited.rs:32:1
    |
 LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL |     match x {}
    |           ^
    |
 note: `IndirectUninhabitedStruct` defined here
-  --> $DIR/auxiliary/uninhabited.rs:28:1
+  --> $DIR/auxiliary/uninhabited.rs:34:1
    |
 LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +43,7 @@ LL |     match x {}
    |           ^
    |
 note: `IndirectUninhabitedTupleStruct` defined here
-  --> $DIR/auxiliary/uninhabited.rs:30:1
+  --> $DIR/auxiliary/uninhabited.rs:36:1
    |
 LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL |     match x {}
    |           ^
    |
 note: `IndirectUninhabitedVariants` defined here
-  --> $DIR/auxiliary/uninhabited.rs:32:1
+  --> $DIR/auxiliary/uninhabited.rs:38:1
    |
 LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
index 745b196a0e3..48f3857bfa7 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
@@ -5,7 +5,7 @@ LL |     match x {}
    |           ^
    |
 note: `IndirectUninhabitedEnum` defined here
-  --> $DIR/auxiliary/uninhabited.rs:26:1
+  --> $DIR/auxiliary/uninhabited.rs:32:1
    |
 LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL |     match x {}
    |           ^
    |
 note: `IndirectUninhabitedStruct` defined here
-  --> $DIR/auxiliary/uninhabited.rs:28:1
+  --> $DIR/auxiliary/uninhabited.rs:34:1
    |
 LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +43,7 @@ LL |     match x {}
    |           ^
    |
 note: `IndirectUninhabitedTupleStruct` defined here
-  --> $DIR/auxiliary/uninhabited.rs:30:1
+  --> $DIR/auxiliary/uninhabited.rs:36:1
    |
 LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL |     match x {}
    |           ^
    |
 note: `IndirectUninhabitedVariants` defined here
-  --> $DIR/auxiliary/uninhabited.rs:32:1
+  --> $DIR/auxiliary/uninhabited.rs:38:1
    |
 LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs
index fd77fab8738..6bee019e897 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs
@@ -11,11 +11,12 @@ use uninhabited::PartiallyInhabitedVariants;
 
 pub fn foo(x: PartiallyInhabitedVariants) {
     match x {
-        PartiallyInhabitedVariants::Struct { .. } => {},
-        PartiallyInhabitedVariants::Struct { .. } => {},
+        PartiallyInhabitedVariants::Struct { .. } => {}
         //~^ ERROR unreachable pattern
-        _ => {},
+        PartiallyInhabitedVariants::Struct { .. } => {}
+        //~^ ERROR unreachable pattern
+        _ => {}
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr
index 956725fc10e..4fa53101a55 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr
@@ -1,16 +1,23 @@
 error: unreachable pattern
-  --> $DIR/issue-65157-repeated-match-arm.rs:15:9
+  --> $DIR/issue-65157-repeated-match-arm.rs:14:9
    |
-LL |         PartiallyInhabitedVariants::Struct { .. } => {},
-   |         ----------------------------------------- matches all the relevant values
-LL |         PartiallyInhabitedVariants::Struct { .. } => {},
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this
+LL |         PartiallyInhabitedVariants::Struct { .. } => {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `PartiallyInhabitedVariants` is uninhabited
    |
+   = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
 note: the lint level is defined here
   --> $DIR/issue-65157-repeated-match-arm.rs:2:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error: unreachable pattern
+  --> $DIR/issue-65157-repeated-match-arm.rs:16:9
+   |
+LL |         PartiallyInhabitedVariants::Struct { .. } => {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `PartiallyInhabitedVariants` is uninhabited
+   |
+   = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs
index c330f3aa05c..58d7bbd2c17 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs
@@ -3,12 +3,7 @@
 
 extern crate uninhabited;
 
-use uninhabited::{
-    UninhabitedEnum,
-    UninhabitedStruct,
-    UninhabitedTupleStruct,
-    UninhabitedVariants,
-};
+use uninhabited::*;
 
 struct A;
 
@@ -19,16 +14,20 @@ 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 empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
+    match x {}
 }
 
-fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+fn cannot_empty_match_on_privately_empty_struct(x: PrivatelyUninhabitedStruct) -> 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 empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
+    match x {}
+}
+
+fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
+    match x {}
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr
index c125756a646..0232e7106aa 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr
@@ -1,15 +1,15 @@
-error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
-  --> $DIR/match.rs:19:11
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
+  --> $DIR/match.rs:14:11
    |
 LL |     match x {}
    |           ^
    |
-note: `UninhabitedEnum` defined here
+note: `uninhabited::UninhabitedEnum` defined here
   --> $DIR/auxiliary/uninhabited.rs:5:1
    |
 LL | pub enum UninhabitedEnum {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+   = note: the matched value is of type `uninhabited::UninhabitedEnum`, which is marked as non-exhaustive
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
    |
 LL ~     match x {
@@ -17,18 +17,18 @@ LL +         _ => todo!(),
 LL ~     }
    |
 
-error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
-  --> $DIR/match.rs:23:11
+error[E0004]: non-exhaustive patterns: type `uninhabited::PrivatelyUninhabitedStruct` is non-empty
+  --> $DIR/match.rs:22:11
    |
 LL |     match x {}
    |           ^
    |
-note: `UninhabitedStruct` defined here
-  --> $DIR/auxiliary/uninhabited.rs:9:1
+note: `uninhabited::PrivatelyUninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:15:1
    |
-LL | pub struct UninhabitedStruct {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedStruct`
+LL | pub struct PrivatelyUninhabitedStruct {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: the matched value is of type `uninhabited::PrivatelyUninhabitedStruct`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
    |
 LL ~     match x {
@@ -36,48 +36,6 @@ LL +         _ => todo!(),
 LL ~     }
    |
 
-error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
-  --> $DIR/match.rs:27:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `UninhabitedTupleStruct` defined here
-  --> $DIR/auxiliary/uninhabited.rs:14:1
-   |
-LL | pub struct UninhabitedTupleStruct(!);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedTupleStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-  --> $DIR/match.rs:31:11
-   |
-LL |     match x {}
-   |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-   |
-note: `UninhabitedVariants` defined here
-  --> $DIR/auxiliary/uninhabited.rs:16:1
-   |
-LL | pub enum UninhabitedVariants {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     #[non_exhaustive] Tuple(!),
-   |                       ----- not covered
-LL |     #[non_exhaustive] Struct { x: ! }
-   |                       ------ not covered
-   = note: the matched value is of type `UninhabitedVariants`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
-   |
-LL ~     match x {
-LL +         UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
-LL ~     }
-   |
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
index 108cac7099e..c214581549c 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
@@ -5,32 +5,28 @@
 extern crate uninhabited;
 
 use uninhabited::{
-    UninhabitedEnum,
-    UninhabitedStruct,
-    UninhabitedTupleStruct,
-    UninhabitedVariants,
+    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 {
+// This test checks that non-exhaustive enums are never considered uninhabited outside their
+// defining crate, and non-exhaustive structs are considered uninhabited the same way as normal
+// ones.
+fn cannot_empty_match_on_non_exhaustive_empty_enum(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 empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
+    match x {}
 }
 
-fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
+    match x {}
 }
 
-fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
+    match x {}
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
index 0c8b14ab69d..d6f0bc724a9 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:21:11
+  --> $DIR/match_with_exhaustive_patterns.rs:17:11
    |
 LL |     match x {}
    |           ^
@@ -17,67 +17,6 @@ LL +         _ => todo!(),
 LL ~     }
    |
 
-error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:25:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `UninhabitedStruct` defined here
-  --> $DIR/auxiliary/uninhabited.rs:9:1
-   |
-LL | pub struct UninhabitedStruct {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:29:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `UninhabitedTupleStruct` defined here
-  --> $DIR/auxiliary/uninhabited.rs:14:1
-   |
-LL | pub struct UninhabitedTupleStruct(!);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedTupleStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-  --> $DIR/match_with_exhaustive_patterns.rs:33:11
-   |
-LL |     match x {}
-   |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-   |
-note: `UninhabitedVariants` defined here
-  --> $DIR/auxiliary/uninhabited.rs:16:1
-   |
-LL | pub enum UninhabitedVariants {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     #[non_exhaustive] Tuple(!),
-   |                       ----- not covered
-LL |     #[non_exhaustive] Struct { x: ! }
-   |                       ------ not covered
-   = note: the matched value is of type `UninhabitedVariants`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
-   |
-LL ~     match x {
-LL +         UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
-LL ~     }
-   |
-
-error: aborting due to 4 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
index 468703c78e0..96620162212 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
@@ -1,5 +1,4 @@
 //@ check-pass
-
 #![deny(unreachable_patterns)]
 #![feature(never_type)]
 
@@ -9,11 +8,12 @@ pub enum UninhabitedEnum {
 
 #[non_exhaustive]
 pub struct UninhabitedStruct {
-    _priv: !,
+    pub never: !,
+    _priv: (),
 }
 
 #[non_exhaustive]
-pub struct UninhabitedTupleStruct(!);
+pub struct UninhabitedTupleStruct(pub !);
 
 pub enum UninhabitedVariants {
     #[non_exhaustive] Tuple(!),
@@ -22,24 +22,21 @@ pub enum 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: UninhabitedEnum) -> A {
+// This checks that `non_exhaustive` annotations do not affect exhaustiveness checking within the
+// defining crate.
+fn empty_match_on_empty_enum(x: UninhabitedEnum) -> A {
     match x {}
 }
 
-fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
     match x {}
 }
 
-fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
     match x {}
 }
 
-fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
     match x {}
 }
 
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
index be55ad51578..edc588777eb 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
@@ -1,14 +1,10 @@
 //@ aux-build:uninhabited.rs
-//@ build-pass (FIXME(62277): could be check-pass?)
 #![deny(unreachable_patterns)]
 
 extern crate uninhabited;
 
 use uninhabited::{
-    PartiallyInhabitedVariants,
-    UninhabitedEnum,
-    UninhabitedStruct,
-    UninhabitedTupleStruct,
+    PartiallyInhabitedVariants, UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct,
     UninhabitedVariants,
 };
 
@@ -32,27 +28,26 @@ 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.
-
+// This test checks that non-exhaustive enums are never considered uninhabited outside their
+// defining crate, and non-exhaustive structs are considered uninhabited the same way as normal
+// ones.
 fn main() {
     match uninhabited_enum() {
-        Some(_x) => (), // This line would normally error.
+        Some(_x) => (), // This would error without `non_exhaustive`
         None => (),
     }
 
     match uninhabited_variant() {
-        Some(_x) => (), // This line would normally error.
+        Some(_x) => (), //~ ERROR unreachable
         None => (),
     }
 
     // This line would normally error.
-    while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {
-    }
+    while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {} //~ ERROR unreachable
 
-    while let Some(_x) = uninhabited_struct() { // This line would normally error.
+    while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable
     }
 
-    while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error.
+    while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable
     }
 }
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.stderr
new file mode 100644
index 00000000000..deaa2ffd927
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.stderr
@@ -0,0 +1,39 @@
+error: unreachable pattern
+  --> $DIR/patterns.rs:41:9
+   |
+LL |         Some(_x) => (),
+   |         ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited
+   |
+   = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
+note: the lint level is defined here
+  --> $DIR/patterns.rs:2:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns.rs:46:15
+   |
+LL |     while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited
+   |
+   = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
+
+error: unreachable pattern
+  --> $DIR/patterns.rs:48:15
+   |
+LL |     while let Some(_x) = uninhabited_struct() {
+   |               ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited
+   |
+   = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
+
+error: unreachable pattern
+  --> $DIR/patterns.rs:51:15
+   |
+LL |     while let Some(_x) = uninhabited_tuple_struct() {
+   |               ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited
+   |
+   = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
index 1194d7b858d..58cced3d23d 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
@@ -6,11 +6,12 @@ pub enum UninhabitedEnum {
 }
 
 #[non_exhaustive]
-pub struct UninhabitedTupleStruct(!);
+pub struct UninhabitedTupleStruct(pub !);
 
 #[non_exhaustive]
 pub struct UninhabitedStruct {
-    _priv: !,
+    pub never: !,
+    _priv: (),
 }
 
 pub enum UninhabitedVariants {
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
index 7e7dc802e7f..38524bf5b95 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:51:9
+  --> $DIR/patterns_same_crate.rs:52:9
    |
 LL |         Some(_x) => (),
    |         ^^^^^^^^ matches no values because `UninhabitedEnum` is uninhabited
@@ -12,7 +12,7 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:56:9
+  --> $DIR/patterns_same_crate.rs:57:9
    |
 LL |         Some(_x) => (),
    |         ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited
@@ -20,7 +20,7 @@ LL |         Some(_x) => (),
    = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:60:15
+  --> $DIR/patterns_same_crate.rs:61:15
    |
 LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited
@@ -28,7 +28,7 @@ LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabite
    = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:64:15
+  --> $DIR/patterns_same_crate.rs:65:15
    |
 LL |     while let Some(_x) = uninhabited_struct() {
    |               ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited
@@ -36,7 +36,7 @@ LL |     while let Some(_x) = uninhabited_struct() {
    = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:67:15
+  --> $DIR/patterns_same_crate.rs:68:15
    |
 LL |     while let Some(_x) = uninhabited_tuple_struct() {
    |               ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited