Skip to content

keep the trailing semicolon on loops that break with a value - #7072

Open
AsthaMishra wants to merge 2 commits into
rust-lang:mainfrom
AsthaMishra:fix-issue-7061
Open

keep the trailing semicolon on loops that break with a value#7072
AsthaMishra wants to merge 2 commits into
rust-lang:mainfrom
AsthaMishra:fix-issue-7061

Conversation

@AsthaMishra

@AsthaMishra AsthaMishra commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

issue : semicolon_for_stmt grouped loop with for, while and discarded trailing semicolon. This is correct for for and while as they evaluate to () but loop can evaluate to some value. so when loop { break v } has the type of v and semicolon discarded then it becomes a bare expression statement, which rustc requires to be () . that's why we got compilation error.

Fix: check the loop body, if it breaks with value then keep the trailing semicolon else remove it as before.

Fixes : #7061

@rustbot rustbot added the S-waiting-on-review Status: awaiting review from the assignee but also interested parties. label Aug 25, 2026
@ytmimi

ytmimi commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

I think #7061 is actually a duplicate of #5377. Does this resolve that issue too?

@ytmimi ytmimi Aug 25, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about loops deeply nested inside other loops loops?

View changes since the review

Comment thread src/utils.rs
Comment on lines +348 to +373
/// Does this `loop` evaluate to something other than `()`?
///
/// `loop { break v }` evaluates to `v`, so the trailing semicolon is what
/// discards that value. Removing it leaves a bare expression statement,
/// which rustc requires to be `()`
fn loop_breaks_with_value(expr: &ast::Expr) -> bool {
struct BreakWithValue(bool);

impl<'ast> visit::Visitor<'ast> for BreakWithValue {
fn visit_expr(&mut self, ex: &'ast ast::Expr) {
match ex.kind {
ast::ExprKind::Break(_, Some(_)) => self.0 = true,
_ => {
visit::walk_expr(self, ex);
}
}
}
}

let ast::ExprKind::Loop(ref block, ..) = expr.kind else {
return false;
};
let mut finder = BreakWithValue(false);
visit::walk_block(&mut finder, block);
finder.0
}

@ytmimi ytmimi Aug 25, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How does rustfmt know that v doesn't resolve to ()? Does it make a difference?

For example:

fn main() {
        'a:  loop  {
                break  'a  some_callback_function_that_returns_empty_tuple()
        };


        'b:  loop  {
                break  'b  some_macro_that_evaluates_to_empty_tuple!()
        };
}

View changes since the review

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rustfmt switches ; around causing type error

3 participants