https://github.com/Lane0218 updated 
https://github.com/llvm/llvm-project/pull/173771

>From 8dce6c2109e79f002e4becd9276e34f1de51d47e Mon Sep 17 00:00:00 2001
From: Lane0218 <[email protected]>
Date: Sun, 28 Dec 2025 21:01:23 +0800
Subject: [PATCH] [clang-format] Keep compound literals stable in macro bodies

Fixes https://github.com/llvm/llvm-project/issues/173583.

Test: FormatTests
---
 clang/lib/Format/UnwrappedLineParser.cpp | 41 ++++++++++++++++++++++--
 clang/unittests/Format/FormatTest.cpp    | 20 ++++++++++++
 2 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index c1a9161b10720..2d1ddde2b438b 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -491,6 +491,31 @@ void UnwrappedLineParser::calculateBraceTypes(bool 
ExpectClassBody) {
   SmallVector<StackEntry, 8> LBraceStack;
   assert(Tok->is(tok::l_brace));
 
+  constexpr int MaxLookBack = 64;
+  const auto IsAddressOfParenExpression = [](const FormatToken *RightParen) {
+    if (!RightParen || RightParen->isNot(tok::r_paren))
+      return false;
+
+    int ParenDepth = 0;
+    const FormatToken *Current = RightParen;
+    const FormatToken *LeftParen = nullptr;
+    for (int I = 0; I < MaxLookBack && Current; ++I) {
+      if (Current->is(tok::r_paren)) {
+        ++ParenDepth;
+      } else if (Current->is(tok::l_paren)) {
+        --ParenDepth;
+        if (ParenDepth == 0) {
+          LeftParen = Current;
+          break;
+        }
+      }
+      Current = Current->Previous;
+    }
+
+    return LeftParen && LeftParen->Previous &&
+           LeftParen->Previous->is(tok::amp);
+  };
+
   do {
     auto *NextTok = Tokens->getNextNonComment();
 
@@ -528,7 +553,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool 
ExpectClassBody) {
           Tok->setBlockKind(BK_Block);
         }
       } else {
-        Tok->setBlockKind(BK_Unknown);
+        // In macro bodies we try to keep compound literal expressions like
+        // `&(type){v}` on a single line. Without this, the '{' can be mistaken
+        // for a block/function body and clang-format will reflow the macro 
with
+        // backslashes and spaces (e.g. `&(type) { v }`).
+        if (IsCpp && Line->InMacroBody && PrevTok &&
+            IsAddressOfParenExpression(PrevTok)) {
+          Tok->setBlockKind(BK_BracedInit);
+        } else {
+          Tok->setBlockKind(BK_Unknown);
+        }
       }
       LBraceStack.push_back({Tok, PrevTok});
       break;
@@ -2563,7 +2597,10 @@ bool UnwrappedLineParser::parseBracedList(bool 
IsAngleBracket, bool IsEnum) {
       // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
       // used for error recovery if we have otherwise determined that this is
       // a braced list.
-      if (Style.isJavaScript()) {
+      // In macro bodies we can also see non-syntactic braced lists (e.g.
+      // compound literal expressions) where clang-format should still remain
+      // stable.
+      if (Style.isJavaScript() || (IsCpp && Line->InMacroBody)) {
         nextToken();
         break;
       }
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 3ee7ce38578aa..8e4dc74378691 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -5858,6 +5858,26 @@ TEST_F(FormatTest, RespectWhitespaceInMacroDefinitions) {
   verifyFormat("#define false((foo)0)", Style);
 }
 
+TEST_F(FormatTest, CompoundLiteralInMacroDefinition) {
+  // https://github.com/llvm/llvm-project/issues/173583
+  //
+  // A C compound literal `(type){...}` is not a function/block. When used in a
+  // macro definition, clang-format should not treat `&` as a function name and
+  // reformat it as if it were `&(type) { ... }`.
+  FormatStyle Style = getLLVMStyle();
+  Style.Language = FormatStyle::LK_Cpp;
+  Style.IndentWidth = 4;
+  Style.TabWidth = 4;
+  Style.UseTab = FormatStyle::UT_Never;
+  Style.AlignEscapedNewlines = FormatStyle::ENAS_LeftWithLastLine;
+  Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+  Style.BreakBeforeBraces = FormatStyle::BS_Attach;
+
+  verifyNoChange("#define getAddr(v, type) &(type){v}", Style);
+  verifyNoChange("#define getAddr2(v, type) int &(type){v;}", Style);
+  verifyNoChange("#define ctos(c) (char[2]){c, '\\0'}", Style);
+}
+
 TEST_F(FormatTest, EmptyLinesInMacroDefinitions) {
   verifyFormat("#define A b;",
                "#define A \\\n"

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to