https://github.com/matthiasgoergens created 
https://github.com/llvm/llvm-project/pull/214990

`26ffc71afa7c` disallowed breaking on either side of `##` to keep pasted 
identifiers together, but the blanket rule also caught the GNU comma-swallowing 
idiom `call(arg, ##__VA_ARGS__)`, so a macro line containing it could never be 
wrapped and stayed over the column limit.

Keep forbidding breaks after `##`, and before `##` except when the previous 
token is a comma: the comma-`##` sequence swallows the comma rather than 
pasting tokens, and a backslash-newline between them leaves the token stream 
unchanged. The two tests cover final and non-final `##__VA_ARGS__` and 
re-format their own output, pinning idempotence.

Fixes #212835.

## Tool use

Per the [LLVM AI Tool Use Policy](https://llvm.org/docs/AIToolPolicy.html): AI
tools were involved throughout the preparation of this change. I am the author
and accountable for the contribution.

Assisted-by: OpenAI Codex
Assisted-by: Claude Code
Assisted-by: Kimi
Assisted-by: DeepSeek


From ff300ec16f5bf53c39a7a2add6369298a4de8979 Mon Sep 17 00:00:00 2001
From: Matthias Goergens <[email protected]>
Date: Sun, 2 Aug 2026 23:28:20 +0800
Subject: [PATCH 1/2] [clang-format] Allow breaks before comma-paste operators

Keep ordinary token-paste sequences unbreakable, but allow a line break between 
a comma and the GNU variadic-macro comma-swallowing operator. This restores 
useful wrapping before ##__VA_ARGS__ without regressing pasted identifiers.
---
 clang/lib/Format/TokenAnnotator.cpp   |  6 +++++-
 clang/unittests/Format/FormatTest.cpp | 15 +++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index b6c33279b0aca..06b28b37582d1 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6511,8 +6511,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine 
&Line,
             !(Right.Next &&
               Right.Next->isOneOf(TT_FunctionDeclarationName, tok::kw_const)));
   }
-  if (Left.is(tok::hashhash) || Right.is(tok::hashhash))
+  if (Left.is(tok::hashhash))
     return false;
+  // Keep pasted identifiers together, but allow a break before the GNU
+  // variadic-macro comma-swallowing extension: , ##__VA_ARGS__.
+  if (Right.is(tok::hashhash))
+    return Left.is(tok::comma);
   if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
                     TT_ClassHeadName, TT_QtProperty, tok::kw_operator)) {
     return true;
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index b72a683ac1fff..a06293690a6b2 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -5985,6 +5985,21 @@ TEST_F(FormatTest, HashInMacroDefinition) {
                Style);
   verifyFormat("#define A void # ## #", Style);
 
+  auto CommaPasteStyle = getLLVMStyleWithColumns(80);
+  CommaPasteStyle.IndentWidth = 4;
+  CommaPasteStyle.ContinuationIndentWidth = 8;
+  CommaPasteStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
+  verifyFormat(
+      "#define M(f, ...)                                                      "
+      "        \\\n"
+      "    auto f = call("
+      "firstArgumentThatIsQuiteLongEnoughToForceAWrapHere11111111,  \\\n"
+      "                  ##__VA_ARGS__);",
+      "#define M(f, ...) \\\n"
+      "    auto f = call("
+      "firstArgumentThatIsQuiteLongEnoughToForceAWrapHere11111111, "
+      "##__VA_ARGS__);",
+      CommaPasteStyle);
   Style.ColumnLimit = 60;
   Style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
   verifyFormat(

From af989b0375b6e3fabba0e36237dcb01b66ae2968 Mon Sep 17 00:00:00 2001
From: Matthias Goergens <[email protected]>
Date: Mon, 3 Aug 2026 02:48:10 +0800
Subject: [PATCH 2/2] [clang-format] Test non-final comma-paste wrapping

---
 clang/unittests/Format/FormatTest.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index a06293690a6b2..bce808a0857c9 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -6000,6 +6000,15 @@ TEST_F(FormatTest, HashInMacroDefinition) {
       "firstArgumentThatIsQuiteLongEnoughToForceAWrapHere11111111, "
       "##__VA_ARGS__);",
       CommaPasteStyle);
+  CommaPasteStyle.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
+  verifyFormat(
+      "#define M(...) \\\n"
+      "    call(firstArgumentThatIsQuiteLongEnoughToForceAWrapHere11111111, 
\\\n"
+      "         ##__VA_ARGS__, extra)",
+      "#define M(...) \\\n"
+      "    call(firstArgumentThatIsQuiteLongEnoughToForceAWrapHere11111111, "
+      "##__VA_ARGS__, extra)",
+      CommaPasteStyle);
   Style.ColumnLimit = 60;
   Style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
   verifyFormat(

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to