https://github.com/serge-sans-paille updated 
https://github.com/llvm/llvm-project/pull/188624

>From 174b065d76f254b59ffc6ae5b0080592d42c457f Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Wed, 25 Mar 2026 22:52:31 +0100
Subject: [PATCH 1/7] [clang] Suggest using __VA_OPT__(,) instead of GNU zero
 variadic macro argument

Also provide an appropriate fixit.
---
 clang/include/clang/Basic/DiagnosticLexKinds.td       |  3 ++-
 clang/lib/Lex/TokenLexer.cpp                          | 11 ++++++++++-
 .../Lexer/gnu-zero-variadic-macro-argument-fixit.c    |  9 +++++++++
 3 files changed, 21 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c

diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 5eceeced311f2..99a3109baa01c 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -769,7 +769,8 @@ def err_paste_at_start : Error<
   "'##' cannot appear at start of macro expansion">;
 def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">;
 def ext_paste_comma : Extension<
-  "token pasting of ',' and __VA_ARGS__ is a GNU extension">, 
InGroup<GNUZeroVariadicMacroArguments>;
+  "token pasting of ',' and __VA_ARGS__ is a GNU extension.%select{| Consider 
using __VA_OPT__(,) instead}0">,
+  InGroup<GNUZeroVariadicMacroArguments>;
 def err_unterm_macro_invoc : Error<
   "unterminated function-like macro invocation">;
 def err_too_many_args_in_macro_invoc : Error<
diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index db4313f766812..699b3a6a6c7d8 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -523,7 +523,16 @@ void TokenLexer::ExpandFunctionArguments() {
           Macro->isVariadic()) {
         VaArgsPseudoPaste = true;
         // Remove the paste operator, report use of the extension.
-        PP.Diag(ResultToks.pop_back_val().getLocation(), 
diag::ext_paste_comma);
+        const bool hint = PP.getLangOpts().C23 || PP.getLangOpts().CPlusPlus20;
+        auto diag = PP.Diag(ResultToks.pop_back_val().getLocation(),
+                            diag::ext_paste_comma)
+                    << hint;
+        if (hint) {
+          diag << FixItHint::CreateReplacement(
+              SourceRange(ResultToks[ResultToks.size() - 1].getLocation(),
+                          CurTok.getLocation()),
+              " __VA_OPT__(,) __VA_ARGS__");
+        }
       }
 
       ResultToks.append(ArgToks, ArgToks+NumToks);
diff --git a/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c 
b/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
new file mode 100644
index 0000000000000..e796ed001c0be
--- /dev/null
+++ b/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fdiagnostics-parseable-fixits %s 
-Wgnu-zero-variadic-macro-arguments -std=c23
+
+void foo(const char* fmt, ...);
+// expected-warning@+1 {{token pasting of ',' and __VA_ARGS__ is a GNU 
extension. Consider using __VA_OPT__(,) instead}}
+#define FOO(format, ...) foo(format, ##__VA_ARGS__)
+
+void bar(void) {
+  FOO("", 0);
+}

>From 7a94b696fab7e349cc93dcaa70f3ef35ec869a2a Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Wed, 25 Mar 2026 23:19:47 +0100
Subject: [PATCH 2/7] fixup! [clang] Suggest using __VA_OPT__(,) instead of GNU
 zero variadic macro argument

---
 clang/lib/Lex/TokenLexer.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index 699b3a6a6c7d8..9550c7cb722d6 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -523,12 +523,13 @@ void TokenLexer::ExpandFunctionArguments() {
           Macro->isVariadic()) {
         VaArgsPseudoPaste = true;
         // Remove the paste operator, report use of the extension.
-        const bool hint = PP.getLangOpts().C23 || PP.getLangOpts().CPlusPlus20;
-        auto diag = PP.Diag(ResultToks.pop_back_val().getLocation(),
+        const unsigned hint =
+            (PP.getLangOpts().C23 || PP.getLangOpts().CPlusPlus20) ? 1u : 0u;
+        auto Diag = PP.Diag(ResultToks.pop_back_val().getLocation(),
                             diag::ext_paste_comma)
                     << hint;
         if (hint) {
-          diag << FixItHint::CreateReplacement(
+          Diag << FixItHint::CreateReplacement(
               SourceRange(ResultToks[ResultToks.size() - 1].getLocation(),
                           CurTok.getLocation()),
               " __VA_OPT__(,) __VA_ARGS__");

>From 79a3f97666871c764bc3ce5914df6710b6c4569c Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Thu, 26 Mar 2026 01:11:15 +0100
Subject: [PATCH 3/7] fixup! fixup! [clang] Suggest using __VA_OPT__(,) instead
 of GNU zero variadic macro argument

---
 clang/include/clang/Basic/DiagnosticLexKinds.td           | 2 +-
 clang/lib/Lex/TokenLexer.cpp                              | 6 +++---
 clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c | 6 ++++--
 3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 99a3109baa01c..8ff5780651e64 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -769,7 +769,7 @@ def err_paste_at_start : Error<
   "'##' cannot appear at start of macro expansion">;
 def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">;
 def ext_paste_comma : Extension<
-  "token pasting of ',' and __VA_ARGS__ is a GNU extension.%select{| Consider 
using __VA_OPT__(,) instead}0">,
+  "token pasting of ',' and __VA_ARGS__ is a GNU extension%select{|; consider 
using __VA_OPT__(,) instead}0">,
   InGroup<GNUZeroVariadicMacroArguments>;
 def err_unterm_macro_invoc : Error<
   "unterminated function-like macro invocation">;
diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index 9550c7cb722d6..42bc08758651f 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -523,12 +523,12 @@ void TokenLexer::ExpandFunctionArguments() {
           Macro->isVariadic()) {
         VaArgsPseudoPaste = true;
         // Remove the paste operator, report use of the extension.
-        const unsigned hint =
+        const unsigned Hint =
             (PP.getLangOpts().C23 || PP.getLangOpts().CPlusPlus20) ? 1u : 0u;
         auto Diag = PP.Diag(ResultToks.pop_back_val().getLocation(),
                             diag::ext_paste_comma)
-                    << hint;
-        if (hint) {
+                    << Hint;
+        if (Hint) {
           Diag << FixItHint::CreateReplacement(
               SourceRange(ResultToks[ResultToks.size() - 1].getLocation(),
                           CurTok.getLocation()),
diff --git a/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c 
b/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
index e796ed001c0be..8a24ba737409a 100644
--- a/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
+++ b/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
@@ -1,7 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fdiagnostics-parseable-fixits %s 
-Wgnu-zero-variadic-macro-arguments -std=c23
+// RUN: %clang_cc1 -fsyntax-only -verify %s 
-Wgnu-zero-variadic-macro-arguments -std=c23
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 
-Wgnu-zero-variadic-macro-arguments -std=c23 2>&1 | FileCheck %s
 
 void foo(const char* fmt, ...);
-// expected-warning@+1 {{token pasting of ',' and __VA_ARGS__ is a GNU 
extension. Consider using __VA_OPT__(,) instead}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:36-[[@LINE+2]]:51}:" __VA_OPT__(,) 
__VA_ARGS__"
+// expected-warning@+1 {{token pasting of ',' and __VA_ARGS__ is a GNU 
extension; consider using __VA_OPT__(,) instead}}
 #define FOO(format, ...) foo(format, ##__VA_ARGS__)
 
 void bar(void) {

>From 472e0350e0d478fd68f57f47f3623490e9f778c7 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Thu, 26 Mar 2026 01:43:12 +0100
Subject: [PATCH 4/7] fixup! fixup! fixup! [clang] Suggest using __VA_OPT__(,)
 instead of GNU zero variadic macro argument

---
 clang/docs/ReleaseNotes.rst                               | 3 +++
 clang/lib/Lex/TokenLexer.cpp                              | 2 +-
 clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c | 2 ++
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0dbe667e4f07a..52cbdd5c6dca9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -323,6 +323,9 @@ Improvements to Clang's diagnostics
   ``-Wunused-private-field`` no longer emits a warning for annotated private
   fields.
 
+- Improved ``-Wgnu-zero-variadic-macro-arguments`` to suggest using
+  ``__VA_OPT__`` if the current language version supports it(#GH188624)
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index 42bc08758651f..ade97bbbe74c2 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -530,7 +530,7 @@ void TokenLexer::ExpandFunctionArguments() {
                     << Hint;
         if (Hint) {
           Diag << FixItHint::CreateReplacement(
-              SourceRange(ResultToks[ResultToks.size() - 1].getLocation(),
+              SourceRange(ResultToks.back().getLocation(),
                           CurTok.getLocation()),
               " __VA_OPT__(,) __VA_ARGS__");
         }
diff --git a/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c 
b/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
index 8a24ba737409a..60e0774f0629e 100644
--- a/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
+++ b/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s 
-Wgnu-zero-variadic-macro-arguments -std=c23
 // RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 
-Wgnu-zero-variadic-macro-arguments -std=c23 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s 
-Wgnu-zero-variadic-macro-arguments -xc++ -std=c++20
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 
-Wgnu-zero-variadic-macro-arguments -xc++ -std=c++20 2>&1 | FileCheck %s
 
 void foo(const char* fmt, ...);
 // CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:36-[[@LINE+2]]:51}:" __VA_OPT__(,) 
__VA_ARGS__"

>From 6422bef072620e85b39e27a186439b04d69f8893 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Thu, 26 Mar 2026 13:55:32 +0100
Subject: [PATCH 5/7] fixup! fixup! fixup! fixup! [clang] Suggest using
 __VA_OPT__(,) instead of GNU zero variadic macro argument

---
 clang/lib/Lex/TokenLexer.cpp | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index ade97bbbe74c2..9acc674f1faf3 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -137,6 +137,10 @@ void TokenLexer::destroy() {
   if (ActualArgs) ActualArgs->destroy(PP);
 }
 
+static bool hasVaOptSupport(const LangOptions &LangOpts) {
+  return LangOpts.C23 || LangOpts.CPlusPlus20;
+}
+
 bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
     SmallVectorImpl<Token> &ResultToks, bool HasPasteOperator, MacroInfo 
*Macro,
     unsigned MacroArgNo, Preprocessor &PP) {
@@ -164,8 +168,11 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
     return false;
 
   // Issue an extension diagnostic for the paste operator.
-  if (HasPasteOperator)
-    PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
+  if (HasPasteOperator) {
+    const bool VaOptSupport = hasVaOptSupport(PP.getLangOpts());
+    PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma)
+        << VaOptSupport;
+  }
 
   // Remove the comma.
   ResultToks.pop_back();
@@ -523,12 +530,11 @@ void TokenLexer::ExpandFunctionArguments() {
           Macro->isVariadic()) {
         VaArgsPseudoPaste = true;
         // Remove the paste operator, report use of the extension.
-        const unsigned Hint =
-            (PP.getLangOpts().C23 || PP.getLangOpts().CPlusPlus20) ? 1u : 0u;
+        const bool VaOptSupport = hasVaOptSupport(PP.getLangOpts());
         auto Diag = PP.Diag(ResultToks.pop_back_val().getLocation(),
                             diag::ext_paste_comma)
-                    << Hint;
-        if (Hint) {
+                    << VaOptSupport;
+        if (VaOptSupport) {
           Diag << FixItHint::CreateReplacement(
               SourceRange(ResultToks.back().getLocation(),
                           CurTok.getLocation()),

>From b252d8577a05cf561a7deb8d3995f3bcd8ba2c10 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Wed, 1 Apr 2026 10:11:58 +0200
Subject: [PATCH 6/7] fixup! fixup! fixup! fixup! fixup! [clang] Suggest using
 __VA_OPT__(,) instead of GNU zero variadic macro argument

---
 clang/include/clang/Basic/DiagnosticLexKinds.td | 3 ++-
 clang/lib/Lex/TokenLexer.cpp                    | 5 ++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 8ff5780651e64..bea0aafac98cf 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -769,7 +769,8 @@ def err_paste_at_start : Error<
   "'##' cannot appear at start of macro expansion">;
 def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">;
 def ext_paste_comma : Extension<
-  "token pasting of ',' and __VA_ARGS__ is a GNU extension%select{|; consider 
using __VA_OPT__(,) instead}0">,
+  "token pasting of ',' and '__VA_ARGS__' is a GNU extension%select{|; "
+  "consider using '__VA_OPT__(,)' instead}0">,
   InGroup<GNUZeroVariadicMacroArguments>;
 def err_unterm_macro_invoc : Error<
   "unterminated function-like macro invocation">;
diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index 9acc674f1faf3..9b18c31e19eb1 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -169,9 +169,8 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
 
   // Issue an extension diagnostic for the paste operator.
   if (HasPasteOperator) {
-    const bool VaOptSupport = hasVaOptSupport(PP.getLangOpts());
     PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma)
-        << VaOptSupport;
+        << hasVaOptSupport(PP.getLangOpts());
   }
 
   // Remove the comma.
@@ -530,7 +529,7 @@ void TokenLexer::ExpandFunctionArguments() {
           Macro->isVariadic()) {
         VaArgsPseudoPaste = true;
         // Remove the paste operator, report use of the extension.
-        const bool VaOptSupport = hasVaOptSupport(PP.getLangOpts());
+        bool VaOptSupport = hasVaOptSupport(PP.getLangOpts());
         auto Diag = PP.Diag(ResultToks.pop_back_val().getLocation(),
                             diag::ext_paste_comma)
                     << VaOptSupport;

>From 3619c9e8812a4f08e5f47522c361e76704af8a9c Mon Sep 17 00:00:00 2001
From: serge-sans-paille <[email protected]>
Date: Wed, 1 Apr 2026 10:47:11 +0200
Subject: [PATCH 7/7] fixup! fixup! fixup! fixup! fixup! fixup! [clang] Suggest
 using __VA_OPT__(,) instead of GNU zero variadic macro argument

---
 clang/test/Lexer/gnu-flags.c                              | 2 +-
 clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c | 2 +-
 clang/test/Preprocessor/macro_fn.c                        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/test/Lexer/gnu-flags.c b/clang/test/Lexer/gnu-flags.c
index 30cfcf710f346..ad9646bb568ea 100644
--- a/clang/test/Lexer/gnu-flags.c
+++ b/clang/test/Lexer/gnu-flags.c
@@ -18,7 +18,7 @@
 #if ALL || ZEROARGS
 // expected-warning@+9 {{passing no argument for the '...' parameter of a 
variadic macro is a C23 extension}}
 // expected-note@+4 {{macro 'efoo' defined here}}
-// expected-warning@+3 {{token pasting of ',' and __VA_ARGS__ is a GNU 
extension}}
+// expected-warning@+3 {{token pasting of ',' and '__VA_ARGS__' is a GNU 
extension}}
 #endif
 
 #define efoo(format, args...) foo(format , ##args)
diff --git a/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c 
b/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
index 60e0774f0629e..32d1fd379709a 100644
--- a/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
+++ b/clang/test/Lexer/gnu-zero-variadic-macro-argument-fixit.c
@@ -5,7 +5,7 @@
 
 void foo(const char* fmt, ...);
 // CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:36-[[@LINE+2]]:51}:" __VA_OPT__(,) 
__VA_ARGS__"
-// expected-warning@+1 {{token pasting of ',' and __VA_ARGS__ is a GNU 
extension; consider using __VA_OPT__(,) instead}}
+// expected-warning@+1 {{token pasting of ',' and '__VA_ARGS__' is a GNU 
extension; consider using '__VA_OPT__(,)' instead}}
 #define FOO(format, ...) foo(format, ##__VA_ARGS__)
 
 void bar(void) {
diff --git a/clang/test/Preprocessor/macro_fn.c 
b/clang/test/Preprocessor/macro_fn.c
index 2e72bd272084e..48fd26daebfab 100644
--- a/clang/test/Preprocessor/macro_fn.c
+++ b/clang/test/Preprocessor/macro_fn.c
@@ -60,7 +60,7 @@ one_dot()   /* empty first argument, elided ... */
     SomeComplicatedStuff((desc), ##__VA_ARGS__)
 
 #ifndef VARIADIC_MACRO_ARGS_REMOVE_COMMA
-/* expected-warning@-3 {{token pasting of ',' and __VA_ARGS__ is a GNU 
extension}} */
+/* expected-warning@-3 {{token pasting of ',' and '__VA_ARGS__' is a GNU 
extension}} */
 #endif
 
 NSAssert(somecond, somedesc)

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

Reply via email to