Skip to content

fix: don’t format mixed macro args (items + non-items) (#6629) #6637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

giammirove
Copy link

Fixes #6629

Problem

The following code:

macro_rules! reproduce {
    (type Fail = $ty:ty; arr = $($arr:expr),*) => {
        ( vec![$($arr),+] )
    };
}

fn main() {
    reproduce!(type Fail = char; arr = 1);
}

is formatted as:

macro_rules! reproduce {
    (type Fail = $ty:ty; arr = $($arr:expr),*) => {
        ( vec![$($arr),+] )
    };
}

fn main() {
    reproduce!(type Fail = char;, arr = 1);
}

Notice the , right after ; in the macro invocation.
Making the formatted code's syntax wrong.

Solution

When formatting a list of commented items into a list (write_list in src/lists.rs), do not add the comma if the item's entry ends with ;.

Changes

  • Modified write_list in src/lists.rs to avoid adding , if the argument ends with ;.
  • Added regression test case issue-6629.rs to prevent future regressions

@giammirove
Copy link
Author

I found an edge case for which my fix would break the code.

The following code:

macro_rules! reproduce {
    (type Fail = $ty:ty; arr = $($arr:expr),+) => {
        ( vec![$($arr),+] )
    };
    ( $expr:expr, $($arr:item),+) => {
        1
    };
}
reproduce!(type Fail = char; arr = 1);

is rewritten as:

reproduce!(type Fail = char;, arr = 1);

which is not valid code.

The problem is related to mixed argument types (items and non items).
The code responsible for parsing the macro arguments is parse_macro_args in src/parse/macros/mod.rs. parse_macro_args interpret type Fail = char; as an item, while arr = 1 as an array of expr.
While parse_macro_args parses the arguments, it does not detect any ;, since ; is part of the item (items are self-terminating).
Therefore, the arguments are later treated as vec![1,2,3,4], and write_list will append , after every argument, breaking the code.
My previous fix was to avoid appending , after ;. Such a fix would break other valid code, see:

reproduce!(23, type Fail = char;, type Fail = char;);

is rewritten as:

reproduce!(23, type Fail = char; type Fail = char;);

which is not valid code, since the macro accepts arguments like ($($arr:item),+).

The problem is therefore related to the presence of both item and non item arguments.
Currently, no implementation accounts for this case scenario in rewrite_macro_inner in src/macros.rs.
The current solution uses a conservative approach, where mixed macro arguments are not formatted.

@giammirove giammirove changed the title fix: do not add commas after ';' in macro args (#6629) fix: don’t format mixed macro args (items + non-items) (#6629) Aug 17, 2025
Items in macro input are self-terminating (their own `;`/`}` closes them),
so treating mixed argument lists as comma lists leads rustfmt to invent a
comma after an item:
```
reproduce!(type Fail = char; arr = 1);
// became
reproduce!(type Fail = char;, arr = 1); // invalid
```
`parse_macro_args` correctly parses `type Fail = char;` as an item and
`arr = 1` as exprs, but later `rewrite_macro_inner`/`write_list` assumes a
comma-separated list and appends a comma after the item.

Fix: be conservative, if a macro invocation contains at least one `$item`
and at least one non-`$item`, do not format it. Keep existing behavior for
all-items (use items path) and no-items (use list formatting).

This avoids inventing commas after items without breaking valid cases like:
```
reproduce!(23, type Fail = char;, type Fail = char;);
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

rustfmt breaks macro code
2 participants