Skip to content

Commit 194e58c

Browse files
Rollup merge of #142798 - camsteffen:recover-semi, r=compiler-errors
Don't fail to parse a struct if a semicolon is used to separate fields The first commit is a small refactor.
2 parents 2681bb0 + 26a6b55 commit 194e58c

File tree

3 files changed

+30
-39
lines changed

3 files changed

+30
-39
lines changed

compiler/rustc_parse/src/parser/item.rs

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,7 +1781,7 @@ impl<'a> Parser<'a> {
17811781
let mut recovered = Recovered::No;
17821782
if self.eat(exp!(OpenBrace)) {
17831783
while self.token != token::CloseBrace {
1784-
match self.parse_field_def(adt_ty) {
1784+
match self.parse_field_def(adt_ty, ident_span) {
17851785
Ok(field) => {
17861786
fields.push(field);
17871787
}
@@ -1894,15 +1894,15 @@ impl<'a> Parser<'a> {
18941894
}
18951895

18961896
/// Parses an element of a struct declaration.
1897-
fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> {
1897+
fn parse_field_def(&mut self, adt_ty: &str, ident_span: Span) -> PResult<'a, FieldDef> {
18981898
self.recover_vcs_conflict_marker();
18991899
let attrs = self.parse_outer_attributes()?;
19001900
self.recover_vcs_conflict_marker();
19011901
self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
19021902
let lo = this.token.span;
19031903
let vis = this.parse_visibility(FollowedByType::No)?;
19041904
let safety = this.parse_unsafe_field();
1905-
this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs)
1905+
this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs, ident_span)
19061906
.map(|field| (field, Trailing::No, UsePreAttrPos::No))
19071907
})
19081908
}
@@ -1915,28 +1915,27 @@ impl<'a> Parser<'a> {
19151915
vis: Visibility,
19161916
safety: Safety,
19171917
attrs: AttrVec,
1918+
ident_span: Span,
19181919
) -> PResult<'a, FieldDef> {
1919-
let mut seen_comma: bool = false;
19201920
let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?;
1921-
if self.token == token::Comma {
1922-
seen_comma = true;
1923-
}
1924-
if self.eat(exp!(Semi)) {
1925-
let sp = self.prev_token.span;
1926-
let mut err =
1927-
self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
1928-
err.span_suggestion_short(
1929-
sp,
1930-
"replace `;` with `,`",
1931-
",",
1932-
Applicability::MachineApplicable,
1933-
);
1934-
return Err(err);
1935-
}
19361921
match self.token.kind {
19371922
token::Comma => {
19381923
self.bump();
19391924
}
1925+
token::Semi => {
1926+
self.bump();
1927+
let sp = self.prev_token.span;
1928+
let mut err =
1929+
self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
1930+
err.span_suggestion_short(
1931+
sp,
1932+
"replace `;` with `,`",
1933+
",",
1934+
Applicability::MachineApplicable,
1935+
);
1936+
err.span_label(ident_span, format!("while parsing this {adt_ty}"));
1937+
err.emit();
1938+
}
19401939
token::CloseBrace => {}
19411940
token::DocComment(..) => {
19421941
let previous_span = self.prev_token.span;
@@ -1945,19 +1944,11 @@ impl<'a> Parser<'a> {
19451944
missing_comma: None,
19461945
};
19471946
self.bump(); // consume the doc comment
1948-
let comma_after_doc_seen = self.eat(exp!(Comma));
1949-
// `seen_comma` is always false, because we are inside doc block
1950-
// condition is here to make code more readable
1951-
if !seen_comma && comma_after_doc_seen {
1952-
seen_comma = true;
1953-
}
1954-
if comma_after_doc_seen || self.token == token::CloseBrace {
1947+
if self.eat(exp!(Comma)) || self.token == token::CloseBrace {
19551948
self.dcx().emit_err(err);
19561949
} else {
1957-
if !seen_comma {
1958-
let sp = previous_span.shrink_to_hi();
1959-
err.missing_comma = Some(sp);
1960-
}
1950+
let sp = previous_span.shrink_to_hi();
1951+
err.missing_comma = Some(sp);
19611952
return Err(self.dcx().create_err(err));
19621953
}
19631954
}

tests/ui/parser/recover/recover-field-semi.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ struct Foo {
33
//~^ ERROR struct fields are separated by `,`
44
}
55

6-
union Bar { //~ ERROR
6+
union Bar {
77
foo: i32;
88
//~^ ERROR union fields are separated by `,`
99
}
@@ -13,4 +13,6 @@ enum Baz {
1313
//~^ ERROR struct fields are separated by `,`
1414
}
1515

16-
fn main() {}
16+
fn main() {
17+
let _ = Foo { foo: "" }; //~ ERROR mismatched types
18+
}

tests/ui/parser/recover/recover-field-semi.stderr

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@ LL | Qux { foo: i32; }
2222
| |
2323
| while parsing this struct
2424

25-
error: unions cannot have zero fields
26-
--> $DIR/recover-field-semi.rs:6:1
25+
error[E0308]: mismatched types
26+
--> $DIR/recover-field-semi.rs:17:24
2727
|
28-
LL | / union Bar {
29-
LL | | foo: i32;
30-
LL | |
31-
LL | | }
32-
| |_^
28+
LL | let _ = Foo { foo: "" };
29+
| ^^ expected `i32`, found `&str`
3330

3431
error: aborting due to 4 previous errors
3532

33+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)