1
Fork 0

Rollup merge of #57779 - estebank:recover-struct-fields, r=davidtwco

Recover from parse errors in literal struct fields and incorrect float literals

Fix #52496.
This commit is contained in:
Mazdak Farrokhzad 2019-01-24 00:19:53 +01:00 committed by GitHub
commit 2dd63a2e10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 225 additions and 44 deletions

View file

@ -100,6 +100,7 @@ pub enum PathStyle {
enum SemiColonMode { enum SemiColonMode {
Break, Break,
Ignore, Ignore,
Comma,
} }
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
@ -1988,6 +1989,44 @@ impl<'a> Parser<'a> {
result.unwrap() result.unwrap()
} }
token::Dot if self.look_ahead(1, |t| match t {
token::Literal(parse::token::Lit::Integer(_) , _) => true,
_ => false,
}) => { // recover from `let x = .4;`
let lo = self.span;
self.bump();
if let token::Literal(
parse::token::Lit::Integer(val),
suffix,
) = self.token {
let suffix = suffix.and_then(|s| {
let s = s.as_str().get();
if ["f32", "f64"].contains(&s) {
Some(s)
} else {
None
}
}).unwrap_or("");
self.bump();
let sp = lo.to(self.prev_span);
let mut err = self.diagnostic()
.struct_span_err(sp, "float literals must have an integer part");
err.span_suggestion_with_applicability(
sp,
"must have an integer part",
format!("0.{}{}", val, suffix),
Applicability::MachineApplicable,
);
err.emit();
return Ok(match suffix {
"f32" => ast::LitKind::Float(val, ast::FloatTy::F32),
"f64" => ast::LitKind::Float(val, ast::FloatTy::F64),
_ => ast::LitKind::FloatUnsuffixed(val),
});
} else {
unreachable!();
};
}
_ => { return self.unexpected_last(&self.token); } _ => { return self.unexpected_last(&self.token); }
}; };
@ -2656,8 +2695,24 @@ impl<'a> Parser<'a> {
break; break;
} }
let mut recovery_field = None;
if let token::Ident(ident, _) = self.token {
if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) {
// Use in case of error after field-looking code: `S { foo: () with a }`
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: false,
attrs: ThinVec::new(),
});
}
}
let mut parsed_field = None;
match self.parse_field() { match self.parse_field() {
Ok(f) => fields.push(f), Ok(f) => parsed_field = Some(f),
Err(mut e) => { Err(mut e) => {
e.span_label(struct_sp, "while parsing this struct"); e.span_label(struct_sp, "while parsing this struct");
e.emit(); e.emit();
@ -2666,19 +2721,28 @@ impl<'a> Parser<'a> {
// what comes next as additional fields, rather than // what comes next as additional fields, rather than
// bailing out until next `}`. // bailing out until next `}`.
if self.token != token::Comma { if self.token != token::Comma {
self.recover_stmt(); self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
break; if self.token != token::Comma {
break;
}
} }
} }
} }
match self.expect_one_of(&[token::Comma], match self.expect_one_of(&[token::Comma],
&[token::CloseDelim(token::Brace)]) { &[token::CloseDelim(token::Brace)]) {
Ok(()) => {} Ok(()) => if let Some(f) = parsed_field.or(recovery_field) {
// only include the field if there's no parse error for the field name
fields.push(f);
}
Err(mut e) => { Err(mut e) => {
if let Some(f) = recovery_field {
fields.push(f);
}
e.span_label(struct_sp, "while parsing this struct");
e.emit(); e.emit();
self.recover_stmt(); self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
break; self.eat(&token::Comma);
} }
} }
} }
@ -4542,13 +4606,13 @@ impl<'a> Parser<'a> {
token::CloseDelim(token::DelimToken::Brace) => { token::CloseDelim(token::DelimToken::Brace) => {
if brace_depth == 0 { if brace_depth == 0 {
debug!("recover_stmt_ return - close delim {:?}", self.token); debug!("recover_stmt_ return - close delim {:?}", self.token);
return; break;
} }
brace_depth -= 1; brace_depth -= 1;
self.bump(); self.bump();
if in_block && bracket_depth == 0 && brace_depth == 0 { if in_block && bracket_depth == 0 && brace_depth == 0 {
debug!("recover_stmt_ return - block end {:?}", self.token); debug!("recover_stmt_ return - block end {:?}", self.token);
return; break;
} }
} }
token::CloseDelim(token::DelimToken::Bracket) => { token::CloseDelim(token::DelimToken::Bracket) => {
@ -4560,7 +4624,7 @@ impl<'a> Parser<'a> {
} }
token::Eof => { token::Eof => {
debug!("recover_stmt_ return - Eof"); debug!("recover_stmt_ return - Eof");
return; break;
} }
token::Semi => { token::Semi => {
self.bump(); self.bump();
@ -4568,7 +4632,17 @@ impl<'a> Parser<'a> {
brace_depth == 0 && brace_depth == 0 &&
bracket_depth == 0 { bracket_depth == 0 {
debug!("recover_stmt_ return - Semi"); 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();
} }
} }
_ => { _ => {

View file

@ -0,0 +1,12 @@
struct Foo { bar: f64, baz: i64, bat: i64 }
fn main() {
let _ = Foo { bar: .5, baz: 42 };
//~^ ERROR float literals must have an integer part
//~| ERROR missing field `bat` in initializer of `Foo`
let bar = 1.5f32;
let _ = Foo { bar.into(), bat: -1, . };
//~^ ERROR expected one of
//~| ERROR missing fields `bar`, `baz` in initializer of `Foo`
//~| ERROR expected identifier, found `.`
}

View file

@ -0,0 +1,37 @@
error: float literals must have an integer part
--> $DIR/issue-52496.rs:4:24
|
LL | let _ = Foo { bar: .5, baz: 42 };
| ^^ help: must have an integer part: `0.5`
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[E0063]: missing fields `bar`, `baz` in initializer of `Foo`
--> $DIR/issue-52496.rs:8:13
|
LL | let _ = Foo { bar.into(), bat: -1, . };
| ^^^ missing `bar`, `baz`
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0063`.

View file

@ -5,7 +5,6 @@ fn main() {
} }
let a = S { foo: (), bar: () }; let a = S { foo: (), bar: () };
let b = S { foo: () with a }; let b = S { foo: () with a, bar: () };
//~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `with` //~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
//~| ERROR missing field `bar` in initializer of `main::S`
} }

View file

@ -1,15 +1,10 @@
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `with` error: expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
--> $DIR/removed-syntax-with-1.rs:8:25 --> $DIR/removed-syntax-with-1.rs:8:25
| |
LL | let b = S { foo: () with a }; LL | let b = S { foo: () with a, bar: () };
| ^^^^ 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` error: aborting due to previous error
--> $DIR/removed-syntax-with-1.rs:8:13
|
LL | let b = S { foo: () with a };
| ^ missing `bar`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0063`.

View file

@ -7,6 +7,5 @@ fn main() {
let a = S { foo: (), bar: () }; let a = S { foo: (), bar: () };
let b = S { foo: (), with a }; let b = S { foo: (), with a };
//~^ ERROR expected one of `,` or `}`, found `a` //~^ ERROR expected one of `,` or `}`, found `a`
//~| ERROR cannot find value `with` in this scope //~| ERROR missing field `bar` in initializer of `main::S`
//~| ERROR struct `main::S` has no field named `with`
} }

View file

@ -2,23 +2,16 @@ error: expected one of `,` or `}`, found `a`
--> $DIR/removed-syntax-with-2.rs:8:31 --> $DIR/removed-syntax-with-2.rs:8:31
| |
LL | let b = S { foo: (), with a }; 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 error[E0063]: missing field `bar` in initializer of `main::S`
--> $DIR/removed-syntax-with-2.rs:8:26 --> $DIR/removed-syntax-with-2.rs:8:13
| |
LL | let b = S { foo: (), with a }; LL | let b = S { foo: (), with a };
| ^^^^ not found in this scope | ^ missing `bar`
error[E0560]: struct `main::S` has no field named `with` error: aborting due to 2 previous errors
--> $DIR/removed-syntax-with-2.rs:8:26
|
LL | let b = S { foo: (), with a };
| ^^^^ `main::S` does not have this field
|
= note: available fields are: `foo`, `bar`
error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0063`.
Some errors occurred: E0425, E0560.
For more information about an error, try `rustc --explain E0425`.

View file

@ -1,6 +1,9 @@
struct Rgb(u8, u8, u8); struct Rgb(u8, u8, u8);
fn main() { fn main() {
let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0` let _ = Rgb { 0, 1, 2 };
//~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb` //~^ 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`
} }

View file

@ -1,17 +1,33 @@
error: expected identifier, found `0` error: expected identifier, found `0`
--> $DIR/struct-field-numeric-shorthand.rs:4:19 --> $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 | --- ^ expected identifier
| | | |
| while parsing this struct | 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` error[E0063]: missing fields `0`, `1`, `2` in initializer of `Rgb`
--> $DIR/struct-field-numeric-shorthand.rs:4:13 --> $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` | ^^^ 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`. For more information about this error, try `rustc --explain E0063`.

View file

@ -0,0 +1,11 @@
fn main() {
let _: usize = .3;
//~^ ERROR float literals must have an integer part
//~| ERROR mismatched types
let _: usize = .42f32;
//~^ ERROR float literals must have an integer part
//~| ERROR mismatched types
let _: usize = .5f64;
//~^ ERROR float literals must have an integer part
//~| ERROR mismatched types
}

View file

@ -0,0 +1,42 @@
error: float literals must have an integer part
--> $DIR/recover-invalid-float.rs:2:20
|
LL | let _: usize = .3;
| ^^ help: must have an integer part: `0.3`
error: float literals must have an integer part
--> $DIR/recover-invalid-float.rs:5:20
|
LL | let _: usize = .42f32;
| ^^^^^^ help: must have an integer part: `0.42f32`
error: float literals must have an integer part
--> $DIR/recover-invalid-float.rs:8:20
|
LL | let _: usize = .5f64;
| ^^^^^ help: must have an integer part: `0.5f64`
error[E0308]: mismatched types
--> $DIR/recover-invalid-float.rs:2:20
|
LL | let _: usize = .3;
| ^^ expected usize, found floating-point number
|
= note: expected type `usize`
found type `{float}`
error[E0308]: mismatched types
--> $DIR/recover-invalid-float.rs:5:20
|
LL | let _: usize = .42f32;
| ^^^^^^ expected usize, found f32
error[E0308]: mismatched types
--> $DIR/recover-invalid-float.rs:8:20
|
LL | let _: usize = .5f64;
| ^^^^^ expected usize, found f64
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0308`.