Skip to content

Commit 7d1b884

Browse files
authored
Unrolled build for #151290
Rollup merge of #151290 - Unique-Usman:ua/nostruct, r=estebank Recover from struct literals with placeholder or empty path Based on earlier work by León Orell Valerian Liehr.
2 parents 4742769 + 54fc546 commit 7d1b884

File tree

8 files changed

+187
-6
lines changed

8 files changed

+187
-6
lines changed

compiler/rustc_parse/messages.ftl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,9 +822,19 @@ parse_struct_literal_body_without_path =
822822
struct literal body without path
823823
.suggestion = you might have forgotten to add the struct literal inside the block
824824
825+
parse_struct_literal_body_without_path_late =
826+
struct literal body without path
827+
.label = struct name missing for struct literal
828+
.suggestion = add the correct type
829+
825830
parse_struct_literal_not_allowed_here = struct literals are not allowed here
826831
.suggestion = surround the struct literal with parentheses
827832
833+
parse_struct_literal_placeholder_path =
834+
placeholder `_` is not allowed for the path in struct literals
835+
.label = not allowed in struct literals
836+
.suggestion = replace it with the correct type
837+
828838
parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
829839
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
830840

compiler/rustc_parse/src/errors.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3684,3 +3684,22 @@ pub(crate) struct ImplReuseInherentImpl {
36843684
#[primary_span]
36853685
pub span: Span,
36863686
}
3687+
3688+
#[derive(Diagnostic)]
3689+
#[diag(parse_struct_literal_placeholder_path)]
3690+
pub(crate) struct StructLiteralPlaceholderPath {
3691+
#[primary_span]
3692+
#[label]
3693+
#[suggestion(applicability = "has-placeholders", code = "/* Type */", style = "verbose")]
3694+
pub span: Span,
3695+
}
3696+
3697+
#[derive(Diagnostic)]
3698+
#[diag(parse_struct_literal_body_without_path_late)]
3699+
pub(crate) struct StructLiteralWithoutPathLate {
3700+
#[primary_span]
3701+
#[label]
3702+
pub span: Span,
3703+
#[suggestion(applicability = "has-placeholders", code = "/* Type */ ", style = "verbose")]
3704+
pub suggestion_span: Span,
3705+
}

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,9 @@ impl<'a> Parser<'a> {
14681468
} else if this.check(exp!(OpenParen)) {
14691469
this.parse_expr_tuple_parens(restrictions)
14701470
} else if this.check(exp!(OpenBrace)) {
1471+
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
1472+
return Ok(expr);
1473+
}
14711474
this.parse_expr_block(None, lo, BlockCheckMode::Default)
14721475
} else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {
14731476
this.parse_expr_closure().map_err(|mut err| {
@@ -1542,6 +1545,9 @@ impl<'a> Parser<'a> {
15421545
} else if this.check_keyword(exp!(Let)) {
15431546
this.parse_expr_let(restrictions)
15441547
} else if this.eat_keyword(exp!(Underscore)) {
1548+
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
1549+
return Ok(expr);
1550+
}
15451551
Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
15461552
} else if this.token_uninterpolated_span().at_least_rust_2018() {
15471553
// `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
@@ -3698,6 +3704,45 @@ impl<'a> Parser<'a> {
36983704
}
36993705
}
37003706

3707+
fn maybe_recover_bad_struct_literal_path(
3708+
&mut self,
3709+
is_underscore_entry_point: bool,
3710+
) -> PResult<'a, Option<Box<Expr>>> {
3711+
if self.may_recover()
3712+
&& self.check_noexpect(&token::OpenBrace)
3713+
&& (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3714+
&& self.is_likely_struct_lit())
3715+
{
3716+
let span = if is_underscore_entry_point {
3717+
self.prev_token.span
3718+
} else {
3719+
self.token.span.shrink_to_lo()
3720+
};
3721+
3722+
self.bump(); // {
3723+
let expr = self.parse_expr_struct(
3724+
None,
3725+
Path::from_ident(Ident::new(kw::Underscore, span)),
3726+
false,
3727+
)?;
3728+
3729+
let guar = if is_underscore_entry_point {
3730+
self.dcx().create_err(errors::StructLiteralPlaceholderPath { span }).emit()
3731+
} else {
3732+
self.dcx()
3733+
.create_err(errors::StructLiteralWithoutPathLate {
3734+
span: expr.span,
3735+
suggestion_span: expr.span.shrink_to_lo(),
3736+
})
3737+
.emit()
3738+
};
3739+
3740+
Ok(Some(self.mk_expr_err(expr.span, guar)))
3741+
} else {
3742+
Ok(None)
3743+
}
3744+
}
3745+
37013746
pub(super) fn parse_struct_fields(
37023747
&mut self,
37033748
pth: ast::Path,

tests/ui/parser/bare-struct-body.stderr

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,12 @@ LL | let x = {
2121
| _____________^
2222
LL | | val: (),
2323
LL | | };
24-
| |_____^
24+
| |_____^ struct name missing for struct literal
2525
|
26-
help: you might have forgotten to add the struct literal inside the block
27-
|
28-
LL ~ let x = { SomeStruct {
29-
LL | val: (),
30-
LL ~ } };
26+
help: add the correct type
3127
|
28+
LL | let x = /* Type */ {
29+
| ++++++++++
3230

3331
error[E0308]: mismatched types
3432
--> $DIR/bare-struct-body.rs:11:14
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
fn main() {
2+
let _ = {foo: (), bar: {} }; //~ ERROR struct literal body without path
3+
//~| NOTE struct name missing for struct literal
4+
//~| HELP add the correct type
5+
let _ = _ {foo: (), bar: {} }; //~ ERROR placeholder `_` is not allowed for the path in struct literals
6+
//~| NOTE not allowed in struct literals
7+
//~| HELP replace it with the correct type
8+
let _ = {foo: ()}; //~ ERROR struct literal body without path
9+
//~| NOTE struct name missing for struct literal
10+
//~| HELP add the correct type
11+
let _ = _ {foo: ()}; //~ ERROR placeholder `_` is not allowed for the path in struct literals
12+
//~| NOTE not allowed in struct literals
13+
//~| HELP replace it with the correct type
14+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error: struct literal body without path
2+
--> $DIR/struct-lit-placeholder-or-empty-path.rs:2:13
3+
|
4+
LL | let _ = {foo: (), bar: {} };
5+
| ^^^^^^^^^^^^^^^^^^^ struct name missing for struct literal
6+
|
7+
help: add the correct type
8+
|
9+
LL | let _ = /* Type */ {foo: (), bar: {} };
10+
| ++++++++++
11+
12+
error: placeholder `_` is not allowed for the path in struct literals
13+
--> $DIR/struct-lit-placeholder-or-empty-path.rs:5:13
14+
|
15+
LL | let _ = _ {foo: (), bar: {} };
16+
| ^ not allowed in struct literals
17+
|
18+
help: replace it with the correct type
19+
|
20+
LL - let _ = _ {foo: (), bar: {} };
21+
LL + let _ = /* Type */ {foo: (), bar: {} };
22+
|
23+
24+
error: struct literal body without path
25+
--> $DIR/struct-lit-placeholder-or-empty-path.rs:8:13
26+
|
27+
LL | let _ = {foo: ()};
28+
| ^^^^^^^^^ struct name missing for struct literal
29+
|
30+
help: add the correct type
31+
|
32+
LL | let _ = /* Type */ {foo: ()};
33+
| ++++++++++
34+
35+
error: placeholder `_` is not allowed for the path in struct literals
36+
--> $DIR/struct-lit-placeholder-or-empty-path.rs:11:13
37+
|
38+
LL | let _ = _ {foo: ()};
39+
| ^ not allowed in struct literals
40+
|
41+
help: replace it with the correct type
42+
|
43+
LL - let _ = _ {foo: ()};
44+
LL + let _ = /* Type */ {foo: ()};
45+
|
46+
47+
error: aborting due to 4 previous errors
48+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Regression test for issue #98282.
2+
3+
mod blah {
4+
pub struct Stuff { x: i32 }
5+
pub fn do_stuff(_: Stuff) {}
6+
}
7+
8+
fn main() {
9+
blah::do_stuff(_ { x: 10 });
10+
//~^ ERROR placeholder `_` is not allowed for the path in struct literals
11+
//~| NOTE not allowed in struct literals
12+
//~| HELP replace it with the correct type
13+
}
14+
15+
#[cfg(FALSE)]
16+
fn disabled() {
17+
blah::do_stuff(_ { x: 10 });
18+
//~^ ERROR placeholder `_` is not allowed for the path in struct literals
19+
//~| NOTE not allowed in struct literals
20+
//~| HELP replace it with the correct type
21+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: placeholder `_` is not allowed for the path in struct literals
2+
--> $DIR/struct-lit-placeholder-path.rs:9:20
3+
|
4+
LL | blah::do_stuff(_ { x: 10 });
5+
| ^ not allowed in struct literals
6+
|
7+
help: replace it with the correct type
8+
|
9+
LL - blah::do_stuff(_ { x: 10 });
10+
LL + blah::do_stuff(/* Type */ { x: 10 });
11+
|
12+
13+
error: placeholder `_` is not allowed for the path in struct literals
14+
--> $DIR/struct-lit-placeholder-path.rs:17:20
15+
|
16+
LL | blah::do_stuff(_ { x: 10 });
17+
| ^ not allowed in struct literals
18+
|
19+
help: replace it with the correct type
20+
|
21+
LL - blah::do_stuff(_ { x: 10 });
22+
LL + blah::do_stuff(/* Type */ { x: 10 });
23+
|
24+
25+
error: aborting due to 2 previous errors
26+

0 commit comments

Comments
 (0)