[clang] [clang] Suggest using __VA_OPT__(,) instead of GNU zero variadic macro argument (PR #188624)

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 25 14:55:32 PDT 2026


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

Also provide an appropriate fixit.

>From 174b065d76f254b59ffc6ae5b0080592d42c457f Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Wed, 25 Mar 2026 22:52:31 +0100
Subject: [PATCH] [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 at +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);
+}



More information about the cfe-commits mailing list