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

Reply via email to