Skip to content

Commit

Permalink
Rollup merge of #78379 - estebank:fn-signature-parse, r=varkor
Browse files Browse the repository at this point in the history
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]`
  • Loading branch information
Dylan-DPC authored Oct 28, 2020
2 parents 1a64e57 + ff61949 commit 892ebe9
Show file tree
Hide file tree
Showing 16 changed files with 79 additions and 48 deletions.
8 changes: 0 additions & 8 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1557,14 +1557,6 @@ impl<'a> Parser<'a> {
}
}

pub(super) fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
let token_str = super::token_descr(&self.token);
let msg = &format!("expected `;` or `{{`, found {}", token_str);
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected `;` or `{`");
Err(err)
}

pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
if let token::DocComment(..) = self.token.kind {
self.struct_span_err(
Expand Down
41 changes: 32 additions & 9 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ impl<'a> Parser<'a> {
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`

let mut sig_hi = self.prev_token.span;
let body = self.parse_fn_body(attrs, &mut sig_hi)?; // `;` or `{ ... }`.
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`.
let fn_sig_span = sig_lo.to(sig_hi);
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
}
Expand All @@ -1549,12 +1549,12 @@ impl<'a> Parser<'a> {
fn parse_fn_body(
&mut self,
attrs: &mut Vec<Attribute>,
ident: &Ident,
sig_hi: &mut Span,
) -> PResult<'a, Option<P<Block>>> {
let (inner_attrs, body) = if self.check(&token::Semi) {
let (inner_attrs, body) = if self.eat(&token::Semi) {
// Include the trailing semicolon in the span of the signature
*sig_hi = self.token.span;
self.bump(); // `;`
*sig_hi = self.prev_token.span;
(Vec::new(), None)
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
Expand All @@ -1574,7 +1574,21 @@ impl<'a> Parser<'a> {
.emit();
(Vec::new(), Some(self.mk_block_err(span)))
} else {
return self.expected_semi_or_open_brace();
if let Err(mut err) =
self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
{
if self.token.kind == token::CloseDelim(token::Brace) {
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
// the AST for typechecking.
err.span_label(ident.span, "while parsing this `fn`");
err.emit();
(Vec::new(), None)
} else {
return Err(err);
}
} else {
unreachable!()
}
};
attrs.extend(inner_attrs);
Ok(body)
Expand Down Expand Up @@ -1652,10 +1666,19 @@ impl<'a> Parser<'a> {
req_name: ReqName,
ret_allow_plus: AllowPlus,
) -> PResult<'a, P<FnDecl>> {
Ok(P(FnDecl {
inputs: self.parse_fn_params(req_name)?,
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
}))
let inputs = self.parse_fn_params(req_name)?;
let output = self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?;

if let ast::FnRetTy::Ty(ty) = &output {
if let TyKind::Path(_, Path { segments, .. }) = &ty.kind {
if let [.., last] = &segments[..] {
// Detect and recover `fn foo() -> Vec<i32>> {}`
self.check_trailing_angle_brackets(last, &[&token::OpenDelim(token::Brace)]);
}
}
}

Ok(P(FnDecl { inputs, output }))
}

/// Parses the parameter list of a function, including the `(` and `)` delimiters.
Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,19 @@ impl<'a> Parser<'a> {
/// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type.
/// The opening `[` bracket is already eaten.
fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
let elt_ty = self.parse_ty()?;
let elt_ty = match self.parse_ty() {
Ok(ty) => ty,
Err(mut err)
if self.look_ahead(1, |t| t.kind == token::CloseDelim(token::Bracket))
| self.look_ahead(1, |t| t.kind == token::Semi) =>
{
// Recover from `[LIT; EXPR]` and `[LIT]`
self.bump();
err.emit();
self.mk_ty(self.prev_token.span, TyKind::Err)
}
Err(err) => return Err(err),
};
let ty = if self.eat(&token::Semi) {
TyKind::Array(elt_ty, self.parse_anon_const_expr()?)
} else {
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/issues/issue-39616.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0`
//~| ERROR expected `;` or `{`, found `]`

fn main() {}
8 changes: 1 addition & 7 deletions src/test/ui/issues/issue-39616.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,5 @@ error: expected type, found `0`
LL | fn foo(a: [0; 1]) {}
| ^ expected type

error: expected `;` or `{`, found `]`
--> $DIR/issue-39616.rs:1:16
|
LL | fn foo(a: [0; 1]) {}
| ^ expected `;` or `{`

error: aborting due to 2 previous errors
error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-58856-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ impl A {
//~^ ERROR cannot find type `A` in this scope
fn b(self>
//~^ ERROR expected one of `)`, `,`, or `:`, found `>`
//~| ERROR expected `;` or `{`, found `>`
//~| ERROR expected one of `->`, `;`, `where`, or `{`, found `>`
}

fn main() {}
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-58856-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ LL | fn b(self>
| |
| unclosed delimiter

error: expected `;` or `{`, found `>`
error: expected one of `->`, `;`, `where`, or `{`, found `>`
--> $DIR/issue-58856-1.rs:3:14
|
LL | impl A {
| - while parsing this item list starting here
LL |
LL | fn b(self>
| ^ expected `;` or `{`
| ^ expected one of `->`, `;`, `where`, or `{`
...
LL | }
| - the item list ends here
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/parser/fn-colon-return-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:`
x
}

fn main() {}
8 changes: 8 additions & 0 deletions src/test/ui/parser/fn-colon-return-type.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: expected one of `->`, `;`, `where`, or `{`, found `:`
--> $DIR/fn-colon-return-type.rs:1:15
|
LL | fn foo(x: i32): i32 {
| ^ expected one of `->`, `;`, `where`, or `{`

error: aborting due to previous error

7 changes: 4 additions & 3 deletions src/test/ui/parser/issue-24780.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Verify that '>' is not both expected and found at the same time, as it used
// to happen in #24780. For example, following should be an error:
// expected one of ..., `>`, ... found `>`
// expected one of ..., `>`, ... found `>`. No longer exactly this, but keeping for posterity.

fn foo() -> Vec<usize>> {
//~^ ERROR expected `;` or `{`, found `>`
fn foo() -> Vec<usize>> { //~ ERROR unmatched angle bracket
Vec::new()
}

fn main() {}
4 changes: 2 additions & 2 deletions src/test/ui/parser/issue-24780.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: expected `;` or `{`, found `>`
error: unmatched angle bracket
--> $DIR/issue-24780.rs:5:23
|
LL | fn foo() -> Vec<usize>> {
| ^ expected `;` or `{`
| ^^ help: remove extra angle bracket

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/parser/issue-6610.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
trait Foo { fn a() } //~ ERROR expected `;` or `{`, found `}`
trait Foo { fn a() } //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `}`

fn main() {}
10 changes: 4 additions & 6 deletions src/test/ui/parser/issue-6610.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
error: expected `;` or `{`, found `}`
error: expected one of `->`, `;`, `where`, or `{`, found `}`
--> $DIR/issue-6610.rs:1:20
|
LL | trait Foo { fn a() }
| - ^
| | |
| | expected `;` or `{`
| | the item list ends here
| while parsing this item list starting here
| - ^ expected one of `->`, `;`, `where`, or `{`
| |
| while parsing this `fn`

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/parser/missing_right_paren.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ error: expected one of `:` or `|`, found `)`
LL | fn main((ؼ
| ^ expected one of `:` or `|`

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

error: aborting due to 4 previous errors

3 changes: 1 addition & 2 deletions src/test/ui/parser/not-a-pred.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// error-pattern: lt

fn f(a: isize, b: isize) : lt(a, b) { }
//~^ ERROR expected one of `->`, `;`, `where`, or `{`, found `:`

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

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/parser/not-a-pred.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: expected `;` or `{`, found `:`
--> $DIR/not-a-pred.rs:3:26
error: expected one of `->`, `;`, `where`, or `{`, found `:`
--> $DIR/not-a-pred.rs:1:26
|
LL | fn f(a: isize, b: isize) : lt(a, b) { }
| ^ expected `;` or `{`
| ^ expected one of `->`, `;`, `where`, or `{`

error: aborting due to previous error

0 comments on commit 892ebe9

Please sign in to comment.