diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-09-03 19:13:24 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-03 19:13:24 +0200 |
| commit | e7504ac70407c116d35a4faa38f3b03bc62457a6 (patch) | |
| tree | c86eabc37c1dbbe0a3a3d78e145d8e0bbdf5c32f /compiler/rustc_pattern_analysis | |
| parent | 51c686f32b937065b22ac416065733980d936f4c (diff) | |
| parent | 6f6a6bc710e538741aa06d40df6492471e4be8af (diff) | |
| download | rust-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``
Diffstat (limited to 'compiler/rustc_pattern_analysis')
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/rustc.rs | 8 |
1 files changed, 1 insertions, 7 deletions
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) |
