Commit Graph

594 Commits

Author SHA1 Message Date
Lukas Wirth
edc405d383 Add expectation for { when parsing lone coroutine qualifiers 2025-06-11 17:11:58 +02:00
Guillaume Gomez
93ca0af08c Rollup merge of #141603 - nnethercote:reduce-P, r=fee1-dead
Reduce `ast::ptr::P` to a typedef of `Box`

As per the MCP at https://github.com/rust-lang/compiler-team/issues/878.

r? `@fee1-dead`
2025-06-06 23:53:16 +02:00
Nicholas Nethercote
04391045d0 Remove Path::is_ident.
It checks that a path has a single segment that matches the given
symbol, and that there are zero generic arguments. It has a single use.

We also have `impl PartialEq<Symbol> for Path` which does exactly the
same thing *except* it doesn't check for zero generic arguments, which
seems like an oversight. It has numerous uses.

This commit removes `Path::is_ident`, adds a test for zero generic
arguments to `PartialEq<Symbol> for Path`, and changes the single use of
`is_ident` to instead use `==`.
2025-06-03 15:21:33 +10:00
Nicholas Nethercote
991c91fdaa Reduce P<T> to a typedef of Box<T>.
Keep the `P` constructor function for now, to minimize immediate churn.

All the `into_inner` calls are removed, which is nice.
2025-05-27 13:29:24 +10:00
Nicholas Nethercote
0f285e346f Remove the one use of P<[T]>.
A `Vec` is fine, the additional word (vector vs. boxed slice) doesn't
matter here.
2025-05-27 02:54:18 +10:00
yukang
5f8954bc41 Fix the issue of typo of comma in arm parsing 2025-05-16 12:40:04 +02:00
Nicholas Nethercote
0984db553d Remove Ident::empty.
All uses have been removed. And it's nonsensical: an identifier by
definition has at least one char.

The commits adds an is-non-empty assertion to `Ident::new` to enforce
this, and converts some `Ident` constructions to use `Ident::new`.
Adding the assertion requires making `Ident::new` and
`Ident::with_dummy_span` non-const, which is no great loss.

The commit amends a couple of places that do path splitting to ensure no
empty identifiers are created.
2025-05-09 13:57:49 +10:00
Kivooeo
f072d30741 resolved conflict 2025-04-25 17:02:59 +05:00
Chris Denton
15f8847a25 Rollup merge of #140144 - nnethercote:fix-140098, r=petrochenkov
Handle another negated literal in `eat_token_lit`.

Extends the change from #139653, which was on expressions, to literals.

Fixes #140098.

r? ``@petrochenkov``
2025-04-22 15:24:08 +00:00
bors
8bf5a8d12f Auto merge of #132833 - est31:stabilize_let_chains, r=fee1-dead
Stabilize let chains in the 2024 edition

# Stabilization report

This proposes the stabilization of `let_chains` ([tracking issue], [RFC 2497]) in the [2024 edition] of Rust.

[tracking issue]: https://github.com/rust-lang/rust/issues/53667
[RFC 2497]: https://github.com/rust-lang/rfcs/pull/2497
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html

## What is being stabilized

The ability to `&&`-chain `let` statements inside `if` and `while` is being stabilized, allowing intermixture with boolean expressions. The patterns inside the `let` sub-expressions can be irrefutable or refutable.

```Rust
struct FnCall<'a> {
    fn_name: &'a str,
    args: Vec<i32>,
}

fn is_legal_ident(s: &str) -> bool {
    s.chars()
        .all(|c| ('a'..='z').contains(&c) || ('A'..='Z').contains(&c))
}

impl<'a> FnCall<'a> {
    fn parse(s: &'a str) -> Option<Self> {
        if let Some((fn_name, after_name)) = s.split_once("(")
            && !fn_name.is_empty()
            && is_legal_ident(fn_name)
            && let Some((args_str, "")) = after_name.rsplit_once(")")
        {
            let args = args_str
                .split(',')
                .map(|arg| arg.parse())
                .collect::<Result<Vec<_>, _>>();
            args.ok().map(|args| FnCall { fn_name, args })
        } else {
            None
        }
    }
    fn exec(&self) -> Option<i32> {
        let iter = self.args.iter().copied();
        match self.fn_name {
            "sum" => Some(iter.sum()),
            "max" => iter.max(),
            "min" => iter.min(),
            _ => None,
        }
    }
}

fn main() {
    println!("{:?}", FnCall::parse("sum(1,2,3)").unwrap().exec());
    println!("{:?}", FnCall::parse("max(4,5)").unwrap().exec());
}
```

The feature will only be stabilized for the 2024 edition and future editions. Users of past editions will get an error with a hint to update the edition.

closes #53667

## Why 2024 edition?

Rust generally tries to ship new features to all editions. So even the oldest editions receive the newest features. However, sometimes a feature requires a breaking change so much that offering the feature without the breaking change makes no sense. This occurs rarely, but has happened in the 2018 edition already with `async` and `await` syntax. It required an edition boundary in order for `async`/`await` to become keywords, and the entire feature foots on those keywords.

In the instance of let chains, the issue is the drop order of `if let` chains. If we want `if let` chains to be compatible with `if let`, drop order makes it hard for us to [generate correct MIR]. It would be strange to have different behaviour for `if let ... {}` and `if true && let ... {}`. So it's better to [stay consistent with `if let`].

In edition 2024, [drop order changes] have been introduced to make `if let` temporaries be lived more shortly. These changes also affected `if let` chains. These changes make sense even if you don't take the `if let` chains MIR generation problem into account. But if we want to use them as the solution to the MIR generation problem, we need to restrict let chains to edition 2024 and beyond: for let chains, it's not just a change towards more sensible behaviour, but one required for correct function.

[generate correct MIR]: https://github.com/rust-lang/rust/issues/104843
[stay consistent with `if let`]: https://github.com/rust-lang/rust/pull/103293#issuecomment-1293408574
[drop order changes]: https://github.com/rust-lang/rust/issues/124085

## Introduction considerations

As edition 2024 is very new, this stabilization PR only makes it possible to use let chains on 2024 without that feature gate, it doesn't mark that feature gate as stable/removed. I would propose to continue offering the `let_chains` feature (behind a feature gate) for a limited time (maybe 3 months after stabilization?) on older editions to allow nightly users to adopt edition 2024 at their own pace. After that, the feature gate shall be marked as *stabilized*, not removed, and replaced by an error on editions 2021 and below.

## Implementation history

* History from before March 14, 2022 can be found in the [original stabilization PR] that was reverted.
* https://github.com/rust-lang/rust/pull/94927
* https://github.com/rust-lang/rust/pull/94951
* https://github.com/rust-lang/rust/pull/94974
* https://github.com/rust-lang/rust/pull/95008
* https://github.com/rust-lang/rust/pull/97295
* https://github.com/rust-lang/rust/pull/98633
* https://github.com/rust-lang/rust/pull/99731
* https://github.com/rust-lang/rust/pull/102394
* https://github.com/rust-lang/rust/pull/100526
* https://github.com/rust-lang/rust/pull/100538
* https://github.com/rust-lang/rust/pull/102998
* https://github.com/rust-lang/rust/pull/103405
* https://github.com/rust-lang/rust/pull/103293
* https://github.com/rust-lang/rust/pull/107251
* https://github.com/rust-lang/rust/pull/110568
* https://github.com/rust-lang/rust/pull/115677
* https://github.com/rust-lang/rust/pull/117743
* https://github.com/rust-lang/rust/pull/117770
* https://github.com/rust-lang/rust/pull/118191
* https://github.com/rust-lang/rust/pull/119554
* https://github.com/rust-lang/rust/pull/129394
* https://github.com/rust-lang/rust/pull/132828
* https://github.com/rust-lang/reference/pull/1179
* https://github.com/rust-lang/reference/pull/1251
* https://github.com/rust-lang/rustfmt/pull/5910

[original stabilization PR]: https://github.com/rust-lang/rust/pull/94927

## Adoption history

### In the compiler

* History before March 14, 2022 can be found in the [original stabilization PR].
* https://github.com/rust-lang/rust/pull/115983
* https://github.com/rust-lang/rust/pull/116549
* https://github.com/rust-lang/rust/pull/116688

### Outside of the compiler

* https://github.com/rust-lang/rust-clippy/pull/11750
* [rspack](https://github.com/web-infra-dev/rspack)
* [risingwave](https://github.com/risingwavelabs/risingwave)
* [dylint](https://github.com/trailofbits/dylint)
* [convex-backend](https://github.com/get-convex/convex-backend)
* [tikv](https://github.com/tikv/tikv)
* [Daft](https://github.com/Eventual-Inc/Daft)
* [greptimedb](https://github.com/GreptimeTeam/greptimedb)

## Tests

<details>

### Intentional restrictions

[`partially-macro-expanded.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs), [`macro-expanded.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs): it is possible to use macros to expand to both the pattern and the expression inside a let chain, but not to the entire `let pat = expr` operand.
[`parens.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs): `if (let pat = expr)` is not allowed in chains
[`ensure-that-let-else-does-not-interact-with-let-chains.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs): `let...else` doesn't support chaining.

### Overlap with match guards

[`move-guard-if-let-chain.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs): test for the `use moved value` error working well in match guards. could maybe be extended with let chains that have more than one `let`
[`shadowing.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs): shadowing in if let guards works as expected
[`ast-validate-guards.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs): let chains in match guards require the match guards feature gate

### Simple cases from the early days

PR #88642 has added some tests with very simple usages of `let else`, mostly as regression tests to early bugs.

[`then-else-blocks.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs)
[`ast-lowering-does-not-wrap-let-chains.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs)
[`issue-90722.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs)
[`issue-92145.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs)

### Drop order/MIR scoping tests

[`issue-100276.rs`](4adafcf40a/tests/ui/drop/issue-100276.rs): let expressions on RHS aren't terminating scopes
[`drop_order.rs`](4adafcf40a/tests/ui/drop/drop_order.rs): exhaustive temporary drop order test for various Rust constructs, including let chains
[`scope.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs): match guard scoping test
[`drop-scope.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs): another match guard scoping test, ensuring that temporaries in if-let guards live for the arm
[`drop_order_if_let_rescope.rs`](4adafcf40a/tests/ui/drop/drop_order_if_let_rescope.rs): if let rescoping on edition 2024, including chains
[`mir_let_chains_drop_order.rs`](4adafcf40a/tests/ui/mir/mir_let_chains_drop_order.rs): comprehensive drop order test for let chains, distinguishes editions 2021 and 2024.
[`issue-99938.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs), [`issue-99852.rs`](4adafcf40a/tests/ui/mir/issue-99852.rs) both bad MIR ICEs fixed by #102394

### Linting

[`irrefutable-lets.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs): trailing and leading irrefutable let patterns get linted for, others don't. The lint is turned off for `else if`.
[`issue-121070-let-range.rs`](4adafcf40a/tests/ui/lint/issue-121070-let-range.rs): regression test for false positive of the unused parens lint, precedence requires the `()`s here

### Parser: intentional restrictions

[`disallowed-positions.rs`](2128d8df0e/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs): `let` in expression context is rejected everywhere except at the top level
[`invalid-let-in-a-valid-let-context.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs): nested `let` is not allowed (let's are no legal expressions just because they are allowed in `if` and `while`).

### Parser: recovery

[`issue-103381.rs`](4adafcf40a/tests/ui/parser/issues/issue-103381.rs): Graceful recovery of incorrect chaining of `if` and `if let`
[`semi-in-let-chain.rs`](4adafcf40a/tests/ui/parser/semi-in-let-chain.rs): Ensure that stray `;`s in let chains give nice errors (`if_chain!` users might be accustomed to `;`s)
[`deli-ident-issue-1.rs`](4adafcf40a/tests/ui/parser/deli-ident-issue-1.rs), [`brace-in-let-chain.rs`](4adafcf40a/tests/ui/parser/brace-in-let-chain.rs): Ensure that stray unclosed `{`s in let chains give nice errors and hints

### Misc

[`conflicting_bindings.rs`](4adafcf40a/tests/ui/pattern/usefulness/conflicting_bindings.rs): the conflicting bindings check also works in let chains. Personally, I'd extend it to chains with multiple let's as well.
[`let-chains-attr.rs`](4adafcf40a/tests/ui/expr/if/attrs/let-chains-attr.rs): attributes work on let chains

### Tangential tests with `#![feature(let_chains)]`

[`if-let.rs`](4adafcf40a/tests/coverage/branch/if-let.rs): MC/DC coverage tests for let chains
[`logical_or_in_conditional.rs`](4adafcf40a/tests/mir-opt/building/logical_or_in_conditional.rs): not really about let chains, more about dropping/scoping behaviour of `||`
[`stringify.rs`](4adafcf40a/tests/ui/macros/stringify.rs): exhaustive test of the `stringify` macro
[`expanded-interpolation.rs`](4adafcf40a/tests/ui/unpretty/expanded-interpolation.rs), [`expanded-exhaustive.rs`](4adafcf40a/tests/ui/unpretty/expanded-exhaustive.rs): Exhaustive test of `-Zunpretty`
[`diverges-not.rs`](4adafcf40a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs): Never type, mostly tangential to let chains

</details>

## Possible future work

* There is proposals to allow `if let Pat(bindings) = expr {}` to be written as `if expr is Pat(bindings) {}` ([RFC 3573]). `if let` chains are a natural extension of the already existing `if let` syntax, and I'd argue orthogonal towards `is` syntax.
  * https://github.com/rust-lang/lang-team/issues/297
* One could have similar chaining inside `let ... else` statements. There is no proposed RFC for this however, nor is it implemented on nightly.
* Match guards have the `if` keyword as well, but on stable Rust, they don't support `let`. The functionality is available via an unstable feature ([`if_let_guard` tracking issue]). Stabilization of let chains affects this feature in so far as match guards containing let chains now only need the `if_let_guard` feature gate be present instead of also the `let_chains` feature (NOTE: this PR doesn't implement this simplification, it's left for future work).

[RFC 3573]: https://github.com/rust-lang/rfcs/pull/3573
[`if_let_guard` tracking issue]: https://github.com/rust-lang/rust/issues/51114

## Open questions / blockers

- [ ] bad recovery if you don't put a `let` (I don't think this is a blocker): [#117977](https://github.com/rust-lang/rust/issues/117977)
- [x] An instance where a temporary lives shorter than with nested ifs, breaking compilation: [#103476](https://github.com/rust-lang/rust/issues/103476). Personally I don't think this is a blocker either, as it's an edge case. Edit: turns out to not reproduce in edition 2025 any more, due to let rescoping. regression test added in #133093
- [x] One should probably extend the tests for `move-guard-if-let-chain.rs` and `conflicting_bindings.rs` to have chains with multiple let's: done in 133093
- [x] Parsing rejection tests: addressed by https://github.com/rust-lang/rust/pull/132828
- [x] [Style](https://rust-lang.zulipchat.com/#narrow/channel/346005-t-style/topic/let.20chains.20stabilization.20and.20formatting): https://github.com/rust-lang/rust/pull/139456
- [x] https://github.com/rust-lang/rust/issues/86730 explicitly mentions `let_else`. I think we can live with `let pat = expr` not evaluating as `expr` for macro_rules macros, especially given that `let pat = expr` is not a legal expression anywhere except inside `if` and `while`.
- [x] Documentation in the reference: https://github.com/rust-lang/reference/pull/1740
- [x] Add chapter to the Rust 2024 [edition guide]: https://github.com/rust-lang/edition-guide/pull/337
- [x] Resolve open questions on desired drop order.

[original reference PR]: https://github.com/rust-lang/reference/pull/1179
[edition guide]: https://github.com/rust-lang/edition-guide
2025-04-22 07:54:10 +00:00
Nicholas Nethercote
6be270be0c Handle another negated literal in eat_token_lit.
Extends the change from #139653, which was on expressions, to literals.

Fixes #140098.
2025-04-22 15:08:32 +10:00
bors
fae7785b60 Auto merge of #139897 - nnethercote:rm-OpenDelim-CloseDelim, r=petrochenkov
Remove `token::{Open,Close}Delim`

By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.

PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.

This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
  pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
  `Delimiter` values to `TokenKind`.

Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
-   } else if self.token != token::CloseDelim(Delimiter::Brace) {
+   } else if self.token != token::CloseBrace {
```

r? `@petrochenkov`
2025-04-22 01:15:06 +00:00
Nicholas Nethercote
bf8ce32558 Remove token::{Open,Close}Delim.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.

PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.

This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
  pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
  `Delimiter` values to `TokenKind`.

Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
-   } else if self.token != token::CloseDelim(Delimiter::Brace) {
+   } else if self.token != token::CloseBrace {
```
2025-04-21 07:35:56 +10:00
est31
5258cb76a5 Don't call ungate_last 2025-04-20 23:14:55 +02:00
Chris Denton
db98b72e34 Rollup merge of #137454 - mu001999-contrib:fix-137414, r=wesleywiser
not lint break with label and unsafe block

fixes #137414

we can't label unsafe blocks, so that we can do not lint them
2025-04-19 14:01:36 +00:00
est31
d75f8cde2f Also allow let chains in match guards 2025-04-18 15:57:29 +02:00
est31
2e61af2fca Stabilize let chains on edition 2024 2025-04-18 14:21:14 +02:00
Matthias Krüger
bf49dfc943 Rollup merge of #139392 - compiler-errors:raw-expr, r=oli-obk
Detect and provide suggestion for `&raw EXPR`

When emitting an error in the parser, and we detect that the previous token was `raw` and we *could* have consumed `const`/`mut`, suggest that this may have been a mistyped raw ref expr. To do this, we add `const`/`mut` to the expected token set when parsing `&raw` as an expression (which does not affect the "good path" of parsing, for the record).

This is kind of a rudimentary error improvement, since it doesn't actually attempt to recover anything, leading to some other knock-on errors b/c we still treat `&raw` as the expression that was parsed... but at least we add the suggestion! I don't think the parser grammar means we can faithfully recover `&raw EXPR` early, i.e. during `parse_expr_borrow`.

Fixes #133231
2025-04-14 18:15:31 +02:00
bors
f836ae4e66 Auto merge of #124141 - nnethercote:rm-Nonterminal-and-TokenKind-Interpolated, r=petrochenkov
Remove `Nonterminal` and `TokenKind::Interpolated`

A third attempt at this; the first attempt was #96724 and the second was #114647.

r? `@ghost`
2025-04-14 03:56:55 +00:00
Nicholas Nethercote
d25c8a8ade Handle a negated literal in eat_token_lit.
Fixes #139495.
2025-04-11 10:57:36 +10:00
Michael Goulet
6dfbe7c986 Detect and provide suggestion for &raw EXPR 2025-04-04 21:36:12 +00:00
Guillaume Gomez
aff2bc7a88 Replace rustc_lexer/unescape with rustc-literal-escaper crate 2025-04-04 14:44:45 +02:00
Nicholas Nethercote
ddcb370bc6 Tighten up assignment operator representations.
In the AST, currently we use `BinOpKind` within `ExprKind::AssignOp` and
`AssocOp::AssignOp`, even though this allows some nonsensical
combinations. E.g. there is no `&&=` operator. Likewise for HIR and
THIR.

This commit introduces `AssignOpKind` which only includes the ten
assignable operators, and uses it in `ExprKind::AssignOp` and
`AssocOp::AssignOp`. (And does similar things for `hir::ExprKind` and
`thir::ExprKind`.) This avoids the possibility of nonsensical
combinations, as seen by the removal of the `bug!` case in
`lang_item_for_binop`.

The commit is mostly plumbing, including:
- Adds an `impl From<AssignOpKind> for BinOpKind` (AST) and `impl
  From<AssignOp> for BinOp` (MIR/THIR).
- `BinOpCategory` can now be created from both `BinOpKind` and
  `AssignOpKind`.
- Replaces the `IsAssign` type with `Op`, which has more information and
  a few methods.
- `suggest_swapping_lhs_and_rhs`: moves the condition to the call site,
  it's easier that way.
- `check_expr_inner`: had to factor out some code into a separate
  method.

I'm on the fence about whether avoiding the nonsensical combinations is
worth the extra code.
2025-04-03 10:23:03 +11:00
Nicholas Nethercote
4d8f7577b5 Impl Copy for Token and TokenKind. 2025-04-02 16:16:49 +11:00
Nicholas Nethercote
bb495d6d3e Remove NtBlock, Nonterminal, and TokenKind::Interpolated.
`NtBlock` is the last remaining variant of `Nonterminal`, so once it is
gone then `Nonterminal` can be removed as well.
2025-04-02 16:07:02 +11:00
Nicholas Nethercote
592d113ff2 Fix problem causing rusqlite compilation to OOM.
This makes the expression re-parsing more like how it's originally done
in `parse_nonterminal`.
2025-04-02 06:21:18 +11:00
Nicholas Nethercote
d59b17c5cd Remove Token::uninterpolated_span.
In favour of the similar method on `Parser`, which works on things
other than identifiers and lifetimes.
2025-04-02 06:21:16 +11:00
Nicholas Nethercote
49ed25b5d2 Remove NtExpr and NtLiteral.
Notes about tests:
- tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs: some messages are
  now duplicated due to repeated parsing.

- tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs: ditto.

- `tests/ui/proc-macro/macro-rules-derive-cfg.rs`: the diff looks large
  but the only difference is the insertion of a single
  invisible-delimited group around a metavar.

- `tests/ui/attributes/nonterminal-expansion.rs`: a slight span
  degradation, somehow related to the recent massive attr parsing
  rewrite (#135726). I couldn't work out exactly what is going wrong,
  but I don't think it's worth holding things up for a single slightly
  suboptimal error message.
2025-04-02 06:20:35 +11:00
Matthias Krüger
0a579d5247 Rollup merge of #138749 - compiler-errors:closure-recovery, r=fmease
Fix closure recovery for missing block when return type is specified

Firstly, fix the `is_array_like_block` condition to make sure we're actually recovering a mistyped *block* rather than some other delimited expression. This fixes #138748.

Secondly, split out the recovery of missing braces on a closure body into a separate recovery. Right now, the suggestion `"you might have meant to write this as part of a block"` originates from `suggest_fixes_misparsed_for_loop_head`, which feels kinda brittle and coincidental since AFAICT that recovery wasn't ever really intended to fix this.

We also can make this `MachineApplicable` in this case.

Fixes #138748

r? `@fmease` or reassign if you're busy/don't wanna review this
2025-03-31 14:36:21 +02:00
León Orell Valerian Liehr
9f336ce2eb Remove now unreachable parse recovery code
StructLiteralNeedingParens is no longer reachable always giving
precedence to StructLiteralNotAllowedHere.

As an aside: The former error struct shouldn't've existed in the
first place. We should've just used the latter in this branch.
2025-03-25 15:15:41 +01:00
León Orell Valerian Liehr
82796dd858 Brace-ident-colon can certainly no longer start a block
thanks to the removal of type ascription.
2025-03-25 15:15:21 +01:00
Michael Goulet
dbda7d44b8 Make dedicated recovery for missing braces on closure with return 2025-03-20 16:02:24 +00:00
Michael Goulet
f90f43d62b Fix diagnostic struct typo, make sure is_array_like_block checks that it's a block 2025-03-20 16:01:13 +00:00
Matthias Krüger
d752721636 Rollup merge of #138435 - eholk:prefix-yield, r=oli-obk
Add support for postfix yield expressions

We've been having a discussion about whether we want postfix yield, or want to stick with prefix yield, or have both. I figured it's easy enough to support both for now and let us play around with them while the feature is still experimental.

This PR treats `yield x` and `x.yield` as semantically equivalent. There was a suggestion to make `yield x` have a `()` type (so it only works in coroutines with `Resume = ()`. I think that'd be worth trying, either in a later PR, or before this one merges, depending on people's opinions.

#43122
2025-03-20 15:36:15 +01:00
Eric Holk
2bd7f73c21 Refactor YieldKind so postfix yield must have an expression 2025-03-18 12:19:43 -07:00
Eric Holk
299e5d0514 Apply suggestions from code review
Co-authored-by: Travis Cross <tc@traviscross.com>
2025-03-18 10:50:33 -07:00
Eric Holk
9b0e7f6264 Teach rustfmt to handle postfix yield
This involved fixing the span when parsing .yield
2025-03-17 17:32:11 -07:00
Zachary S
f478853f42 If a label is placed on the block of a loop instead of the header, suggest moving it to the header. 2025-03-17 01:59:37 -05:00
Eric Holk
1c0916a2b3 Preserve yield position during pretty printing 2025-03-14 12:21:59 -07:00
Eric Holk
edf65e735c Add support for postfix yield expressions
We had a discussion[1] today about whether postfix yield would make sense.
It's easy enough to support both in the parser, so we might as well have
both and see how people use it while the feature is experimental.

[1]: https://rust-lang.zulipchat.com/#narrow/channel/481571-t-lang.2Fgen/topic/postfix-yield/with/505231568
2025-03-14 12:21:58 -07:00
Moritz Hedtke
66c49c73ee Make Parser::parse_expr_cond public.
This allows usage in rustfmt and rustfmt forks.
2025-03-14 19:55:55 +01:00
bors
aaa2d47dae Auto merge of #138083 - nnethercote:rm-NtItem-NtStmt, r=petrochenkov
Remove `NtItem` and `NtStmt`

Another piece of #124141.

r? `@petrochenkov`
2025-03-12 14:18:36 +00:00
Nicholas Nethercote
141719f68a Remove NtItem and NtStmt.
This involves replacing `nt_pretty_printing_compatibility_hack` with
`stream_pretty_printing_compatibility_hack`.

The handling of statements in `transcribe` is slightly different to
other nonterminal kinds, due to the lack of `from_ast` implementation
for empty statements.

Notable test changes:
- `tests/ui/proc-macro/expand-to-derive.rs`: the diff looks large but
  the only difference is the insertion of a single invisible-delimited
  group around a metavar.
2025-03-07 14:51:07 +11:00
Santiago Pastorino
81a926cc2a Use closure parse code 2025-03-06 17:58:32 -03:00
Santiago Pastorino
05c516446a Implement .use keyword as an alias of clone 2025-03-06 17:58:32 -03:00
bors
fd17deacce Auto merge of #137959 - matthiaskrgr:rollup-62vjvwr, r=matthiaskrgr
Rollup of 12 pull requests

Successful merges:

 - #135767 (Future incompatibility warning `unsupported_fn_ptr_calling_conventions`: Also warn in dependencies)
 - #137852 (Remove layouting dead code for non-array SIMD types.)
 - #137863 (Fix pretty printing of unsafe binders)
 - #137882 (do not build additional stage on compiler paths)
 - #137894 (Revert "store ScalarPair via memset when one side is undef and the other side can be memset")
 - #137902 (Make `ast::TokenKind` more like `lexer::TokenKind`)
 - #137921 (Subtree update of `rust-analyzer`)
 - #137922 (A few cleanups after the removal of `cfg(not(parallel))`)
 - #137939 (fix order on shl impl)
 - #137946 (Fix docker run-local docs)
 - #137955 (Always allow rustdoc-json tests to contain long lines)
 - #137958 (triagebot.toml: Don't label `test/rustdoc-json` as A-rustdoc-search)

r? `@ghost`
`@rustbot` modify labels: rollup
2025-03-04 02:27:56 +00:00
Matthias Krüger
9aff9c070a Rollup merge of #134900 - dtolnay:unoprange, r=compiler-errors,davidtwco
Fix parsing of ranges after unary operators

Fixes https://github.com/rust-lang/rust/issues/134899.

This PR aligns the parsing for unary `!` and `-` and `*` with how unary `&` is already parsed [here](5c0a6e68cf/compiler/rustc_parse/src/parser/expr.rs (L848-L854)).
2025-03-03 10:40:57 +01:00
Nicholas Nethercote
53167c0b7f Rename ast::TokenKind::Not as ast::TokenKind::Bang.
For consistency with `rustc_lexer::TokenKind::Bang`, and because other
`ast::TokenKind` variants generally have syntactic names instead of
semantic names (e.g. `Star` and `DotDot` instead of `Mul` and `Range`).
2025-03-03 09:26:13 +11:00
Nicholas Nethercote
2a1e2e9632 Replace ast::TokenKind::BinOp{,Eq} and remove BinOpToken.
`BinOpToken` is badly named, because it only covers the assignable
binary ops and excludes comparisons and `&&`/`||`. Its use in
`ast::TokenKind` does allow a small amount of code sharing, but it's a
clumsy factoring.

This commit removes `ast::TokenKind::BinOp{,Eq}`, replacing each one
with 10 individual variants. This makes `ast::TokenKind` more similar to
`rustc_lexer::TokenKind`, which has individual variants for all
operators.

Although the number of lines of code increases, the number of chars
decreases due to the frequent use of shorter names like `token::Plus`
instead of `token::BinOp(BinOpToken::Plus)`.
2025-03-03 09:26:11 +11:00
bors
aa3c2d73ef Auto merge of #137517 - nnethercote:rm-NtPat-NtItem-NtStmt, r=petrochenkov
Remove `NtPat`, `NtMeta`, and `NtPath`

Another part of #124141.

r? `@petrochenkov`
2025-02-28 21:32:39 +00:00