From b1f169fe7a19cf10f70ee2aa2513276185c70e9b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Esteban=20K=C3=BCber?= Date: Sun, 20 Jan 2019 00:37:06 -0800 Subject: [PATCH] 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. --- src/libsyntax/parse/parser.rs | 47 ++++++++++++++--- src/test/ui/issues/issue-52496.rs | 13 +++++ src/test/ui/issues/issue-52496.stderr | 50 +++++++++++++++++++ .../ui/parser/removed-syntax-with-1.stderr | 4 +- .../ui/parser/removed-syntax-with-2.stderr | 4 +- .../parser/struct-field-numeric-shorthand.rs | 7 ++- .../struct-field-numeric-shorthand.stderr | 22 ++++++-- 7 files changed, 132 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/issues/issue-52496.rs create mode 100644 src/test/ui/issues/issue-52496.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7e15b231276..9b20937cf93 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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 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 {} 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(); } } _ => { diff --git a/src/test/ui/issues/issue-52496.rs b/src/test/ui/issues/issue-52496.rs new file mode 100644 index 00000000000..d2636b7ecb3 --- /dev/null +++ b/src/test/ui/issues/issue-52496.rs @@ -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 `.` +} diff --git a/src/test/ui/issues/issue-52496.stderr b/src/test/ui/issues/issue-52496.stderr new file mode 100644 index 00000000000..c98de6ffbed --- /dev/null +++ b/src/test/ui/issues/issue-52496.stderr @@ -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`. diff --git a/src/test/ui/parser/removed-syntax-with-1.stderr b/src/test/ui/parser/removed-syntax-with-1.stderr index 77ed4fcea51..b5956ad339d 100644 --- a/src/test/ui/parser/removed-syntax-with-1.stderr +++ b/src/test/ui/parser/removed-syntax-with-1.stderr @@ -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 diff --git a/src/test/ui/parser/removed-syntax-with-2.stderr b/src/test/ui/parser/removed-syntax-with-2.stderr index 5642d2f45ff..ee7560017a6 100644 --- a/src/test/ui/parser/removed-syntax-with-2.stderr +++ b/src/test/ui/parser/removed-syntax-with-2.stderr @@ -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 diff --git a/src/test/ui/parser/struct-field-numeric-shorthand.rs b/src/test/ui/parser/struct-field-numeric-shorthand.rs index 914588f51e1..58c40b3d96a 100644 --- a/src/test/ui/parser/struct-field-numeric-shorthand.rs +++ b/src/test/ui/parser/struct-field-numeric-shorthand.rs @@ -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` } diff --git a/src/test/ui/parser/struct-field-numeric-shorthand.stderr b/src/test/ui/parser/struct-field-numeric-shorthand.stderr index f5dc226934e..cfb1f820147 100644 --- a/src/test/ui/parser/struct-field-numeric-shorthand.stderr +++ b/src/test/ui/parser/struct-field-numeric-shorthand.stderr @@ -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`. -- 2.44.0