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

Also provide an appropriate fixit.
This commit is contained in:
serge-sans-paille 2026-04-01 12:09:02 +00:00 committed by GitHub
parent 26b755c09b
commit c67092066e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 39 additions and 6 deletions

View File

@ -350,6 +350,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
----------------------------------

View File

@ -769,7 +769,9 @@ 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<

View File

@ -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,10 @@ 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) {
PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma)
<< hasVaOptSupport(PP.getLangOpts());
}
// Remove the comma.
ResultToks.pop_back();
@ -523,7 +529,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);
bool VaOptSupport = hasVaOptSupport(PP.getLangOpts());
auto Diag = PP.Diag(ResultToks.pop_back_val().getLocation(),
diag::ext_paste_comma)
<< VaOptSupport;
if (VaOptSupport) {
Diag << FixItHint::CreateReplacement(
SourceRange(ResultToks.back().getLocation(),
CurTok.getLocation()),
" __VA_OPT__(,) __VA_ARGS__");
}
}
ResultToks.append(ArgToks, ArgToks+NumToks);

View File

@ -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)

View File

@ -0,0 +1,13 @@
// 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__"
// 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);
}

View File

@ -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)