There was an inconsistency where in the case of array repeat
expressions, we forgot to eat the `const` keyword of mgca const blocks.
Thus, we ended up parsing them as an anon const containing an inline
const, instead of simply an anon const as they should be.
This commit fixes that issue and also makes the parsing for mgca const
blocks more consistent and simpler in general. For example, we avoid
doing a lookahead check to ensure there's a curly brace coming. There
should always be one after a `const` keyword in an expression context,
and that's handled by the mgca const block parsing function.
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.
148725 moved the default to being homogeneous; this adds heterogeneous ones back under an obvious-bikeshed syntax so people can experiment with that as well.
Essentially resolves 149025 by letting them move to this syntax instead.
Contract variables can be declared in the `requires` clause and
can be referenced both in `requires` and `ensures`, subject to usual
borrow checking rules.
This allows any setup common to both the `requires` and `ensures`
clauses to only be done once.
This improves the case where someone tries to write a `match` expr where the patterns have type ascription syntax. Makes them less verbose, by giving up on the first encounter in the block, and makes them more accurate by only treating them as a struct literal if successfuly parsed as such.
Reject invalid literal suffixes in tuple indexing, tuple struct indexing, and struct field name position
Tracking issue: rust-lang/rust#60210
Closes rust-lang/rust#60210
## Summary
Bump the ["suffixes on a tuple index are invalid" non-lint pseudo future-incompatibility warning (#60210)][issue-60210][^non-lint] to a **hard error** across all editions, rejecting the remaining carve outs from accidentally accepted invalid suffixes since Rust **1.27**.
- We accidentally accepted invalid suffixes in tuple indexing positions in Rust **1.27**. Originally reported at https://github.com/rust-lang/rust/issues/59418.
- We tried to hard reject all invalid suffixes in https://github.com/rust-lang/rust/pull/59421, but unfortunately it turns out there were proc macros accidentally relying on it: https://github.com/rust-lang/rust/issues/60138.
- We temporarily accepted `{i,u}{32,size}` in https://github.com/rust-lang/rust/pull/60186 (the "*carve outs*") to mitigate *immediate* ecosystem impact, but it came with an FCW warning indicating that we wanted to reject it after a few Rust releases.
- Now (1.89.0) is a few Rust releases later (1.35.0), thus I'm proposing to **also reject the carve outs**.
- `std::mem::offset_of!` stabilized in Rust **1.77.0** happens to use the same "don't expect suffix" code path which has the carve outs, so it also accepted the carve out suffixes. I'm proposing to **reject this case as well**.
## What specifically breaks?
Code that still relied on invalid `{i,u}{32,size}` suffixes being temporarily accepted by rust-lang/rust#60186 as an ecosystem impact mitigation measure (cf. rust-lang/rust#60138). Specifically, the following cases (particularly the construction of these forms in proc macros like reported in rust-lang/rust#60138):
### Position 1: Invalid `{i,u}{32,size}` suffixes in tuple indexing
```rs
fn main() {
let _x = (42,).0invalid; // Already error, already rejected by #59421
let _x = (42,).0i8; // Already error, not one of the #60186 carve outs.
let _x = (42,).0usize; // warning: suffixes on a tuple index are invalid
}
```
### Position 2: Invalid `{i,u}{32,size}` suffixes in tuple struct indexing
```rs
fn main() {
struct X(i32);
let _x = X(42);
let _x = _x.0invalid; // Already error, already rejected by #59421
let _x = _x.0i8; // Already error, not one of the #60186 carve outs.
let _x = _x.0usize; // warning: suffixes on a tuple index are invalid
}
```
### Position 3: Invalid `{i,u}{32,size}` suffixes in numeric struct field names
```rs
fn main() {
struct X(i32, i32, i32);
let _x = X(1, 2, 3);
let _y = X { 0usize: 42, 1: 42, 2: 42 }; // warning: suffixes on a tuple index are invalid
match _x {
X { 0usize: 1, 1: 2, 2: 3 } => todo!(), // warning: suffixes on a tuple index are invalid
_ => {}
}
}
```
### Position 4: Invalid `{i,u}{32,size}` suffixes in `std::mem::offset_of!`
While investigating the warning, unfortunately I noticed `std::mem::offset_of!` also happens to use the "expect no suffix" code path which had the carve outs. So this was accepted since Rust **1.77.0** with the same FCW:
```rs
fn main() {
#[repr(C)]
pub struct Struct<T>(u8, T);
assert_eq!(std::mem::offset_of!(Struct<u32>, 0usize), 0);
//~^ WARN suffixes on a tuple index are invalid
}
```
### The above forms in proc macros
For instance, constructions like (see tracking issue rust-lang/rust#60210):
```rs
let i = 0;
quote! { foo.$i }
```
where the user needs to actually write
```rs
let i = syn::Index::from(0);
quote! { foo.$i }
```
### Crater results
Conducted a crater run (https://github.com/rust-lang/rust/pull/145463#issuecomment-3194920383).
- 256af3c72f: genuine regression; "invalid suffix `usize`" in derive macro. Has a ton of other build warnings, last updated 6 years ago.
- Exactly the kind of intended breakage. Minimized down to 256af3c72f/validates_derive/src/lib.rs (L71-L75), where when interpolation uses `quote`'s `ToTokens` on a `usize` index (i.e. on tuple struct `Tup(())`), the generated suffix becomes `.0usize` (cf. Position 2).
- Notified crate author of breakage in https://github.com/AmlingPalantir/r4/issues/1.
- Other failures are unrelated or spurious.
## Review remarks
- Commits 1-3 expands the test coverage to better reflect the current situation before doing any functional changes.
- Commit 4 is an intentional **breaking change**. We bump the non-lint "suffixes on a tuple index are invalid" warning into a hard error. Thus, this will need a crater run and a T-lang FCP.
## Tasks
- [x] Run crater to check if anyone is still relying on this being not a hard error. Determine degree of ecosystem breakage.
- [x] If degree of breakage seems acceptable, draft nomination report for T-lang for FCP.
- [x] Determine hard error on Edition 2024+, or on all editions.
## Accompanying Reference update
- https://github.com/rust-lang/reference/pull/1966
[^non-lint]: The FCW was implemented as a *non-lint* warning (meaning it has no associated lint name, and you can't `#![deny(..)]` it) because spans coming from proc macros could not be distinguished from regular field access. This warning was also intentionally impossible to silence. See https://github.com/rust-lang/rust/pull/60186#issuecomment-485581694.
[issue-60210]: https://github.com/rust-lang/rust/issues/60210
Gate static closures behind a parser feature
I'd like to gate `static ||` closures behind a feature gate, since we shouldn't allow people to take advantage of this syntax if it's currently unstable. Right now, since it's only rejected after ast lowering, it's accessible to macros.
Let's crater this to see if we can claw it back without breaking anyone's code.
Implement parsing of pinned borrows
This PR implements part of #130494.
EDIT: It introduces `&pin mut $place` and `&pin const $place` as sugars for `std::pin::pin!($place)` and its shared reference equivalent, except that `$place` will not be moved when borrowing. The borrow check will be in charge of enforcing places cannot be moved or mutably borrowed since being pinned till dropped.
### Implementation steps:
- [x] parse the `&pin mut $place` and `&pin const $place` syntaxes
- [ ] borrowck of `&pin mut|const`
- [ ] support autoref of `&pin mut|const` when needed
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 `==`.
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.
Handle another negated literal in `eat_token_lit`.
Extends the change from #139653, which was on expressions, to literals.
Fixes#140098.
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`
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 {
```