From 94e9973b92c481d20e5fe1466bbc47f818101d5f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 26 Jun 2025 17:53:01 +0000 Subject: Add Ident::is_non_reserved_ident --- compiler/rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 3 +-- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/parser/path.rs | 8 +++----- compiler/rustc_parse/src/parser/stmt.rs | 2 +- 5 files changed, 7 insertions(+), 10 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a64bb424117..1df0ccbd8af 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2731,7 +2731,7 @@ impl<'a> Parser<'a> { return first_pat; } if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) - || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + || !self.look_ahead(1, |token| token.is_non_reserved_ident()) { let mut snapshot_type = self.create_snapshot_for_diagnostic(); snapshot_type.bump(); // `:` diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4e312aab497..3cedc86dc0d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3875,8 +3875,7 @@ impl<'a> Parser<'a> { // Check if a colon exists one ahead. This means we're parsing a fieldname. let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq); // Proactively check whether parsing the field will be incorrect. - let is_wrong = this.token.is_ident() - && !this.token.is_reserved_ident() + let is_wrong = this.token.is_non_reserved_ident() && !this.look_ahead(1, |t| { t == &token::Colon || t == &token::Eq diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b2e90251367..cfc0399b0ca 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -685,7 +685,7 @@ impl<'a> Parser<'a> { /// Is the given keyword `kw` followed by a non-reserved identifier? fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { - self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) + self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_non_reserved_ident()) } #[inline] diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9bce2fa74ca..1f4049f197f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -126,7 +126,7 @@ impl<'a> Parser<'a> { /// ``` fn recover_colon_before_qpath_proj(&mut self) -> bool { if !self.check_noexpect(&TokenKind::Colon) - || self.look_ahead(1, |t| !t.is_ident() || t.is_reserved_ident()) + || self.look_ahead(1, |t| !t.is_non_reserved_ident()) { return false; } @@ -260,7 +260,7 @@ impl<'a> Parser<'a> { if self.may_recover() && style == PathStyle::Expr // (!) && self.token == token::Colon - && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + && self.look_ahead(1, |token| token.is_non_reserved_ident()) { // Emit a special error message for `a::b:c` to help users // otherwise, `a: c` might have meant to introduce a new binding @@ -334,9 +334,7 @@ impl<'a> Parser<'a> { self.expect_gt().map_err(|mut err| { // Try to recover a `:` into a `::` if self.token == token::Colon - && self.look_ahead(1, |token| { - token.is_ident() && !token.is_reserved_ident() - }) + && self.look_ahead(1, |token| token.is_non_reserved_ident()) { err.cancel(); err = self.dcx().create_err(PathSingleColon { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index c37cb0881c3..2fa6520f2a4 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -798,7 +798,7 @@ impl<'a> Parser<'a> { } if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) { // Likely `foo.await bar` - } else if !self.prev_token.is_reserved_ident() && self.prev_token.is_ident() { + } else if self.prev_token.is_non_reserved_ident() { // Likely `foo bar` } else if self.prev_token.kind == token::Question { // `foo? bar` -- cgit 1.4.1-3-g733a5 From e63921262ccd2ece7e0861d634f111136da1f7da Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 26 Jun 2025 17:53:39 +0000 Subject: Make recovery for enum with struct field a bit more accurate --- compiler/rustc_parse/src/parser/item.rs | 3 ++- tests/ui/structs-enums/recover-enum-with-bad-where.rs | 6 ++++++ tests/ui/structs-enums/recover-enum-with-bad-where.stderr | 10 ++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/ui/structs-enums/recover-enum-with-bad-where.rs create mode 100644 tests/ui/structs-enums/recover-enum-with-bad-where.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5088caa80f8..9ed7124a11c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1552,7 +1552,8 @@ impl<'a> Parser<'a> { }) .map_err(|mut err| { err.span_label(ident.span, "while parsing this enum"); - if self.token == token::Colon { + // Try to recover `enum Foo { ident : Ty }`. + if self.prev_token.is_non_reserved_ident() && self.token == token::Colon { let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); match self.parse_ty() { diff --git a/tests/ui/structs-enums/recover-enum-with-bad-where.rs b/tests/ui/structs-enums/recover-enum-with-bad-where.rs new file mode 100644 index 00000000000..850ee6caa1a --- /dev/null +++ b/tests/ui/structs-enums/recover-enum-with-bad-where.rs @@ -0,0 +1,6 @@ +pub enum Foo +where: +//~^ ERROR expected one of `#`, `{`, lifetime, or type, found `:` + T: Missing, {} + +fn main() {} diff --git a/tests/ui/structs-enums/recover-enum-with-bad-where.stderr b/tests/ui/structs-enums/recover-enum-with-bad-where.stderr new file mode 100644 index 00000000000..6f28ff56bab --- /dev/null +++ b/tests/ui/structs-enums/recover-enum-with-bad-where.stderr @@ -0,0 +1,10 @@ +error: expected one of `#`, `{`, lifetime, or type, found `:` + --> $DIR/recover-enum-with-bad-where.rs:2:6 + | +LL | pub enum Foo + | --- while parsing this enum +LL | where: + | ^ expected one of `#`, `{`, lifetime, or type + +error: aborting due to 1 previous error + -- cgit 1.4.1-3-g733a5 From 4e51e67a24d940d3c8069062d07f663ee2034ac3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 26 Jun 2025 18:08:15 +0000 Subject: Better recovery --- compiler/rustc_parse/src/parser/generics.rs | 14 ++++++++++++++ tests/ui/structs-enums/recover-enum-with-bad-where.rs | 4 +++- tests/ui/structs-enums/recover-enum-with-bad-where.stderr | 15 ++++++++++----- 3 files changed, 27 insertions(+), 6 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index c05479feb61..af1d1a1ec66 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -353,6 +353,20 @@ impl<'a> Parser<'a> { if !self.eat_keyword(exp!(Where)) { return Ok((where_clause, None)); } + + if self.eat_noexpect(&token::Colon) { + let colon_span = self.prev_token.span; + self.dcx() + .struct_span_err(colon_span, "unexpected colon after `where`") + .with_span_suggestion_short( + colon_span, + "remove the colon", + "", + Applicability::MachineApplicable, + ) + .emit(); + } + where_clause.has_where_token = true; let where_lo = self.prev_token.span; diff --git a/tests/ui/structs-enums/recover-enum-with-bad-where.rs b/tests/ui/structs-enums/recover-enum-with-bad-where.rs index 850ee6caa1a..cf7747d710b 100644 --- a/tests/ui/structs-enums/recover-enum-with-bad-where.rs +++ b/tests/ui/structs-enums/recover-enum-with-bad-where.rs @@ -1,6 +1,8 @@ pub enum Foo where: -//~^ ERROR expected one of `#`, `{`, lifetime, or type, found `:` +//~^ ERROR unexpected colon after `where` T: Missing, {} +//~^ ERROR cannot find trait `Missing` in this scope +// (evidence that we continue parsing after the erroneous colon) fn main() {} diff --git a/tests/ui/structs-enums/recover-enum-with-bad-where.stderr b/tests/ui/structs-enums/recover-enum-with-bad-where.stderr index 6f28ff56bab..30b73f59e8c 100644 --- a/tests/ui/structs-enums/recover-enum-with-bad-where.stderr +++ b/tests/ui/structs-enums/recover-enum-with-bad-where.stderr @@ -1,10 +1,15 @@ -error: expected one of `#`, `{`, lifetime, or type, found `:` +error: unexpected colon after `where` --> $DIR/recover-enum-with-bad-where.rs:2:6 | -LL | pub enum Foo - | --- while parsing this enum LL | where: - | ^ expected one of `#`, `{`, lifetime, or type + | ^ help: remove the colon -error: aborting due to 1 previous error +error[E0405]: cannot find trait `Missing` in this scope + --> $DIR/recover-enum-with-bad-where.rs:4:8 + | +LL | T: Missing, {} + | ^^^^^^^ not found in this scope + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0405`. -- cgit 1.4.1-3-g733a5