-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the min_exhaustive_patterns
feature gate
#118803
Conversation
r? @cjgillot (rustbot has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
(I'll create the tracking issue if this is deemed a good idea) |
I haven't looked at the code, one thing that's unclear from reading the description (which is very good :3): you say that references may not point to valid data, and that matching on a place that may not be valid will require an arm in the future. Does this mean that |
That is indeed my intention. But not if that breaks a lot of code. I'll do a crater run to see. FWIW, the lint currently suggests
🥰 |
☔ The latest upstream changes (presumably #118823) made this pull request unmergeable. Please resolve the merge conflicts. |
de5f50b
to
c49123d
Compare
This comment has been minimized.
This comment has been minimized.
This will start warning immediately on stable, right? In that case we should probably get t-lang approval for this. |
Hm... I'm not sure I am a fan of this. I think many people will be confused by why that even makes a difference. The fact that blocks force a place-to-val coercion is not super widely known I think. I think the better proposal would be |
I've started a t-opsem Zulip discussion about this: https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/Matching.20on.20references.20to.20uninhabted.20types |
No, the lint is gated under
Hm, fair. I eventually want to suggest |
Doesn't that just affect whether you can |
Ah yeah it does, but what I meant is that I also only emit it when the feature gate is on. This PR doesn't change anything when the feature gate is off. |
Ah I see, sounds good. No need to involve t-lang then. But it'd still be good to see what t-opsem thinks. My current sense (also based on what @Nilstrieb said above about this being a common pattern) is it may be better to say we assume that all the values in the match expression satisfy their safety invariant. That's usually what we do in Rust, since most Rust is safe code. That would mean only raw pointer derefs and unions fields should stop working with empty matches, which I also assume will cause way fewer regressions. |
Ok! If that's deemed a reasonable assumption then I'd like that too. |
This comment was marked as outdated.
This comment was marked as outdated.
c49123d
to
8587f11
Compare
This comment has been minimized.
This comment has been minimized.
8587f11
to
55df836
Compare
This comment has been minimized.
This comment has been minimized.
55df836
to
944e869
Compare
Alright, I have removed the lint as this will require more decisions. The intent of this feature is to stabilize an uncontroversial subset of I'll clean this up and open a tracking issue so we can merge this and decide what to do about |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
782c768
to
aace614
Compare
This comment was marked as outdated.
This comment was marked as outdated.
aace614
to
a92a331
Compare
Alright, this is ready again! This PR adds a feature gate as per the T-lang experimental feature process. The tracking issue is #119612. @scottmcm is my T-lang liaison for this (as part of the never patterns work). I removed the lint that sparked discussion. Now the feature gate is only about allowing more match arms to be omitted. @rustbot ready |
a92a331
to
95a14d4
Compare
let empty_arms_are_unreachable = place_validity.is_known_valid() && can_omit_empty_arms; | ||
// Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if | ||
// it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`). | ||
let empty_arms_are_unreachable = place_validity.is_known_valid() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was hard to understand what was going on here until i noticed that:
- these bools flipped order
- the old
can_omit_empty_arms
was "inlined" intoempty_arms_are_unreachable
- the new
can_omit_empty_arms
is not enabled for the new min feature gate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried so hard to make it legible :') The new can_omit_empty_arms
is enabled with the feature gate, but only exactly when empty_arms_are_unreachable
is true, i.e. the place must be known_valid
.
I tried to present it as "the base case is can_omit_empty_arms == empty_arms_are_unreachable
, on top of which there are two exceptions" but I guess that wasn't clear
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right -- empty_arms_are_unreachable ||
in the new can_omit_empty_arms
.
@bors r+ |
… r=compiler-errors Add the `min_exhaustive_patterns` feature gate ## Motivation Pattern-matching on empty types is tricky around unsafe code. For that reason, current stable rust conservatively requires arms for empty types in all but the simplest case. It has long been the intention to allow omitting empty arms when it's safe to do so. The [`exhaustive_patterns`](rust-lang#51085) feature allows the omission of all empty arms, but hasn't been stabilized because that was deemed dangerous around unsafe code. ## Proposal This feature aims to stabilize an uncontroversial subset of exhaustive_patterns. Namely: when `min_exhaustive_patterns` is enabled and the data we're matching on is guaranteed to be valid by rust's operational semantics, then we allow empty arms to be omitted. E.g.: ```rust let x: Result<T, !> = foo(); match x { // ok Ok(y) => ..., } let Ok(y) = x; // ok ``` If the place is not guaranteed to hold valid data (namely ptr dereferences, ref dereferences (conservatively) and union field accesses), then we keep stable behavior i.e. we (usually) require arms for the empty cases. ```rust unsafe { let ptr: *const Result<u32, !> = ...; match *ptr { Ok(x) => { ... } Err(_) => { ... } // still required } } let foo: Result<u32, &!> = ...; match foo { Ok(x) => { ... } Err(&_) => { ... } // still required because of the dereference } unsafe { let ptr: *const ! = ...; match *ptr {} // already allowed on stable } ``` Note that we conservatively consider that a valid reference can point to invalid data, hence we don't allow arms of type `&!` and similar cases to be omitted. This could eventually change depending on [opsem decisions](rust-lang/unsafe-code-guidelines#413). Whenever opsem is undecided on a case, we conservatively keep today's stable behavior. I proposed this behavior in the [`never_patterns`](rust-lang#118155) feature gate but it makes sense on its own and could be stabilized more quickly. The two proposals nicely complement each other. ## Unresolved Questions Part of the question is whether this requires an RFC. I'd argue this doesn't need one since there is no design question beyond the intent to omit unreachable patterns, but I'm aware the problem can be framed in ways that require design (I'm thinking of the [original never patterns proposal](https://smallcultfollowing.com/babysteps/blog/2018/08/13/never-patterns-exhaustive-matching-and-uninhabited-types-oh-my/), which would frame this behavior as "auto-nevering" happening). EDIT: I initially proposed a future-compatibility lint as part of this feature, I don't anymore.
…mpiler-errors Rollup of 8 pull requests Successful merges: - rust-lang#118803 (Add the `min_exhaustive_patterns` feature gate) - rust-lang#119286 (show linker output even if the linker succeeds) - rust-lang#119616 (Add a new `wasm32-wasi-preview2` target) - rust-lang#120124 (Split assembly tests for ELF and MachO) - rust-lang#120201 (Bump some deps with syn 1.0 dependencies) - rust-lang#120204 (Builtin macros effectively have implicit #[collapse_debuginfo(yes)]) - rust-lang#120322 (Don't manually resolve async closures in `rustc_resolve`) - rust-lang#120356 (Fix broken markdown in csky-unknown-linux-gnuabiv2.md) r? `@ghost` `@rustbot` modify labels: rollup
… r=compiler-errors Add the `min_exhaustive_patterns` feature gate ## Motivation Pattern-matching on empty types is tricky around unsafe code. For that reason, current stable rust conservatively requires arms for empty types in all but the simplest case. It has long been the intention to allow omitting empty arms when it's safe to do so. The [`exhaustive_patterns`](rust-lang#51085) feature allows the omission of all empty arms, but hasn't been stabilized because that was deemed dangerous around unsafe code. ## Proposal This feature aims to stabilize an uncontroversial subset of exhaustive_patterns. Namely: when `min_exhaustive_patterns` is enabled and the data we're matching on is guaranteed to be valid by rust's operational semantics, then we allow empty arms to be omitted. E.g.: ```rust let x: Result<T, !> = foo(); match x { // ok Ok(y) => ..., } let Ok(y) = x; // ok ``` If the place is not guaranteed to hold valid data (namely ptr dereferences, ref dereferences (conservatively) and union field accesses), then we keep stable behavior i.e. we (usually) require arms for the empty cases. ```rust unsafe { let ptr: *const Result<u32, !> = ...; match *ptr { Ok(x) => { ... } Err(_) => { ... } // still required } } let foo: Result<u32, &!> = ...; match foo { Ok(x) => { ... } Err(&_) => { ... } // still required because of the dereference } unsafe { let ptr: *const ! = ...; match *ptr {} // already allowed on stable } ``` Note that we conservatively consider that a valid reference can point to invalid data, hence we don't allow arms of type `&!` and similar cases to be omitted. This could eventually change depending on [opsem decisions](rust-lang/unsafe-code-guidelines#413). Whenever opsem is undecided on a case, we conservatively keep today's stable behavior. I proposed this behavior in the [`never_patterns`](rust-lang#118155) feature gate but it makes sense on its own and could be stabilized more quickly. The two proposals nicely complement each other. ## Unresolved Questions Part of the question is whether this requires an RFC. I'd argue this doesn't need one since there is no design question beyond the intent to omit unreachable patterns, but I'm aware the problem can be framed in ways that require design (I'm thinking of the [original never patterns proposal](https://smallcultfollowing.com/babysteps/blog/2018/08/13/never-patterns-exhaustive-matching-and-uninhabited-types-oh-my/), which would frame this behavior as "auto-nevering" happening). EDIT: I initially proposed a future-compatibility lint as part of this feature, I don't anymore.
…iaskrgr Rollup of 8 pull requests Successful merges: - rust-lang#107464 (Add `str::Lines::remainder`) - rust-lang#118803 (Add the `min_exhaustive_patterns` feature gate) - rust-lang#119466 (Initial implementation of `str::from_raw_parts[_mut]`) - rust-lang#120053 (Specialize `Bytes` on `StdinLock<'_>`) - rust-lang#120124 (Split assembly tests for ELF and MachO) - rust-lang#120204 (Builtin macros effectively have implicit #[collapse_debuginfo(yes)]) - rust-lang#120322 (Don't manually resolve async closures in `rustc_resolve`) - rust-lang#120356 (Fix broken markdown in csky-unknown-linux-gnuabiv2.md) r? `@ghost` `@rustbot` modify labels: rollup
…iaskrgr Rollup of 8 pull requests Successful merges: - rust-lang#107464 (Add `str::Lines::remainder`) - rust-lang#118803 (Add the `min_exhaustive_patterns` feature gate) - rust-lang#119466 (Initial implementation of `str::from_raw_parts[_mut]`) - rust-lang#120053 (Specialize `Bytes` on `StdinLock<'_>`) - rust-lang#120124 (Split assembly tests for ELF and MachO) - rust-lang#120204 (Builtin macros effectively have implicit #[collapse_debuginfo(yes)]) - rust-lang#120322 (Don't manually resolve async closures in `rustc_resolve`) - rust-lang#120356 (Fix broken markdown in csky-unknown-linux-gnuabiv2.md) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#118803 - Nadrieril:min-exhaustive-patterns, r=compiler-errors Add the `min_exhaustive_patterns` feature gate ## Motivation Pattern-matching on empty types is tricky around unsafe code. For that reason, current stable rust conservatively requires arms for empty types in all but the simplest case. It has long been the intention to allow omitting empty arms when it's safe to do so. The [`exhaustive_patterns`](rust-lang#51085) feature allows the omission of all empty arms, but hasn't been stabilized because that was deemed dangerous around unsafe code. ## Proposal This feature aims to stabilize an uncontroversial subset of exhaustive_patterns. Namely: when `min_exhaustive_patterns` is enabled and the data we're matching on is guaranteed to be valid by rust's operational semantics, then we allow empty arms to be omitted. E.g.: ```rust let x: Result<T, !> = foo(); match x { // ok Ok(y) => ..., } let Ok(y) = x; // ok ``` If the place is not guaranteed to hold valid data (namely ptr dereferences, ref dereferences (conservatively) and union field accesses), then we keep stable behavior i.e. we (usually) require arms for the empty cases. ```rust unsafe { let ptr: *const Result<u32, !> = ...; match *ptr { Ok(x) => { ... } Err(_) => { ... } // still required } } let foo: Result<u32, &!> = ...; match foo { Ok(x) => { ... } Err(&_) => { ... } // still required because of the dereference } unsafe { let ptr: *const ! = ...; match *ptr {} // already allowed on stable } ``` Note that we conservatively consider that a valid reference can point to invalid data, hence we don't allow arms of type `&!` and similar cases to be omitted. This could eventually change depending on [opsem decisions](rust-lang/unsafe-code-guidelines#413). Whenever opsem is undecided on a case, we conservatively keep today's stable behavior. I proposed this behavior in the [`never_patterns`](rust-lang#118155) feature gate but it makes sense on its own and could be stabilized more quickly. The two proposals nicely complement each other. ## Unresolved Questions Part of the question is whether this requires an RFC. I'd argue this doesn't need one since there is no design question beyond the intent to omit unreachable patterns, but I'm aware the problem can be framed in ways that require design (I'm thinking of the [original never patterns proposal](https://smallcultfollowing.com/babysteps/blog/2018/08/13/never-patterns-exhaustive-matching-and-uninhabited-types-oh-my/), which would frame this behavior as "auto-nevering" happening). EDIT: I initially proposed a future-compatibility lint as part of this feature, I don't anymore.
Motivation
Pattern-matching on empty types is tricky around unsafe code. For that reason, current stable rust conservatively requires arms for empty types in all but the simplest case. It has long been the intention to allow omitting empty arms when it's safe to do so. The
exhaustive_patterns
feature allows the omission of all empty arms, but hasn't been stabilized because that was deemed dangerous around unsafe code.Proposal
This feature aims to stabilize an uncontroversial subset of exhaustive_patterns. Namely: when
min_exhaustive_patterns
is enabled and the data we're matching on is guaranteed to be valid by rust's operational semantics, then we allow empty arms to be omitted. E.g.:If the place is not guaranteed to hold valid data (namely ptr dereferences, ref dereferences (conservatively) and union field accesses), then we keep stable behavior i.e. we (usually) require arms for the empty cases.
Note that we conservatively consider that a valid reference can point to invalid data, hence we don't allow arms of type
&!
and similar cases to be omitted. This could eventually change depending on opsem decisions. Whenever opsem is undecided on a case, we conservatively keep today's stable behavior.I proposed this behavior in the
never_patterns
feature gate but it makes sense on its own and could be stabilized more quickly. The two proposals nicely complement each other.Unresolved Questions
Part of the question is whether this requires an RFC. I'd argue this doesn't need one since there is no design question beyond the intent to omit unreachable patterns, but I'm aware the problem can be framed in ways that require design (I'm thinking of the original never patterns proposal, which would frame this behavior as "auto-nevering" happening).
EDIT: I initially proposed a future-compatibility lint as part of this feature, I don't anymore.