diff options
| author | Michael Goulet <michael@errs.io> | 2025-03-18 18:23:32 +0000 | 
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2025-03-18 18:23:36 +0000 | 
| commit | f6107ca17342c34b3fd19bb88e3e57f99b07864e (patch) | |
| tree | 09b21036931d928ca9a939d7f9928810b8127d66 | |
| parent | 75530e9f72a1990ed2305e16fd51d02f47048f12 (diff) | |
| download | rust-f6107ca17342c34b3fd19bb88e3e57f99b07864e.tar.gz rust-f6107ca17342c34b3fd19bb88e3e57f99b07864e.zip  | |
Consider fields to be inhabited if they are unstable
6 files changed, 95 insertions, 1 deletions
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 4a5f6d80f24..329c5af4d1b 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -84,6 +84,15 @@ impl<'tcx> VariantDef { InhabitedPredicate::all( tcx, self.fields.iter().map(|field| { + // Unstable fields are always considered to be inhabited. In the future, + // this could be extended to be conditional on the field being unstable + // only within the module that's querying the inhabitedness, like: + // `let pred = pred.or(InhabitedPredicate::IsUnstable(field.did));` + // but this is unnecessary for now, since it would only affect nightly-only + // code or code within the standard library itself. + if tcx.lookup_stability(field.did).is_some_and(|stab| stab.is_unstable()) { + return InhabitedPredicate::True; + } let pred = tcx.type_of(field.did).instantiate_identity().inhabited_predicate(tcx); if adt.is_enum() { return pred; diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 88194c737a6..68d4d083a74 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -232,7 +232,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { 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; + let is_unstable = cx + .tcx + .lookup_stability(field.did) + .is_some_and(|stab| stab.is_unstable()); + let skip = is_uninhabited && (!is_visible || is_unstable); (ty, PrivateUninhabitedField(skip)) }); cx.dropless_arena.alloc_from_iter(tys) diff --git a/tests/ui/uninhabited/auxiliary/staged-api.rs b/tests/ui/uninhabited/auxiliary/staged-api.rs new file mode 100644 index 00000000000..342ecf020ea --- /dev/null +++ b/tests/ui/uninhabited/auxiliary/staged-api.rs @@ -0,0 +1,8 @@ +#![feature(staged_api)] +#![stable(feature = "stable", since = "1.0.0")] + +#[stable(feature = "stable", since = "1.0.0")] +pub struct Foo<T> { + #[unstable(feature = "unstable", issue = "none")] + pub field: T, +} diff --git a/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr b/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr new file mode 100644 index 00000000000..de9c2a6fcf7 --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr @@ -0,0 +1,22 @@ +error[E0004]: non-exhaustive patterns: type `Foo<Void>` is non-empty + --> $DIR/uninhabited-unstable-field.rs:13:11 + | +LL | match x {} + | ^ + | +note: `Foo<Void>` defined here + --> $DIR/auxiliary/staged-api.rs:5:1 + | +LL | pub struct Foo<T> { + | ^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `Foo<Void>` +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: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/uninhabited/uninhabited-unstable-field.exhaustive.stderr b/tests/ui/uninhabited/uninhabited-unstable-field.exhaustive.stderr new file mode 100644 index 00000000000..9e0feb4c473 --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-unstable-field.exhaustive.stderr @@ -0,0 +1,22 @@ +error[E0004]: non-exhaustive patterns: type `Foo<Void>` is non-empty + --> $DIR/uninhabited-unstable-field.rs:13:11 + | +LL | match x {} + | ^ + | +note: `Foo<Void>` defined here + --> $DIR/auxiliary/staged-api.rs:5:1 + | +LL | pub struct Foo<T> { + | ^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `Foo<Void>` +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: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/uninhabited/uninhabited-unstable-field.rs b/tests/ui/uninhabited/uninhabited-unstable-field.rs new file mode 100644 index 00000000000..9b507c518ab --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-unstable-field.rs @@ -0,0 +1,29 @@ +//@ aux-build: staged-api.rs +//@ revisions: current exhaustive + +#![feature(exhaustive_patterns)] + +extern crate staged_api; + +use staged_api::Foo; + +enum Void {} + +fn demo(x: Foo<Void>) { + match x {} + //~^ ERROR non-exhaustive patterns +} + +// Ensure that the pattern is not considered unreachable. +fn demo2(x: Foo<Void>) { + match x { + Foo { .. } => {} + } +} + +// Same as above, but for wildcard. +fn demo3(x: Foo<Void>) { + match x { _ => {} } +} + +fn main() {}  | 
