Syntactically reject tuple index shorthands in struct patterns to fix a correctness regression
Split out of PR rust-lang/rust#154492. This fixes a correctness regression introduced in PR rust-lang/rust#81235 from 2021. Crater was run in my other PR and didn't report any real regressions (https://github.com/rust-lang/rust/pull/154492#issuecomment-4187544786); a rerun has been issued for a few spurious builds (https://github.com/rust-lang/rust/pull/154492#issuecomment-4237077272) but I'm certain it won't find anything either.
This is a theoretical breaking change that doesn't need any T-lang input IMHO since it's such a minute, niche and crystal clear bug that's not worth bothering them with (such a decision is not unprecedented). I'm adding it to the compatibility section of the release notes as is customary.
The Reference doesn't need updating since it didn't adopt this bug and thus accurately describes this part of the grammar as it used to be before 2021-02-23 and as it's meant to be.
The majority of the diff is doc comment additions & necessary UI test restructurings.
Move and clean up some ui test
`ui/reserved` -> `ui/keyword`
`ui/deref-patterns` -> `ui/pattern/deref-patterns`
`ui/unknown-unstable-lints` -> `ui/lint/unknown-lints`
Tests related to unknown_lints that were located above lint have also been moved to a subdirectory, and duplicate tests have been deleted.
And delete unnecessary `//@ check-fail`
r? Kivooeo
Move tests from `tests/ui/issues/` to appropriate directories
In this PR, I am moving the following test from `tests/ui/issues` directory to the appropriate directories, followed by the addition of issue links at the top and reblessing of the stderr files:
| old-name | new-sub-dir | new-name |
|-|-|-|
| `issue-29516.rs` | `auto-traits/` | `distinct-type-tuple-by-negative-impl.rs` |
| `issue-3874.rs` | `binding/` | `ref-in-let-lhs-in-field.rs` |
| `issue-32782.rs` | `feature-gates/` | `feature-gate-check-nested-macro-invocation.rs` |
| `issue-32782.stderr` | `feature-gates/` | `feature-gate-check-nested-macro-invocation.stderr` |
| `issue-5100.rs` | `pattern/` | `match-errors-derived-error-suppression.rs` |
| `issue-5100.stderr` | `pattern/` | `match-errors-derived-error-suppression.stderr` |
| `issue-21033.rs` | `pattern/` | `match-struct-var-having-boxed-field.rs` |
r? Kivooeo
r? Teapot4195
Update tracking issue number of future-incompatibility lint `unstable_syntax_pre_expansion`
Issue rust-lang/rust#65860 has never been a proper tracking issue, it has always been a normal issue that reported a pass→fail regression which was subsequently fixed and which elicited a discussion spanning 50 comments. Years later the formerly offending errors were reintroduced as warnings which link to said issue (see section *Pre-History* in issue rust-lang/rust#154045 for details).
A few weeks ago I closed this issue (https://github.com/rust-lang/rust/issues/65860#issuecomment-4083652176) in favor of a new super focused & structured tracking issue, rust-lang/rust#154045. That means people now have to jump through hoops to arrive at the new tracking issue which is less than ideal (it's very likely that this user had to do so: https://github.com/rust-lang/rust/issues/154045#issuecomment-4207339422), let's fix that.
Part of rust-lang/rust#154045.
Suggest using equality comparison instead of pattern matching on non-structural constant in pattern
When encountering a pattern containing a non-structural constant (not marked as `#[derive(PartialEq)]` to make it suitable for pattern matching, `C` in the examples below), we would previously not provide additional guidance. With this PR, the `help` in the following examples are added:
```
error: constant of non-structural type `partial_eq::S` in a pattern
--> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:16:18
|
LL | struct S;
| -------- `partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
...
LL | const C: S = S;
| ---------- constant defined here
...
LL | Some(C) => {}
| ^ constant of non-structural type
|
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
--> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:5:5
|
LL | impl PartialEq<S> for S {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add a condition to the match arm checking for equality
|
LL - Some(C) => {}
LL + Some(binding) if binding == C => {}
|
```
```
error: constant of non-structural type `partial_eq::S` in a pattern
--> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:22:18
|
LL | struct S;
| -------- `partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
...
LL | const C: S = S;
| ---------- constant defined here
...
LL | let Some(C) = Some(S) else { return; };
| ^ constant of non-structural type
|
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
--> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:5:5
|
LL | impl PartialEq<S> for S {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: check for equality instead of pattern matching
|
LL - let Some(C) = Some(S) else { return; };
LL + if Some(C) == Some(S) { return; };
|
```
The suggestion accounts for a few conditions:
- if the type is not from the local crate and has no `PartialEq` impl, the user can't make it structural, so we don't provide the suggestion
- regardless of whether the type is local or remote, if it has a manual `PartialEq`, explain that with a derived `PartialEq` you could use equality
- if the type is local and has no impl, suggest adding a derived `PartialEq` and use equality check instead of pattern matching
- when suggesting equality, account for `if-let` to suggest chaining (edition dependent), `match` arm with a present `if` check, `match` arm without an existing `if` check
- when encountering `let-else`, we suggest turning it into an `if` expression instead (this doesn't check for additional bindings beyond the constant, which would suggest incorrect code in some more complex cases).
Fixrust-lang/rust#42753.
Guard patterns: lowering to THIR
This pr implements lowering of guard patterns to THIR
r? @Nadrieril
cc @max-niederman
Tracking issue: rust-lang/rust#129967
```
error: constant of non-structural type `partial_eq::S` in a pattern
--> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:16:18
|
LL | struct S;
| -------- `partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
...
LL | const C: S = S;
| ---------- constant defined here
...
LL | Some(C) => {}
| ^ constant of non-structural type
|
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
--> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:5:5
|
LL | impl PartialEq<S> for S {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add a condition to the match arm checking for equality
|
LL - Some(C) => {}
LL + Some(binding) if binding == C => {}
|
```
stop marking `deref_patterns` as an incomplete feature
This PR removes the `incomplete_feature` warning for `deref_patterns`. The reason given for this in the tracking issue (rust-lang/rust#87121) was
> Per policy, the `incomplete_feature` is supposed to stay on until the feature has an accepted RFC. We're slowly working on writing up that RFC so it'll take some more time unfortunately.
>
> I don't know of any compiler crashes it causes today. The feature should be pretty usable.
However, I could not find any evidence of such a policy. The [lint documentation](https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#incomplete-features) for `incomplete_features` also only mentions features that are more likely to cause errors.
There are also many other features without an RFC that are not considered incomplete, e.g. `macro_metavar_expr_concat`, `negative_impls` or `yeet_expr`.
The feature does not cause any known ICEs either.
The concrete motivation is to use this feature to replace `box_patterns` in the compiler and pave the way towards removing that legacy feature.
Stabilize `if let` guards (`feature(if_let_guard)`)
## Summary
This proposes the stabilization of `if let` guards (tracking issue: rust-lang/rust#51114, RFC: rust-lang/rfcs#2294). This feature allows `if let` expressions to be used directly within match arm guards, enabling conditional pattern matching within guard clauses.
## What is being stabilized
The ability to use `if let` expressions within match arm guards.
Example:
```rust
enum Command {
Run(String),
Stop,
Pause,
}
fn process_command(cmd: Command, state: &mut String) {
match cmd {
Command::Run(name) if let Some(first_char) = name.chars().next() && first_char.is_ascii_alphabetic() => {
// Both `name` and `first_char` are available here
println!("Running command: {} (starts with '{}')", name, first_char);
state.push_str(&format!("Running {}", name));
}
Command::Run(name) => {
println!("Cannot run command '{}'. Invalid name.", name);
}
Command::Stop if state.contains("running") => {
println!("Stopping current process.");
state.clear();
}
_ => {
println!("Unhandled command or state.");
}
}
}
```
## Motivation
The primary motivation for `if let` guards is to reduce nesting and improve readability when conditional logic depends on pattern matching. Without this feature, such logic requires nested `if let` statements within match arms:
```rust
// Without if let guards
match value {
Some(x) => {
if let Ok(y) = compute(x) {
// Both `x` and `y` are available here
println!("{}, {}", x, y);
}
}
_ => {}
}
// With if let guards
match value {
Some(x) if let Ok(y) = compute(x) => {
// Both `x` and `y` are available here
println!("{}, {}", x, y);
}
_ => {}
}
```
## Implementation and Testing
The feature has been implemented and tested comprehensively across different scenarios:
### Core Functionality Tests
**Scoping and variable binding:**
- [`scope.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs) - Verifies that bindings created in `if let` guards are properly scoped and available in match arms
- [`shadowing.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs) - Tests that variable shadowing works correctly within guards
- [`scoping-consistency.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs) - Ensures temporaries in guards remain valid for the duration of their match arms
**Type system integration:**
- [`type-inference.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/type-inference.rs) - Confirms type inference works correctly in `if let` guards
- [`typeck.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs) - Verifies type mismatches are caught appropriately
**Pattern matching semantics:**
- [`exhaustive.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.rs) - Validates that `if let` guards are correctly handled in exhaustiveness analysis
- [`move-guard-if-let.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let.rs) and [`move-guard-if-let-chain.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs) - Test that conditional moves in guards are tracked correctly by the borrow checker
### Error Handling and Diagnostics
- [`warns.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs) - Tests warnings for irrefutable patterns and unreachable code in guards
- [`parens.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs) - Ensures parentheses around `let` expressions are properly rejected
- [`macro-expanded.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs) - Verifies macro expansions that produce invalid constructs are caught
- [`guard-mutability-2.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.rs) - Tests mutability and ownership violations in guards
- [`ast-validate-guards.rs`](5796073c13/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs) - Validates AST-level syntax restrictions
### Drop Order and Temporaries
**Key insight:** Unlike `let_chains` in regular `if` expressions, `if let` guards do not have drop order inconsistencies because:
1. Match guards are clearly scoped to their arms
2. There is no "else block" equivalent that could cause temporal confusion
- [`drop-order.rs`](5796073c13/tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs) - Check drop order of temporaries create in match guards
- [`compare-drop-order.rs`](aef3f5fdf0/tests/ui/rfcs/rfc-2294-if-let-guard/compare-drop-order.rs) - Compares drop order between `if let` guards and nested `if let` in match arms, confirming they behave identically across all editions
- rust-lang/rust#140981 - A complicated drop order test involved `let chain` was made by @est31
- [`drop-order-comparisons-let-chains.rs`](902b4d2878/tests/ui/drop/drop-order-comparisons-let-chains.rs) - Compares drop order between `let chains` in `if let guard` and regular `if` expressions
- [`if-let-guards.rs`](5650d716e0/tests/ui/drop/if-let-guards.rs) - Test correctness of drop order for bindings and temporaries
- [`if-let-guards-2`](3a6c8c8f3d/tests/ui/drop/if-let-guards-2.rs) - The same test as above but more comprehensive and tests more interactions between different features and their drop order, checking that drop order is correct, created by @traviscross
## Edition Compatibility
This feature stabilizes on all editions, unlike `let chains` which was limited to edition 2024. This is safe because:
1. `if let` guards don't suffer from the drop order issues that affected `let chains` in regular `if` expressions
2. The scoping is unambiguous - guards are clearly tied to their match arms
3. Extensive testing confirms identical behavior across all editions
## Interactions with Future Features
The lang team has reviewed potential interactions with planned "guard patterns" and determined that stabilizing `if let` guards now does not create obstacles for future work. The scoping and evaluation semantics established here align with what guard patterns will need.
## Unresolved Issues
- [x] - rust-lang/rust#140981
- [x] - added tests description by @jieyouxu request
- [x] - Concers from @scottmcm about stabilizing this across all editions
- [x] - check if drop order in all edition when using `let chains` inside `if let` guard is the same
- [x] - interactions with guard patters
- [x] - pattern bindings drops before guard bindings https://github.com/rust-lang/rust/pull/143376
- [x] - documentaion (https://github.com/rust-lang/reference/pull/1957)
- [ ] (non-blocking) add tests for [this](https://github.com/rust-lang/rust/issues/145237) and [this](https://github.com/rust-lang/rust/pull/141295#issuecomment-3173059821)
---
**Related:**
- Tracking Issue: rust-lang/rust#51114
- RFC: rust-lang/rfcs#2294
- Documentation PR: https://github.com/rust-lang/reference/pull/1957
Remove "failed to resolve" and use the same format we use in other resolution errors "cannot find `name`".
```
error[E0433]: cannot find `nonexistent` in `existent`
--> $DIR/custom_attr_multisegment_error.rs:5:13
|
LL | #[existent::nonexistent]
| ^^^^^^^^^^^ could not find `nonexistent` in `existent`
```
Fix suppression of `unused_assignment` in binding of `unused_variable`
Unused assignments to an unused variable should trigger only the `unused_variables` lint and not also the `unused_assignments` lint. This was previously implemented by checking whether the span of the assignee was within the span of the binding pattern, however that failed to capture situations was imported from elsewhere (eg from the input tokenstream of a proc-macro that generates the binding pattern).
By comparing the span of the assignee to those of the variable introductions instead, a reported stable-to-stable regression is resolved.
This fix also impacted some other preexisting tests, which had (undesirably) been triggering both the `unused_variables` and `unused_assignments` lints on the same initializing assignment; those tests have therefore now been updated to expect only the former lint.
Fixesrust-lang/rust#151514
r? cjgillot (as author of reworked liveness testing in rust-lang/rust#142390)
Unused assignments to an unused variable should trigger only the
`unused_variables` lint and not also the `unused_assignments` lint.
This was previously implemented by checking whether the span of the
assignee was within the span of the binding pattern, however that failed
to capture situations was imported from elsewhere (eg from the input
tokenstream of a proc-macro that generates the binding pattern).
By comparing the span of the assignee to those of the variable
introductions instead, a reported stable-to-stable regression is
resolved.
This fix also impacted some other preexisting tests, which had
(undesirably) been triggering both the `unused_variables` and
`unused_assignments` lints on the same initializing assignment; those
tests have therefore now been updated to expect only the former lint.
Avoid ICEs after bad patterns, for the other syntactic variants
This PR introduces changes equivalent to the ones in rust-lang/rust#126320, but also for struct and tuple patterns, instead of tuple struct patterns only.
Fixesrust-lang/rust#150507.
Fix ICE by rejecting const blocks in patterns during AST lowering (closes#148138)
This PR fixes the ICE reported in rust-lang/rust#148138.
The root cause is that `const` blocks aren’t allowed in pattern position, but the AST lowering logic still attempted to create `PatExprKind::ConstBlock`, allowing invalid HIR to reach type checking and trigger a `span_bug!`.
Following the discussion in the issue, this patch removes the `ConstBlock` lowering path from `lower_expr_within_pat`. Any `ExprKind::ConstBlock` inside a pattern is now handled consistently with other invalid pattern expressions.
A new UI test is included to ensure the compiler reports a proper error and to prevent regressions.
Closesrust-lang/rust#148138.
This fixes the ICE reported by rejecting `const` blocks in
pattern position during AST lowering.
Previously, `ExprKind::ConstBlock` could reach HIR as `PatExprKind::ConstBlock`,
allowing invalid patterns to be type-checked and triggering an ICE.
This patch removes the lowering path for const blocks in patterns
and emits a proper diagnostic instead.
A new UI test is added to ensure the compiler reports a regular error
and to prevent regressions.
Suggest struct pattern when destructuring Range with .. syntax
implemented a new diagnostic in rustc_resolve to detect invalid range destructuring attempts (e.g., let start..end = range). The fix identifies when resolution fails for identifiers acting as range bounds specifically handling cases where bounds are parsed as expressions and suggests the correct struct pattern syntax (std::ops::Range { start, end }). This replaces confusing "cannot find value" errors with actionable help, verified by a new UI test covering various identifier names.
Fixesrust-lang/rust#149777
Tidying up tests/ui/issues 14 tests [5/N]
> [!NOTE]
> Intermediate commits are intended to help review, but will be squashed add comment commit prior to merge.
part of rust-lang/rust#133895
move `tests/ui/inherent-impls-overlap-check` to `tests/ui/duplicate/inherent-impls-overlap-check`.
r? Kivooeo
Tidying up tests/ui/issues 33 tests [4/N]
> [!NOTE]
> Intermediate commits are intended to help review, but will be squashed add comment commit prior to merge.
part of rust-lang/rust#133895
`tests/ui/compile-flags` split it into `tests/ui/compile-flags/invalid/` and `tests/ui/compile-flags/run-pass/`
r? Kivooeo