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
