From e9fb744207b64ff60e7f3dcec3897d76131b165a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 20 Jul 2025 14:41:27 +0200 Subject: [PATCH 1/2] Add test --- tests/ui/uninhabited/auxiliary/staged-api.rs | 6 +++++ .../uninhabited-unstable-field.current.stderr | 25 +++++++++++++++++-- ...inhabited-unstable-field.exhaustive.stderr | 25 +++++++++++++++++-- .../uninhabited/uninhabited-unstable-field.rs | 23 ++++++++++++++--- 4 files changed, 71 insertions(+), 8 deletions(-) diff --git a/tests/ui/uninhabited/auxiliary/staged-api.rs b/tests/ui/uninhabited/auxiliary/staged-api.rs index 342ecf020ea5e..925bb1e0c65a0 100644 --- a/tests/ui/uninhabited/auxiliary/staged-api.rs +++ b/tests/ui/uninhabited/auxiliary/staged-api.rs @@ -6,3 +6,9 @@ pub struct Foo { #[unstable(feature = "unstable", issue = "none")] pub field: T, } + +#[unstable(feature = "my_coro_state", issue = "none")] +pub enum MyCoroutineState { + Yielded(Y), + Complete(R), +} diff --git a/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr b/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr index 9e0feb4c473f8..704475ece4846 100644 --- a/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr +++ b/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `Foo` is non-empty - --> $DIR/uninhabited-unstable-field.rs:13:11 + --> $DIR/uninhabited-unstable-field.rs:15:11 | LL | match x {} | ^ @@ -17,6 +17,27 @@ LL + _ => todo!(), LL ~ } | -error: aborting due to 1 previous error +error[E0004]: non-exhaustive patterns: `MyCoroutineState::Complete(_)` not covered + --> $DIR/uninhabited-unstable-field.rs:34:11 + | +LL | match x { + | ^ pattern `MyCoroutineState::Complete(_)` not covered + | +note: `MyCoroutineState` defined here + --> $DIR/auxiliary/staged-api.rs:11:1 + | +LL | pub enum MyCoroutineState { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Yielded(Y), +LL | Complete(R), + | -------- not covered + = note: the matched value is of type `MyCoroutineState` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ MyCoroutineState::Yielded(_) => {}, +LL + MyCoroutineState::Complete(_) => todo!() + | + +error: aborting due to 2 previous errors 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 index 9e0feb4c473f8..704475ece4846 100644 --- a/tests/ui/uninhabited/uninhabited-unstable-field.exhaustive.stderr +++ b/tests/ui/uninhabited/uninhabited-unstable-field.exhaustive.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `Foo` is non-empty - --> $DIR/uninhabited-unstable-field.rs:13:11 + --> $DIR/uninhabited-unstable-field.rs:15:11 | LL | match x {} | ^ @@ -17,6 +17,27 @@ LL + _ => todo!(), LL ~ } | -error: aborting due to 1 previous error +error[E0004]: non-exhaustive patterns: `MyCoroutineState::Complete(_)` not covered + --> $DIR/uninhabited-unstable-field.rs:34:11 + | +LL | match x { + | ^ pattern `MyCoroutineState::Complete(_)` not covered + | +note: `MyCoroutineState` defined here + --> $DIR/auxiliary/staged-api.rs:11:1 + | +LL | pub enum MyCoroutineState { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Yielded(Y), +LL | Complete(R), + | -------- not covered + = note: the matched value is of type `MyCoroutineState` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ MyCoroutineState::Yielded(_) => {}, +LL + MyCoroutineState::Complete(_) => todo!() + | + +error: aborting due to 2 previous errors 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 index 9b507c518ab64..44527319ffd8b 100644 --- a/tests/ui/uninhabited/uninhabited-unstable-field.rs +++ b/tests/ui/uninhabited/uninhabited-unstable-field.rs @@ -1,11 +1,13 @@ //@ aux-build: staged-api.rs //@ revisions: current exhaustive - -#![feature(exhaustive_patterns)] +#![cfg_attr(exhaustive, feature(exhaustive_patterns))] +#![feature(never_type)] +#![feature(my_coro_state)] // Custom feature from `staged-api.rs` +#![deny(unreachable_patterns)] extern crate staged_api; -use staged_api::Foo; +use staged_api::{Foo, MyCoroutineState}; enum Void {} @@ -23,7 +25,20 @@ fn demo2(x: Foo) { // Same as above, but for wildcard. fn demo3(x: Foo) { - match x { _ => {} } + match x { + _ => {} + } +} + +fn unstable_enum(x: MyCoroutineState) { + match x { + //~^ ERROR non-exhaustive patterns + MyCoroutineState::Yielded(_) => {} + } + match x { + MyCoroutineState::Yielded(_) => {} + MyCoroutineState::Complete(_) => {} + } } fn main() {} From 3567ab19a0edb4f6c7ca88157d84caa3e1564326 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 20 Jul 2025 14:28:58 +0200 Subject: [PATCH 2/2] Don't consider unstable fields always-inhabited This reverts the hack in https://github.com/rust-lang/rust/pull/133889 now that `Pin`'s field is no longer public. --- .../rustc_middle/src/ty/inhabitedness/mod.rs | 16 ------- compiler/rustc_pattern_analysis/src/rustc.rs | 7 +-- .../uninhabited-unstable-field.current.stderr | 43 ------------------- ...inhabited-unstable-field.exhaustive.stderr | 43 ------------------- .../uninhabited/uninhabited-unstable-field.rs | 17 ++++---- .../uninhabited-unstable-field.stderr | 40 +++++++++++++++++ 6 files changed, 51 insertions(+), 115 deletions(-) delete mode 100644 tests/ui/uninhabited/uninhabited-unstable-field.current.stderr delete mode 100644 tests/ui/uninhabited/uninhabited-unstable-field.exhaustive.stderr create mode 100644 tests/ui/uninhabited/uninhabited-unstable-field.stderr diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 2a336cc21f492..7eb74b52b44c6 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -43,7 +43,6 @@ //! This code should only compile in modules where the uninhabitedness of `Foo` //! is visible. -use rustc_span::sym; use rustc_type_ir::TyKind::*; use tracing::instrument; @@ -85,21 +84,6 @@ 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. - // HACK: We filter out `rustc_private` fields since with the flag - // `-Zforce-unstable-if-unmarked` we consider all unmarked fields to be - // unstable when building the compiler. - if tcx - .lookup_stability(field.did) - .is_some_and(|stab| stab.is_unstable() && stab.feature != sym::rustc_private) - { - 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 ee72b676b38e1..0c1b0d622f229 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use crate::constructor::Constructor::*; use crate::constructor::{ @@ -238,10 +238,7 @@ 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 is_unstable = cx.tcx.lookup_stability(field.did).is_some_and(|stab| { - stab.is_unstable() && stab.feature != sym::rustc_private - }); - let skip = is_uninhabited && (!is_visible || is_unstable); + let skip = is_uninhabited && !is_visible; (ty, PrivateUninhabitedField(skip)) }); cx.dropless_arena.alloc_from_iter(tys) diff --git a/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr b/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr deleted file mode 100644 index 704475ece4846..0000000000000 --- a/tests/ui/uninhabited/uninhabited-unstable-field.current.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0004]: non-exhaustive patterns: type `Foo` is non-empty - --> $DIR/uninhabited-unstable-field.rs:15:11 - | -LL | match x {} - | ^ - | -note: `Foo` defined here - --> $DIR/auxiliary/staged-api.rs:5:1 - | -LL | pub struct Foo { - | ^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `Foo` -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: `MyCoroutineState::Complete(_)` not covered - --> $DIR/uninhabited-unstable-field.rs:34:11 - | -LL | match x { - | ^ pattern `MyCoroutineState::Complete(_)` not covered - | -note: `MyCoroutineState` defined here - --> $DIR/auxiliary/staged-api.rs:11:1 - | -LL | pub enum MyCoroutineState { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | Yielded(Y), -LL | Complete(R), - | -------- not covered - = note: the matched value is of type `MyCoroutineState` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown - | -LL ~ MyCoroutineState::Yielded(_) => {}, -LL + MyCoroutineState::Complete(_) => todo!() - | - -error: aborting due to 2 previous errors - -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 deleted file mode 100644 index 704475ece4846..0000000000000 --- a/tests/ui/uninhabited/uninhabited-unstable-field.exhaustive.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0004]: non-exhaustive patterns: type `Foo` is non-empty - --> $DIR/uninhabited-unstable-field.rs:15:11 - | -LL | match x {} - | ^ - | -note: `Foo` defined here - --> $DIR/auxiliary/staged-api.rs:5:1 - | -LL | pub struct Foo { - | ^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `Foo` -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: `MyCoroutineState::Complete(_)` not covered - --> $DIR/uninhabited-unstable-field.rs:34:11 - | -LL | match x { - | ^ pattern `MyCoroutineState::Complete(_)` not covered - | -note: `MyCoroutineState` defined here - --> $DIR/auxiliary/staged-api.rs:11:1 - | -LL | pub enum MyCoroutineState { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | Yielded(Y), -LL | Complete(R), - | -------- not covered - = note: the matched value is of type `MyCoroutineState` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown - | -LL ~ MyCoroutineState::Yielded(_) => {}, -LL + MyCoroutineState::Complete(_) => todo!() - | - -error: aborting due to 2 previous errors - -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 index 44527319ffd8b..321b864aa27de 100644 --- a/tests/ui/uninhabited/uninhabited-unstable-field.rs +++ b/tests/ui/uninhabited/uninhabited-unstable-field.rs @@ -1,6 +1,9 @@ //@ aux-build: staged-api.rs -//@ revisions: current exhaustive -#![cfg_attr(exhaustive, feature(exhaustive_patterns))] +//! The field of `Pin` used to be public, which would cause `Pin` to be uninhabited. To remedy +//! this, we temporarily made it so unstable fields are always considered inhabited. This has now +//! been reverted, and this file ensures that we don't special-case unstable fields wrt +//! inhabitedness anymore. +#![feature(exhaustive_patterns)] #![feature(never_type)] #![feature(my_coro_state)] // Custom feature from `staged-api.rs` #![deny(unreachable_patterns)] @@ -13,31 +16,29 @@ enum Void {} fn demo(x: Foo) { match x {} - //~^ ERROR non-exhaustive patterns } -// Ensure that the pattern is not considered unreachable. +// Ensure that the pattern is considered unreachable. fn demo2(x: Foo) { match x { - Foo { .. } => {} + Foo { .. } => {} //~ ERROR unreachable } } // Same as above, but for wildcard. fn demo3(x: Foo) { match x { - _ => {} + _ => {} //~ ERROR unreachable } } fn unstable_enum(x: MyCoroutineState) { match x { - //~^ ERROR non-exhaustive patterns MyCoroutineState::Yielded(_) => {} } match x { MyCoroutineState::Yielded(_) => {} - MyCoroutineState::Complete(_) => {} + MyCoroutineState::Complete(_) => {} //~ ERROR unreachable } } diff --git a/tests/ui/uninhabited/uninhabited-unstable-field.stderr b/tests/ui/uninhabited/uninhabited-unstable-field.stderr new file mode 100644 index 0000000000000..a0c9f9366a6b5 --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-unstable-field.stderr @@ -0,0 +1,40 @@ +error: unreachable pattern + --> $DIR/uninhabited-unstable-field.rs:24:9 + | +LL | Foo { .. } => {} + | ^^^^^^^^^^------ + | | + | matches no values because `Foo` is uninhabited + | help: remove the match arm + | + = 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/uninhabited-unstable-field.rs:9:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/uninhabited-unstable-field.rs:31:9 + | +LL | _ => {} + | ^------ + | | + | matches no values because `Foo` is uninhabited + | help: remove the match arm + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: unreachable pattern + --> $DIR/uninhabited-unstable-field.rs:41:9 + | +LL | MyCoroutineState::Complete(_) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ + | | + | matches no values because `!` is uninhabited + | help: remove the match arm + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: aborting due to 3 previous errors +