Skip to content

Recover shorthand struct literals in if conditions - #162295

Open
chenyukang wants to merge 3 commits into
rust-lang:mainfrom
chenyukang:yukang-fix-147877-struct-literal-condition-diagnostic
Open

chenyukang wants to merge 3 commits into
rust-lang:mainfrom
chenyukang:yukang-fix-147877-struct-literal-condition-diagnostic

Conversation

@chenyukang

@chenyukang chenyukang commented Sep 4, 2026 •

Copy link
Copy Markdown
Member

Fixes #147877

@rustbot

rustbot commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

The parser was modified, potentially altering the grammar of (stable) Rust
which would be a breaking change.

cc @fmease

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 4, 2026
@rustbot

rustbot commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

r? @khyperia

rustbot has assigned @khyperia.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 75 candidates
  • Random selection from 20 candidates

Comment thread compiler/rustc_parse/src/parser/expr.rs Outdated
Comment on lines +3754 to +3762
(self.look_ahead(1, |t| t.is_ident())
&& self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon))
// When struct literals are prohibited, `{ ident }` is normally parsed as a block. A
// second opening brace strongly suggests that the first pair belongs to a struct
// literal and the second starts the surrounding body.
|| (self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
&& self.look_ahead(1, Token::is_non_reserved_ident)
&& self.look_ahead(2, |token| *token == token::CloseBrace)
&& self.look_ahead(3, |token| *token == token::OpenBrace))

@fmease fmease Sep 4, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This modifies the stable grammar of Rust and is thus not acceptable.

It regresses stable code like the following:

fn scope(cond: bool) {
    let u = ();

    if cond {
        u
    }

    {
        println!();
    }
}

or smaller:

#[cfg(false)] fn f() { if x { x } {} }

View changes since the review

@chenyukang chenyukang Sep 4, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aha, yes! I didn't notice is_likely_struct_lit is on happy path, let me think about it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the code.

This fix adds a lightweight extra { check after parsing each if or while body in error_on_ambiguous_struct_literal. If another block follows, it inspects the parsed AST to detect whether a shorthand struct literal was misinterpreted as the body.

I am not entirely satisfied with adding work to the normal parsing path, but I have not found a cleaner recovery point.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 4, 2026
@chenyukang
chenyukang force-pushed the yukang-fix-147877-struct-literal-condition-diagnostic branch 2 times, most recently from e8c0c3c to ac7bb57 Compare September 4, 2026 23:31
@fmease fmease assigned fmease and unassigned khyperia Sep 7, 2026
@fmease fmease added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 7, 2026

@fmease fmease left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! Some comments but we're almost good to go!

View changes since this review

Comment thread compiler/rustc_parse/src/parser/expr.rs Outdated
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
}

fn error_on_ambiguous_struct_literal(&self, head: &Expr, body: &ast::Block) -> PResult<'a, ()> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you rename this to recover_from_*, move it into parser/expr/diagnostics.rs & make it pub(super) there?

Comment thread compiler/rustc_parse/src/parser/expr.rs Outdated
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
}

fn error_on_ambiguous_struct_literal(&self, head: &Expr, body: &ast::Block) -> PResult<'a, ()> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you're probably aware of, this isn't the only function in this module that tries to recover from "ambiguous struct literals", we also have maybe_parse_struct_expr (with predicate is_likely_struct_lit).

It's been a while for me since I last looked at the impl of maybe_parse_struct_expr but I'm wondering is there are way to

  1. somehow consolidate those two approaches or
  2. remove maybe_parse_struct_expr entirely & use error_on_ambiguous_struct_literal in more places / make it smarter & more general or
  3. if that doesn't work out rename both functions in such a way that it is clear for the reader how these two functions differ (e.g., what "patterns of code" they're trying to recover from)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe_parse_struct_expr contains happy path code, so seems not good for the first two options, I extract a recover function from it, see commit:

cca7701

is it clearer?

Comment thread compiler/rustc_parse/src/parser/expr.rs Resolved
@fmease fmease added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 23, 2026
@chenyukang
chenyukang force-pushed the yukang-fix-147877-struct-literal-condition-diagnostic branch from ac7bb57 to e470f2d Compare October 25, 2026 04:18
@rustbot

rustbot commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@chenyukang
chenyukang force-pushed the yukang-fix-147877-struct-literal-condition-diagnostic branch from e470f2d to 6612f74 Compare October 25, 2026 04:29
@fmease fmease added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Nov 1, 2026
@rust-bors

rust-bors Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

☔ The latest upstream changes (presumably #165375) made this pull request unmergeable. Please resolve the merge conflicts by rebasing.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Weird error message when a struct literal is used in a condition of an if statement

4 participants