Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -822,9 +822,19 @@ parse_struct_literal_body_without_path =
struct literal body without path
.suggestion = you might have forgotten to add the struct literal inside the block

parse_struct_literal_body_without_path_late =
struct literal body without path
.label = struct name missing for struct literal
.suggestion = add the correct type

parse_struct_literal_not_allowed_here = struct literals are not allowed here
.suggestion = surround the struct literal with parentheses

parse_struct_literal_placeholder_path =
placeholder `_` is not allowed for the path in struct literals
.label = not allowed in struct literals
.suggestion = replace it with the correct type

parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)

Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3684,3 +3684,22 @@ pub(crate) struct ImplReuseInherentImpl {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_struct_literal_placeholder_path)]
pub(crate) struct StructLiteralPlaceholderPath {
#[primary_span]
#[label]
#[suggestion(applicability = "has-placeholders", code = "/* Type */", style = "verbose")]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_struct_literal_body_without_path_late)]
pub(crate) struct StructLiteralWithoutPathLate {
#[primary_span]
#[label]
pub span: Span,
#[suggestion(applicability = "has-placeholders", code = "/* Type */ ", style = "verbose")]
pub suggestion_span: Span,
}
45 changes: 45 additions & 0 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,9 @@ impl<'a> Parser<'a> {
} else if this.check(exp!(OpenParen)) {
this.parse_expr_tuple_parens(restrictions)
} else if this.check(exp!(OpenBrace)) {
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
return Ok(expr);
}
this.parse_expr_block(None, lo, BlockCheckMode::Default)
} else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {
this.parse_expr_closure().map_err(|mut err| {
Expand Down Expand Up @@ -1542,6 +1545,9 @@ impl<'a> Parser<'a> {
} else if this.check_keyword(exp!(Let)) {
this.parse_expr_let(restrictions)
} else if this.eat_keyword(exp!(Underscore)) {
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
return Ok(expr);
}
Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
} else if this.token_uninterpolated_span().at_least_rust_2018() {
// `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
Expand Down Expand Up @@ -3698,6 +3704,45 @@ impl<'a> Parser<'a> {
}
}

fn maybe_recover_bad_struct_literal_path(
&mut self,
is_underscore_entry_point: bool,
) -> PResult<'a, Option<Box<Expr>>> {
if self.may_recover()
&& self.check_noexpect(&token::OpenBrace)
&& (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
&& self.is_likely_struct_lit())
{
let span = if is_underscore_entry_point {
self.prev_token.span
} else {
self.token.span.shrink_to_lo()
};

self.bump(); // {
let expr = self.parse_expr_struct(
None,
Path::from_ident(Ident::new(kw::Underscore, span)),
false,
)?;

let guar = if is_underscore_entry_point {
self.dcx().create_err(errors::StructLiteralPlaceholderPath { span }).emit()
} else {
self.dcx()
.create_err(errors::StructLiteralWithoutPathLate {
span: expr.span,
suggestion_span: expr.span.shrink_to_lo(),
})
.emit()
};

Ok(Some(self.mk_expr_err(expr.span, guar)))
} else {
Ok(None)
}
}

pub(super) fn parse_struct_fields(
&mut self,
pth: ast::Path,
Expand Down
10 changes: 4 additions & 6 deletions tests/ui/parser/bare-struct-body.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ LL | let x = {
| _____________^
LL | | val: (),
LL | | };
| |_____^
| |_____^ struct name missing for struct literal
|
help: you might have forgotten to add the struct literal inside the block
|
LL ~ let x = { SomeStruct {
LL | val: (),
LL ~ } };
help: add the correct type
|
LL | let x = /* Type */ {
| ++++++++++

error[E0308]: mismatched types
--> $DIR/bare-struct-body.rs:11:14
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/parser/struct-lit-placeholder-or-empty-path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
fn main() {
let _ = {foo: (), bar: {} }; //~ ERROR struct literal body without path
//~| NOTE struct name missing for struct literal
//~| HELP add the correct type
let _ = _ {foo: (), bar: {} }; //~ ERROR placeholder `_` is not allowed for the path in struct literals
//~| NOTE not allowed in struct literals
//~| HELP replace it with the correct type
let _ = {foo: ()}; //~ ERROR struct literal body without path
//~| NOTE struct name missing for struct literal
//~| HELP add the correct type
let _ = _ {foo: ()}; //~ ERROR placeholder `_` is not allowed for the path in struct literals
//~| NOTE not allowed in struct literals
//~| HELP replace it with the correct type
}
48 changes: 48 additions & 0 deletions tests/ui/parser/struct-lit-placeholder-or-empty-path.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
error: struct literal body without path
--> $DIR/struct-lit-placeholder-or-empty-path.rs:2:13
|
LL | let _ = {foo: (), bar: {} };
| ^^^^^^^^^^^^^^^^^^^ struct name missing for struct literal
|
help: add the correct type
|
LL | let _ = /* Type */ {foo: (), bar: {} };
| ++++++++++

error: placeholder `_` is not allowed for the path in struct literals
--> $DIR/struct-lit-placeholder-or-empty-path.rs:5:13
|
LL | let _ = _ {foo: (), bar: {} };
| ^ not allowed in struct literals
|
help: replace it with the correct type
|
LL - let _ = _ {foo: (), bar: {} };
LL + let _ = /* Type */ {foo: (), bar: {} };
|

error: struct literal body without path
--> $DIR/struct-lit-placeholder-or-empty-path.rs:8:13
|
LL | let _ = {foo: ()};
| ^^^^^^^^^ struct name missing for struct literal
|
help: add the correct type
|
LL | let _ = /* Type */ {foo: ()};
| ++++++++++

error: placeholder `_` is not allowed for the path in struct literals
--> $DIR/struct-lit-placeholder-or-empty-path.rs:11:13
|
LL | let _ = _ {foo: ()};
| ^ not allowed in struct literals
|
help: replace it with the correct type
|
LL - let _ = _ {foo: ()};
LL + let _ = /* Type */ {foo: ()};
|

error: aborting due to 4 previous errors

21 changes: 21 additions & 0 deletions tests/ui/suggestions/struct-lit-placeholder-path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Regression test for issue #98282.

mod blah {
pub struct Stuff { x: i32 }
pub fn do_stuff(_: Stuff) {}
}

fn main() {
blah::do_stuff(_ { x: 10 });
//~^ ERROR placeholder `_` is not allowed for the path in struct literals
//~| NOTE not allowed in struct literals
//~| HELP replace it with the correct type
}

#[cfg(FALSE)]
fn disabled() {
blah::do_stuff(_ { x: 10 });
//~^ ERROR placeholder `_` is not allowed for the path in struct literals
//~| NOTE not allowed in struct literals
//~| HELP replace it with the correct type
}
26 changes: 26 additions & 0 deletions tests/ui/suggestions/struct-lit-placeholder-path.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: placeholder `_` is not allowed for the path in struct literals
--> $DIR/struct-lit-placeholder-path.rs:9:20
|
LL | blah::do_stuff(_ { x: 10 });
| ^ not allowed in struct literals
|
help: replace it with the correct type
|
LL - blah::do_stuff(_ { x: 10 });
LL + blah::do_stuff(/* Type */ { x: 10 });
|

error: placeholder `_` is not allowed for the path in struct literals
--> $DIR/struct-lit-placeholder-path.rs:17:20
|
LL | blah::do_stuff(_ { x: 10 });
| ^ not allowed in struct literals
|
help: replace it with the correct type
|
LL - blah::do_stuff(_ { x: 10 });
LL + blah::do_stuff(/* Type */ { x: 10 });
|

error: aborting due to 2 previous errors

Loading