Skip to content

Commit ff61949

Browse files
committed
Tweak invalid fn header and body parsing
* Recover empty `fn` bodies when encountering `}` * Recover trailing `>` in return types * Recover from non-type in array type `[<BAD TOKEN>; LEN]`
1 parent 040f568 commit ff61949

File tree

7 files changed

+53
-27
lines changed

7 files changed

+53
-27
lines changed

compiler/rustc_parse/src/parser/item.rs

+30-8
Original file line numberDiff line numberDiff line change
@@ -1538,7 +1538,7 @@ impl<'a> Parser<'a> {
15381538
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
15391539

15401540
let mut sig_hi = self.prev_token.span;
1541-
let body = self.parse_fn_body(attrs, &mut sig_hi)?; // `;` or `{ ... }`.
1541+
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`.
15421542
let fn_sig_span = sig_lo.to(sig_hi);
15431543
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
15441544
}
@@ -1549,6 +1549,7 @@ impl<'a> Parser<'a> {
15491549
fn parse_fn_body(
15501550
&mut self,
15511551
attrs: &mut Vec<Attribute>,
1552+
ident: &Ident,
15521553
sig_hi: &mut Span,
15531554
) -> PResult<'a, Option<P<Block>>> {
15541555
let (inner_attrs, body) = if self.eat(&token::Semi) {
@@ -1573,9 +1574,21 @@ impl<'a> Parser<'a> {
15731574
.emit();
15741575
(Vec::new(), Some(self.mk_block_err(span)))
15751576
} else {
1576-
return self
1577-
.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
1578-
.map(|_| None);
1577+
if let Err(mut err) =
1578+
self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
1579+
{
1580+
if self.token.kind == token::CloseDelim(token::Brace) {
1581+
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
1582+
// the AST for typechecking.
1583+
err.span_label(ident.span, "while parsing this `fn`");
1584+
err.emit();
1585+
(Vec::new(), None)
1586+
} else {
1587+
return Err(err);
1588+
}
1589+
} else {
1590+
unreachable!()
1591+
}
15791592
};
15801593
attrs.extend(inner_attrs);
15811594
Ok(body)
@@ -1653,10 +1666,19 @@ impl<'a> Parser<'a> {
16531666
req_name: ReqName,
16541667
ret_allow_plus: AllowPlus,
16551668
) -> PResult<'a, P<FnDecl>> {
1656-
Ok(P(FnDecl {
1657-
inputs: self.parse_fn_params(req_name)?,
1658-
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
1659-
}))
1669+
let inputs = self.parse_fn_params(req_name)?;
1670+
let output = self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?;
1671+
1672+
if let ast::FnRetTy::Ty(ty) = &output {
1673+
if let TyKind::Path(_, Path { segments, .. }) = &ty.kind {
1674+
if let [.., last] = &segments[..] {
1675+
// Detect and recover `fn foo() -> Vec<i32>> {}`
1676+
self.check_trailing_angle_brackets(last, &[&token::OpenDelim(token::Brace)]);
1677+
}
1678+
}
1679+
}
1680+
1681+
Ok(P(FnDecl { inputs, output }))
16601682
}
16611683

16621684
/// Parses the parameter list of a function, including the `(` and `)` delimiters.

compiler/rustc_parse/src/parser/ty.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,19 @@ impl<'a> Parser<'a> {
265265
/// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type.
266266
/// The opening `[` bracket is already eaten.
267267
fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
268-
let elt_ty = self.parse_ty()?;
268+
let elt_ty = match self.parse_ty() {
269+
Ok(ty) => ty,
270+
Err(mut err)
271+
if self.look_ahead(1, |t| t.kind == token::CloseDelim(token::Bracket))
272+
| self.look_ahead(1, |t| t.kind == token::Semi) =>
273+
{
274+
// Recover from `[LIT; EXPR]` and `[LIT]`
275+
self.bump();
276+
err.emit();
277+
self.mk_ty(self.prev_token.span, TyKind::Err)
278+
}
279+
Err(err) => return Err(err),
280+
};
269281
let ty = if self.eat(&token::Semi) {
270282
TyKind::Array(elt_ty, self.parse_anon_const_expr()?)
271283
} else {

src/test/ui/issues/issue-39616.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0`
2-
//~| ERROR expected one of `)`, `,`, `->`, `;`, `where`, or `{`, found `]`
32

43
fn main() {}

src/test/ui/issues/issue-39616.stderr

+1-7
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,5 @@ error: expected type, found `0`
44
LL | fn foo(a: [0; 1]) {}
55
| ^ expected type
66

7-
error: expected one of `)`, `,`, `->`, `;`, `where`, or `{`, found `]`
8-
--> $DIR/issue-39616.rs:1:16
9-
|
10-
LL | fn foo(a: [0; 1]) {}
11-
| ^ expected one of `)`, `,`, `->`, `;`, `where`, or `{`
12-
13-
error: aborting due to 2 previous errors
7+
error: aborting due to previous error
148

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Verify that '>' is not both expected and found at the same time, as it used
22
// to happen in #24780. For example, following should be an error:
3-
// expected one of ..., `>`, ... found `>`
3+
// expected one of ..., `>`, ... found `>`. No longer exactly this, but keeping for posterity.
44

5-
fn foo() -> Vec<usize>> {
6-
//~^ ERROR expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>`
5+
fn foo() -> Vec<usize>> { //~ ERROR unmatched angle bracket
76
Vec::new()
87
}
8+
9+
fn main() {}

src/test/ui/parser/issue-24780.stderr

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

77
error: aborting due to previous error
88

src/test/ui/parser/issue-6610.stderr

+3-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ error: expected one of `->`, `;`, `where`, or `{`, found `}`
22
--> $DIR/issue-6610.rs:1:20
33
|
44
LL | trait Foo { fn a() }
5-
| - ^
6-
| | |
7-
| | expected one of `->`, `;`, `where`, or `{`
8-
| | the item list ends here
9-
| while parsing this item list starting here
5+
| - ^ expected one of `->`, `;`, `where`, or `{`
6+
| |
7+
| while parsing this `fn`
108

119
error: aborting due to previous error
1210

0 commit comments

Comments
 (0)