Skip to content

Commit

Permalink
min_exhaustive_patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Dec 20, 2023
1 parent f9d52dc commit 944e869
Show file tree
Hide file tree
Showing 11 changed files with 788 additions and 146 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,9 @@ declare_features! (
(unstable, macro_metavar_expr, "1.61.0", Some(83527)),
/// Allows `#[marker]` on certain traits allowing overlapping implementations.
(unstable, marker_trait_attr, "1.30.0", Some(29864)),
/// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are
/// unambiguously sound.
(unstable, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", None),

Check failure on line 517 in compiler/rustc_feature/src/unstable.rs

View workflow job for this annotation

GitHub Actions / PR - mingw-check-tidy

no tracking issue for feature min_exhaustive_patterns
/// A minimal, sound subset of specialization intended to be used by the
/// standard library until the soundness issues with specialization
/// are fixed.
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
fn is_known_valid_scrutinee(&self, scrutinee: &Expr<'tcx>) -> bool {
use ExprKind::*;
match &scrutinee.kind {
// Both pointers and references can validly point to a place with invalid data.
// Pointers can validly point to a place with invalid data. It is undecided whether
// references can too, so we conservatively assume they can.
Deref { .. } => false,
// Inherit validity of the parent place, unless the parent is an union.
Field { lhs, .. } => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_pattern_analysis/src/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,7 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
// In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
// types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
if !pcx.mcx.tycx.is_exhaustive_patterns_feature_on()
&& !pcx.mcx.tycx.is_min_exhaustive_patterns_feature_on()
&& !(pcx.is_scrutinee && matches!(self, Self::NoConstructors))
{
// Treat all missing constructors as nonempty.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_pattern_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub trait TypeCx: Sized + Clone + fmt::Debug {

fn is_opaque_ty(ty: Self::Ty) -> bool;
fn is_exhaustive_patterns_feature_on(&self) -> bool;
fn is_min_exhaustive_patterns_feature_on(&self) -> bool;

/// The number of fields for this constructor.
fn ctor_arity(&self, ctor: &Constructor<Self>, ty: Self::Ty) -> usize;
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
// `field.ty()` doesn't normalize after substituting.
let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
let is_uninhabited = cx.tcx.features().exhaustive_patterns && cx.is_uninhabited(ty);
let is_uninhabited = (cx.tcx.features().exhaustive_patterns
|| cx.tcx.features().min_exhaustive_patterns)
&& cx.is_uninhabited(ty);

if is_uninhabited && (!is_visible || is_non_exhaustive) {
None
Expand Down Expand Up @@ -873,6 +875,9 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
fn is_exhaustive_patterns_feature_on(&self) -> bool {
self.tcx.features().exhaustive_patterns
}
fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
self.tcx.features().min_exhaustive_patterns
}
fn is_opaque_ty(ty: Self::Ty) -> bool {
matches!(ty.kind(), ty::Alias(ty::Opaque, ..))
}
Expand Down
16 changes: 11 additions & 5 deletions compiler/rustc_pattern_analysis/src/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1199,17 +1199,23 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(

debug!("ty: {ty:?}");
let pcx = &PlaceCtxt { mcx, ty, is_scrutinee: is_top_level };
let ctors_for_ty = pcx.ctors_for_ty();
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.

// Whether the place/column we are inspecting is known to contain valid data.
let place_validity = matrix.place_validity[0];
// For backwards compability we allow omitting some empty arms that we ideally shouldn't.
let place_validity = place_validity.allow_omitting_side_effecting_arms();
let mut place_validity = matrix.place_validity[0];
if !mcx.tycx.is_min_exhaustive_patterns_feature_on()
|| (is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors))
{
// For backwards compability we allow omitting some empty arms that we ideally shouldn't.
place_validity = place_validity.allow_omitting_side_effecting_arms();
}

// Analyze the constructors present in this column.
let ctors = matrix.heads().map(|p| p.ctor());
let ctors_for_ty = pcx.ctors_for_ty();
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
let split_set = ctors_for_ty.split(pcx, ctors);

// Decide what constructors to report.
let all_missing = split_set.present.is_empty();

// Build the set of constructors we will specialize with. It must cover the whole type.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,7 @@ symbols! {
min_const_fn,
min_const_generics,
min_const_unsafe_fn,
min_exhaustive_patterns,
min_specialization,
min_type_alias_impl_trait,
minnumf32,
Expand Down
Loading

0 comments on commit 944e869

Please sign in to comment.