rust-lang / rust-lang/rustfmt

Closure parameter wrapping appears to ignore block-prefix width

Open
#7,113 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-async-blocks A-blocks A-closures A-gen-blocks C-bug SO-max_width
Dominant language
Rust
Stars
7k
Forks
1.1k
Avg merge
2d 13h
Merged PRs (30d)
24

Description

Translation assisted by an LLM.

Summary

The decision to wrap closure parameters appears not to account for the full
width between the closing | and the opening { of the body. Prefixes such as
unsafe, async, and async move can make the line exceed max_width, but
rustfmt still joins the parameters onto that line.

Is this a width-budget bug, or an intentional formatting rule?

I tried to format this standalone example, which compiles with Rust edition 2024
(with warnings):

fn accept<F>(_: F) {}
fn main() {
    accept(
        move |first_argument_name_long: u64,
              second_argument_name_long: u64| unsafe {
            let value = 1;
            value
        },
    );
}
Expected behavior

Keep the resulting code within max_width = 80, for example by splitting the
closure parameters or using another suitable layout for the closure body.
I am not requesting preservation of arbitrary manual line breaks.

Actual behavior

Rustfmt produces:

fn accept<F>(_: F) {}
fn main() {
    accept(
        move |first_argument_name_long: u64, second_argument_name_long: u64| unsafe {
            let value = 1;
            value
        },
    );
}

The closure's first line is 85 columns including indentation, exceeding the
configured 80-column limit. Formatting exits successfully without warnings.
Splitting the parameters manually results in the same 85-column line again.

Configuration

rustfmt.toml:

max_width = 80
use_small_heuristics = "Max"
style_edition = "2027"

Command:

rustfmt +nightly --edition 2024 --config-path rustfmt.toml < repro.rs

The language edition is 2024; the formatting style edition is 2027.

Reproduction Steps

  1. Save the input above as repro.rs in a temporary directory.
  2. Save the configuration above as rustfmt.toml in the same directory.
  3. Run the command above from that directory.
  4. Observe that the two parameter lines are joined into an 85-column line.

Meta

Tested nightly version:

rustfmt 1.10.0-nightly (67854e511d 2026-08-15)

This is the installed nightly tested, not a claim about the latest nightly.

The same example also reproduces on the following stable version with
style_edition = "2024" and otherwise the same configuration:

rustfmt 1.9.0-stable (59807616e1 2026-04-14)

Additional observations

In the same example, changing only the body prefix produces 78 columns for
{, 84 for async {, 89 for async move {, and 85 for unsafe {. All four
keep the parameters on one line. This is not specific to async blocks.

Related issues

Possibly related: #325 (closed), #2063, #6831, #6538 and #6687. Here rustfmt actively joins
breakable parameters into an over-width line, rather than preserving unformatted
input. Please let me know if an existing issue already covers this case.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by saving the supplied example as repro.rs with the shown rustfmt.toml, then run the documented rustfmt +nightly command to reproduce the over-width output. Trace the closure-parameter formatting entry point and add or update a regression test for the prefixes shown; done means formatting respects max_width = 80 without warnings.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.