[clang] [clang] Suggest using __VA_OPT__(,) instead of GNU zero variadic macro argument (PR #188624)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 26 05:56:15 PDT 2026
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 <sguelton at mozilla.com>
Date: Wed, 25 Mar 2026 22:52:31 +0100
Subject: [PATCH 1/5] [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);
+}
>From 7a94b696fab7e349cc93dcaa70f3ef35ec869a2a Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Wed, 25 Mar 2026 23:19:47 +0100
Subject: [PATCH 2/5] 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 <sguelton at mozilla.com>
Date: Thu, 26 Mar 2026 01:11:15 +0100
Subject: [PATCH 3/5] 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 at +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 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) {
>From 472e0350e0d478fd68f57f47f3623490e9f778c7 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Thu, 26 Mar 2026 01:43:12 +0100
Subject: [PATCH 4/5] 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 <sguelton at mozilla.com>
Date: Thu, 26 Mar 2026 13:55:32 +0100
Subject: [PATCH 5/5] 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()),
More information about the cfe-commits
mailing list