https://github.com/sstwcw updated 
https://github.com/llvm/llvm-project/pull/223266

>From dac247bb35b3c365b151a3008eeabb0b5d4f9894 Mon Sep 17 00:00:00 2001
From: sstwcw <[email protected]>
Date: Sun, 13 Sep 2026 18:29:48 +0000
Subject: [PATCH 1/3] [clang-format] Stop treating the new expression as a
 lambda

before

```C++
x = new a *[] { nullptr };
x = new a *[] {
  nullptr, //
      nullptr,
};
```

after

```C++
x = new a *[]{nullptr};
x = new a *[]{
    nullptr, //
    nullptr,
};
```

Fixes #38820.

The program previously treated the part starting with the square
brackets as a lambda when the type ended in a star.
---
 clang/lib/Format/UnwrappedLineParser.cpp      | 22 ++++++++++++++++++-
 clang/unittests/Format/FormatTest.cpp         | 10 +++++++++
 clang/unittests/Format/TokenAnnotatorTest.cpp | 10 +++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index ac3eb6fa5bcf5..ddef3ba5ce909 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -2473,7 +2473,25 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
   nextToken();
   if (Previous) {
     const auto *PrevPrev = Previous->getPreviousNonComment();
-    if (Previous->is(tok::star) && PrevPrev && PrevPrev->isTypeName(LangOpts))
+    // The star may be part of the type in a trailing return type or new
+    // expression. Then the square brackets will mean array instead of capture.
+    auto StarIsType = [&]() {
+      if (!PrevPrev)
+        return false;
+      if (PrevPrev->isTypeName(LangOpts))
+        return true;
+      if (PrevPrev->isNot(tok::identifier))
+        return false;
+      const auto *Tok = PrevPrev->getPreviousNonComment();
+      // Skip the placement part of the new expression.
+      if (Tok && Tok->is(tok::r_paren)) {
+        Tok = Tok->MatchingParen;
+        if (Tok)
+          Tok = Tok->getPreviousNonComment();
+      }
+      return Tok && Tok->is(tok::kw_new);
+    };
+    if (Previous->is(tok::star) && StarIsType())
       return false;
     if (Previous->closesScope()) {
       // Not a potential C-style cast.
@@ -2753,6 +2771,8 @@ bool UnwrappedLineParser::parseParens(TokenType 
StarAndAmpTokenType,
           FormatTok->setBlockKind(BK_BracedInit);
         }
       }
+      RParen->MatchingParen = LParen;
+      LParen->MatchingParen = RParen;
       return SeenEqual;
     }
     case tok::r_brace:
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 5aed37aa56d52..57d5d3ed1914d 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -12303,6 +12303,16 @@ TEST_F(FormatTest, UnderstandsNewAndDelete) {
                "  p->delete ();\n"
                "}");
 
+  verifyFormat("x = new a *[]{nullptr};");
+  verifyFormat("x = new (a) a *[]{\n"
+               "    nullptr, //\n"
+               "    nullptr,\n"
+               "};");
+  verifyFormat("x = new a *[]{\n"
+               "    nullptr, //\n"
+               "    nullptr,\n"
+               "};");
+
   FormatStyle AfterPlacementOperator = getLLVMStyle();
   AfterPlacementOperator.SpaceBeforeParens = FormatStyle::SBPO_Custom;
   EXPECT_TRUE(
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp 
b/clang/unittests/Format/TokenAnnotatorTest.cpp
index f5ff5229f7232..a6f5af43f5799 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -2459,6 +2459,16 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
   EXPECT_TOKEN(Tokens[3], tok::star, TT_BinaryOperator);
   EXPECT_TOKEN(Tokens[4], tok::l_square, TT_LambdaLSquare);
   EXPECT_TOKEN(Tokens[6], tok::l_brace, TT_LambdaLBrace);
+
+  // The new declarator is not a lambda.
+  Tokens = annotate("x = new a *[]{};");
+  ASSERT_EQ(Tokens.size(), 11u) << Tokens;
+  EXPECT_TOKEN(Tokens[4], tok::star, TT_PointerOrReference);
+  EXPECT_TOKEN(Tokens[5], tok::l_square, TT_ArraySubscriptLSquare);
+  Tokens = annotate("x = new (a) a *[]{};");
+  ASSERT_EQ(Tokens.size(), 14u) << Tokens;
+  EXPECT_TOKEN(Tokens[7], tok::star, TT_PointerOrReference);
+  EXPECT_TOKEN(Tokens[8], tok::l_square, TT_ArraySubscriptLSquare);
 }
 
 TEST_F(TokenAnnotatorTest, UnderstandsFunctionAnnotations) {

>From 81f52304bc8950911927982f331ec4c0c1d7ebac Mon Sep 17 00:00:00 2001
From: sstwcw <[email protected]>
Date: Thu, 1 Oct 2026 14:26:10 +0000
Subject: [PATCH 2/3] Use parseNew

---
 clang/lib/Format/UnwrappedLineParser.cpp | 101 +++++++++++++----------
 clang/lib/Format/UnwrappedLineParser.h   |   4 +-
 clang/unittests/Format/FormatTest.cpp    |  16 ++++
 3 files changed, 77 insertions(+), 44 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index ddef3ba5ce909..036750059d431 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -2182,9 +2182,10 @@ void UnwrappedLineParser::parseStructuralElement(
       parseSquare();
       break;
     case tok::kw_new:
-      if (Style.isCSharp() &&
-          (Tokens->peekNextToken()->isAccessSpecifierKeyword() ||
-           (Previous && Previous->isAccessSpecifierKeyword()))) {
+      if ((Style.isCSharp() &&
+           (Tokens->peekNextToken()->isAccessSpecifierKeyword() ||
+            (Previous && Previous->isAccessSpecifierKeyword()))) ||
+          FormatTok->endsSequence(tok::kw_new, tok::kw_operator)) {
         nextToken();
       } else {
         parseNew();
@@ -2473,25 +2474,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
   nextToken();
   if (Previous) {
     const auto *PrevPrev = Previous->getPreviousNonComment();
-    // The star may be part of the type in a trailing return type or new
-    // expression. Then the square brackets will mean array instead of capture.
-    auto StarIsType = [&]() {
-      if (!PrevPrev)
-        return false;
-      if (PrevPrev->isTypeName(LangOpts))
-        return true;
-      if (PrevPrev->isNot(tok::identifier))
-        return false;
-      const auto *Tok = PrevPrev->getPreviousNonComment();
-      // Skip the placement part of the new expression.
-      if (Tok && Tok->is(tok::r_paren)) {
-        Tok = Tok->MatchingParen;
-        if (Tok)
-          Tok = Tok->getPreviousNonComment();
-      }
-      return Tok && Tok->is(tok::kw_new);
-    };
-    if (Previous->is(tok::star) && StarIsType())
+    if (Previous->is(tok::star) && PrevPrev && PrevPrev->isTypeName(LangOpts))
       return false;
     if (Previous->closesScope()) {
       // Not a potential C-style cast.
@@ -2517,7 +2500,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
     if (Next->is(tok::greater))
       return false;
   }
-  parseSquare(/*LambdaIntroducer=*/true);
+  parseSquare(/*SkipLambda=*/true);
   return true;
 }
 
@@ -2771,8 +2754,6 @@ bool UnwrappedLineParser::parseParens(TokenType 
StarAndAmpTokenType,
           FormatTok->setBlockKind(BK_BracedInit);
         }
       }
-      RParen->MatchingParen = LParen;
-      LParen->MatchingParen = RParen;
       return SeenEqual;
     }
     case tok::r_brace:
@@ -2853,8 +2834,8 @@ bool UnwrappedLineParser::parseParens(TokenType 
StarAndAmpTokenType,
   return SeenEqual;
 }
 
-void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) {
-  if (!LambdaIntroducer) {
+void UnwrappedLineParser::parseSquare(bool SkipLambda) {
+  if (!SkipLambda) {
     assert(FormatTok->is(tok::l_square) && "'[' expected.");
     if (tryToParseLambda())
       return;
@@ -3363,28 +3344,62 @@ void UnwrappedLineParser::parseNew() {
 
       nextToken();
     } while (!eof());
-  }
+  } else if (Style.isJava()) {
+    // In Java, we can parse everything up to the parens, which aren't 
optional.
+    do {
+      // There should not be a ;, { or } before the new's open paren.
+      if (FormatTok->isOneOf(tok::semi, tok::l_brace, tok::r_brace))
+        return;
 
-  if (!Style.isJava())
-    return;
+      // Consume the parens.
+      if (FormatTok->is(tok::l_paren)) {
+        parseParens();
 
-  // In Java, we can parse everything up to the parens, which aren't optional.
-  do {
-    // There should not be a ;, { or } before the new's open paren.
-    if (FormatTok->isOneOf(tok::semi, tok::l_brace, tok::r_brace))
+        // If there is a class body of an anonymous class, consume that as
+        // child.
+        if (FormatTok->is(tok::l_brace))
+          parseChildBlock();
+        return;
+      }
+      nextToken();
+    } while (!eof());
+  } else if (Style.isCpp()) {
+    // The brace should not appear here in a new expression. It likely means
+    // that the line is incomplete or that new is not a keyword such as in
+    // Objective-C.
+    if (FormatTok->is(tok::l_brace))
       return;
-
-    // Consume the parens.
+    if (FormatTok->is(tok::l_paren))
+      parseParens();
     if (FormatTok->is(tok::l_paren)) {
       parseParens();
-
-      // If there is a class body of an anonymous class, consume that as child.
-      if (FormatTok->is(tok::l_brace))
-        parseChildBlock();
-      return;
+    } else {
+      // When there are 2 pairs of parentheses, the second will be the type.
+      // Otherwise, the type may be outside parentheses. It is handled here.
+      while (!eof()) {
+        if (FormatTok->isOneOf(tok::kw_alignas, tok::kw_decltype)) {
+          nextToken();
+          if (FormatTok->is(tok::l_paren))
+            parseParens();
+        } else if (FormatTok->is(tok::l_square)) {
+          nextToken();
+          parseSquare(/*SkipLambda=*/true);
+        } else if (FormatTok->is(tok::less)) {
+          nextToken();
+          parseBracedList(/*IsAngleBracket=*/true);
+        } else if (FormatTok->Tok.getIdentifierInfo() ||
+                   FormatTok->isOneOf(tok::coloncolon, tok::star)) {
+          nextToken();
+        } else {
+          break;
+        }
+      }
     }
-    nextToken();
-  } while (!eof());
+    if (FormatTok->is(tok::l_brace))
+      parseBracedList();
+    else if (FormatTok->is(tok::l_paren))
+      parseParens();
+  }
 }
 
 void UnwrappedLineParser::parseLoopBody(bool KeepBraces, bool WrapRightBrace) {
diff --git a/clang/lib/Format/UnwrappedLineParser.h 
b/clang/lib/Format/UnwrappedLineParser.h
index 8fa4e9f7540d5..aede5c2e47428 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -150,7 +150,9 @@ class UnwrappedLineParser {
   bool parseBracedList(bool IsAngleBracket = false, bool IsEnum = false);
   bool parseParens(TokenType StarAndAmpTokenType = TT_Unknown,
                    bool InMacroCall = false);
-  void parseSquare(bool LambdaIntroducer = false);
+  // SkipLambda means the square does not begin a lambda expression. The 
opening
+  // square bracket is assumed to be consumed when it is true.
+  void parseSquare(bool SkipLambda = false);
   void keepAncestorBraces();
   void parseUnbracedBody(bool CheckEOF = false);
   void handleAttributes();
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 57d5d3ed1914d..6b90f350f654a 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -12312,6 +12312,22 @@ TEST_F(FormatTest, UnderstandsNewAndDelete) {
                "    nullptr, //\n"
                "    nullptr,\n"
                "};");
+  verifyFormat("x = new a::a *[]{\n"
+               "    nullptr, //\n"
+               "    nullptr,\n"
+               "};");
+  verifyFormat("x = new a<a> *[]{\n"
+               "    nullptr, //\n"
+               "    nullptr,\n"
+               "};");
+  verifyFormat("x = new (a) a<a> *[]{\n"
+               "    nullptr, //\n"
+               "    nullptr,\n"
+               "};");
+  verifyFormat("x = new (a *[]){\n"
+               "    nullptr, //\n"
+               "    nullptr,\n"
+               "};");
 
   FormatStyle AfterPlacementOperator = getLLVMStyle();
   AfterPlacementOperator.SpaceBeforeParens = FormatStyle::SBPO_Custom;

>From 1bd843fe5c5a8e121423a4c337e7c0410bed0ffd Mon Sep 17 00:00:00 2001
From: sstwcw <[email protected]>
Date: Thu, 8 Oct 2026 13:46:31 +0000
Subject: [PATCH 3/3] Add test

---
 clang/unittests/Format/FormatTest.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 6b90f350f654a..36d6d1b37d188 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -12328,6 +12328,10 @@ TEST_F(FormatTest, UnderstandsNewAndDelete) {
                "    nullptr, //\n"
                "    nullptr,\n"
                "};");
+  verifyFormat("x = new (a)(a<a> *[]){\n"
+               "    nullptr, //\n"
+               "    nullptr,\n"
+               "};");
 
   FormatStyle AfterPlacementOperator = getLLVMStyle();
   AfterPlacementOperator.SpaceBeforeParens = FormatStyle::SBPO_Custom;

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

Reply via email to