Skip to content

Commit 892ebe9

Browse files
authored
Rollup merge of #78379 - estebank:fn-signature-parse, r=varkor
Tweak invalid `fn` header and body parsing * Rely on regular "expected"/"found" parser error for `fn`, fix #77115 * Recover empty `fn` bodies when encountering `}` * Recover trailing `>` in return types * Recover from non-type in array type `[<BAD TOKEN>; LEN]`
2 parents 1a64e57 + ff61949 commit 892ebe9

16 files changed

+79
-48
lines changed

compiler/rustc_parse/src/parser/diagnostics.rs

-8
Original file line numberDiff line numberDiff line change
@@ -1557,14 +1557,6 @@ impl<'a> Parser<'a> {
15571557
}
15581558
}
15591559

1560-
pub(super) fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
1561-
let token_str = super::token_descr(&self.token);
1562-
let msg = &format!("expected `;` or `{{`, found {}", token_str);
1563-
let mut err = self.struct_span_err(self.token.span, msg);
1564-
err.span_label(self.token.span, "expected `;` or `{`");
1565-
Err(err)
1566-
}
1567-
15681560
pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
15691561
if let token::DocComment(..) = self.token.kind {
15701562
self.struct_span_err(

compiler/rustc_parse/src/parser/item.rs

+32-9
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,12 +1549,12 @@ 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>>> {
1554-
let (inner_attrs, body) = if self.check(&token::Semi) {
1555+
let (inner_attrs, body) = if self.eat(&token::Semi) {
15551556
// Include the trailing semicolon in the span of the signature
1556-
*sig_hi = self.token.span;
1557-
self.bump(); // `;`
1557+
*sig_hi = self.prev_token.span;
15581558
(Vec::new(), None)
15591559
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
15601560
self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
@@ -1574,7 +1574,21 @@ impl<'a> Parser<'a> {
15741574
.emit();
15751575
(Vec::new(), Some(self.mk_block_err(span)))
15761576
} else {
1577-
return self.expected_semi_or_open_brace();
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+
}
15781592
};
15791593
attrs.extend(inner_attrs);
15801594
Ok(body)
@@ -1652,10 +1666,19 @@ impl<'a> Parser<'a> {
16521666
req_name: ReqName,
16531667
ret_allow_plus: AllowPlus,
16541668
) -> PResult<'a, P<FnDecl>> {
1655-
Ok(P(FnDecl {
1656-
inputs: self.parse_fn_params(req_name)?,
1657-
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
1658-
}))
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 }))
16591682
}
16601683

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

src/test/ui/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 `;` or `{`, found `>`
5+
//~| ERROR expected one of `->`, `;`, `where`, or `{`, found `>`
66
}
77

88
fn main() {}

src/test/ui/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 `;` 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 `;` or `{`
16+
| ^ expected one of `->`, `;`, `where`, or `{`
1717
...
1818
LL | }
1919
| - the item list ends here
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:`
2+
x
3+
}
4+
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected one of `->`, `;`, `where`, or `{`, found `:`
2+
--> $DIR/fn-colon-return-type.rs:1:15
3+
|
4+
LL | fn foo(x: i32): i32 {
5+
| ^ expected one of `->`, `;`, `where`, or `{`
6+
7+
error: aborting due to previous error
8+

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 `;` 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 `;` or `{`, found `>`
1+
error: unmatched angle bracket
22
--> $DIR/issue-24780.rs:5:23
33
|
44
LL | fn foo() -> Vec<usize>> {
5-
| ^ expected `;` or `{`
5+
| ^^ help: remove extra angle bracket
66

77
error: aborting due to previous error
88

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
trait Foo { fn a() } //~ ERROR expected `;` or `{`, found `}`
1+
trait Foo { fn a() } //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `}`
22

33
fn main() {}

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

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
error: expected `;` or `{`, found `}`
1+
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 `;` 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

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 `;` 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 `;` or `{`
29+
| ^ expected one of `->`, `;`, `where`, or `{`
3030

3131
error: aborting due to 4 previous errors
3232

src/test/ui/parser/not-a-pred.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
// error-pattern: lt
2-
31
fn f(a: isize, b: isize) : lt(a, b) { }
2+
//~^ ERROR expected one of `->`, `;`, `where`, or `{`, found `:`
43

54
fn lt(a: isize, b: isize) { }
65

src/test/ui/parser/not-a-pred.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected `;` or `{`, found `:`
2-
--> $DIR/not-a-pred.rs:3:26
1+
error: expected one of `->`, `;`, `where`, or `{`, found `:`
2+
--> $DIR/not-a-pred.rs:1:26
33
|
44
LL | fn f(a: isize, b: isize) : lt(a, b) { }
5-
| ^ expected `;` or `{`
5+
| ^ expected one of `->`, `;`, `where`, or `{`
66

77
error: aborting due to previous error
88

0 commit comments

Comments
 (0)