Skip to content

Commit 725702e

Browse files
committed
min_exhaustive_patterns
1 parent 57ad505 commit 725702e

File tree

11 files changed

+788
-146
lines changed

11 files changed

+788
-146
lines changed

compiler/rustc_feature/src/unstable.rs

+3
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ declare_features! (
512512
(unstable, macro_metavar_expr, "1.61.0", Some(83527)),
513513
/// Allows `#[marker]` on certain traits allowing overlapping implementations.
514514
(unstable, marker_trait_attr, "1.30.0", Some(29864)),
515+
/// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are
516+
/// unambiguously sound.
517+
(unstable, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", None),
515518
/// A minimal, sound subset of specialization intended to be used by the
516519
/// standard library until the soundness issues with specialization
517520
/// are fixed.

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,8 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
298298
fn is_known_valid_scrutinee(&self, scrutinee: &Expr<'tcx>) -> bool {
299299
use ExprKind::*;
300300
match &scrutinee.kind {
301-
// Both pointers and references can validly point to a place with invalid data.
301+
// Pointers can validly point to a place with invalid data. It is undecided whether
302+
// references can too, so we conservatively assume they can.
302303
Deref { .. } => false,
303304
// Inherit validity of the parent place, unless the parent is an union.
304305
Field { lhs, .. } => {

compiler/rustc_pattern_analysis/src/constructor.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,7 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
10091009
// In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
10101010
// types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
10111011
if !pcx.mcx.tycx.is_exhaustive_patterns_feature_on()
1012+
&& !pcx.mcx.tycx.is_min_exhaustive_patterns_feature_on()
10121013
&& !(pcx.is_scrutinee && matches!(self, Self::NoConstructors))
10131014
{
10141015
// Treat all missing constructors as nonempty.

compiler/rustc_pattern_analysis/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub trait TypeCx: Sized + Clone + fmt::Debug {
6464

6565
fn is_opaque_ty(ty: Self::Ty) -> bool;
6666
fn is_exhaustive_patterns_feature_on(&self) -> bool;
67+
fn is_min_exhaustive_patterns_feature_on(&self) -> bool;
6768

6869
/// The number of fields for this constructor.
6970
fn ctor_arity(&self, ctor: &Constructor<Self>, ty: Self::Ty) -> usize;

compiler/rustc_pattern_analysis/src/rustc.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
119119
// `field.ty()` doesn't normalize after substituting.
120120
let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
121121
let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
122-
let is_uninhabited = cx.tcx.features().exhaustive_patterns && cx.is_uninhabited(ty);
122+
let is_uninhabited = (cx.tcx.features().exhaustive_patterns
123+
|| cx.tcx.features().min_exhaustive_patterns)
124+
&& cx.is_uninhabited(ty);
123125

124126
if is_uninhabited && (!is_visible || is_non_exhaustive) {
125127
None
@@ -873,6 +875,9 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
873875
fn is_exhaustive_patterns_feature_on(&self) -> bool {
874876
self.tcx.features().exhaustive_patterns
875877
}
878+
fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
879+
self.tcx.features().min_exhaustive_patterns
880+
}
876881
fn is_opaque_ty(ty: Self::Ty) -> bool {
877882
matches!(ty.kind(), ty::Alias(ty::Opaque, ..))
878883
}

compiler/rustc_pattern_analysis/src/usefulness.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -1199,17 +1199,23 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
11991199

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

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

12081214
// Analyze the constructors present in this column.
12091215
let ctors = matrix.heads().map(|p| p.ctor());
1210-
let ctors_for_ty = pcx.ctors_for_ty();
1211-
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
12121216
let split_set = ctors_for_ty.split(pcx, ctors);
1217+
1218+
// Decide what constructors to report.
12131219
let all_missing = split_set.present.is_empty();
12141220

12151221
// Build the set of constructors we will specialize with. It must cover the whole type.

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,7 @@ symbols! {
10151015
min_const_fn,
10161016
min_const_generics,
10171017
min_const_unsafe_fn,
1018+
min_exhaustive_patterns,
10181019
min_specialization,
10191020
min_type_alias_impl_trait,
10201021
minnumf32,

0 commit comments

Comments
 (0)