https://github.com/itzexpoexpo updated 
https://github.com/llvm/llvm-project/pull/154580

From 877d155b65a054a240490d3c7e2015673f964466 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Wed, 20 Aug 2025 19:28:23 +0200
Subject: [PATCH 01/19] [clang-format] Add option
 AllowShortRecordsOnASingleLine

This commit supersedes PR #151970 by adding the option
AllowShortRecordsOnASingleLine that allows the following formatting:

  struct foo {};
  struct bar { int i; };
  struct baz
  {
    int i;
    int j;
    int k;
  };
---
 clang/docs/ClangFormatStyleOptions.rst      | 32 +++++++++
 clang/include/clang/Format/Format.h         | 26 ++++++++
 clang/lib/Format/Format.cpp                 | 11 ++++
 clang/lib/Format/TokenAnnotator.cpp         | 13 ++--
 clang/lib/Format/UnwrappedLineFormatter.cpp | 22 ++++++-
 clang/lib/Format/UnwrappedLineParser.cpp    | 23 +++++--
 clang/unittests/Format/ConfigParseTest.cpp  |  8 +++
 clang/unittests/Format/FormatTest.cpp       | 73 +++++++++++++++++++++
 8 files changed, 193 insertions(+), 15 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 6be4d512bda6a..2b26db6b4f680 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2096,6 +2096,38 @@ the configuration (without a prefix: ``Auto``).
 **AllowShortNamespacesOnASingleLine** (``Boolean``) 
:versionbadge:`clang-format 20` :ref:`¶ <AllowShortNamespacesOnASingleLine>`
   If ``true``, ``namespace a { class b; }`` can be put on a single line.
 
+.. _AllowShortRecordsOnASingleLine:
+
+**AllowShortRecordsOnASingleLine** (``ShortRecordStyle``) :ref:`¶ 
<AllowShortRecordsOnASingleLine>`
+  Dependent on the value, ``struct bar { int i; }`` can be put on a single
+  line.
+
+  Possible values:
+
+  * ``SRS_Never`` (in configuration: ``Never``)
+    Never merge records into a single line.
+
+  * ``SRS_Empty`` (in configuration: ``Empty``)
+    Only merge empty records.
+
+    .. code-block:: c++
+
+      struct foo {};
+      struct bar
+      {
+        int i;
+      };
+
+  * ``SRS_All`` (in configuration: ``All``)
+    Merge all records that fit on a single line.
+
+    .. code-block:: c++
+
+      struct foo {};
+      struct bar { int i; };
+
+
+
 .. _AlwaysBreakAfterDefinitionReturnType:
 
 **AlwaysBreakAfterDefinitionReturnType** 
(``DefinitionReturnTypeBreakingStyle``) :versionbadge:`clang-format 3.7` 
:ref:`¶ <AlwaysBreakAfterDefinitionReturnType>`
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 03cff5f8cfb66..7a254b73ac2d3 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -992,6 +992,32 @@ struct FormatStyle {
   /// \version 20
   bool AllowShortNamespacesOnASingleLine;
 
+  /// Different styles for merging short records
+  /// (``class``,``struct``,``union``).
+  enum ShortRecordStyle : int8_t {
+    /// Never merge records into a single line.
+    SRS_Never,
+    /// Only merge empty records.
+    /// \code
+    ///   struct foo {};
+    ///   struct bar
+    ///   {
+    ///     int i;
+    ///   };
+    /// \endcode
+    SRS_Empty,
+    /// Merge all records that fit on a single line.
+    /// \code
+    ///   struct foo {};
+    ///   struct bar { int i; };
+    /// \endcode
+    SRS_All
+  };
+
+  /// Dependent on the value, ``struct bar { int i; }`` can be put on a single
+  /// line.
+  ShortRecordStyle AllowShortRecordsOnASingleLine;
+
   /// Different ways to break after the function definition return type.
   /// This option is **deprecated** and is retained for backwards 
compatibility.
   enum DefinitionReturnTypeBreakingStyle : int8_t {
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index f095d2c18cfcf..19ed5029b6af4 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -680,6 +680,14 @@ template <> struct 
ScalarEnumerationTraits<FormatStyle::ShortLambdaStyle> {
   }
 };
 
+template <> struct ScalarEnumerationTraits<FormatStyle::ShortRecordStyle> {
+  static void enumeration(IO &IO, FormatStyle::ShortRecordStyle &Value) {
+    IO.enumCase(Value, "Never", FormatStyle::SRS_Never);
+    IO.enumCase(Value, "Empty", FormatStyle::SRS_Empty);
+    IO.enumCase(Value, "All", FormatStyle::SRS_All);
+  }
+};
+
 template <> struct MappingTraits<FormatStyle::SortIncludesOptions> {
   static void enumInput(IO &IO, FormatStyle::SortIncludesOptions &Value) {
     IO.enumCase(Value, "Never", FormatStyle::SortIncludesOptions({}));
@@ -1043,6 +1051,8 @@ template <> struct MappingTraits<FormatStyle> {
                    Style.AllowShortIfStatementsOnASingleLine);
     IO.mapOptional("AllowShortLambdasOnASingleLine",
                    Style.AllowShortLambdasOnASingleLine);
+    IO.mapOptional("AllowShortRecordsOnASingleLine",
+                   Style.AllowShortRecordsOnASingleLine);
     IO.mapOptional("AllowShortLoopsOnASingleLine",
                    Style.AllowShortLoopsOnASingleLine);
     IO.mapOptional("AllowShortNamespacesOnASingleLine",
@@ -1574,6 +1584,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
   LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
   LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
   LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
+  LLVMStyle.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Never;
   LLVMStyle.AllowShortLoopsOnASingleLine = false;
   LLVMStyle.AllowShortNamespacesOnASingleLine = false;
   LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
diff --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index bbb7ef2c337d6..e235bc0734270 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -5949,12 +5949,15 @@ bool TokenAnnotator::mustBreakBefore(const 
AnnotatedLine &Line,
       return true;
     }
 
-    // Don't attempt to interpret struct return types as structs.
+    // Don't attempt to interpret record return types as records.
     if (Right.isNot(TT_FunctionLBrace)) {
-      return (Line.startsWith(tok::kw_class) &&
-              Style.BraceWrapping.AfterClass) ||
-             (Line.startsWith(tok::kw_struct) &&
-              Style.BraceWrapping.AfterStruct);
+      return ((Line.startsWith(tok::kw_class) &&
+               Style.BraceWrapping.AfterClass) ||
+              (Line.startsWith(tok::kw_struct) &&
+               Style.BraceWrapping.AfterStruct) ||
+              (Line.startsWith(tok::kw_union) &&
+               Style.BraceWrapping.AfterUnion)) &&
+             Style.AllowShortRecordsOnASingleLine == FormatStyle::SRS_Never;
     }
   }
 
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 2a7bfd1a7dc5b..eb7d8301b621a 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -456,6 +456,19 @@ class LineJoiner {
       }
     }
 
+    auto ShouldMergeShortRecords = [this, &I, &NextLine, PreviousLine,
+                                    TheLine]() {
+      if (Style.AllowShortRecordsOnASingleLine == FormatStyle::SRS_All)
+        return true;
+      if (Style.AllowShortRecordsOnASingleLine == FormatStyle::SRS_Empty &&
+          NextLine.First->is(tok::r_brace)) {
+        return true;
+      }
+      return false;
+    };
+
+    bool MergeShortRecord = ShouldMergeShortRecords();
+
     // Don't merge an empty template class or struct if SplitEmptyRecords
     // is defined.
     if (PreviousLine && Style.BraceWrapping.SplitEmptyRecord &&
@@ -498,7 +511,8 @@ class LineJoiner {
         // elsewhere.
         ShouldMerge = !Style.BraceWrapping.AfterClass ||
                       (NextLine.First->is(tok::r_brace) &&
-                       !Style.BraceWrapping.SplitEmptyRecord);
+                       !Style.BraceWrapping.SplitEmptyRecord) ||
+                      MergeShortRecord;
       } else if (TheLine->InPPDirective ||
                  !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
                                           tok::kw_struct)) {
@@ -873,9 +887,11 @@ class LineJoiner {
         return 1;
       } else if (Limit != 0 && !Line.startsWithNamespace() &&
                  !startsExternCBlock(Line)) {
-        // We don't merge short records.
-        if (isRecordLBrace(*Line.Last))
+        // Merge short records only when requested.
+        if (isRecordLBrace(*Line.Last) &&
+            Style.AllowShortRecordsOnASingleLine == FormatStyle::SRS_Never) {
           return 0;
+        }
 
         // Check that we still have three lines and they fit into the limit.
         if (I + 2 == E || I[2]->Type == LT_Invalid)
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index f4bbfcf8461bc..13fb6bf8b8a74 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -952,20 +952,26 @@ static bool isIIFE(const UnwrappedLine &Line,
 }
 
 static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
-                                   const FormatToken &InitialToken) {
+                                   const FormatToken &InitialToken,
+                                   const FormatToken &NextToken) {
   tok::TokenKind Kind = InitialToken.Tok.getKind();
   if (InitialToken.is(TT_NamespaceMacro))
     Kind = tok::kw_namespace;
 
+  bool IsEmptyBlock = NextToken.is(tok::r_brace);
+  bool WrapRecordAllowed =
+      !(IsEmptyBlock &&
+        Style.AllowShortRecordsOnASingleLine != FormatStyle::SRS_Never);
+
   switch (Kind) {
   case tok::kw_namespace:
     return Style.BraceWrapping.AfterNamespace;
   case tok::kw_class:
-    return Style.BraceWrapping.AfterClass;
+    return Style.BraceWrapping.AfterClass && WrapRecordAllowed;
   case tok::kw_union:
-    return Style.BraceWrapping.AfterUnion;
+    return Style.BraceWrapping.AfterUnion && WrapRecordAllowed;
   case tok::kw_struct:
-    return Style.BraceWrapping.AfterStruct;
+    return Style.BraceWrapping.AfterStruct && WrapRecordAllowed;
   case tok::kw_enum:
     return Style.BraceWrapping.AfterEnum;
   default:
@@ -3197,7 +3203,7 @@ void UnwrappedLineParser::parseNamespace() {
   if (FormatTok->is(tok::l_brace)) {
     FormatTok->setFinalizedType(TT_NamespaceLBrace);
 
-    if (ShouldBreakBeforeBrace(Style, InitialToken))
+    if (ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken()))
       addUnwrappedLine();
 
     unsigned AddLevels =
@@ -3862,7 +3868,7 @@ bool UnwrappedLineParser::parseEnum() {
   }
 
   if (!Style.AllowShortEnumsOnASingleLine &&
-      ShouldBreakBeforeBrace(Style, InitialToken)) {
+      ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken())) {
     addUnwrappedLine();
   }
   // Parse enum body.
@@ -4157,8 +4163,11 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, 
bool IsJavaRecord) {
     if (ParseAsExpr) {
       parseChildBlock();
     } else {
-      if (ShouldBreakBeforeBrace(Style, InitialToken))
+      if (Style.AllowShortRecordsOnASingleLine != FormatStyle::SRS_All &&
+          ShouldBreakBeforeBrace(Style, InitialToken,
+                                 *Tokens->peekNextToken())) {
         addUnwrappedLine();
+      }
 
       unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u;
       parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false);
diff --git a/clang/unittests/Format/ConfigParseTest.cpp 
b/clang/unittests/Format/ConfigParseTest.cpp
index 7c993c0f8fd33..8fd62e422bc00 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -654,6 +654,14 @@ TEST(ConfigParseTest, ParsesConfiguration) {
   CHECK_PARSE("AllowShortLambdasOnASingleLine: true",
               AllowShortLambdasOnASingleLine, FormatStyle::SLS_All);
 
+  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Never;
+  CHECK_PARSE("AllowShortRecordsOnASingleLine: Empty",
+              AllowShortRecordsOnASingleLine, FormatStyle::SRS_Empty);
+  CHECK_PARSE("AllowShortRecordsOnASingleLine: All",
+              AllowShortRecordsOnASingleLine, FormatStyle::SRS_All);
+  CHECK_PARSE("AllowShortRecordsOnASingleLine: Never",
+              AllowShortRecordsOnASingleLine, FormatStyle::SRS_Never);
+
   Style.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Both;
   CHECK_PARSE("SpaceAroundPointerQualifiers: Default",
               SpaceAroundPointerQualifiers, FormatStyle::SAPQ_Default);
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 4e9d31895998f..d16aba7ac6140 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -8575,6 +8575,19 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) {
                Style);
 }
 
+TEST_F(FormatTest, BreakFunctionsReturningRecords) {
+  FormatStyle Style = getLLVMStyle();
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.AfterFunction = true;
+  Style.BraceWrapping.AfterClass = false;
+  Style.BraceWrapping.AfterStruct = false;
+  Style.BraceWrapping.AfterUnion = false;
+
+  verifyFormat("class Bar foo() {}", Style);
+  verifyFormat("struct Bar foo() {}", Style);
+  verifyFormat("union Bar foo() {}", Style);
+}
+
 TEST_F(FormatTest, DontBreakBeforeQualifiedOperator) {
   // Regression test for https://bugs.llvm.org/show_bug.cgi?id=40516:
   // Prefer keeping `::` followed by `operator` together.
@@ -15277,6 +15290,66 @@ TEST_F(FormatTest, NeverMergeShortRecords) {
                Style);
 }
 
+TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
+  FormatStyle Style = getLLVMStyle();
+
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.AfterClass = true;
+  Style.BraceWrapping.AfterStruct = true;
+  Style.BraceWrapping.AfterUnion = true;
+  Style.BraceWrapping.SplitEmptyRecord = false;
+  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Never;
+
+  verifyFormat("class foo\n{\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("class foo\n{};", Style);
+
+  verifyFormat("struct foo\n{\n"
+               "  int bar;\n"
+               "};",
+               Style);
+  verifyFormat("struct foo\n{};", Style);
+
+  verifyFormat("union foo\n{\n"
+               "  int bar;\n"
+               "};",
+               Style);
+  verifyFormat("union foo\n{};", Style);
+
+  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Empty;
+
+  verifyFormat("class foo\n{\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("class foo {};", Style);
+
+  verifyFormat("struct foo\n{\n"
+               "  int bar;\n"
+               "};",
+               Style);
+  verifyFormat("struct foo {};", Style);
+
+  verifyFormat("union foo\n{\n"
+               "  int bar;\n"
+               "};",
+               Style);
+  verifyFormat("union foo {};", Style);
+
+  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_All;
+
+  verifyFormat("class foo { void bar(); };", Style);
+  verifyFormat("class foo {};", Style);
+
+  verifyFormat("struct foo { int bar; };", Style);
+  verifyFormat("struct foo {};", Style);
+
+  verifyFormat("union foo { int bar; };", Style);
+  verifyFormat("union foo {};", Style);
+}
+
 TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
   // Elaborate type variable declarations.
   verifyFormat("struct foo a = {bar};\nint n;");

From 498c5d479c8df2625e0114b0e646ee913120744f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Wed, 20 Aug 2025 23:54:07 +0200
Subject: [PATCH 02/19] Fixup: option order, inline MergeShortRecord lambda

---
 clang/lib/Format/Format.cpp                 |  4 ++--
 clang/lib/Format/UnwrappedLineFormatter.cpp | 18 ++++++++----------
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 19ed5029b6af4..b3e103cc24545 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1051,12 +1051,12 @@ template <> struct MappingTraits<FormatStyle> {
                    Style.AllowShortIfStatementsOnASingleLine);
     IO.mapOptional("AllowShortLambdasOnASingleLine",
                    Style.AllowShortLambdasOnASingleLine);
-    IO.mapOptional("AllowShortRecordsOnASingleLine",
-                   Style.AllowShortRecordsOnASingleLine);
     IO.mapOptional("AllowShortLoopsOnASingleLine",
                    Style.AllowShortLoopsOnASingleLine);
     IO.mapOptional("AllowShortNamespacesOnASingleLine",
                    Style.AllowShortNamespacesOnASingleLine);
+    IO.mapOptional("AllowShortRecordsOnASingleLine",
+                   Style.AllowShortRecordsOnASingleLine);
     IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
                    Style.AlwaysBreakAfterDefinitionReturnType);
     IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index eb7d8301b621a..d74463766619a 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -456,18 +456,16 @@ class LineJoiner {
       }
     }
 
-    auto ShouldMergeShortRecords = [this, &I, &NextLine, PreviousLine,
-                                    TheLine]() {
-      if (Style.AllowShortRecordsOnASingleLine == FormatStyle::SRS_All)
-        return true;
-      if (Style.AllowShortRecordsOnASingleLine == FormatStyle::SRS_Empty &&
-          NextLine.First->is(tok::r_brace)) {
+    const bool MergeShortRecord = [this, &NextLine]() {
+      switch (Style.AllowShortRecordsOnASingleLine) {
+      case FormatStyle::SRS_All:
         return true;
+      case FormatStyle::SRS_Empty:
+        return NextLine.First->is(tok::r_brace);
+      case FormatStyle::SRS_Never:
+        return false;
       }
-      return false;
-    };
-
-    bool MergeShortRecord = ShouldMergeShortRecords();
+    }();
 
     // Don't merge an empty template class or struct if SplitEmptyRecords
     // is defined.

From f5968a4443ab8573c21d2938f8c6ef771a3bceaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Sun, 24 Aug 2025 15:24:59 +0200
Subject: [PATCH 03/19] Use consistently named enum values

---
 clang/include/clang/Format/Format.h         | 2 +-
 clang/lib/Format/Format.cpp                 | 2 +-
 clang/lib/Format/UnwrappedLineFormatter.cpp | 2 +-
 clang/lib/Format/UnwrappedLineParser.cpp    | 2 +-
 clang/unittests/Format/ConfigParseTest.cpp  | 4 ++--
 clang/unittests/Format/FormatTest.cpp       | 2 +-
 6 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 7a254b73ac2d3..78cc342efd478 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1011,7 +1011,7 @@ struct FormatStyle {
     ///   struct foo {};
     ///   struct bar { int i; };
     /// \endcode
-    SRS_All
+    SRS_Always
   };
 
   /// Dependent on the value, ``struct bar { int i; }`` can be put on a single
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index b3e103cc24545..355fc71aef0bf 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -684,7 +684,7 @@ template <> struct 
ScalarEnumerationTraits<FormatStyle::ShortRecordStyle> {
   static void enumeration(IO &IO, FormatStyle::ShortRecordStyle &Value) {
     IO.enumCase(Value, "Never", FormatStyle::SRS_Never);
     IO.enumCase(Value, "Empty", FormatStyle::SRS_Empty);
-    IO.enumCase(Value, "All", FormatStyle::SRS_All);
+    IO.enumCase(Value, "Always", FormatStyle::SRS_Always);
   }
 };
 
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index d74463766619a..31c0c7d41586c 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -458,7 +458,7 @@ class LineJoiner {
 
     const bool MergeShortRecord = [this, &NextLine]() {
       switch (Style.AllowShortRecordsOnASingleLine) {
-      case FormatStyle::SRS_All:
+      case FormatStyle::SRS_Always:
         return true;
       case FormatStyle::SRS_Empty:
         return NextLine.First->is(tok::r_brace);
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index 13fb6bf8b8a74..cdb4a1cb6a738 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -4163,7 +4163,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, 
bool IsJavaRecord) {
     if (ParseAsExpr) {
       parseChildBlock();
     } else {
-      if (Style.AllowShortRecordsOnASingleLine != FormatStyle::SRS_All &&
+      if (Style.AllowShortRecordsOnASingleLine != FormatStyle::SRS_Always &&
           ShouldBreakBeforeBrace(Style, InitialToken,
                                  *Tokens->peekNextToken())) {
         addUnwrappedLine();
diff --git a/clang/unittests/Format/ConfigParseTest.cpp 
b/clang/unittests/Format/ConfigParseTest.cpp
index 8fd62e422bc00..d0a62134f31af 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -657,8 +657,8 @@ TEST(ConfigParseTest, ParsesConfiguration) {
   Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Never;
   CHECK_PARSE("AllowShortRecordsOnASingleLine: Empty",
               AllowShortRecordsOnASingleLine, FormatStyle::SRS_Empty);
-  CHECK_PARSE("AllowShortRecordsOnASingleLine: All",
-              AllowShortRecordsOnASingleLine, FormatStyle::SRS_All);
+  CHECK_PARSE("AllowShortRecordsOnASingleLine: Always",
+              AllowShortRecordsOnASingleLine, FormatStyle::SRS_Always);
   CHECK_PARSE("AllowShortRecordsOnASingleLine: Never",
               AllowShortRecordsOnASingleLine, FormatStyle::SRS_Never);
 
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index d16aba7ac6140..a66049244b789 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15338,7 +15338,7 @@ TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
                Style);
   verifyFormat("union foo {};", Style);
 
-  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_All;
+  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Always;
 
   verifyFormat("class foo { void bar(); };", Style);
   verifyFormat("class foo {};", Style);

From bdd54a3cf3f0f87ede591caa4f602534e56c3119 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Sun, 24 Aug 2025 15:54:21 +0200
Subject: [PATCH 04/19] Change option name to use singular form

---
 clang/include/clang/Format/Format.h         |  2 +-
 clang/lib/Format/Format.cpp                 |  6 +++---
 clang/lib/Format/TokenAnnotator.cpp         |  2 +-
 clang/lib/Format/UnwrappedLineFormatter.cpp |  4 ++--
 clang/lib/Format/UnwrappedLineParser.cpp    |  4 ++--
 clang/unittests/Format/ConfigParseTest.cpp  | 14 +++++++-------
 clang/unittests/Format/FormatTest.cpp       |  6 +++---
 7 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 78cc342efd478..fe438a3cecd85 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1016,7 +1016,7 @@ struct FormatStyle {
 
   /// Dependent on the value, ``struct bar { int i; }`` can be put on a single
   /// line.
-  ShortRecordStyle AllowShortRecordsOnASingleLine;
+  ShortRecordStyle AllowShortRecordOnASingleLine;
 
   /// Different ways to break after the function definition return type.
   /// This option is **deprecated** and is retained for backwards 
compatibility.
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 355fc71aef0bf..7cec1b5dd34c9 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1055,8 +1055,8 @@ template <> struct MappingTraits<FormatStyle> {
                    Style.AllowShortLoopsOnASingleLine);
     IO.mapOptional("AllowShortNamespacesOnASingleLine",
                    Style.AllowShortNamespacesOnASingleLine);
-    IO.mapOptional("AllowShortRecordsOnASingleLine",
-                   Style.AllowShortRecordsOnASingleLine);
+    IO.mapOptional("AllowShortRecordOnASingleLine",
+                   Style.AllowShortRecordOnASingleLine);
     IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
                    Style.AlwaysBreakAfterDefinitionReturnType);
     IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
@@ -1584,7 +1584,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
   LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
   LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
   LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
-  LLVMStyle.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Never;
+  LLVMStyle.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
   LLVMStyle.AllowShortLoopsOnASingleLine = false;
   LLVMStyle.AllowShortNamespacesOnASingleLine = false;
   LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
diff --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index e235bc0734270..ea0f73be14a7a 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -5957,7 +5957,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine 
&Line,
                Style.BraceWrapping.AfterStruct) ||
               (Line.startsWith(tok::kw_union) &&
                Style.BraceWrapping.AfterUnion)) &&
-             Style.AllowShortRecordsOnASingleLine == FormatStyle::SRS_Never;
+             Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Never;
     }
   }
 
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 31c0c7d41586c..268e6f2e5948a 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -457,7 +457,7 @@ class LineJoiner {
     }
 
     const bool MergeShortRecord = [this, &NextLine]() {
-      switch (Style.AllowShortRecordsOnASingleLine) {
+      switch (Style.AllowShortRecordOnASingleLine) {
       case FormatStyle::SRS_Always:
         return true;
       case FormatStyle::SRS_Empty:
@@ -887,7 +887,7 @@ class LineJoiner {
                  !startsExternCBlock(Line)) {
         // Merge short records only when requested.
         if (isRecordLBrace(*Line.Last) &&
-            Style.AllowShortRecordsOnASingleLine == FormatStyle::SRS_Never) {
+            Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Never) {
           return 0;
         }
 
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index cdb4a1cb6a738..4cc81a2cb51be 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -961,7 +961,7 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
   bool IsEmptyBlock = NextToken.is(tok::r_brace);
   bool WrapRecordAllowed =
       !(IsEmptyBlock &&
-        Style.AllowShortRecordsOnASingleLine != FormatStyle::SRS_Never);
+        Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never);
 
   switch (Kind) {
   case tok::kw_namespace:
@@ -4163,7 +4163,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, 
bool IsJavaRecord) {
     if (ParseAsExpr) {
       parseChildBlock();
     } else {
-      if (Style.AllowShortRecordsOnASingleLine != FormatStyle::SRS_Always &&
+      if (Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Always &&
           ShouldBreakBeforeBrace(Style, InitialToken,
                                  *Tokens->peekNextToken())) {
         addUnwrappedLine();
diff --git a/clang/unittests/Format/ConfigParseTest.cpp 
b/clang/unittests/Format/ConfigParseTest.cpp
index d0a62134f31af..97e2dcda9c90c 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -654,13 +654,13 @@ TEST(ConfigParseTest, ParsesConfiguration) {
   CHECK_PARSE("AllowShortLambdasOnASingleLine: true",
               AllowShortLambdasOnASingleLine, FormatStyle::SLS_All);
 
-  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Never;
-  CHECK_PARSE("AllowShortRecordsOnASingleLine: Empty",
-              AllowShortRecordsOnASingleLine, FormatStyle::SRS_Empty);
-  CHECK_PARSE("AllowShortRecordsOnASingleLine: Always",
-              AllowShortRecordsOnASingleLine, FormatStyle::SRS_Always);
-  CHECK_PARSE("AllowShortRecordsOnASingleLine: Never",
-              AllowShortRecordsOnASingleLine, FormatStyle::SRS_Never);
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
+  CHECK_PARSE("AllowShortRecordOnASingleLine: Empty",
+              AllowShortRecordOnASingleLine, FormatStyle::SRS_Empty);
+  CHECK_PARSE("AllowShortRecordOnASingleLine: Always",
+              AllowShortRecordOnASingleLine, FormatStyle::SRS_Always);
+  CHECK_PARSE("AllowShortRecordOnASingleLine: Never",
+              AllowShortRecordOnASingleLine, FormatStyle::SRS_Never);
 
   Style.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Both;
   CHECK_PARSE("SpaceAroundPointerQualifiers: Default",
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index a66049244b789..39aec18a82bd7 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15298,7 +15298,7 @@ TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
   Style.BraceWrapping.AfterStruct = true;
   Style.BraceWrapping.AfterUnion = true;
   Style.BraceWrapping.SplitEmptyRecord = false;
-  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Never;
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
 
   verifyFormat("class foo\n{\n"
                "  void bar();\n"
@@ -15318,7 +15318,7 @@ TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
                Style);
   verifyFormat("union foo\n{};", Style);
 
-  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Empty;
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
 
   verifyFormat("class foo\n{\n"
                "  void bar();\n"
@@ -15338,7 +15338,7 @@ TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
                Style);
   verifyFormat("union foo {};", Style);
 
-  Style.AllowShortRecordsOnASingleLine = FormatStyle::SRS_Always;
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
 
   verifyFormat("class foo { void bar(); };", Style);
   verifyFormat("class foo {};", Style);

From 4f695bd782f96788fe21b9b96e5de9d9471d5985 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Sun, 24 Aug 2025 15:56:58 +0200
Subject: [PATCH 05/19] Fix docs after rename

---
 clang/docs/ClangFormatStyleOptions.rst | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 2b26db6b4f680..2cddeb3c22581 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2096,9 +2096,9 @@ the configuration (without a prefix: ``Auto``).
 **AllowShortNamespacesOnASingleLine** (``Boolean``) 
:versionbadge:`clang-format 20` :ref:`¶ <AllowShortNamespacesOnASingleLine>`
   If ``true``, ``namespace a { class b; }`` can be put on a single line.
 
-.. _AllowShortRecordsOnASingleLine:
+.. _AllowShortRecordOnASingleLine:
 
-**AllowShortRecordsOnASingleLine** (``ShortRecordStyle``) :ref:`¶ 
<AllowShortRecordsOnASingleLine>`
+**AllowShortRecordOnASingleLine** (``ShortRecordStyle``) :ref:`¶ 
<AllowShortRecordOnASingleLine>`
   Dependent on the value, ``struct bar { int i; }`` can be put on a single
   line.
 
@@ -2118,7 +2118,7 @@ the configuration (without a prefix: ``Auto``).
         int i;
       };
 
-  * ``SRS_All`` (in configuration: ``All``)
+  * ``SRS_Always`` (in configuration: ``Always``)
     Merge all records that fit on a single line.
 
     .. code-block:: c++

From 584c50e3868210c8be40f86189dad114ba4ae1e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Mon, 25 Aug 2025 00:38:53 +0200
Subject: [PATCH 06/19] Fixup documentation

---
 clang/docs/ClangFormatStyleOptions.rst | 2 +-
 clang/include/clang/Format/Format.h    | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 2cddeb3c22581..03150f26c8411 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2098,7 +2098,7 @@ the configuration (without a prefix: ``Auto``).
 
 .. _AllowShortRecordOnASingleLine:
 
-**AllowShortRecordOnASingleLine** (``ShortRecordStyle``) :ref:`¶ 
<AllowShortRecordOnASingleLine>`
+**AllowShortRecordOnASingleLine** (``ShortRecordStyle``) 
:versionbadge:`clang-format 22` :ref:`¶ <AllowShortRecordOnASingleLine>`
   Dependent on the value, ``struct bar { int i; }`` can be put on a single
   line.
 
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index fe438a3cecd85..1735a0665566f 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -992,8 +992,8 @@ struct FormatStyle {
   /// \version 20
   bool AllowShortNamespacesOnASingleLine;
 
-  /// Different styles for merging short records
-  /// (``class``,``struct``,``union``).
+  /// Different styles for merging short records (``class``,``struct``, and
+  /// ``union``).
   enum ShortRecordStyle : int8_t {
     /// Never merge records into a single line.
     SRS_Never,
@@ -1016,6 +1016,7 @@ struct FormatStyle {
 
   /// Dependent on the value, ``struct bar { int i; }`` can be put on a single
   /// line.
+  /// \version 22
   ShortRecordStyle AllowShortRecordOnASingleLine;
 
   /// Different ways to break after the function definition return type.

From 606ae3d6d3c6e32d71ef02d6b6031b87c2ecc1e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Tue, 26 Aug 2025 23:54:53 +0200
Subject: [PATCH 07/19] Fix SplitEmptyRecord handling, docs

---
 clang/docs/ClangFormatStyleOptions.rst      |  2 +-
 clang/include/clang/Format/Format.h         |  2 +-
 clang/lib/Format/UnwrappedLineFormatter.cpp |  2 +-
 clang/lib/Format/UnwrappedLineParser.cpp    |  3 ++-
 clang/unittests/Format/FormatTest.cpp       | 25 ++++++++++++---------
 5 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 03150f26c8411..2872d84a96d16 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2099,7 +2099,7 @@ the configuration (without a prefix: ``Auto``).
 .. _AllowShortRecordOnASingleLine:
 
 **AllowShortRecordOnASingleLine** (``ShortRecordStyle``) 
:versionbadge:`clang-format 22` :ref:`¶ <AllowShortRecordOnASingleLine>`
-  Dependent on the value, ``struct bar { int i; }`` can be put on a single
+  Dependent on the value, ``struct bar { int i; };`` can be put on a single
   line.
 
   Possible values:
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 1735a0665566f..b4734506d1667 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1014,7 +1014,7 @@ struct FormatStyle {
     SRS_Always
   };
 
-  /// Dependent on the value, ``struct bar { int i; }`` can be put on a single
+  /// Dependent on the value, ``struct bar { int i; };`` can be put on a single
   /// line.
   /// \version 22
   ShortRecordStyle AllowShortRecordOnASingleLine;
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 268e6f2e5948a..04ab177543daf 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -465,7 +465,7 @@ class LineJoiner {
       case FormatStyle::SRS_Never:
         return false;
       }
-    }();
+    }() && !Style.BraceWrapping.SplitEmptyRecord;
 
     // Don't merge an empty template class or struct if SplitEmptyRecords
     // is defined.
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index 4cc81a2cb51be..87db07291e815 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -961,7 +961,8 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
   bool IsEmptyBlock = NextToken.is(tok::r_brace);
   bool WrapRecordAllowed =
       !(IsEmptyBlock &&
-        Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never);
+        Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never) ||
+      Style.BraceWrapping.SplitEmptyRecord;
 
   switch (Kind) {
   case tok::kw_namespace:
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 39aec18a82bd7..af9d8d994b684 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15318,6 +15318,17 @@ TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
                Style);
   verifyFormat("union foo\n{};", Style);
 
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
+
+  verifyFormat("class foo { void bar(); };", Style);
+  verifyFormat("class foo {};", Style);
+
+  verifyFormat("struct foo { int bar; };", Style);
+  verifyFormat("struct foo {};", Style);
+
+  verifyFormat("union foo { int bar; };", Style);
+  verifyFormat("union foo {};", Style);
+
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
 
   verifyFormat("class foo\n{\n"
@@ -15338,16 +15349,10 @@ TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
                Style);
   verifyFormat("union foo {};", Style);
 
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
-
-  verifyFormat("class foo { void bar(); };", Style);
-  verifyFormat("class foo {};", Style);
-
-  verifyFormat("struct foo { int bar; };", Style);
-  verifyFormat("struct foo {};", Style);
-
-  verifyFormat("union foo { int bar; };", Style);
-  verifyFormat("union foo {};", Style);
+  Style.BraceWrapping.SplitEmptyRecord = true;
+  verifyFormat("class foo\n{\n}", Style);
+  verifyFormat("struct foo\n{\n}", Style);
+  verifyFormat("union foo\n{\n}", Style);
 }
 
 TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {

From e7eb541ce03d01885618d514889888122c90f5ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Sat, 30 Aug 2025 17:41:51 +0200
Subject: [PATCH 08/19] Fix behavior of Never, add EmptyIfAttached

---
 clang/docs/ClangFormatStyleOptions.rst      |   4 +
 clang/include/clang/Format/Format.h         |   3 +
 clang/lib/Format/Format.cpp                 |   3 +-
 clang/lib/Format/UnwrappedLineFormatter.cpp |  43 ++++----
 clang/lib/Format/UnwrappedLineParser.cpp    |   4 +-
 clang/unittests/Format/ConfigParseTest.cpp  |   8 +-
 clang/unittests/Format/FormatTest.cpp       | 114 ++++++++++++++++++--
 7 files changed, 144 insertions(+), 35 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 2872d84a96d16..e0881174f89b2 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2107,6 +2107,10 @@ the configuration (without a prefix: ``Auto``).
   * ``SRS_Never`` (in configuration: ``Never``)
     Never merge records into a single line.
 
+  * ``SRS_EmptyIfAttached`` (in configuration: ``EmptyIfAttached``)
+    Only merge empty records if the opening brace was not wrapped,
+    i.e. the corresponding ``BraceWrapping.After...`` option was not set.
+
   * ``SRS_Empty`` (in configuration: ``Empty``)
     Only merge empty records.
 
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index b4734506d1667..c07b1f8290992 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -997,6 +997,9 @@ struct FormatStyle {
   enum ShortRecordStyle : int8_t {
     /// Never merge records into a single line.
     SRS_Never,
+    /// Only merge empty records if the opening brace was not wrapped,
+    /// i.e. the corresponding ``BraceWrapping.After...`` option was not set.
+    SRS_EmptyIfAttached,
     /// Only merge empty records.
     /// \code
     ///   struct foo {};
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 7cec1b5dd34c9..e575a05490865 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -683,6 +683,7 @@ template <> struct 
ScalarEnumerationTraits<FormatStyle::ShortLambdaStyle> {
 template <> struct ScalarEnumerationTraits<FormatStyle::ShortRecordStyle> {
   static void enumeration(IO &IO, FormatStyle::ShortRecordStyle &Value) {
     IO.enumCase(Value, "Never", FormatStyle::SRS_Never);
+    IO.enumCase(Value, "EmptyIfAttached", FormatStyle::SRS_EmptyIfAttached);
     IO.enumCase(Value, "Empty", FormatStyle::SRS_Empty);
     IO.enumCase(Value, "Always", FormatStyle::SRS_Always);
   }
@@ -1584,7 +1585,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
   LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
   LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
   LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
-  LLVMStyle.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
+  LLVMStyle.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
   LLVMStyle.AllowShortLoopsOnASingleLine = false;
   LLVMStyle.AllowShortNamespacesOnASingleLine = false;
   LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 04ab177543daf..593aafe3ca19a 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -456,17 +456,6 @@ class LineJoiner {
       }
     }
 
-    const bool MergeShortRecord = [this, &NextLine]() {
-      switch (Style.AllowShortRecordOnASingleLine) {
-      case FormatStyle::SRS_Always:
-        return true;
-      case FormatStyle::SRS_Empty:
-        return NextLine.First->is(tok::r_brace);
-      case FormatStyle::SRS_Never:
-        return false;
-      }
-    }() && !Style.BraceWrapping.SplitEmptyRecord;
-
     // Don't merge an empty template class or struct if SplitEmptyRecords
     // is defined.
     if (PreviousLine && Style.BraceWrapping.SplitEmptyRecord &&
@@ -496,6 +485,18 @@ class LineJoiner {
                  : 0;
     }
 
+    const bool MergeShortRecord = [this, &NextLine]() {
+      switch (Style.AllowShortRecordOnASingleLine) {
+      case FormatStyle::SRS_Always:
+        return true;
+      case FormatStyle::SRS_EmptyIfAttached:
+      case FormatStyle::SRS_Empty:
+        return NextLine.First->is(tok::r_brace);
+      case FormatStyle::SRS_Never:
+        return false;
+      }
+    }();
+
     if (TheLine->Last->is(tok::l_brace)) {
       bool ShouldMerge = false;
       // Try to merge records.
@@ -503,14 +504,16 @@ class LineJoiner {
         ShouldMerge = Style.AllowShortEnumsOnASingleLine;
       } else if (TheLine->Last->is(TT_CompoundRequirementLBrace)) {
         ShouldMerge = Style.AllowShortCompoundRequirementOnASingleLine;
-      } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace)) {
-        // NOTE: We use AfterClass (whereas AfterStruct exists) for both 
classes
-        // and structs, but it seems that wrapping is still handled correctly
-        // elsewhere.
-        ShouldMerge = !Style.BraceWrapping.AfterClass ||
-                      (NextLine.First->is(tok::r_brace) &&
-                       !Style.BraceWrapping.SplitEmptyRecord) ||
-                      MergeShortRecord;
+      } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace,
+                                        TT_UnionLBrace)) {
+        if (Style.AllowShortRecordOnASingleLine > FormatStyle::SRS_Never) {
+          // NOTE: We use AfterClass (whereas AfterStruct exists) for both
+          // classes and structs, but it seems that wrapping is still handled
+          // correctly elsewhere.
+          ShouldMerge =
+              !Style.BraceWrapping.AfterClass ||
+              (MergeShortRecord && !Style.BraceWrapping.SplitEmptyRecord);
+        }
       } else if (TheLine->InPPDirective ||
                  !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
                                           tok::kw_struct)) {
@@ -887,7 +890,7 @@ class LineJoiner {
                  !startsExternCBlock(Line)) {
         // Merge short records only when requested.
         if (isRecordLBrace(*Line.Last) &&
-            Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Never) {
+            Style.AllowShortRecordOnASingleLine < FormatStyle::SRS_Always) {
           return 0;
         }
 
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index 87db07291e815..5378b2b32aaf4 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -960,8 +960,8 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
 
   bool IsEmptyBlock = NextToken.is(tok::r_brace);
   bool WrapRecordAllowed =
-      !(IsEmptyBlock &&
-        Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never) ||
+      !(IsEmptyBlock && Style.AllowShortRecordOnASingleLine >
+                            FormatStyle::SRS_EmptyIfAttached) ||
       Style.BraceWrapping.SplitEmptyRecord;
 
   switch (Kind) {
diff --git a/clang/unittests/Format/ConfigParseTest.cpp 
b/clang/unittests/Format/ConfigParseTest.cpp
index 97e2dcda9c90c..ec08cfab5daf9 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -654,13 +654,15 @@ TEST(ConfigParseTest, ParsesConfiguration) {
   CHECK_PARSE("AllowShortLambdasOnASingleLine: true",
               AllowShortLambdasOnASingleLine, FormatStyle::SLS_All);
 
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
+  CHECK_PARSE("AllowShortRecordOnASingleLine: Never",
+              AllowShortRecordOnASingleLine, FormatStyle::SRS_Never);
+  CHECK_PARSE("AllowShortRecordOnASingleLine: EmptyIfAttached",
+              AllowShortRecordOnASingleLine, FormatStyle::SRS_EmptyIfAttached);
   CHECK_PARSE("AllowShortRecordOnASingleLine: Empty",
               AllowShortRecordOnASingleLine, FormatStyle::SRS_Empty);
   CHECK_PARSE("AllowShortRecordOnASingleLine: Always",
               AllowShortRecordOnASingleLine, FormatStyle::SRS_Always);
-  CHECK_PARSE("AllowShortRecordOnASingleLine: Never",
-              AllowShortRecordOnASingleLine, FormatStyle::SRS_Never);
 
   Style.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Both;
   CHECK_PARSE("SpaceAroundPointerQualifiers: Default",
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index af9d8d994b684..9a2f122788150 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15290,14 +15290,87 @@ TEST_F(FormatTest, NeverMergeShortRecords) {
                Style);
 }
 
-TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
+TEST_F(FormatTest, AllowShortRecordOnASingleLine) {
   FormatStyle Style = getLLVMStyle();
 
   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.SplitEmptyRecord = false;
+
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
+
+  verifyFormat("class foo {\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("class foo {\n};", Style);
+
+  verifyFormat("struct foo {\n"
+               "  int bar;\n"
+               "};",
+               Style);
+  verifyFormat("struct foo {\n};", Style);
+
+  verifyFormat("union foo {\n"
+               "  int bar;\n"
+               "};",
+               Style);
+  verifyFormat("union foo {\n};", Style);
+
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
+
+  verifyFormat("class foo {\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("class foo {};", Style);
+
+  verifyFormat("struct foo {\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("struct foo {};", Style);
+
+  verifyFormat("union foo {\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("union foo {};", Style);
+
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
+
+  verifyFormat("class foo {\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("class foo {};", Style);
+
+  verifyFormat("struct foo {\n"
+               "  int bar;\n"
+               "};",
+               Style);
+  verifyFormat("struct foo {};", Style);
+
+  verifyFormat("union foo {\n"
+               "  int bar;\n"
+               "};",
+               Style);
+  verifyFormat("union foo {};", Style);
+
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
+
+  verifyFormat("class foo { void bar(); };", Style);
+  verifyFormat("class foo {};", Style);
+
+  verifyFormat("struct foo { int bar; };", Style);
+  verifyFormat("struct foo {};", Style);
+
+  verifyFormat("union foo { int bar; };", Style);
+  verifyFormat("union foo {};", Style);
+
   Style.BraceWrapping.AfterClass = true;
   Style.BraceWrapping.AfterStruct = true;
   Style.BraceWrapping.AfterUnion = true;
-  Style.BraceWrapping.SplitEmptyRecord = false;
+
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
 
   verifyFormat("class foo\n{\n"
@@ -15318,16 +15391,25 @@ TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
                Style);
   verifyFormat("union foo\n{};", Style);
 
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
 
-  verifyFormat("class foo { void bar(); };", Style);
-  verifyFormat("class foo {};", Style);
+  verifyFormat("class foo\n{\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("class foo\n{};", Style);
 
-  verifyFormat("struct foo { int bar; };", Style);
-  verifyFormat("struct foo {};", Style);
+  verifyFormat("struct foo\n{\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("struct foo\n{};", Style);
 
-  verifyFormat("union foo { int bar; };", Style);
-  verifyFormat("union foo {};", Style);
+  verifyFormat("union foo\n{\n"
+               "  void bar();\n"
+               "};",
+               Style);
+  verifyFormat("union foo\n{};", Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
 
@@ -15349,7 +15431,21 @@ TEST_F(FormatTest, AllowShortRecordsOnASingleLine) {
                Style);
   verifyFormat("union foo {};", Style);
 
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
+
+  verifyFormat("class foo { void bar(); };", Style);
+  verifyFormat("class foo {};", Style);
+
+  verifyFormat("struct foo { int bar; };", Style);
+  verifyFormat("struct foo {};", Style);
+
+  verifyFormat("union foo { int bar; };", Style);
+  verifyFormat("union foo {};", Style);
+
+  // Ensure option gets overriden by SplitEmptyRecord
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
   Style.BraceWrapping.SplitEmptyRecord = true;
+
   verifyFormat("class foo\n{\n}", Style);
   verifyFormat("struct foo\n{\n}", Style);
   verifyFormat("union foo\n{\n}", Style);

From 37b37e14be9eda4307732db664599e7178f397ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Tue, 2 Sep 2025 21:11:56 +0200
Subject: [PATCH 09/19] Fix incorrect handling of left brace wrapping

---
 clang/lib/Format/UnwrappedLineFormatter.cpp |  36 ++++--
 clang/lib/Format/UnwrappedLineParser.cpp    |   5 +-
 clang/unittests/Format/FormatTest.cpp       | 124 +++++++-------------
 3 files changed, 65 insertions(+), 100 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 593aafe3ca19a..13925e2ccf287 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -260,6 +260,14 @@ class LineJoiner {
       }
     }
 
+    // Try merging record blocks that have had their left brace wrapped.
+    if (TheLine->First->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union) 
&&
+        NextLine.First->is(tok::l_brace) && NextLine.First == NextLine.Last &&
+        I + 2 != E && !I[2]->First->is(tok::r_brace)) {
+      if (unsigned MergedLines = tryMergeSimpleBlock(I, E, Limit))
+        return MergedLines;
+    }
+
     const auto *PreviousLine = I != AnnotatedLines.begin() ? I[-1] : nullptr;
     // Handle empty record blocks where the brace has already been wrapped.
     if (PreviousLine && TheLine->Last->is(tok::l_brace) &&
@@ -485,17 +493,17 @@ class LineJoiner {
                  : 0;
     }
 
-    const bool MergeShortRecord = [this, &NextLine]() {
+    const bool TryMergeShortRecord = [this, &NextLine]() {
       switch (Style.AllowShortRecordOnASingleLine) {
-      case FormatStyle::SRS_Always:
-        return true;
+      case FormatStyle::SRS_Never:
+        return false;
       case FormatStyle::SRS_EmptyIfAttached:
       case FormatStyle::SRS_Empty:
         return NextLine.First->is(tok::r_brace);
-      case FormatStyle::SRS_Never:
-        return false;
+      case FormatStyle::SRS_Always:
+        return true;
       }
-    }();
+    }() && !Style.BraceWrapping.SplitEmptyRecord;
 
     if (TheLine->Last->is(tok::l_brace)) {
       bool ShouldMerge = false;
@@ -510,9 +518,7 @@ class LineJoiner {
           // NOTE: We use AfterClass (whereas AfterStruct exists) for both
           // classes and structs, but it seems that wrapping is still handled
           // correctly elsewhere.
-          ShouldMerge =
-              !Style.BraceWrapping.AfterClass ||
-              (MergeShortRecord && !Style.BraceWrapping.SplitEmptyRecord);
+          ShouldMerge = !Style.BraceWrapping.AfterClass || TryMergeShortRecord;
         }
       } else if (TheLine->InPPDirective ||
                  !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
@@ -945,9 +951,15 @@ class LineJoiner {
         return 0;
       Limit -= 2;
       unsigned MergedLines = 0;
-      if (Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never ||
-          (I[1]->First == I[1]->Last && I + 2 != E &&
-           I[2]->First->is(tok::r_brace))) {
+
+      bool TryMergeBlock =
+          Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never;
+      bool TryMergeRecord =
+          Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always;
+      bool NextIsEmptyBlock = I[1]->First == I[1]->Last && I + 2 != E &&
+                              I[2]->First->is(tok::r_brace);
+
+      if (TryMergeBlock || TryMergeRecord || NextIsEmptyBlock) {
         MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
         // If we managed to merge the block, count the statement header, which
         // is on a separate line.
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index 5378b2b32aaf4..e2b5072d1bf8c 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -4164,11 +4164,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, 
bool IsJavaRecord) {
     if (ParseAsExpr) {
       parseChildBlock();
     } else {
-      if (Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Always &&
-          ShouldBreakBeforeBrace(Style, InitialToken,
-                                 *Tokens->peekNextToken())) {
+      if (ShouldBreakBeforeBrace(Style, InitialToken, 
*Tokens->peekNextToken()))
         addUnwrappedLine();
-      }
 
       unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u;
       parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false);
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 9a2f122788150..c0affdb7148c5 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15290,162 +15290,118 @@ TEST_F(FormatTest, NeverMergeShortRecords) {
                Style);
 }
 
-TEST_F(FormatTest, AllowShortRecordOnASingleLine) {
+TEST_F(FormatTest, AllowShortRecordOnASingleLineNonSplit) {
   FormatStyle Style = getLLVMStyle();
 
   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
   Style.BraceWrapping.SplitEmptyRecord = false;
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
-
   verifyFormat("class foo {\n"
                "  void bar();\n"
                "};",
                Style);
   verifyFormat("class foo {\n};", Style);
 
-  verifyFormat("struct foo {\n"
-               "  int bar;\n"
-               "};",
-               Style);
-  verifyFormat("struct foo {\n};", Style);
-
-  verifyFormat("union foo {\n"
-               "  int bar;\n"
-               "};",
-               Style);
-  verifyFormat("union foo {\n};", Style);
-
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
-
   verifyFormat("class foo {\n"
                "  void bar();\n"
                "};",
                Style);
   verifyFormat("class foo {};", Style);
 
-  verifyFormat("struct foo {\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("struct foo {};", Style);
-
-  verifyFormat("union foo {\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("union foo {};", Style);
-
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
-
   verifyFormat("class foo {\n"
                "  void bar();\n"
                "};",
                Style);
   verifyFormat("class foo {};", Style);
 
-  verifyFormat("struct foo {\n"
-               "  int bar;\n"
-               "};",
-               Style);
-  verifyFormat("struct foo {};", Style);
-
-  verifyFormat("union foo {\n"
-               "  int bar;\n"
-               "};",
-               Style);
-  verifyFormat("union foo {};", Style);
-
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
-
   verifyFormat("class foo { void bar(); };", Style);
   verifyFormat("class foo {};", Style);
 
-  verifyFormat("struct foo { int bar; };", Style);
-  verifyFormat("struct foo {};", Style);
-
-  verifyFormat("union foo { int bar; };", Style);
-  verifyFormat("union foo {};", Style);
-
   Style.BraceWrapping.AfterClass = true;
   Style.BraceWrapping.AfterStruct = true;
   Style.BraceWrapping.AfterUnion = true;
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
-
   verifyFormat("class foo\n{\n"
                "  void bar();\n"
                "};",
                Style);
   verifyFormat("class foo\n{};", Style);
 
-  verifyFormat("struct foo\n{\n"
-               "  int bar;\n"
-               "};",
-               Style);
-  verifyFormat("struct foo\n{};", Style);
-
-  verifyFormat("union foo\n{\n"
-               "  int bar;\n"
-               "};",
-               Style);
-  verifyFormat("union foo\n{};", Style);
-
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
-
   verifyFormat("class foo\n{\n"
                "  void bar();\n"
                "};",
                Style);
   verifyFormat("class foo\n{};", Style);
 
-  verifyFormat("struct foo\n{\n"
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
+  verifyFormat("class foo\n{\n"
                "  void bar();\n"
                "};",
                Style);
-  verifyFormat("struct foo\n{};", Style);
+  verifyFormat("class foo {};", Style);
 
-  verifyFormat("union foo\n{\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("union foo\n{};", Style);
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
+  verifyFormat("class foo { void bar(); };", Style);
+  verifyFormat("class foo {};", Style);
+}
 
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
+TEST_F(FormatTest, AllowShortRecordOnASingleLineSplit) {
+  FormatStyle Style = getLLVMStyle();
 
-  verifyFormat("class foo\n{\n"
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.SplitEmptyRecord = true;
+
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
+  verifyFormat("class foo {\n"
                "  void bar();\n"
                "};",
                Style);
-  verifyFormat("class foo {};", Style);
+  verifyFormat("class foo {\n};", Style);
 
-  verifyFormat("struct foo\n{\n"
-               "  int bar;\n"
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
+  verifyFormat("class foo {\n"
+               "  void bar();\n"
                "};",
                Style);
-  verifyFormat("struct foo {};", Style);
+  verifyFormat("class foo {};", Style);
 
-  verifyFormat("union foo\n{\n"
-               "  int bar;\n"
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
+  verifyFormat("class foo {\n"
+               "  void bar();\n"
                "};",
                Style);
-  verifyFormat("union foo {};", Style);
+  verifyFormat("class foo {};", Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
-
   verifyFormat("class foo { void bar(); };", Style);
   verifyFormat("class foo {};", Style);
 
-  verifyFormat("struct foo { int bar; };", Style);
-  verifyFormat("struct foo {};", Style);
+  Style.BraceWrapping.AfterClass = true;
+  Style.BraceWrapping.AfterStruct = true;
+  Style.BraceWrapping.AfterUnion = true;
+
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
+  verifyFormat("class foo\n{\n}", Style);
+  verifyFormat("struct foo\n{\n}", Style);
+  verifyFormat("union foo\n{\n}", Style);
 
-  verifyFormat("union foo { int bar; };", Style);
-  verifyFormat("union foo {};", Style);
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
+  verifyFormat("class foo\n{\n}", Style);
+  verifyFormat("struct foo\n{\n}", Style);
+  verifyFormat("union foo\n{\n}", Style);
 
-  // Ensure option gets overriden by SplitEmptyRecord
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
-  Style.BraceWrapping.SplitEmptyRecord = true;
+  verifyFormat("class foo\n{\n}", Style);
+  verifyFormat("struct foo\n{\n}", Style);
+  verifyFormat("union foo\n{\n}", Style);
 
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
   verifyFormat("class foo\n{\n}", Style);
   verifyFormat("struct foo\n{\n}", Style);
   verifyFormat("union foo\n{\n}", Style);

From 04fb58e05dfd5c36560708ce003afc472cbb8761 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Wed, 3 Sep 2025 17:49:31 +0200
Subject: [PATCH 10/19] Fixup test cases

---
 clang/unittests/Format/FormatTest.cpp | 64 +++++++++++++++------------
 1 file changed, 36 insertions(+), 28 deletions(-)

diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index c0affdb7148c5..fd9f7ef251362 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15291,7 +15291,7 @@ TEST_F(FormatTest, NeverMergeShortRecords) {
 }
 
 TEST_F(FormatTest, AllowShortRecordOnASingleLineNonSplit) {
-  FormatStyle Style = getLLVMStyle();
+  auto Style = getLLVMStyle();
 
   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
   Style.BraceWrapping.SplitEmptyRecord = false;
@@ -15301,7 +15301,9 @@ TEST_F(FormatTest, 
AllowShortRecordOnASingleLineNonSplit) {
                "  void bar();\n"
                "};",
                Style);
-  verifyFormat("class foo {\n};", Style);
+  verifyFormat("class foo {\n"
+               "};",
+               Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
   verifyFormat("class foo {\n"
@@ -15322,25 +15324,26 @@ TEST_F(FormatTest, 
AllowShortRecordOnASingleLineNonSplit) {
   verifyFormat("class foo {};", Style);
 
   Style.BraceWrapping.AfterClass = true;
-  Style.BraceWrapping.AfterStruct = true;
-  Style.BraceWrapping.AfterUnion = true;
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
-  verifyFormat("class foo\n{\n"
+  verifyFormat("class foo\n"
+               "{\n"
                "  void bar();\n"
                "};",
                Style);
   verifyFormat("class foo\n{};", Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
-  verifyFormat("class foo\n{\n"
+  verifyFormat("class foo\n"
+               "{\n"
                "  void bar();\n"
                "};",
                Style);
   verifyFormat("class foo\n{};", Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
-  verifyFormat("class foo\n{\n"
+  verifyFormat("class foo\n"
+               "{\n"
                "  void bar();\n"
                "};",
                Style);
@@ -15352,24 +15355,26 @@ TEST_F(FormatTest, 
AllowShortRecordOnASingleLineNonSplit) {
 }
 
 TEST_F(FormatTest, AllowShortRecordOnASingleLineSplit) {
-  FormatStyle Style = getLLVMStyle();
+  auto Style = getLLVMStyle();
 
-  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
-  Style.BraceWrapping.SplitEmptyRecord = true;
+  EXPECT_EQ(Style.BraceWrapping.SplitEmptyRecord, true);
 
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
+  EXPECT_EQ(Style.AllowShortRecordOnASingleLine,
+            FormatStyle::SRS_EmptyIfAttached);
   verifyFormat("class foo {\n"
                "  void bar();\n"
                "};",
                Style);
-  verifyFormat("class foo {\n};", Style);
+  verifyFormat("class foo {};", Style);
 
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
   verifyFormat("class foo {\n"
                "  void bar();\n"
                "};",
                Style);
-  verifyFormat("class foo {};", Style);
+  verifyFormat("class foo {\n"
+               "};",
+               Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
   verifyFormat("class foo {\n"
@@ -15382,29 +15387,32 @@ TEST_F(FormatTest, 
AllowShortRecordOnASingleLineSplit) {
   verifyFormat("class foo { void bar(); };", Style);
   verifyFormat("class foo {};", Style);
 
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
   Style.BraceWrapping.AfterClass = true;
-  Style.BraceWrapping.AfterStruct = true;
-  Style.BraceWrapping.AfterUnion = true;
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
-  verifyFormat("class foo\n{\n}", Style);
-  verifyFormat("struct foo\n{\n}", Style);
-  verifyFormat("union foo\n{\n}", Style);
+  verifyFormat("class foo\n"
+               "{\n"
+               "}",
+               Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
-  verifyFormat("class foo\n{\n}", Style);
-  verifyFormat("struct foo\n{\n}", Style);
-  verifyFormat("union foo\n{\n}", Style);
+  verifyFormat("class foo\n"
+               "{\n"
+               "}",
+               Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
-  verifyFormat("class foo\n{\n}", Style);
-  verifyFormat("struct foo\n{\n}", Style);
-  verifyFormat("union foo\n{\n}", Style);
+  verifyFormat("class foo\n"
+               "{\n"
+               "}",
+               Style);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
-  verifyFormat("class foo\n{\n}", Style);
-  verifyFormat("struct foo\n{\n}", Style);
-  verifyFormat("union foo\n{\n}", Style);
+  verifyFormat("class foo\n"
+               "{\n"
+               "}",
+               Style);
 }
 
 TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {

From a5e5bff795d02387635d828ce57def0ce2772915 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Wed, 3 Sep 2025 17:59:08 +0200
Subject: [PATCH 11/19] Fixup ShouldBreakBeforeBrace

---
 clang/lib/Format/UnwrappedLineParser.cpp | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index e2b5072d1bf8c..60c0accf0f251 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -953,15 +953,14 @@ static bool isIIFE(const UnwrappedLine &Line,
 
 static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
                                    const FormatToken &InitialToken,
-                                   const FormatToken &NextToken) {
+                                   bool IsEmptyBlock) {
   tok::TokenKind Kind = InitialToken.Tok.getKind();
   if (InitialToken.is(TT_NamespaceMacro))
     Kind = tok::kw_namespace;
 
-  bool IsEmptyBlock = NextToken.is(tok::r_brace);
   bool WrapRecordAllowed =
-      !(IsEmptyBlock && Style.AllowShortRecordOnASingleLine >
-                            FormatStyle::SRS_EmptyIfAttached) ||
+      !IsEmptyBlock ||
+      Style.AllowShortRecordOnASingleLine < FormatStyle::SRS_Empty ||
       Style.BraceWrapping.SplitEmptyRecord;
 
   switch (Kind) {
@@ -3204,8 +3203,10 @@ void UnwrappedLineParser::parseNamespace() {
   if (FormatTok->is(tok::l_brace)) {
     FormatTok->setFinalizedType(TT_NamespaceLBrace);
 
-    if (ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken()))
+    if (ShouldBreakBeforeBrace(Style, InitialToken,
+                               Tokens->peekNextToken()->is(tok::r_brace))) {
       addUnwrappedLine();
+    }
 
     unsigned AddLevels =
         Style.NamespaceIndentation == FormatStyle::NI_All ||
@@ -3869,7 +3870,8 @@ bool UnwrappedLineParser::parseEnum() {
   }
 
   if (!Style.AllowShortEnumsOnASingleLine &&
-      ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken())) {
+      ShouldBreakBeforeBrace(Style, InitialToken,
+                             Tokens->peekNextToken()->is(tok::r_brace))) {
     addUnwrappedLine();
   }
   // Parse enum body.
@@ -4164,8 +4166,10 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, 
bool IsJavaRecord) {
     if (ParseAsExpr) {
       parseChildBlock();
     } else {
-      if (ShouldBreakBeforeBrace(Style, InitialToken, 
*Tokens->peekNextToken()))
+      if (ShouldBreakBeforeBrace(Style, InitialToken,
+                                 Tokens->peekNextToken()->is(tok::r_brace))) {
         addUnwrappedLine();
+      }
 
       unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u;
       parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false);

From b343d7253f70cd3b13a5a73d26e7e735ca29129c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Thu, 4 Sep 2025 16:08:04 +0200
Subject: [PATCH 12/19] Fixups

---
 clang/lib/Format/TokenAnnotator.cpp         |   1 +
 clang/lib/Format/UnwrappedLineFormatter.cpp |  13 +-
 clang/unittests/Format/FormatTest.cpp       | 139 +++++---------------
 3 files changed, 40 insertions(+), 113 deletions(-)

diff --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index ea0f73be14a7a..8e066ab783f5b 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -5950,6 +5950,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine 
&Line,
     }
 
     // Don't attempt to interpret record return types as records.
+    // FIXME: Not covered by tests.
     if (Right.isNot(TT_FunctionLBrace)) {
       return ((Line.startsWith(tok::kw_class) &&
                Style.BraceWrapping.AfterClass) ||
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 13925e2ccf287..0743915e8de33 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -261,9 +261,10 @@ class LineJoiner {
     }
 
     // Try merging record blocks that have had their left brace wrapped.
-    if (TheLine->First->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union) 
&&
-        NextLine.First->is(tok::l_brace) && NextLine.First == NextLine.Last &&
-        I + 2 != E && !I[2]->First->is(tok::r_brace)) {
+    if (NextLine.First->isOneOf(TT_ClassLBrace, TT_StructLBrace,
+                                TT_UnionLBrace) &&
+        NextLine.First == NextLine.Last && I + 2 != E &&
+        !I[2]->First->is(tok::r_brace)) {
       if (unsigned MergedLines = tryMergeSimpleBlock(I, E, Limit))
         return MergedLines;
     }
@@ -493,7 +494,7 @@ class LineJoiner {
                  : 0;
     }
 
-    const bool TryMergeShortRecord = [this, &NextLine]() {
+    const bool TryMergeShortRecord = [&]() {
       switch (Style.AllowShortRecordOnASingleLine) {
       case FormatStyle::SRS_Never:
         return false;
@@ -514,7 +515,7 @@ class LineJoiner {
         ShouldMerge = Style.AllowShortCompoundRequirementOnASingleLine;
       } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace,
                                         TT_UnionLBrace)) {
-        if (Style.AllowShortRecordOnASingleLine > FormatStyle::SRS_Never) {
+        if (Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never) {
           // NOTE: We use AfterClass (whereas AfterStruct exists) for both
           // classes and structs, but it seems that wrapping is still handled
           // correctly elsewhere.
@@ -896,7 +897,7 @@ class LineJoiner {
                  !startsExternCBlock(Line)) {
         // Merge short records only when requested.
         if (isRecordLBrace(*Line.Last) &&
-            Style.AllowShortRecordOnASingleLine < FormatStyle::SRS_Always) {
+            Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Always) {
           return 0;
         }
 
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index fd9f7ef251362..c9d19e6b91b3f 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -8575,19 +8575,6 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) {
                Style);
 }
 
-TEST_F(FormatTest, BreakFunctionsReturningRecords) {
-  FormatStyle Style = getLLVMStyle();
-  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
-  Style.BraceWrapping.AfterFunction = true;
-  Style.BraceWrapping.AfterClass = false;
-  Style.BraceWrapping.AfterStruct = false;
-  Style.BraceWrapping.AfterUnion = false;
-
-  verifyFormat("class Bar foo() {}", Style);
-  verifyFormat("struct Bar foo() {}", Style);
-  verifyFormat("union Bar foo() {}", Style);
-}
-
 TEST_F(FormatTest, DontBreakBeforeQualifiedOperator) {
   // Regression test for https://bugs.llvm.org/show_bug.cgi?id=40516:
   // Prefer keeping `::` followed by `operator` together.
@@ -15290,129 +15277,67 @@ TEST_F(FormatTest, NeverMergeShortRecords) {
                Style);
 }
 
-TEST_F(FormatTest, AllowShortRecordOnASingleLineNonSplit) {
+TEST_F(FormatTest, AllowShortRecordOnASingleLine) {
   auto Style = getLLVMStyle();
-
-  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
-  Style.BraceWrapping.SplitEmptyRecord = false;
+  EXPECT_EQ(Style.AllowShortRecordOnASingleLine,
+            FormatStyle::SRS_EmptyIfAttached);
 
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
   verifyFormat("class foo {\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("class foo {\n"
-               "};",
-               Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
-  verifyFormat("class foo {\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("class foo {};", Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
-  verifyFormat("class foo {\n"
-               "  void bar();\n"
+               "};\n"
+               "class bar {\n"
+               "  int i;\n"
                "};",
                Style);
-  verifyFormat("class foo {};", Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
-  verifyFormat("class foo { void bar(); };", Style);
-  verifyFormat("class foo {};", Style);
-
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
   Style.BraceWrapping.AfterClass = true;
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
   verifyFormat("class foo\n"
                "{\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("class foo\n{};", Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
-  verifyFormat("class foo\n"
+               "};\n"
+               "class bar\n"
                "{\n"
-               "  void bar();\n"
+               "  int i;\n"
                "};",
                Style);
-  verifyFormat("class foo\n{};", Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
+  Style.BraceWrapping.SplitEmptyRecord = false;
   verifyFormat("class foo\n"
-               "{\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("class foo {};", Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
-  verifyFormat("class foo { void bar(); };", Style);
-  verifyFormat("class foo {};", Style);
-}
-
-TEST_F(FormatTest, AllowShortRecordOnASingleLineSplit) {
-  auto Style = getLLVMStyle();
-
-  EXPECT_EQ(Style.BraceWrapping.SplitEmptyRecord, true);
-
-  EXPECT_EQ(Style.AllowShortRecordOnASingleLine,
-            FormatStyle::SRS_EmptyIfAttached);
-  verifyFormat("class foo {\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("class foo {};", Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
-  verifyFormat("class foo {\n"
-               "  void bar();\n"
-               "};",
-               Style);
-  verifyFormat("class foo {\n"
-               "};",
+               "{};",
                Style);
 
+  Style = getLLVMStyle();
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
-  verifyFormat("class foo {\n"
-               "  void bar();\n"
+  verifyFormat("class foo {};\n"
+               "class bar {\n"
+               "  int i;\n"
                "};",
                Style);
-  verifyFormat("class foo {};", Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
-  verifyFormat("class foo { void bar(); };", Style);
-  verifyFormat("class foo {};", Style);
-
   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
   Style.BraceWrapping.AfterClass = true;
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
-  verifyFormat("class foo\n"
-               "{\n"
-               "}",
-               Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_EmptyIfAttached;
   verifyFormat("class foo\n"
                "{\n"
-               "}",
-               Style);
-
-  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
-  verifyFormat("class foo\n"
+               "};\n"
+               "class bar\n"
                "{\n"
-               "}",
+               "  int i;\n"
+               "};",
                Style);
+  Style.BraceWrapping.SplitEmptyRecord = false;
+  verifyFormat("class foo {};", Style);
 
+  Style = getLLVMStyle();
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
+  verifyFormat("class foo {};\n"
+               "class bar { int i; };",
+               Style);
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.AfterClass = true;
   verifyFormat("class foo\n"
                "{\n"
-               "}",
+               "};\n"
+               "class bar { int i; };",
                Style);
+  Style.BraceWrapping.SplitEmptyRecord = false;
+  verifyFormat("class foo {};", Style);
 }
 
 TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {

From 02928665649018d1c59d1c728747f6e3c45d38e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Fri, 5 Sep 2025 17:02:45 +0200
Subject: [PATCH 13/19] Update release notes, fixup UnwrappedLineFormatter

---
 clang/docs/ReleaseNotes.rst                 |  1 +
 clang/lib/Format/UnwrappedLineFormatter.cpp | 16 +++++++++-------
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 51e5973098c14..042a6df4ffee2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -472,6 +472,7 @@ clang-format
 - Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.
 - Add ``NumericLiteralCase`` option for enforcing character case in numeric
   literals.
+- Add ``AllowShortRecordOnASingleLine`` option and set it to 
``EmptyIfAttached`` for LLVM style.
 
 libclang
 --------
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 0743915e8de33..a7920e7bd3295 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -494,7 +494,7 @@ class LineJoiner {
                  : 0;
     }
 
-    const bool TryMergeShortRecord = [&]() {
+    auto TryMergeShortRecord = [&]() {
       switch (Style.AllowShortRecordOnASingleLine) {
       case FormatStyle::SRS_Never:
         return false;
@@ -504,7 +504,7 @@ class LineJoiner {
       case FormatStyle::SRS_Always:
         return true;
       }
-    }() && !Style.BraceWrapping.SplitEmptyRecord;
+    };
 
     if (TheLine->Last->is(tok::l_brace)) {
       bool ShouldMerge = false;
@@ -519,7 +519,9 @@ class LineJoiner {
           // NOTE: We use AfterClass (whereas AfterStruct exists) for both
           // classes and structs, but it seems that wrapping is still handled
           // correctly elsewhere.
-          ShouldMerge = !Style.BraceWrapping.AfterClass || TryMergeShortRecord;
+          ShouldMerge =
+              !Style.BraceWrapping.AfterClass ||
+              (TryMergeShortRecord() && !Style.BraceWrapping.SplitEmptyRecord);
         }
       } else if (TheLine->InPPDirective ||
                  !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
@@ -953,12 +955,12 @@ class LineJoiner {
       Limit -= 2;
       unsigned MergedLines = 0;
 
-      bool TryMergeBlock =
+      const bool TryMergeBlock =
           Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never;
-      bool TryMergeRecord =
+      const bool TryMergeRecord =
           Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always;
-      bool NextIsEmptyBlock = I[1]->First == I[1]->Last && I + 2 != E &&
-                              I[2]->First->is(tok::r_brace);
+      const bool NextIsEmptyBlock = I[1]->First == I[1]->Last && I + 2 != E &&
+                                    I[2]->First->is(tok::r_brace);
 
       if (TryMergeBlock || TryMergeRecord || NextIsEmptyBlock) {
         MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);

From e0c028e31e1ba1c382cac7cb7250f27e0ae5fb21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Sun, 7 Sep 2025 13:21:26 +0200
Subject: [PATCH 14/19] Fixup FormatStyle::operator==, misc
 UnwrappedLineFormatter

---
 clang/include/clang/Format/Format.h         |  1 +
 clang/lib/Format/UnwrappedLineFormatter.cpp | 26 +++++++++++++--------
 2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index c07b1f8290992..e2a0ed025e241 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -5492,6 +5492,7 @@ struct FormatStyle {
            AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine &&
            AllowShortNamespacesOnASingleLine ==
                R.AllowShortNamespacesOnASingleLine &&
+           AllowShortRecordOnASingleLine == R.AllowShortRecordOnASingleLine &&
            AlwaysBreakBeforeMultilineStrings ==
                R.AlwaysBreakBeforeMultilineStrings &&
            AttributeMacros == R.AttributeMacros &&
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index a7920e7bd3295..9b108a1d7a7fe 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -494,7 +494,7 @@ class LineJoiner {
                  : 0;
     }
 
-    auto TryMergeShortRecord = [&]() {
+    auto TryMergeShortRecord = [&] {
       switch (Style.AllowShortRecordOnASingleLine) {
       case FormatStyle::SRS_Never:
         return false;
@@ -521,7 +521,7 @@ class LineJoiner {
           // correctly elsewhere.
           ShouldMerge =
               !Style.BraceWrapping.AfterClass ||
-              (TryMergeShortRecord() && !Style.BraceWrapping.SplitEmptyRecord);
+              (!Style.BraceWrapping.SplitEmptyRecord && TryMergeShortRecord());
         }
       } else if (TheLine->InPPDirective ||
                  !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
@@ -898,7 +898,11 @@ class LineJoiner {
       } else if (Limit != 0 && !Line.startsWithNamespace() &&
                  !startsExternCBlock(Line)) {
         // Merge short records only when requested.
-        if (isRecordLBrace(*Line.Last) &&
+        if (Line.Last->isOneOf(TT_EnumLBrace, TT_RecordLBrace))
+          return 0;
+
+        if (Line.Last->isOneOf(TT_ClassLBrace, TT_StructLBrace,
+                               TT_UnionLBrace) &&
             Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Always) {
           return 0;
         }
@@ -955,14 +959,16 @@ class LineJoiner {
       Limit -= 2;
       unsigned MergedLines = 0;
 
-      const bool TryMergeBlock =
-          Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never;
-      const bool TryMergeRecord =
-          Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always;
-      const bool NextIsEmptyBlock = I[1]->First == I[1]->Last && I + 2 != E &&
-                                    I[2]->First->is(tok::r_brace);
+      auto TryMergeBlock = [&] {
+        if (Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never ||
+            Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always) {
+          return true;
+        }
+        return I[1]->First == I[1]->Last && I + 2 != E &&
+               I[2]->First->is(tok::r_brace);
+      };
 
-      if (TryMergeBlock || TryMergeRecord || NextIsEmptyBlock) {
+      if (TryMergeBlock()) {
         MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
         // If we managed to merge the block, count the statement header, which
         // is on a separate line.

From 8948ef2a3a40f0706331829a5770869e44dadd9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Mon, 8 Sep 2025 01:28:12 +0200
Subject: [PATCH 15/19] Fix interaction between AllowShortRecord and
 AllowShortBlocks options

---
 clang/lib/Format/UnwrappedLineFormatter.cpp | 10 +++++++---
 clang/unittests/Format/FormatTest.cpp       |  3 +++
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 9b108a1d7a7fe..afccd366f5a39 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -264,7 +264,8 @@ class LineJoiner {
     if (NextLine.First->isOneOf(TT_ClassLBrace, TT_StructLBrace,
                                 TT_UnionLBrace) &&
         NextLine.First == NextLine.Last && I + 2 != E &&
-        !I[2]->First->is(tok::r_brace)) {
+        !I[2]->First->is(tok::r_brace) &&
+        Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never) {
       if (unsigned MergedLines = tryMergeSimpleBlock(I, E, Limit))
         return MergedLines;
     }
@@ -273,7 +274,7 @@ class LineJoiner {
     // Handle empty record blocks where the brace has already been wrapped.
     if (PreviousLine && TheLine->Last->is(tok::l_brace) &&
         TheLine->First == TheLine->Last) {
-      bool EmptyBlock = NextLine.First->is(tok::r_brace);
+      const bool EmptyBlock = NextLine.First->is(tok::r_brace);
 
       const FormatToken *Tok = PreviousLine->First;
       if (Tok && Tok->is(tok::comment))
@@ -289,7 +290,9 @@ class LineJoiner {
         Tok = Tok->getNextNonComment();
       if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
                               tok::kw_extern, Keywords.kw_interface)) {
-        return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock
+        return (EmptyBlock && !Style.BraceWrapping.SplitEmptyRecord) ||
+                       (!EmptyBlock && Style.AllowShortBlocksOnASingleLine ==
+                                           FormatStyle::SBS_Always)
                    ? tryMergeSimpleBlock(I, E, Limit)
                    : 0;
       }
@@ -903,6 +906,7 @@ class LineJoiner {
 
         if (Line.Last->isOneOf(TT_ClassLBrace, TT_StructLBrace,
                                TT_UnionLBrace) &&
+            Line.Last != Line.First &&
             Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Always) {
           return 0;
         }
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index c9d19e6b91b3f..f79d7d051cf0b 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15303,6 +15303,9 @@ TEST_F(FormatTest, AllowShortRecordOnASingleLine) {
   verifyFormat("class foo\n"
                "{};",
                Style);
+  Style.BraceWrapping.SplitEmptyRecord = true;
+  Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Always;
+  verifyFormat("class foo\n{ int i; };", Style);
 
   Style = getLLVMStyle();
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;

From a11cb9cce8cbda14849162057de8d8bbe618b897 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Mon, 8 Sep 2025 10:27:25 +0200
Subject: [PATCH 16/19] Fix incorrect merge check

---
 clang/lib/Format/UnwrappedLineFormatter.cpp |  7 +++----
 clang/unittests/Format/FormatTest.cpp       | 19 ++++++++++++++++---
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index afccd366f5a39..874f901d8ad6b 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -265,7 +265,7 @@ class LineJoiner {
                                 TT_UnionLBrace) &&
         NextLine.First == NextLine.Last && I + 2 != E &&
         !I[2]->First->is(tok::r_brace) &&
-        Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never) {
+        Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always) {
       if (unsigned MergedLines = tryMergeSimpleBlock(I, E, Limit))
         return MergedLines;
     }
@@ -276,9 +276,7 @@ class LineJoiner {
         TheLine->First == TheLine->Last) {
       const bool EmptyBlock = NextLine.First->is(tok::r_brace);
 
-      const FormatToken *Tok = PreviousLine->First;
-      if (Tok && Tok->is(tok::comment))
-        Tok = Tok->getNextNonComment();
+      const FormatToken *Tok = PreviousLine->getFirstNonComment();
 
       if (Tok && Tok->getNamespaceToken()) {
         return !Style.BraceWrapping.SplitEmptyNamespace && EmptyBlock
@@ -288,6 +286,7 @@ class LineJoiner {
 
       if (Tok && Tok->is(tok::kw_typedef))
         Tok = Tok->getNextNonComment();
+
       if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
                               tok::kw_extern, Keywords.kw_interface)) {
         return (EmptyBlock && !Style.BraceWrapping.SplitEmptyRecord) ||
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index f79d7d051cf0b..25150ae86ebab 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15303,9 +15303,6 @@ TEST_F(FormatTest, AllowShortRecordOnASingleLine) {
   verifyFormat("class foo\n"
                "{};",
                Style);
-  Style.BraceWrapping.SplitEmptyRecord = true;
-  Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Always;
-  verifyFormat("class foo\n{ int i; };", Style);
 
   Style = getLLVMStyle();
   Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
@@ -15341,6 +15338,22 @@ TEST_F(FormatTest, AllowShortRecordOnASingleLine) {
                Style);
   Style.BraceWrapping.SplitEmptyRecord = false;
   verifyFormat("class foo {};", Style);
+
+  Style = getLLVMStyle();
+  Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Always;
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.AfterClass = true;
+
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never;
+  verifyFormat("class foo\n"
+               "{ int i; };",
+               Style);
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty;
+  verifyFormat("class foo\n"
+               "{ int i; };",
+               Style);
+  Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always;
+  verifyFormat("class foo { int i; };", Style);
 }
 
 TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {

From 5c0251477752b90db8695e9867549610f515a1d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Mon, 8 Sep 2025 23:05:13 +0200
Subject: [PATCH 17/19] Add const, change is to isNot

---
 clang/lib/Format/UnwrappedLineFormatter.cpp | 2 +-
 clang/lib/Format/UnwrappedLineParser.cpp    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 874f901d8ad6b..4b4055a01f613 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -264,7 +264,7 @@ class LineJoiner {
     if (NextLine.First->isOneOf(TT_ClassLBrace, TT_StructLBrace,
                                 TT_UnionLBrace) &&
         NextLine.First == NextLine.Last && I + 2 != E &&
-        !I[2]->First->is(tok::r_brace) &&
+        I[2]->First->isNot(tok::r_brace) &&
         Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always) {
       if (unsigned MergedLines = tryMergeSimpleBlock(I, E, Limit))
         return MergedLines;
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index 60c0accf0f251..ad7258dfd5c34 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -958,7 +958,7 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
   if (InitialToken.is(TT_NamespaceMacro))
     Kind = tok::kw_namespace;
 
-  bool WrapRecordAllowed =
+  const bool WrapRecordAllowed =
       !IsEmptyBlock ||
       Style.AllowShortRecordOnASingleLine < FormatStyle::SRS_Empty ||
       Style.BraceWrapping.SplitEmptyRecord;

From 5c6ff92fff841cb5b2a9383f3b6b4d3ad88ed956 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Mon, 15 Sep 2025 17:44:12 +0200
Subject: [PATCH 18/19] Extract record merging into a separate function

---
 clang/lib/Format/UnwrappedLineFormatter.cpp | 111 ++++++++++++++------
 1 file changed, 79 insertions(+), 32 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 2ed2c874a649b..25480cb387517 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -266,18 +266,17 @@ class LineJoiner {
       }
     }
 
-    // Try merging record blocks that have had their left brace wrapped.
+    // Try merging record blocks that have had their left brace wrapped into
+    // a single line.
     if (NextLine.First->isOneOf(TT_ClassLBrace, TT_StructLBrace,
-                                TT_UnionLBrace) &&
-        NextLine.First == NextLine.Last && I + 2 != E &&
-        I[2]->First->isNot(tok::r_brace) &&
-        Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always) {
-      if (unsigned MergedLines = tryMergeSimpleBlock(I, E, Limit))
+                                TT_UnionLBrace)) {
+      if (unsigned MergedLines = tryMergeRecord(I, E, Limit))
         return MergedLines;
     }
 
     const auto *PreviousLine = I != AnnotatedLines.begin() ? I[-1] : nullptr;
-    // Handle empty record blocks where the brace has already been wrapped.
+
+    // Handle blocks where the brace has already been wrapped.
     if (PreviousLine && TheLine->Last->is(tok::l_brace) &&
         TheLine->First == TheLine->Last) {
       const bool EmptyBlock = NextLine.First->is(tok::r_brace);
@@ -293,11 +292,11 @@ class LineJoiner {
       if (Tok && Tok->is(tok::kw_typedef))
         Tok = Tok->getNextNonComment();
 
-      if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
-                              tok::kw_extern, Keywords.kw_interface)) {
-        return (EmptyBlock && !Style.BraceWrapping.SplitEmptyRecord) ||
-                       (!EmptyBlock && Style.AllowShortBlocksOnASingleLine ==
-                                           FormatStyle::SBS_Always)
+      if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union))
+        return tryMergeRecord(I, E, Limit);
+
+      if (Tok && Tok->isOneOf(tok::kw_extern, Keywords.kw_interface)) {
+        return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock
                    ? tryMergeSimpleBlock(I, E, Limit)
                    : 0;
       }
@@ -502,18 +501,6 @@ class LineJoiner {
                  : 0;
     }
 
-    auto TryMergeShortRecord = [&] {
-      switch (Style.AllowShortRecordOnASingleLine) {
-      case FormatStyle::SRS_Never:
-        return false;
-      case FormatStyle::SRS_EmptyIfAttached:
-      case FormatStyle::SRS_Empty:
-        return NextLine.First->is(tok::r_brace);
-      case FormatStyle::SRS_Always:
-        return true;
-      }
-    };
-
     if (TheLine->Last->is(tok::l_brace)) {
       bool ShouldMerge = false;
       // Try to merge records.
@@ -523,14 +510,7 @@ class LineJoiner {
         ShouldMerge = Style.AllowShortCompoundRequirementOnASingleLine;
       } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace,
                                         TT_UnionLBrace)) {
-        if (Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never) {
-          // NOTE: We use AfterClass (whereas AfterStruct exists) for both
-          // classes and structs, but it seems that wrapping is still handled
-          // correctly elsewhere.
-          ShouldMerge =
-              !Style.BraceWrapping.AfterClass ||
-              (!Style.BraceWrapping.SplitEmptyRecord && TryMergeShortRecord());
-        }
+        return tryMergeRecord(I, E, Limit);
       } else if (TheLine->InPPDirective ||
                  !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
                                           tok::kw_struct)) {
@@ -600,6 +580,73 @@ class LineJoiner {
     return 0;
   }
 
+  unsigned tryMergeRecord(ArrayRef<AnnotatedLine *>::const_iterator I,
+                          ArrayRef<AnnotatedLine *>::const_iterator E,
+                          unsigned Limit) {
+    const auto *Line = I[0];
+    const auto *NextLine = I[1];
+
+    auto GetRelevantAfterOption = [&](const FormatToken *tok) {
+      switch (tok->getType()) {
+      case TT_StructLBrace:
+        return Style.BraceWrapping.AfterStruct;
+      case TT_ClassLBrace:
+        return Style.BraceWrapping.AfterClass;
+      case TT_UnionLBrace:
+        return Style.BraceWrapping.AfterUnion;
+      };
+    };
+
+    // Current line begins both record and block, brace was not wrapped.
+    if (Line->Last->isOneOf(TT_StructLBrace, TT_ClassLBrace, TT_UnionLBrace)) {
+      auto TryMergeShortRecord = [&] {
+        switch (Style.AllowShortRecordOnASingleLine) {
+        case FormatStyle::SRS_EmptyIfAttached:
+        case FormatStyle::SRS_Empty:
+          return NextLine->First->is(tok::r_brace);
+        case FormatStyle::SRS_Always:
+          return true;
+        }
+      };
+
+      if (Style.AllowShortRecordOnASingleLine != FormatStyle::SRS_Never &&
+          (!GetRelevantAfterOption(Line->Last) ||
+           (!Style.BraceWrapping.SplitEmptyRecord && TryMergeShortRecord()))) {
+        return tryMergeSimpleBlock(I, E, Limit);
+      }
+    }
+
+    // Cases where the l_brace was wrapped.
+    // Current line begins record, next line block.
+    if (NextLine->First->isOneOf(TT_StructLBrace, TT_ClassLBrace,
+                                 TT_UnionLBrace)) {
+      if (NextLine->First == NextLine->Last && I + 2 != E &&
+          I[2]->First->isNot(tok::r_brace) &&
+          Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always) {
+        return tryMergeSimpleBlock(I, E, Limit);
+      }
+    }
+
+    if (I == AnnotatedLines.begin())
+      return 0;
+
+    const auto *PreviousLine = I[-1];
+
+    // Previous line begins record, current line block.
+    if (PreviousLine->First->isOneOf(tok::kw_struct, tok::kw_class,
+                                     tok::kw_union)) {
+      const bool IsEmptyBlock =
+          Line->Last->is(tok::l_brace) && NextLine->First->is(tok::r_brace);
+
+      if (IsEmptyBlock && !Style.BraceWrapping.SplitEmptyRecord ||
+          Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Always) {
+        return tryMergeSimpleBlock(I, E, Limit);
+      }
+    }
+
+    return 0;
+  }
+
   unsigned
   tryMergeSimplePPDirective(ArrayRef<AnnotatedLine *>::const_iterator I,
                             ArrayRef<AnnotatedLine *>::const_iterator E,

From 437e8bd2c53d1b0098b8998840ed7beb5658a38d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoe...@gmail.com>
Date: Mon, 15 Sep 2025 18:48:00 +0200
Subject: [PATCH 19/19] Minor fixes for tryMergeRecord

---
 clang/lib/Format/UnwrappedLineFormatter.cpp | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 25480cb387517..5fc0fe29e4742 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -10,6 +10,7 @@
 #include "FormatToken.h"
 #include "NamespaceEndCommentsFixer.h"
 #include "WhitespaceManager.h"
+#include "clang/Basic/TokenKinds.h"
 #include "llvm/Support/Debug.h"
 #include <queue>
 
@@ -586,8 +587,8 @@ class LineJoiner {
     const auto *Line = I[0];
     const auto *NextLine = I[1];
 
-    auto GetRelevantAfterOption = [&](const FormatToken *tok) {
-      switch (tok->getType()) {
+    auto GetRelevantAfterOption = [&](const FormatToken *Tok) {
+      switch (Tok->getType()) {
       case TT_StructLBrace:
         return Style.BraceWrapping.AfterStruct;
       case TT_ClassLBrace:
@@ -620,8 +621,12 @@ class LineJoiner {
     // Current line begins record, next line block.
     if (NextLine->First->isOneOf(TT_StructLBrace, TT_ClassLBrace,
                                  TT_UnionLBrace)) {
-      if (NextLine->First == NextLine->Last && I + 2 != E &&
-          I[2]->First->isNot(tok::r_brace) &&
+      if (I + 2 == E)
+        return 0;
+
+      const bool IsEmptyBlock = I[2]->First->is(tok::r_brace);
+
+      if (!IsEmptyBlock &&
           Style.AllowShortRecordOnASingleLine == FormatStyle::SRS_Always) {
         return tryMergeSimpleBlock(I, E, Limit);
       }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to