Recover from parse errors in struct literal fields
Attempt to recover from parse errors while parsing a struct's literal fields by skipping tokens until a comma or the closing brace is found. This allows errors in other fields to be reported.
This commit is contained in:
parent
0c0c585281
commit
b1f169fe7a
@ -100,6 +100,7 @@ pub enum PathStyle {
|
||||
enum SemiColonMode {
|
||||
Break,
|
||||
Ignore,
|
||||
Comma,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
@ -2656,18 +2657,37 @@ fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Att
|
||||
break;
|
||||
}
|
||||
|
||||
let mut recovery_field = None;
|
||||
if let token::Ident(ident, _) = self.token {
|
||||
if !self.token.is_reserved_ident() {
|
||||
let mut ident = ident.clone();
|
||||
ident.span = self.span;
|
||||
recovery_field = Some(ast::Field {
|
||||
ident,
|
||||
span: self.span,
|
||||
expr: self.mk_expr(self.span, ExprKind::Err, ThinVec::new()),
|
||||
is_shorthand: true,
|
||||
attrs: ThinVec::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
match self.parse_field() {
|
||||
Ok(f) => fields.push(f),
|
||||
Err(mut e) => {
|
||||
e.span_label(struct_sp, "while parsing this struct");
|
||||
e.emit();
|
||||
if let Some(f) = recovery_field {
|
||||
fields.push(f);
|
||||
}
|
||||
|
||||
// If the next token is a comma, then try to parse
|
||||
// what comes next as additional fields, rather than
|
||||
// bailing out until next `}`.
|
||||
if self.token != token::Comma {
|
||||
self.recover_stmt();
|
||||
break;
|
||||
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
|
||||
if self.token != token::Comma {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2676,9 +2696,10 @@ fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Att
|
||||
&[token::CloseDelim(token::Brace)]) {
|
||||
Ok(()) => {}
|
||||
Err(mut e) => {
|
||||
e.span_label(struct_sp, "while parsing this struct");
|
||||
e.emit();
|
||||
self.recover_stmt();
|
||||
break;
|
||||
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
|
||||
self.eat(&token::Comma);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4538,13 +4559,13 @@ fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockM
|
||||
token::CloseDelim(token::DelimToken::Brace) => {
|
||||
if brace_depth == 0 {
|
||||
debug!("recover_stmt_ return - close delim {:?}", self.token);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
brace_depth -= 1;
|
||||
self.bump();
|
||||
if in_block && bracket_depth == 0 && brace_depth == 0 {
|
||||
debug!("recover_stmt_ return - block end {:?}", self.token);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
token::CloseDelim(token::DelimToken::Bracket) => {
|
||||
@ -4556,7 +4577,7 @@ fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockM
|
||||
}
|
||||
token::Eof => {
|
||||
debug!("recover_stmt_ return - Eof");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
token::Semi => {
|
||||
self.bump();
|
||||
@ -4564,7 +4585,17 @@ fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockM
|
||||
brace_depth == 0 &&
|
||||
bracket_depth == 0 {
|
||||
debug!("recover_stmt_ return - Semi");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
token::Comma => {
|
||||
if break_on_semi == SemiColonMode::Comma &&
|
||||
brace_depth == 0 &&
|
||||
bracket_depth == 0 {
|
||||
debug!("recover_stmt_ return - Semi");
|
||||
break;
|
||||
} else {
|
||||
self.bump();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
13
src/test/ui/issues/issue-52496.rs
Normal file
13
src/test/ui/issues/issue-52496.rs
Normal file
@ -0,0 +1,13 @@
|
||||
struct Foo { bar: f64, baz: i64, bat: i64 }
|
||||
|
||||
fn main() {
|
||||
let _ = Foo { bar: .5, baz: 42 };
|
||||
//~^ ERROR expected expression
|
||||
//~| ERROR missing field `bat` in initializer of `Foo`
|
||||
let bar = 1.5f32;
|
||||
let _ = Foo { bar.into(), bat: -1, . };
|
||||
//~^ ERROR expected one of
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR missing field `baz` in initializer of `Foo`
|
||||
//~| ERROR expected identifier, found `.`
|
||||
}
|
50
src/test/ui/issues/issue-52496.stderr
Normal file
50
src/test/ui/issues/issue-52496.stderr
Normal file
@ -0,0 +1,50 @@
|
||||
error: expected expression, found `.`
|
||||
--> $DIR/issue-52496.rs:4:24
|
||||
|
|
||||
LL | let _ = Foo { bar: .5, baz: 42 };
|
||||
| --- ^ expected expression
|
||||
| |
|
||||
| while parsing this struct
|
||||
|
||||
error: expected one of `,` or `}`, found `.`
|
||||
--> $DIR/issue-52496.rs:8:22
|
||||
|
|
||||
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||
| --- ^ expected one of `,` or `}` here
|
||||
| |
|
||||
| while parsing this struct
|
||||
|
||||
error: expected identifier, found `.`
|
||||
--> $DIR/issue-52496.rs:8:40
|
||||
|
|
||||
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||
| --- ^ expected identifier
|
||||
| |
|
||||
| while parsing this struct
|
||||
|
||||
error[E0063]: missing field `bat` in initializer of `Foo`
|
||||
--> $DIR/issue-52496.rs:4:13
|
||||
|
|
||||
LL | let _ = Foo { bar: .5, baz: 42 };
|
||||
| ^^^ missing `bat`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-52496.rs:8:19
|
||||
|
|
||||
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||
| ^^^ expected f64, found f32
|
||||
help: you can cast an `f32` to `f64` in a lossless way
|
||||
|
|
||||
LL | let _ = Foo { bar: bar.into().into(), bat: -1, . };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0063]: missing field `baz` in initializer of `Foo`
|
||||
--> $DIR/issue-52496.rs:8:13
|
||||
|
|
||||
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||
| ^^^ missing `baz`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors occurred: E0063, E0308.
|
||||
For more information about an error, try `rustc --explain E0063`.
|
@ -2,7 +2,9 @@ error: expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
|
||||
--> $DIR/removed-syntax-with-1.rs:8:25
|
||||
|
|
||||
LL | let b = S { foo: () with a };
|
||||
| ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator here
|
||||
| - ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator here
|
||||
| |
|
||||
| while parsing this struct
|
||||
|
||||
error[E0063]: missing field `bar` in initializer of `main::S`
|
||||
--> $DIR/removed-syntax-with-1.rs:8:13
|
||||
|
@ -2,7 +2,9 @@ error: expected one of `,` or `}`, found `a`
|
||||
--> $DIR/removed-syntax-with-2.rs:8:31
|
||||
|
|
||||
LL | let b = S { foo: (), with a };
|
||||
| ^ expected one of `,` or `}` here
|
||||
| - ^ expected one of `,` or `}` here
|
||||
| |
|
||||
| while parsing this struct
|
||||
|
||||
error[E0425]: cannot find value `with` in this scope
|
||||
--> $DIR/removed-syntax-with-2.rs:8:26
|
||||
|
@ -1,6 +1,9 @@
|
||||
struct Rgb(u8, u8, u8);
|
||||
|
||||
fn main() {
|
||||
let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
|
||||
//~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb`
|
||||
let _ = Rgb { 0, 1, 2 };
|
||||
//~^ ERROR expected identifier, found `0`
|
||||
//~| ERROR expected identifier, found `1`
|
||||
//~| ERROR expected identifier, found `2`
|
||||
//~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb`
|
||||
}
|
||||
|
@ -1,17 +1,33 @@
|
||||
error: expected identifier, found `0`
|
||||
--> $DIR/struct-field-numeric-shorthand.rs:4:19
|
||||
|
|
||||
LL | let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
|
||||
LL | let _ = Rgb { 0, 1, 2 };
|
||||
| --- ^ expected identifier
|
||||
| |
|
||||
| while parsing this struct
|
||||
|
||||
error: expected identifier, found `1`
|
||||
--> $DIR/struct-field-numeric-shorthand.rs:4:22
|
||||
|
|
||||
LL | let _ = Rgb { 0, 1, 2 };
|
||||
| --- ^ expected identifier
|
||||
| |
|
||||
| while parsing this struct
|
||||
|
||||
error: expected identifier, found `2`
|
||||
--> $DIR/struct-field-numeric-shorthand.rs:4:25
|
||||
|
|
||||
LL | let _ = Rgb { 0, 1, 2 };
|
||||
| --- ^ expected identifier
|
||||
| |
|
||||
| while parsing this struct
|
||||
|
||||
error[E0063]: missing fields `0`, `1`, `2` in initializer of `Rgb`
|
||||
--> $DIR/struct-field-numeric-shorthand.rs:4:13
|
||||
|
|
||||
LL | let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
|
||||
LL | let _ = Rgb { 0, 1, 2 };
|
||||
| ^^^ missing `0`, `1`, `2`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0063`.
|
||||
|
Loading…
Reference in New Issue
Block a user