Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 6 commits into from
Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 77 additions & 8 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub enum PathStyle {
enum SemiColonMode {
Break,
Ignore,
Comma,
}

#[derive(Clone, Copy, PartialEq, Debug)]
Expand Down Expand Up @@ -1988,6 +1989,44 @@ impl<'a> Parser<'a> {

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); }
};

Expand Down Expand Up @@ -2656,18 +2695,37 @@ impl<'a> Parser<'a> {
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;
}
}
}
}
Expand All @@ -2676,9 +2734,10 @@ impl<'a> Parser<'a> {
&[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);
}
}
}
Expand Down Expand Up @@ -4538,13 +4597,13 @@ impl<'a> Parser<'a> {
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) => {
Expand All @@ -4556,15 +4615,25 @@ impl<'a> Parser<'a> {
}
token::Eof => {
debug!("recover_stmt_ return - Eof");
return;
break;
}
token::Semi => {
self.bump();
if break_on_semi == SemiColonMode::Break &&
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();
}
}
_ => {
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/issues/issue-52496.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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 mismatched types
//~| ERROR missing field `baz` in initializer of `Foo`
//~| ERROR expected identifier, found `.`
}
48 changes: 48 additions & 0 deletions src/test/ui/issues/issue-52496.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
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[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.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`.
4 changes: 3 additions & 1 deletion src/test/ui/parser/removed-syntax-with-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/parser/removed-syntax-with-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/parser/struct-field-numeric-shorthand.rs
Original file line number Diff line number Diff line change
@@ -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`
}
22 changes: 19 additions & 3 deletions src/test/ui/parser/struct-field-numeric-shorthand.stderr
Original file line number Diff line number Diff line change
@@ -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`.
11 changes: 11 additions & 0 deletions src/test/ui/suggestions/recover-invalid-float.rs
Original file line number Diff line number Diff line change
@@ -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
}
42 changes: 42 additions & 0 deletions src/test/ui/suggestions/recover-invalid-float.stderr
Original file line number Diff line number Diff line change
@@ -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`.