https://github.com/maith-s created
https://github.com/llvm/llvm-project/pull/216237
Fixes #51678
The check flagged a macro argument used as the type-name in a C11 _Generic
selection, e.g.:
#define assert_type(expr, type) _Generic((expr), type : (expr))
Parenthesizing `type` there is a syntax error. The check now tracks
paren/brace/square nesting via a stack, and recognizes when a macro argument
sits directly inside a _Generic's argument list and is followed by ':' --
skipping it the same way other special-cased positions (namespaces, template
args, goto labels) already are.
Added tests covering the reported case and nested _Generic.
>From a7a91caaf4a86c57ca0af2cda97186f68491e555 Mon Sep 17 00:00:00 2001
From: Maithili Shingne <[email protected]>
Date: Thu, 13 Aug 2026 22:45:23 -0400
Subject: [PATCH] [clang-tidy] Fix bugprone-macro-parentheses false positive
for _Generic
Fixes #51678
The check flagged a macro argument used as the type-name in a C11
_Generic selection, e.g.:
#define assert_type(expr, type) _Generic((expr), type : (expr))
Parenthesizing `type` there is a syntax error. The check now tracks
paren/brace/square nesting via a stack, and recognizes when a macro
argument sits directly inside a _Generic's argument list and is
followed by ':' -- skipping it the same way other special-cased
positions (namespaces, template args, goto labels) already are.
Added tests covering the reported case and nested _Generic.
---
.../bugprone/MacroParenthesesCheck.cpp | 25 +++++++++++++++++--
clang-tools-extra/docs/ReleaseNotes.rst | 5 ++++
.../checkers/bugprone/macro-parentheses.cpp | 7 ++++++
3 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
index a51bce1484a42..a482337272c1d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
@@ -179,7 +179,25 @@ void MacroParenthesesPPCallbacks::argument(const Token
&MacroNameTok,
// Skip the goto argument with an arbitrary number of subsequent stars.
bool FoundGoto = false;
+ // Tracks, for each open paren/brace/square, whether it's the argument
+ // list of a C11 _Generic selection -- e.g. _Generic(expr, type: value).
+ // An argument in the type-name position must not be parenthesized.
+ llvm::SmallVector<char, 8> GenericAssocStack;
+ bool PendingGeneric = false;
+
for (auto TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE; ++TI) {
+ const Token &Tok = *TI;
+
+ if (Tok.isOneOf(tok::l_paren, tok::l_brace, tok::l_square)) {
+ GenericAssocStack.push_back(PendingGeneric && Tok.is(tok::l_paren));
+ PendingGeneric = false;
+ } else if (Tok.isOneOf(tok::r_paren, tok::r_brace, tok::r_square)) {
+ if (!GenericAssocStack.empty())
+ GenericAssocStack.pop_back();
+ } else if (Tok.is(tok::kw__Generic)) {
+ PendingGeneric = true;
+ }
+
// First token.
if (TI == MI->tokens_begin())
continue;
@@ -191,8 +209,6 @@ void MacroParenthesesPPCallbacks::argument(const Token
&MacroNameTok,
const Token &Prev = *std::prev(TI);
const Token &Next = *std::next(TI);
- const Token &Tok = *TI;
-
// There should not be extra parentheses in possible variable declaration.
if (VarDecl) {
if (Tok.isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren))
@@ -233,6 +249,11 @@ void MacroParenthesesPPCallbacks::argument(const Token
&MacroNameTok,
if (Next.is(tok::coloncolon))
continue;
+ // Argument is the type-name of a C11 _Generic association.
+ if (Next.is(tok::colon) && !GenericAssocStack.empty() &&
+ GenericAssocStack.back())
+ continue;
+
// String concatenation.
if (isStringLiteral(Prev.getKind()) || isStringLiteral(Next.getKind()))
continue;
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst
b/clang-tools-extra/docs/ReleaseNotes.rst
index b85ece288881e..ddf9e2ed4cd6c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -905,6 +905,11 @@ Changes in existing checks
note to suggest materializing the temporary range when iterating over
temporary
range expressions or initializer lists, as reusing them directly could be
unsafe.
+- Improved :doc:`bugprone-macro-parentheses
+ <clang-tidy/checks/bugprone/macro-parentheses>` check by fixing a false
positive
+ for macro arguments used as the type-name in a C11 ``_Generic`` selection,
where
+ parenthesizing them would be invalid.
+
Removed checks
^^^^^^^^^^^^^^
diff --git
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
index a3ce47d3d0885..4db2b0798654f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
@@ -50,6 +50,13 @@
#define GOOD33(x) if (!a__##x) a_##x = &f(#x)
#define GOOD34(x, y) if (x) goto y;
#define GOOD35(x, y) if (x) goto *(y);
+#if __STDC_VERSION__ >= 201112L
+#define GOOD36(expr, type) _Generic((expr), type : (expr))
+#endif
+#if __STDC_VERSION__ >= 201112L
+#define GOOD37(expr, type, inner_expr, inner_type) \
+ _Generic((expr), type : _Generic((inner_expr), inner_type : (inner_expr)))
+#endif
// These are allowed for now..
#define MAYBE1 *12.34
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits