Rollup merge of #105141 - ohno418:fix-ice-on-invalid-var-decl-in-macro-call, r=compiler-errors

Fix ICE on invalid variable declarations in macro calls

This fixes ICE that happens with invalid variable declarations in macro calls like:

```rust
macro_rules! m { ($s:stmt) => {} }
m! { var x }
m! { auto x }
m! { mut x }
```

Found this is because of not collecting tokens on recovery, so I changed to force collect them.

Fixes https://github.com/rust-lang/rust/issues/103529.
This commit is contained in:
Matthias Krüger 2022-12-04 16:25:32 +01:00 committed by GitHub
commit b1816833bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 19 deletions

View File

@ -72,14 +72,22 @@ impl<'a> Parser<'a> {
Ok(Some(if self.token.is_keyword(kw::Let) { Ok(Some(if self.token.is_keyword(kw::Let) {
self.parse_local_mk(lo, attrs, capture_semi, force_collect)? self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
} else if self.is_kw_followed_by_ident(kw::Mut) { } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::MissingLet)? self.recover_stmt_local_after_let(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
} else if self.is_kw_followed_by_ident(kw::Auto) { } else if self.is_kw_followed_by_ident(kw::Auto) && self.may_recover() {
self.bump(); // `auto` self.bump(); // `auto`
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)? self.recover_stmt_local_after_let(
} else if self.is_kw_followed_by_ident(sym::var) { lo,
attrs,
InvalidVariableDeclarationSub::UseLetNotAuto,
)?
} else if self.is_kw_followed_by_ident(sym::var) && self.may_recover() {
self.bump(); // `var` self.bump(); // `var`
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)? self.recover_stmt_local_after_let(
lo,
attrs,
InvalidVariableDeclarationSub::UseLetNotVar,
)?
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
// We have avoided contextual keywords like `union`, items with `crate` visibility, // We have avoided contextual keywords like `union`, items with `crate` visibility,
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
@ -213,13 +221,21 @@ impl<'a> Parser<'a> {
} }
} }
fn recover_stmt_local( fn recover_stmt_local_after_let(
&mut self, &mut self,
lo: Span, lo: Span,
attrs: AttrWrapper, attrs: AttrWrapper,
subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub, subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub,
) -> PResult<'a, Stmt> { ) -> PResult<'a, Stmt> {
let stmt = self.recover_local_after_let(lo, attrs)?; let stmt =
self.collect_tokens_trailing_token(attrs, ForceCollect::Yes, |this, attrs| {
let local = this.parse_local(attrs)?;
// FIXME - maybe capture semicolon in recovery?
Ok((
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
TrailingToken::None,
))
})?;
self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) }); self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
Ok(stmt) Ok(stmt)
} }
@ -243,17 +259,6 @@ impl<'a> Parser<'a> {
}) })
} }
fn recover_local_after_let(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let local = this.parse_local(attrs)?;
// FIXME - maybe capture semicolon in recovery?
Ok((
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
TrailingToken::None,
))
})
}
/// Parses a local variable declaration. /// Parses a local variable declaration.
fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> { fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
let lo = self.prev_token.span; let lo = self.prev_token.span;

View File

@ -0,0 +1,13 @@
macro_rules! m {
($s:stmt) => {}
}
m! { mut x }
//~^ ERROR expected expression, found keyword `mut`
//~| ERROR expected a statement
m! { auto x }
//~^ ERROR invalid variable declaration
m! { var x }
//~^ ERROR invalid variable declaration
fn main() {}

View File

@ -0,0 +1,39 @@
error: expected expression, found keyword `mut`
--> $DIR/issue-103529.rs:5:6
|
LL | m! { mut x }
| ^^^ expected expression
error: expected a statement
--> $DIR/issue-103529.rs:5:10
|
LL | ($s:stmt) => {}
| ------- while parsing argument for this `stmt` macro fragment
...
LL | m! { mut x }
| ^
error: invalid variable declaration
--> $DIR/issue-103529.rs:8:6
|
LL | m! { auto x }
| ^^^^
|
help: write `let` instead of `auto` to introduce a new variable
|
LL | m! { let x }
| ~~~
error: invalid variable declaration
--> $DIR/issue-103529.rs:10:6
|
LL | m! { var x }
| ^^^
|
help: write `let` instead of `var` to introduce a new variable
|
LL | m! { let x }
| ~~~
error: aborting due to 4 previous errors