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 2 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
73 changes: 65 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,32 @@ impl<'a> Parser<'a> {

result.unwrap()
}
token::Dot if self.look_ahead(1, |t| match t {
token::Literal(parse::token::Lit::Integer(_) , None) => true,
_ => false,
}) => { // recover from `let x = .4;`
let lo = self.span;
self.bump();
if let token::Literal(
parse::token::Lit::Integer(val),
None
) = self.token {
self.bump();
let sp = lo.to(self.prev_span);
let mut err = self.diagnostic()
.struct_span_err(sp, "numeric float literals must have a significant");
err.span_suggestion_with_applicability(
sp,
"numeric float literals must have a significant",
format!("0.{}", val),
Applicability::MachineApplicable,
);
err.emit();
return Ok(ast::LitKind::Float(val, ast::FloatTy::F32));
estebank marked this conversation as resolved.
Show resolved Hide resolved
} else {
unreachable!();
};
}
_ => { return self.unexpected_last(&self.token); }
};

Expand Down Expand Up @@ -2656,18 +2683,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 +2722,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 +4585,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 +4603,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
14 changes: 14 additions & 0 deletions src/test/ui/issues/issue-52496.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
struct Foo { bar: f64, baz: i64, bat: i64 }

fn main() {
let _ = Foo { bar: .5, baz: 42 };
//~^ ERROR numeric float literals must have a significant
estebank marked this conversation as resolved.
Show resolved Hide resolved
//~| ERROR missing field `bat` in initializer of `Foo`
//~| ERROR mismatched types
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`
estebank marked this conversation as resolved.
Show resolved Hide resolved
//~| ERROR expected identifier, found `.`
}
58 changes: 58 additions & 0 deletions src/test/ui/issues/issue-52496.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
error: numeric float literals must have a significant
--> $DIR/issue-52496.rs:4:24
|
LL | let _ = Foo { bar: .5, baz: 42 };
| ^^ help: numeric float literals must have a significant: `0.5`

error: expected one of `,` or `}`, found `.`
--> $DIR/issue-52496.rs:9: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:9:40
|
LL | let _ = Foo { bar.into(), bat: -1, . };
| --- ^ expected identifier
| |
| while parsing this struct

error[E0308]: mismatched types
--> $DIR/issue-52496.rs:4:24
|
LL | let _ = Foo { bar: .5, baz: 42 };
| ^^ expected f64, found f32
help: change the type of the numeric literal from `f32` to `f64`
|
LL | let _ = Foo { bar: .5f64, baz: 42 };
| ^^^^^

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:9:19
|
LL | let _ = Foo { bar.into(), bat: -1, . };
| ^^^ expected f64, found f32
estebank marked this conversation as resolved.
Show resolved Hide resolved
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:9:13
|
LL | let _ = Foo { bar.into(), bat: -1, . };
| ^^^ missing `baz`

error: aborting due to 7 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`.