Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ impl<'a> Parser<'a> {
// `raw [ const | mut ]`.
let found_raw = self.eat_keyword(exp!(Raw));
assert!(found_raw);
let mutability = self.parse_const_or_mut().unwrap();
let mutability = self.parse_mut_or_const().unwrap();
(ast::BorrowKind::Raw, mutability)
} else {
match self.parse_pin_and_mut() {
Expand Down
21 changes: 17 additions & 4 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1302,12 +1302,16 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr_with_attrs(span.to(blk_span), kind, attrs))
}

/// Parses mutability (`mut` or nothing).
/// Parse nothing or `mut`.
fn parse_mutability(&mut self) -> Mutability {
if self.eat_keyword(exp!(Mut)) { Mutability::Mut } else { Mutability::Not }
}

/// Parses reference binding mode (`ref`, `ref mut`, `ref pin const`, `ref pin mut`, or nothing).
/// Parse nothing or a by-reference mode.
///
/// ```ebnf
/// ByRef = "ref" PinAndMut?
/// ```
fn parse_byref(&mut self) -> ByRef {
if self.eat_keyword(exp!(Ref)) {
let (pinnedness, mutability) = self.parse_pin_and_mut();
Expand All @@ -1317,8 +1321,12 @@ impl<'a> Parser<'a> {
}
}

/// Possibly parses mutability (`const` or `mut`).
fn parse_const_or_mut(&mut self) -> Option<Mutability> {
/// Parse nothing or "explicit" mutability.
///
/// ```ebnf
/// MutOrConst = "mut" | "const"
/// ```
fn parse_mut_or_const(&mut self) -> Option<Mutability> {
if self.eat_keyword(exp!(Mut)) {
Some(Mutability::Mut)
} else if self.eat_keyword(exp!(Const)) {
Expand All @@ -1328,6 +1336,11 @@ impl<'a> Parser<'a> {
}
}

/// Parse a field name.
///
/// ```enbf
/// FieldName = IntLit | Ident
/// ```
fn parse_field_name(&mut self) -> PResult<'a, Ident> {
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind
{
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1731,11 +1731,14 @@ impl<'a> Parser<'a> {
self.dcx().emit_err(DotDotDotForRemainingFields { span: self.token.span, token_str });
}

/// Parse a field in a struct pattern.
///
/// ```ebnf
/// PatField = FieldName ":" Pat | "box"? "mut"? ByRef? Ident
/// ```
fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> {
// Check if a colon exists one ahead. This means we're parsing a fieldname.
let hi;
let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
// Parsing a pattern of the form `fieldname: pat`.
let fieldname = self.parse_field_name()?;
self.bump();
let pat = self.parse_pat_allow_top_guard(
Expand All @@ -1747,7 +1750,6 @@ impl<'a> Parser<'a> {
hi = pat.span;
(pat, fieldname, false)
} else {
// Parsing a pattern of the form `(box) (ref) (mut) fieldname`.
let is_box = self.eat_keyword(exp!(Box));
if is_box {
self.psess.gated_spans.gate(sym::box_patterns, self.prev_token.span);
Expand All @@ -1756,7 +1758,7 @@ impl<'a> Parser<'a> {
let mutability = self.parse_mutability();
let by_ref = self.parse_byref();

let fieldname = self.parse_field_name()?;
Copy link
Copy Markdown
Member Author

@fmease fmease Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the culprit.

Prior to the regressing PR #81235 this used to be let fieldname = self.parse_ident()?;.

Changing it (back) to parse_ident_common makes it consistent again with its expression counterpart, cf:

let ident = this.parse_ident_common(false)?;

View changes since the review

let fieldname = self.parse_ident_common(false)?;
hi = self.prev_token.span;
let ann = BindingMode(by_ref, mutability);
let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname);
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ impl<'a> Parser<'a> {
/// Parses a raw pointer with a C-style typo
fn parse_ty_c_style_pointer(&mut self) -> PResult<'a, TyKind> {
let kw_span = self.token.span;
let mutbl = self.parse_const_or_mut();
let mutbl = self.parse_mut_or_const();

if let Some(mutbl) = mutbl
&& self.eat(exp!(Star))
Expand Down Expand Up @@ -630,7 +630,7 @@ impl<'a> Parser<'a> {

/// Parses a raw pointer type: `*[const | mut] $type`.
fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {
let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
let mutbl = self.parse_mut_or_const().unwrap_or_else(|| {
let span = self.prev_token.span;
self.dcx().emit_err(ExpectedMutOrConstInRawPointerType {
span,
Expand Down Expand Up @@ -774,14 +774,16 @@ impl<'a> Parser<'a> {
})
}

/// Parses `pin` and `mut` annotations on references, patterns, or borrow modifiers.
/// Parse nothing, mutability or `pin` followed by "explicit" mutability.
///
/// It must be either `pin const`, `pin mut`, `mut`, or nothing (immutable).
/// ```ebnf
/// PinAndMut = "pin" MutOrConst | "mut"
/// ```
pub(crate) fn parse_pin_and_mut(&mut self) -> (Pinnedness, Mutability) {
if self.token.is_ident_named(sym::pin) && self.look_ahead(1, Token::is_mutability) {
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
assert!(self.eat_keyword(exp!(Pin)));
let mutbl = self.parse_const_or_mut().unwrap();
let mutbl = self.parse_mut_or_const().unwrap();
(Pinnedness::Pinned, mutbl)
} else {
(Pinnedness::Not, self.parse_mutability())
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/parser/struct-expr-pat-tuple-index-shorthand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Check that tuple indices in struct exprs & pats don't have a shorthand.
// If they did it would be possible to bind and reference numeric identifiers
// which is undesirable.

struct Rgb(u8, u8, u8);

#[cfg(false)] // ensures that this is a *syntax* error, not just a semantic one!
fn scope() {
// FIXME: Better recover and also report a diagnostic for the other two fields.
let Rgb { 0, 1, 2 };
//~^ ERROR expected identifier, found `0`

let _ = Rgb { 0, 1, 2 };
//~^ ERROR expected identifier, found `0`
//~| ERROR expected identifier, found `1`
//~| ERROR expected identifier, found `2`
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
error: expected identifier, found `0`
--> $DIR/struct-field-numeric-shorthand.rs:4:19
--> $DIR/struct-expr-pat-tuple-index-shorthand.rs:10:15
|
LL | let Rgb { 0, 1, 2 };
| --- ^ expected identifier
| |
| while parsing the fields for this pattern

error: expected identifier, found `0`
--> $DIR/struct-expr-pat-tuple-index-shorthand.rs:13:19
|
LL | let _ = Rgb { 0, 1, 2 };
| --- ^ expected identifier
| |
| while parsing this struct

error: expected identifier, found `1`
--> $DIR/struct-field-numeric-shorthand.rs:4:22
--> $DIR/struct-expr-pat-tuple-index-shorthand.rs:13:22
|
LL | let _ = Rgb { 0, 1, 2 };
| --- ^ expected identifier
| |
| while parsing this struct

error: expected identifier, found `2`
--> $DIR/struct-field-numeric-shorthand.rs:4:25
--> $DIR/struct-expr-pat-tuple-index-shorthand.rs:13:25
|
LL | let _ = Rgb { 0, 1, 2 };
| --- ^ expected identifier
| |
| while parsing this struct

error: aborting due to 3 previous errors
error: aborting due to 4 previous errors

8 changes: 0 additions & 8 deletions tests/ui/parser/struct-field-numeric-shorthand.rs

This file was deleted.

4 changes: 3 additions & 1 deletion tests/ui/pattern/self-ctor-133272.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error: expected identifier, found keyword `Self`
--> $DIR/self-ctor-133272.rs:17:21
|
LL | let S { ref Self } = todo!();
| ^^^^ expected identifier, found keyword
| - ^^^^ expected identifier, found keyword
| |
| while parsing the fields for this pattern

error[E0422]: cannot find struct, variant or union type `S` in this scope
--> $DIR/self-ctor-133272.rs:17:13
Expand Down
1 change: 0 additions & 1 deletion tests/ui/self/self_type_keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ pub fn main() {
Foo { Self } => (),
//~^ ERROR expected identifier, found keyword `Self`
//~| ERROR mismatched types
//~| ERROR `Foo` does not have a field named `Self`
}
}

Expand Down
22 changes: 9 additions & 13 deletions tests/ui/self/self_type_keyword.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,24 @@ error: expected identifier, found keyword `Self`
--> $DIR/self_type_keyword.rs:22:15
|
LL | Foo { Self } => (),
| ^^^^ expected identifier, found keyword
| --- ^^^^ expected identifier, found keyword
| |
| while parsing the fields for this pattern

error: expected identifier, found keyword `Self`
--> $DIR/self_type_keyword.rs:30:26
--> $DIR/self_type_keyword.rs:29:26
|
LL | extern crate core as Self;
| ^^^^ expected identifier, found keyword

error: expected identifier, found keyword `Self`
--> $DIR/self_type_keyword.rs:35:32
--> $DIR/self_type_keyword.rs:34:32
|
LL | use std::option::Option as Self;
| ^^^^ expected identifier, found keyword

error: expected identifier, found keyword `Self`
--> $DIR/self_type_keyword.rs:40:11
--> $DIR/self_type_keyword.rs:39:11
|
LL | trait Self {}
| ^^^^ expected identifier, found keyword
Expand Down Expand Up @@ -88,13 +90,7 @@ LL | match 15 {
LL | Foo { Self } => (),
| ^^^^^^^^^^^^ expected integer, found `Foo`

error[E0026]: struct `Foo` does not have a field named `Self`
--> $DIR/self_type_keyword.rs:22:15
|
LL | Foo { Self } => (),
| ^^^^ struct `Foo` does not have this field

error: aborting due to 13 previous errors
error: aborting due to 12 previous errors

Some errors have detailed explanations: E0026, E0308, E0392, E0531.
For more information about an error, try `rustc --explain E0026`.
Some errors have detailed explanations: E0308, E0392, E0531.
For more information about an error, try `rustc --explain E0308`.
11 changes: 11 additions & 0 deletions tests/ui/structs/struct-pat-unmentioned-tuple-indices.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// On unmentioned tuple indices in struct patterns, don't suggest turning the pattern into a
// tuple struct pattern and keep the struct pattern in the suggestion.
// issue: <https://github.com/rust-lang/rust/issues/108284>

struct S(i32, f32);
enum E { V(i32, f32) }

fn main() {
let S { 0: _ } = S(1, 2.2); //~ ERROR: pattern does not mention field `1`
let E::V { 0: _ } = E::V(1, 2.2); //~ ERROR: pattern does not mention field `1`
}
41 changes: 41 additions & 0 deletions tests/ui/structs/struct-pat-unmentioned-tuple-indices.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
error[E0027]: pattern does not mention field `1`
--> $DIR/struct-pat-unmentioned-tuple-indices.rs:9:9
|
LL | let S { 0: _ } = S(1, 2.2);
| ^^^^^^^^^^ missing field `1`
|
help: include the missing field in the pattern
|
LL | let S { 0: _, 1: _ } = S(1, 2.2);
| ++++++
help: if you don't care about this missing field, you can explicitly ignore it
|
LL | let S { 0: _, 1: _ } = S(1, 2.2);
| ++++++
help: or always ignore missing fields here
|
LL | let S { 0: _, .. } = S(1, 2.2);
| ++++

error[E0027]: pattern does not mention field `1`
--> $DIR/struct-pat-unmentioned-tuple-indices.rs:10:9
|
LL | let E::V { 0: _ } = E::V(1, 2.2);
| ^^^^^^^^^^^^^ missing field `1`
|
help: include the missing field in the pattern
|
LL | let E::V { 0: _, 1: _ } = E::V(1, 2.2);
| ++++++
help: if you don't care about this missing field, you can explicitly ignore it
|
LL | let E::V { 0: _, 1: _ } = E::V(1, 2.2);
| ++++++
help: or always ignore missing fields here
|
LL | let E::V { 0: _, .. } = E::V(1, 2.2);
| ++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0027`.
18 changes: 0 additions & 18 deletions tests/ui/structs/struct-tuple-field-names.rs

This file was deleted.

47 changes: 0 additions & 47 deletions tests/ui/structs/struct-tuple-field-names.stderr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
struct S(i32);
enum E { V(i32) }

fn main() {
let S {} = S(0); //~ ERROR tuple variant `S` written as struct variant
let E::V {} = E::V(0); //~ ERROR tuple variant `E::V` written as struct variant
}
Loading
Loading