Skip to content

Commit 9461780

Browse files
Rollup merge of #84793 - estebank:parse-struct-field-default, r=davidtwco
Recover from invalid `struct` item syntax Parse unsupported "default field const values": ```rust struct S { field: Type = const_val, } ``` Recover from small `:` typo and provide suggestion: ```rust struct S { field; Type, field2= Type, } ```
2 parents e1ff91f + 7697ce4 commit 9461780

4 files changed

+207
-1
lines changed

compiler/rustc_parse/src/parser/item.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,37 @@ impl<'a> Parser<'a> {
13991399
Ok(a_var)
14001400
}
14011401

1402+
fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
1403+
if let Err(mut err) = self.expect(&token::Colon) {
1404+
let sm = self.sess.source_map();
1405+
let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start());
1406+
let semi_typo = self.token.kind == token::Semi
1407+
&& self.look_ahead(1, |t| {
1408+
t.is_path_start()
1409+
// We check that we are in a situation like `foo; bar` to avoid bad suggestions
1410+
// when there's no type and `;` was used instead of a comma.
1411+
&& match (sm.lookup_line(self.token.span.hi()), sm.lookup_line(t.span.lo())) {
1412+
(Ok(l), Ok(r)) => l.line == r.line,
1413+
_ => true,
1414+
}
1415+
});
1416+
if eq_typo || semi_typo {
1417+
self.bump();
1418+
// Gracefully handle small typos.
1419+
err.span_suggestion_short(
1420+
self.prev_token.span,
1421+
"field names and their types are separated with `:`",
1422+
":".to_string(),
1423+
Applicability::MachineApplicable,
1424+
);
1425+
err.emit();
1426+
} else {
1427+
return Err(err);
1428+
}
1429+
}
1430+
Ok(())
1431+
}
1432+
14021433
/// Parses a structure field.
14031434
fn parse_name_and_ty(
14041435
&mut self,
@@ -1408,8 +1439,21 @@ impl<'a> Parser<'a> {
14081439
attrs: Vec<Attribute>,
14091440
) -> PResult<'a, FieldDef> {
14101441
let name = self.parse_field_ident(adt_ty, lo)?;
1411-
self.expect(&token::Colon)?;
1442+
self.expect_field_ty_separator()?;
14121443
let ty = self.parse_ty()?;
1444+
if self.token.kind == token::Eq {
1445+
self.bump();
1446+
let const_expr = self.parse_anon_const_expr()?;
1447+
let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
1448+
self.struct_span_err(sp, "default values on `struct` fields aren't supported")
1449+
.span_suggestion(
1450+
sp,
1451+
"remove this unsupported default value",
1452+
String::new(),
1453+
Applicability::MachineApplicable,
1454+
)
1455+
.emit();
1456+
}
14131457
Ok(FieldDef {
14141458
span: lo.to(self.prev_token.span),
14151459
ident: Some(name),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
4+
enum E {
5+
A,
6+
}
7+
8+
struct S {
9+
field1: i32, //~ ERROR default values on `struct` fields aren't supported
10+
field2: E, //~ ERROR default values on `struct` fields aren't supported
11+
field3: i32, //~ ERROR default values on `struct` fields aren't supported
12+
field4: i32, //~ ERROR default values on `struct` fields aren't supported
13+
field5: E, //~ ERROR default values on `struct` fields aren't supported
14+
field6: E, //~ ERROR default values on `struct` fields aren't supported
15+
}
16+
17+
struct S1 {
18+
field1: i32, //~ ERROR expected `,`, or `}`, found `field2`
19+
field2: E, //~ ERROR expected `,`, or `}`, found `field3`
20+
field3: i32, //~ ERROR default values on `struct` fields aren't supported
21+
field4: i32, //~ ERROR default values on `struct` fields aren't supported
22+
field5: E, //~ ERROR default values on `struct` fields aren't supported
23+
field6: E, //~ ERROR default values on `struct` fields aren't supported
24+
}
25+
26+
struct S2 {
27+
field1 : i32, //~ ERROR expected `:`, found `=`
28+
field2: E, //~ ERROR expected `:`, found `;`
29+
}
30+
31+
const fn foo(_: i32) -> E {
32+
E::A
33+
}
34+
35+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
4+
enum E {
5+
A,
6+
}
7+
8+
struct S {
9+
field1: i32 = 42, //~ ERROR default values on `struct` fields aren't supported
10+
field2: E = E::A, //~ ERROR default values on `struct` fields aren't supported
11+
field3: i32 = 1 + 2, //~ ERROR default values on `struct` fields aren't supported
12+
field4: i32 = { 1 + 2 }, //~ ERROR default values on `struct` fields aren't supported
13+
field5: E = foo(42), //~ ERROR default values on `struct` fields aren't supported
14+
field6: E = { foo(42) }, //~ ERROR default values on `struct` fields aren't supported
15+
}
16+
17+
struct S1 {
18+
field1: i32 //~ ERROR expected `,`, or `}`, found `field2`
19+
field2: E //~ ERROR expected `,`, or `}`, found `field3`
20+
field3: i32 = 1 + 2, //~ ERROR default values on `struct` fields aren't supported
21+
field4: i32 = { 1 + 2 }, //~ ERROR default values on `struct` fields aren't supported
22+
field5: E = foo(42), //~ ERROR default values on `struct` fields aren't supported
23+
field6: E = { foo(42) }, //~ ERROR default values on `struct` fields aren't supported
24+
}
25+
26+
struct S2 {
27+
field1 = i32, //~ ERROR expected `:`, found `=`
28+
field2; E, //~ ERROR expected `:`, found `;`
29+
}
30+
31+
const fn foo(_: i32) -> E {
32+
E::A
33+
}
34+
35+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
error: default values on `struct` fields aren't supported
2+
--> $DIR/struct-default-values-and-missing-field-separator.rs:9:16
3+
|
4+
LL | field1: i32 = 42,
5+
| ^^^^^ help: remove this unsupported default value
6+
7+
error: default values on `struct` fields aren't supported
8+
--> $DIR/struct-default-values-and-missing-field-separator.rs:10:14
9+
|
10+
LL | field2: E = E::A,
11+
| ^^^^^^^ help: remove this unsupported default value
12+
13+
error: default values on `struct` fields aren't supported
14+
--> $DIR/struct-default-values-and-missing-field-separator.rs:11:16
15+
|
16+
LL | field3: i32 = 1 + 2,
17+
| ^^^^^^^^ help: remove this unsupported default value
18+
19+
error: default values on `struct` fields aren't supported
20+
--> $DIR/struct-default-values-and-missing-field-separator.rs:12:16
21+
|
22+
LL | field4: i32 = { 1 + 2 },
23+
| ^^^^^^^^^^^^ help: remove this unsupported default value
24+
25+
error: default values on `struct` fields aren't supported
26+
--> $DIR/struct-default-values-and-missing-field-separator.rs:13:14
27+
|
28+
LL | field5: E = foo(42),
29+
| ^^^^^^^^^^ help: remove this unsupported default value
30+
31+
error: default values on `struct` fields aren't supported
32+
--> $DIR/struct-default-values-and-missing-field-separator.rs:14:14
33+
|
34+
LL | field6: E = { foo(42) },
35+
| ^^^^^^^^^^^^^^ help: remove this unsupported default value
36+
37+
error: expected `,`, or `}`, found `field2`
38+
--> $DIR/struct-default-values-and-missing-field-separator.rs:18:16
39+
|
40+
LL | field1: i32
41+
| ^ help: try adding a comma: `,`
42+
43+
error: expected `,`, or `}`, found `field3`
44+
--> $DIR/struct-default-values-and-missing-field-separator.rs:19:14
45+
|
46+
LL | field2: E
47+
| ^ help: try adding a comma: `,`
48+
49+
error: default values on `struct` fields aren't supported
50+
--> $DIR/struct-default-values-and-missing-field-separator.rs:20:16
51+
|
52+
LL | field3: i32 = 1 + 2,
53+
| ^^^^^^^^ help: remove this unsupported default value
54+
55+
error: default values on `struct` fields aren't supported
56+
--> $DIR/struct-default-values-and-missing-field-separator.rs:21:16
57+
|
58+
LL | field4: i32 = { 1 + 2 },
59+
| ^^^^^^^^^^^^ help: remove this unsupported default value
60+
61+
error: default values on `struct` fields aren't supported
62+
--> $DIR/struct-default-values-and-missing-field-separator.rs:22:14
63+
|
64+
LL | field5: E = foo(42),
65+
| ^^^^^^^^^^ help: remove this unsupported default value
66+
67+
error: default values on `struct` fields aren't supported
68+
--> $DIR/struct-default-values-and-missing-field-separator.rs:23:14
69+
|
70+
LL | field6: E = { foo(42) },
71+
| ^^^^^^^^^^^^^^ help: remove this unsupported default value
72+
73+
error: expected `:`, found `=`
74+
--> $DIR/struct-default-values-and-missing-field-separator.rs:27:12
75+
|
76+
LL | field1 = i32,
77+
| ^
78+
| |
79+
| expected `:`
80+
| help: field names and their types are separated with `:`
81+
82+
error: expected `:`, found `;`
83+
--> $DIR/struct-default-values-and-missing-field-separator.rs:28:11
84+
|
85+
LL | field2; E,
86+
| ^
87+
| |
88+
| expected `:`
89+
| help: field names and their types are separated with `:`
90+
91+
error: aborting due to 14 previous errors
92+

0 commit comments

Comments
 (0)