Turn remaining non-structural-const-in-pattern lints into hard errors
This completes the implementation of https://github.com/rust-lang/rust/issues/120362 by turning our remaining future-compat lints into hard errors: indirect_structural_match and pointer_structural_match.
They have been future-compat lints for a while (indirect_structural_match for many years, pointer_structural_match since Rust 1.75 (released Dec 28, 2023)), and have shown up in dependency breakage reports since Rust 1.78 (just released on May 2, 2024). I don't expect a lot of code will still depend on them, but we will of course do a crater run.
A lot of cleanup is now possible in const_to_pat, but that is deferred to a later PR.
Fixes https://github.com/rust-lang/rust/issues/70861
never patterns: suggest `!` patterns on non-exhaustive matches
When a match is non-exhaustive we now suggest never patterns whenever it makes sense.
r? ``@compiler-errors``
match lowering: don't collect test alternatives ahead of time
I'm very happy with this one. Before this, when sorting candidates into the possible test branches, we manually computed `usize` indices to determine in which branch each candidate goes. To make this work we had a first pass that collected the possible alternatives we'd have to deal with, and a second pass that actually sorts the candidates.
In this PR, I replace `usize` indices with a dedicated enum. This makes `sort_candidates` easier to follow, and we don't need the first pass anymore.
r? ``@matthewjasper``
Before, the SwitchInt cases were computed in two passes: if the first
pass accepted e.g. 0..=5 and then 1, the second pass would not accept
0..=5 anymore because 1 would be listed in the SwitchInt options.
Now there's a single pass, so if we sort 0..=5 we must take care to not
sort a subsequent 1.
mark `min_exhaustive_patterns` as complete
This is step 1 and 2 of my [proposal](https://github.com/rust-lang/rust/issues/119612#issuecomment-1918097361) to move `min_exhaustive_patterns` forward. The vast majority of in-tree use cases of `exhaustive_patterns` are covered by `min_exhaustive_patterns`. There are a few cases that still require `exhaustive_patterns` in tests and they're all behind references.
r? ``@ghost``
Make `min_exhaustive_patterns` match `exhaustive_patterns` better
Split off from https://github.com/rust-lang/rust/pull/120742.
There remained two edge cases where `min_exhaustive_patterns` wasn't behaving like `exhaustive_patterns`. This fixes them, and tests the feature in a bunch more cases. I essentially went through all uses of `exhaustive_patterns` to see which ones would be interesting to compare between the two features.
r? `@compiler-errors`
make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern
These arms would never be hit anyway, so the pattern makes little sense. We have had a future-compat lint against float matches in general for a *long* time, so I hope we can get away with immediately making this a hard error.
This is part of implementing https://github.com/rust-lang/rfcs/pull/3535.
Closes https://github.com/rust-lang/rust/issues/41620 by removing the lint.
https://github.com/rust-lang/reference/pull/1456 updates the reference to match.
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`](https://github.com/rust-lang/rust/issues/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](https://github.com/rust-lang/unsafe-code-guidelines/issues/413). Whenever opsem is undecided on a case, we conservatively keep today's stable behavior.
I proposed this behavior in the [`never_patterns`](https://github.com/rust-lang/rust/issues/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.
Fix scoping for let chains in match guards
If let guards were previously represented as a different type of guard in HIR and THIR. This meant that let chains in match guards were not handled correctly because they were treated exactly like normal guards.
- Remove `hir::Guard` and `thir::Guard`.
- Make the scoping different between normal guards and if let guards also check for let chains.
closes#118593
Exhaustiveness: Improve complexity on some wide matches
https://github.com/rust-lang/rust/issues/118437 revealed an exponential case in exhaustiveness checking. While [exponential cases are unavoidable](https://compilercrim.es/rust-np/), this one only showed up after my https://github.com/rust-lang/rust/pull/117611 rewrite of the algorithm. I remember anticipating a case like this and dismissing it as unrealistic, but here we are :').
The tricky match is as follows:
```rust
match command {
BaseCommand { field01: true, .. } => {}
BaseCommand { field02: true, .. } => {}
BaseCommand { field03: true, .. } => {}
BaseCommand { field04: true, .. } => {}
BaseCommand { field05: true, .. } => {}
BaseCommand { field06: true, .. } => {}
BaseCommand { field07: true, .. } => {}
BaseCommand { field08: true, .. } => {}
BaseCommand { field09: true, .. } => {}
BaseCommand { field10: true, .. } => {}
// ...20 more of the same
_ => {}
}
```
To fix this, this PR formalizes a concept of "relevancy" (naming is hard) that was already used to decide what patterns to report. Now we track it for every row, which in wide matches like the above can drastically cut on the number of cases we explore. After this fix, the above match is checked with linear-many cases instead of exponentially-many.
Fixes https://github.com/rust-lang/rust/issues/118437
r? `@cjgillot`
Rewrite exhaustiveness in one pass
This is at least my 4th attempt at this in as many years x) Previous attempts were all too complicated or too slow. But we're finally here!
The previous version of the exhaustiveness algorithm computed reachability for each arm then exhaustiveness of the whole match. Since each of these steps does roughly the same things, this rewrites the algorithm to do them all in one go. I also think this makes things much simpler.
I also rewrote the documentation of the algorithm in depth. Hopefully it's up-to-date and easier to follow now. Plz comment if anything's unclear.
r? `@oli-obk` I think you're one of the rare other people to understand the exhaustiveness algorithm?
cc `@varkor` I know you're not active anymore, but if you feel like having a look you might enjoy this :D
Fixes https://github.com/rust-lang/rust/issues/79307