From 70cabe99cc46ed823c825e97087c125afb564f3d Mon Sep 17 00:00:00 2001 From: Gianmaria Rovelli Date: Sat, 16 Aug 2025 17:52:28 +0100 Subject: [PATCH 1/3] fix: do not add commas after ';' in macro args (#6629) --- src/lists.rs | 10 ++++++---- tests/source/issue-6629.rs | 9 +++++++++ tests/target/issue-6629.rs | 9 +++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/source/issue-6629.rs create mode 100644 tests/target/issue-6629.rs diff --git a/src/lists.rs b/src/lists.rs index 9d811e5d9b5..e4fdad198de 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -288,10 +288,12 @@ where let inner_item = item.item.as_ref().or_else(|err| Err(err.clone()))?; let first = i == 0; let last = iter.peek().is_none(); - let mut separate = match sep_place { - SeparatorPlace::Front => !first, - SeparatorPlace::Back => !last || trailing_separator, - }; + let ends_with_semi = inner_item.ends_with(";"); + let mut separate = !ends_with_semi + && match sep_place { + SeparatorPlace::Front => !first, + SeparatorPlace::Back => !last || trailing_separator, + }; let item_sep_len = if separate { sep_len } else { 0 }; // Item string may be multi-line. Its length (used for block comment alignment) diff --git a/tests/source/issue-6629.rs b/tests/source/issue-6629.rs new file mode 100644 index 00000000000..85dba6a0786 --- /dev/null +++ b/tests/source/issue-6629.rs @@ -0,0 +1,9 @@ +macro_rules! reproduce { + (type Fail = $ty:ty; arr = $($arr:expr),*) => { + ( vec![$($arr),+] ) + }; +} + +fn main() { + reproduce!(type Fail = char; arr = 1); +} diff --git a/tests/target/issue-6629.rs b/tests/target/issue-6629.rs new file mode 100644 index 00000000000..85dba6a0786 --- /dev/null +++ b/tests/target/issue-6629.rs @@ -0,0 +1,9 @@ +macro_rules! reproduce { + (type Fail = $ty:ty; arr = $($arr:expr),*) => { + ( vec![$($arr),+] ) + }; +} + +fn main() { + reproduce!(type Fail = char; arr = 1); +} From f9182d6d0d39f217dc72d10b1218af3489a44e14 Mon Sep 17 00:00:00 2001 From: Gianmaria Rovelli Date: Sun, 17 Aug 2025 13:10:51 +0100 Subject: [PATCH 2/3] test: reproduce edge case where the fix for #6629 fails --- tests/source/issue-6629.rs | 6 +++++- tests/target/issue-6629.rs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/source/issue-6629.rs b/tests/source/issue-6629.rs index 85dba6a0786..1ed9927f132 100644 --- a/tests/source/issue-6629.rs +++ b/tests/source/issue-6629.rs @@ -1,9 +1,13 @@ macro_rules! reproduce { - (type Fail = $ty:ty; arr = $($arr:expr),*) => { + (type Fail = $ty:ty; arr = $($arr:expr),+) => { ( vec![$($arr),+] ) }; + ( $expr:expr, $($arr:item),+) => { + 1 + }; } fn main() { reproduce!(type Fail = char; arr = 1); + reproduce!(23, type Fail = char;, type Fail = char;); } diff --git a/tests/target/issue-6629.rs b/tests/target/issue-6629.rs index 85dba6a0786..1ed9927f132 100644 --- a/tests/target/issue-6629.rs +++ b/tests/target/issue-6629.rs @@ -1,9 +1,13 @@ macro_rules! reproduce { - (type Fail = $ty:ty; arr = $($arr:expr),*) => { + (type Fail = $ty:ty; arr = $($arr:expr),+) => { ( vec![$($arr),+] ) }; + ( $expr:expr, $($arr:item),+) => { + 1 + }; } fn main() { reproduce!(type Fail = char; arr = 1); + reproduce!(23, type Fail = char;, type Fail = char;); } From 2acdadd0c4e942acd5aab1e90a87a71cb4cf456f Mon Sep 17 00:00:00 2001 From: Gianmaria Rovelli Date: Sun, 17 Aug 2025 13:40:27 +0100 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20don=E2=80=99t=20format=20mixed=20mac?= =?UTF-8?q?ro=20args=20(items=20+=20non-items)=20(#6629)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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;); ``` --- src/lists.rs | 10 ++++------ src/macros.rs | 6 +++++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/lists.rs b/src/lists.rs index e4fdad198de..9d811e5d9b5 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -288,12 +288,10 @@ where let inner_item = item.item.as_ref().or_else(|err| Err(err.clone()))?; let first = i == 0; let last = iter.peek().is_none(); - let ends_with_semi = inner_item.ends_with(";"); - let mut separate = !ends_with_semi - && match sep_place { - SeparatorPlace::Front => !first, - SeparatorPlace::Back => !last || trailing_separator, - }; + let mut separate = match sep_place { + SeparatorPlace::Front => !first, + SeparatorPlace::Back => !last || trailing_separator, + }; let item_sep_len = if separate { sep_len } else { 0 }; // Item string may be multi-line. Its length (used for block comment alignment) diff --git a/src/macros.rs b/src/macros.rs index 16897e57dcb..eed6238acfc 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -256,7 +256,8 @@ fn rewrite_macro_inner( } }; - if !arg_vec.is_empty() && arg_vec.iter().all(MacroArg::is_item) { + let has_item = arg_vec.iter().any(MacroArg::is_item); + if has_item && arg_vec.iter().all(MacroArg::is_item) { return rewrite_macro_with_items( context, &arg_vec, @@ -268,6 +269,9 @@ fn rewrite_macro_inner( mac.span(), ); } + if has_item { + return return_macro_parse_failure_fallback(context, shape.indent, position, mac.span()); + } match style { Delimiter::Parenthesis => {