Skip to content

Commit 74437e4

Browse files
committed
Do not add ; to expected tokens list when it's wrong
There's a few spots where semicolons are checked for to do error recovery, and should not be suggested (or checked for other stuff). Fixes #87647
1 parent 532d2b1 commit 74437e4

16 files changed

+90
-51
lines changed

compiler/rustc_parse/src/parser/attr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{AttrWrapper, Capturing, ForceCollect, Parser, PathStyle};
1+
use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
22
use rustc_ast as ast;
33
use rustc_ast::attr;
44
use rustc_ast::token::{self, Nonterminal};
@@ -177,7 +177,7 @@ impl<'a> Parser<'a> {
177177
AttrWrapper::empty(),
178178
true,
179179
false,
180-
|_| true,
180+
FnParseMode { req_name: |_| true, req_body: true },
181181
ForceCollect::No,
182182
) {
183183
Ok(Some(item)) => {

compiler/rustc_parse/src/parser/diagnostics.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,8 @@ impl<'a> Parser<'a> {
11291129
}
11301130

11311131
pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
1132-
if self.eat(&token::Semi) {
1132+
if self.token.kind == TokenKind::Semi {
1133+
self.bump();
11331134
let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
11341135
err.span_suggestion_short(
11351136
self.prev_token.span,

compiler/rustc_parse/src/parser/item.rs

+51-22
Original file line numberDiff line numberDiff line change
@@ -78,24 +78,25 @@ pub(super) type ItemInfo = (Ident, ItemKind);
7878

7979
impl<'a> Parser<'a> {
8080
pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<P<Item>>> {
81-
self.parse_item_(|_| true, force_collect).map(|i| i.map(P))
81+
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
82+
self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(P))
8283
}
8384

8485
fn parse_item_(
8586
&mut self,
86-
req_name: ReqName,
87+
fn_parse_mode: FnParseMode,
8788
force_collect: ForceCollect,
8889
) -> PResult<'a, Option<Item>> {
8990
let attrs = self.parse_outer_attributes()?;
90-
self.parse_item_common(attrs, true, false, req_name, force_collect)
91+
self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
9192
}
9293

9394
pub(super) fn parse_item_common(
9495
&mut self,
9596
attrs: AttrWrapper,
9697
mac_allowed: bool,
9798
attrs_allowed: bool,
98-
req_name: ReqName,
99+
fn_parse_mode: FnParseMode,
99100
force_collect: ForceCollect,
100101
) -> PResult<'a, Option<Item>> {
101102
// Don't use `maybe_whole` so that we have precise control
@@ -113,7 +114,8 @@ impl<'a> Parser<'a> {
113114
let mut unclosed_delims = vec![];
114115
let item =
115116
self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
116-
let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
117+
let item =
118+
this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode);
117119
unclosed_delims.append(&mut this.unclosed_delims);
118120
Ok((item?, TrailingToken::None))
119121
})?;
@@ -127,12 +129,13 @@ impl<'a> Parser<'a> {
127129
mut attrs: Vec<Attribute>,
128130
mac_allowed: bool,
129131
attrs_allowed: bool,
130-
req_name: ReqName,
132+
fn_parse_mode: FnParseMode,
131133
) -> PResult<'a, Option<Item>> {
132134
let lo = self.token.span;
133135
let vis = self.parse_visibility(FollowedByType::No)?;
134136
let mut def = self.parse_defaultness();
135-
let kind = self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, req_name)?;
137+
let kind =
138+
self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, fn_parse_mode)?;
136139
if let Some((ident, kind)) = kind {
137140
self.error_on_unconsumed_default(def, &kind);
138141
let span = lo.to(self.prev_token.span);
@@ -192,7 +195,7 @@ impl<'a> Parser<'a> {
192195
lo: Span,
193196
vis: &Visibility,
194197
def: &mut Defaultness,
195-
req_name: ReqName,
198+
fn_parse_mode: FnParseMode,
196199
) -> PResult<'a, Option<ItemInfo>> {
197200
let def_final = def == &Defaultness::Final;
198201
let mut def = || mem::replace(def, Defaultness::Final);
@@ -219,7 +222,7 @@ impl<'a> Parser<'a> {
219222
(Ident::empty(), ItemKind::Use(tree))
220223
} else if self.check_fn_front_matter(def_final) {
221224
// FUNCTION ITEM
222-
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
225+
let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo)?;
223226
(ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
224227
} else if self.eat_keyword(kw::Extern) {
225228
if self.eat_keyword(kw::Crate) {
@@ -733,23 +736,26 @@ impl<'a> Parser<'a> {
733736
&mut self,
734737
force_collect: ForceCollect,
735738
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
736-
self.parse_assoc_item(|_| true, force_collect)
739+
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
740+
self.parse_assoc_item(fn_parse_mode, force_collect)
737741
}
738742

739743
pub fn parse_trait_item(
740744
&mut self,
741745
force_collect: ForceCollect,
742746
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
743-
self.parse_assoc_item(|edition| edition >= Edition::Edition2018, force_collect)
747+
let fn_parse_mode =
748+
FnParseMode { req_name: |edition| edition >= Edition::Edition2018, req_body: false };
749+
self.parse_assoc_item(fn_parse_mode, force_collect)
744750
}
745751

746752
/// Parses associated items.
747753
fn parse_assoc_item(
748754
&mut self,
749-
req_name: ReqName,
755+
fn_parse_mode: FnParseMode,
750756
force_collect: ForceCollect,
751757
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
752-
Ok(self.parse_item_(req_name, force_collect)?.map(
758+
Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
753759
|Item { attrs, id, span, vis, ident, kind, tokens }| {
754760
let kind = match AssocItemKind::try_from(kind) {
755761
Ok(kind) => kind,
@@ -944,7 +950,8 @@ impl<'a> Parser<'a> {
944950
&mut self,
945951
force_collect: ForceCollect,
946952
) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
947-
Ok(self.parse_item_(|_| true, force_collect)?.map(
953+
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
954+
Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
948955
|Item { attrs, id, span, vis, ident, kind, tokens }| {
949956
let kind = match ForeignItemKind::try_from(kind) {
950957
Ok(kind) => kind,
@@ -1484,7 +1491,8 @@ impl<'a> Parser<'a> {
14841491
if !is_raw && ident.is_reserved() {
14851492
let err = if self.check_fn_front_matter(false) {
14861493
// We use `parse_fn` to get a span for the function
1487-
if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
1494+
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
1495+
if let Err(mut db) = self.parse_fn(&mut Vec::new(), fn_parse_mode, lo) {
14881496
db.delay_as_bug();
14891497
}
14901498
let mut err = self.struct_span_err(
@@ -1700,23 +1708,33 @@ impl<'a> Parser<'a> {
17001708
/// The function decides if, per-parameter `p`, `p` must have a pattern or just a type.
17011709
type ReqName = fn(Edition) -> bool;
17021710

1711+
/// Parsing configuration for functions.
1712+
/// This include the edition-specific name requirements, plus information on whether the
1713+
/// function is allowed to go without a body.
1714+
#[derive(Clone, Copy)]
1715+
pub(crate) struct FnParseMode {
1716+
pub req_name: ReqName,
1717+
pub req_body: bool,
1718+
}
1719+
17031720
/// Parsing of functions and methods.
17041721
impl<'a> Parser<'a> {
17051722
/// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`.
17061723
fn parse_fn(
17071724
&mut self,
17081725
attrs: &mut Vec<Attribute>,
1709-
req_name: ReqName,
1726+
fn_parse_mode: FnParseMode,
17101727
sig_lo: Span,
17111728
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
17121729
let header = self.parse_fn_front_matter()?; // `const ... fn`
17131730
let ident = self.parse_ident()?; // `foo`
17141731
let mut generics = self.parse_generics()?; // `<'a, T, ...>`
1715-
let decl = self.parse_fn_decl(req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
1732+
let decl =
1733+
self.parse_fn_decl(fn_parse_mode.req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
17161734
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
17171735

17181736
let mut sig_hi = self.prev_token.span;
1719-
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`.
1737+
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body)?; // `;` or `{ ... }`.
17201738
let fn_sig_span = sig_lo.to(sig_hi);
17211739
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
17221740
}
@@ -1729,9 +1747,17 @@ impl<'a> Parser<'a> {
17291747
attrs: &mut Vec<Attribute>,
17301748
ident: &Ident,
17311749
sig_hi: &mut Span,
1750+
req_body: bool,
17321751
) -> PResult<'a, Option<P<Block>>> {
1733-
let (inner_attrs, body) = if self.eat(&token::Semi) {
1752+
let has_semi = if req_body {
1753+
self.token.kind == TokenKind::Semi
1754+
} else {
1755+
// Only include `;` in list of expected tokens if body is not required
1756+
self.check(&TokenKind::Semi)
1757+
};
1758+
let (inner_attrs, body) = if has_semi {
17341759
// Include the trailing semicolon in the span of the signature
1760+
self.expect_semi()?;
17351761
*sig_hi = self.prev_token.span;
17361762
(Vec::new(), None)
17371763
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
@@ -1752,9 +1778,12 @@ impl<'a> Parser<'a> {
17521778
.emit();
17531779
(Vec::new(), Some(self.mk_block_err(span)))
17541780
} else {
1755-
if let Err(mut err) =
1756-
self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
1757-
{
1781+
let expected = if req_body {
1782+
&[token::OpenDelim(token::Brace)][..]
1783+
} else {
1784+
&[token::Semi, token::OpenDelim(token::Brace)]
1785+
};
1786+
if let Err(mut err) = self.expected_one_of_not_found(&[], &expected) {
17581787
if self.token.kind == token::CloseDelim(token::Brace) {
17591788
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
17601789
// the AST for typechecking.

compiler/rustc_parse/src/parser/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::lexer::UnmatchedBrace;
1414
pub use attr_wrapper::AttrWrapper;
1515
pub use diagnostics::AttemptLocalParseRecovery;
1616
use diagnostics::Error;
17+
pub(crate) use item::FnParseMode;
1718
pub use pat::{RecoverColon, RecoverComma};
1819
pub use path::PathStyle;
1920

compiler/rustc_parse/src/parser/stmt.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use super::expr::LhsExpr;
44
use super::pat::RecoverComma;
55
use super::path::PathStyle;
66
use super::TrailingToken;
7-
use super::{AttrWrapper, BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode};
7+
use super::{
8+
AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
9+
};
810
use crate::maybe_whole;
911

1012
use rustc_ast as ast;
@@ -79,9 +81,13 @@ impl<'a> Parser<'a> {
7981
} else {
8082
self.parse_stmt_path_start(lo, attrs)
8183
}?
82-
} else if let Some(item) =
83-
self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)?
84-
{
84+
} else if let Some(item) = self.parse_item_common(
85+
attrs.clone(),
86+
false,
87+
true,
88+
FnParseMode { req_name: |_| true, req_body: true },
89+
force_collect,
90+
)? {
8591
// FIXME: Bad copy of attrs
8692
self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
8793
} else if self.eat(&token::Semi) {

src/test/ui/fn/fn-recover-return-sign2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33

44
fn foo() => impl Fn() => bool {
55
//~^ ERROR return types are denoted using `->`
6-
//~| ERROR expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>`
6+
//~| ERROR expected one of `+`, `->`, `::`, `where`, or `{`, found `=>`
77
unimplemented!()
88
}

src/test/ui/fn/fn-recover-return-sign2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ error: return types are denoted using `->`
44
LL | fn foo() => impl Fn() => bool {
55
| ^^ help: use `->` instead
66

7-
error: expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>`
7+
error: expected one of `+`, `->`, `::`, `where`, or `{`, found `=>`
88
--> $DIR/fn-recover-return-sign2.rs:4:23
99
|
1010
LL | fn foo() => impl Fn() => bool {
11-
| ^^ expected one of `+`, `->`, `::`, `;`, `where`, or `{`
11+
| ^^ expected one of `+`, `->`, `::`, `where`, or `{`
1212

1313
error: aborting due to 2 previous errors
1414

src/test/ui/parser/issues/issue-24780.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// to happen in #24780. For example, following should be an error:
33
// expected one of ..., `>`, ... found `>`.
44

5-
fn foo() -> Vec<usize>> { //~ ERROR expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>`
5+
fn foo() -> Vec<usize>> { //~ ERROR expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
66
Vec::new()
77
}
88

Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>`
1+
error: expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
22
--> $DIR/issue-24780.rs:5:23
33
|
44
LL | fn foo() -> Vec<usize>> {
5-
| ^ expected one of `!`, `+`, `::`, `;`, `where`, or `{`
5+
| ^ expected one of `!`, `+`, `::`, `where`, or `{`
66

77
error: aborting due to previous error
88

src/test/ui/parser/issues/issue-58856-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ impl A {
22
//~^ ERROR cannot find type `A` in this scope
33
fn b(self>
44
//~^ ERROR expected one of `)`, `,`, or `:`, found `>`
5-
//~| ERROR expected one of `->`, `;`, `where`, or `{`, found `>`
5+
//~| ERROR expected one of `->`, `where`, or `{`, found `>`
66
}
77

88
fn main() {}

src/test/ui/parser/issues/issue-58856-1.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ LL | fn b(self>
66
| |
77
| unclosed delimiter
88

9-
error: expected one of `->`, `;`, `where`, or `{`, found `>`
9+
error: expected one of `->`, `where`, or `{`, found `>`
1010
--> $DIR/issue-58856-1.rs:3:14
1111
|
1212
LL | impl A {
1313
| - while parsing this item list starting here
1414
LL |
1515
LL | fn b(self>
16-
| ^ expected one of `->`, `;`, `where`, or `{`
16+
| ^ expected one of `->`, `where`, or `{`
1717
...
1818
LL | }
1919
| - the item list ends here

src/test/ui/parser/issues/issue-84148-1.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ LL | fn f(t:for<>t?)
1313
| expected one of `(`, `)`, `+`, `,`, `::`, or `<`
1414
| help: missing `,`
1515

16-
error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
16+
error: expected one of `->`, `where`, or `{`, found `<eof>`
1717
--> $DIR/issue-84148-1.rs:1:15
1818
|
1919
LL | fn f(t:for<>t?)
20-
| ^ expected one of `->`, `;`, `where`, or `{`
20+
| ^ expected one of `->`, `where`, or `{`
2121

2222
error: aborting due to 3 previous errors
2323

src/test/ui/parser/issues/issue-84148-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ LL | fn f(t:for<>t?
2121
| expected one of `(`, `)`, `+`, `,`, `::`, or `<`
2222
| help: missing `,`
2323

24-
error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
24+
error: expected one of `->`, `where`, or `{`, found `<eof>`
2525
--> $DIR/issue-84148-2.rs:4:16
2626
|
2727
LL | fn f(t:for<>t?
28-
| ^ expected one of `->`, `;`, `where`, or `{`
28+
| ^ expected one of `->`, `where`, or `{`
2929

3030
error: aborting due to 4 previous errors
3131

src/test/ui/parser/issues/issue-87635.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ struct Foo {}
22

33
impl Foo {
44
pub fn bar()
5-
//~^ ERROR: expected `;`, found `}`
6-
//~| ERROR: associated function in `impl` without body
5+
//~^ ERROR: associated function in `impl` without body
76
}
7+
//~^ERROR expected one of `->`, `where`, or `{`, found `}`
88

99
fn main() {}

src/test/ui/parser/issues/issue-87635.stderr

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
error: expected `;`, found `}`
2-
--> $DIR/issue-87635.rs:4:17
1+
error: expected one of `->`, `where`, or `{`, found `}`
2+
--> $DIR/issue-87635.rs:6:1
33
|
44
LL | pub fn bar()
5-
| ^ help: add `;` here
6-
...
5+
| --- - expected one of `->`, `where`, or `{`
6+
| |
7+
| while parsing this `fn`
8+
LL |
79
LL | }
8-
| - unexpected token
10+
| ^ unexpected token
911

1012
error: associated function in `impl` without body
1113
--> $DIR/issue-87635.rs:4:5

src/test/ui/parser/missing_right_paren.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ error: expected one of `:` or `|`, found `)`
2222
LL | fn main((ؼ
2323
| ^ expected one of `:` or `|`
2424

25-
error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
25+
error: expected one of `->`, `where`, or `{`, found `<eof>`
2626
--> $DIR/missing_right_paren.rs:3:11
2727
|
2828
LL | fn main((ؼ
29-
| ^ expected one of `->`, `;`, `where`, or `{`
29+
| ^ expected one of `->`, `where`, or `{`
3030

3131
error: aborting due to 4 previous errors
3232

0 commit comments

Comments
 (0)