[clang] [clang-format] Add BreakBeforeTemplateClose option (PR #118046)

via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 27 20:58:11 PST 2025


https://github.com/leijurv updated https://github.com/llvm/llvm-project/pull/118046

>From 1caf823165b16f6701993d586df51d5cdbf0885e Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Fri, 29 Nov 2024 21:54:36 -0600
Subject: [PATCH 01/13] [clang-format] Add BreakBeforeTemplateClose option

---
 clang/docs/ClangFormatStyleOptions.rst     |  21 ++++
 clang/docs/ReleaseNotes.rst                |   1 +
 clang/include/clang/Format/Format.h        |  20 ++++
 clang/lib/Format/ContinuationIndenter.cpp  |  11 ++
 clang/lib/Format/ContinuationIndenter.h    |  26 ++--
 clang/lib/Format/Format.cpp                |   2 +
 clang/lib/Format/TokenAnnotator.cpp        |   2 +-
 clang/unittests/Format/ConfigParseTest.cpp |   1 +
 clang/unittests/Format/FormatTest.cpp      | 131 +++++++++++++++++++++
 9 files changed, 206 insertions(+), 9 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 4be448171699ca..84ab1b0a2eff61 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3416,6 +3416,27 @@ the configuration (without a prefix: ``Auto``).
 
 
 
+.. _BreakBeforeTemplateClose:
+
+**BreakBeforeTemplateClose** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateClose>`
+  If ``true``, a line break will be placed before the ``>`` in a multiline
+  template declaration.
+
+  .. code-block:: c++
+
+     true:
+     template <
+         typename Foo,
+         typename Bar,
+         typename Baz
+     >
+
+     false:
+     template <
+         typename Foo,
+         typename Bar,
+         typename Baz>
+
 .. _BreakBeforeTernaryOperators:
 
 **BreakBeforeTernaryOperators** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <BreakBeforeTernaryOperators>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e44aefa90ab386..867d4b5d8c3f18 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -976,6 +976,7 @@ clang-format
   ``Never``, and ``true`` to ``Always``.
 - Adds ``RemoveEmptyLinesInUnwrappedLines`` option.
 - Adds ``KeepFormFeed`` option and set it to ``true`` for ``GNU`` style.
+- Adds ``BreakBeforeTemplateClose`` option.
 
 libclang
 --------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 6383934afa2c40..bffd964f6aa8aa 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2248,6 +2248,25 @@ struct FormatStyle {
   /// \version 16
   BreakBeforeInlineASMColonStyle BreakBeforeInlineASMColon;
 
+  /// If ``true``, a line break will be placed before the ``>`` in a multiline
+  /// template declaration.
+  /// \code
+  ///    true:
+  ///    template <
+  ///        typename Foo,
+  ///        typename Bar,
+  ///        typename Baz
+  ///    >
+  ///
+  ///    false:
+  ///    template <
+  ///        typename Foo,
+  ///        typename Bar,
+  ///        typename Baz>
+  /// \endcode
+  /// \version 20
+  bool BreakBeforeTemplateClose;
+
   /// If ``true``, ternary operators will be placed after line breaks.
   /// \code
   ///    true:
@@ -5184,6 +5203,7 @@ struct FormatStyle {
            BreakBeforeBraces == R.BreakBeforeBraces &&
            BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations &&
            BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon &&
+           BreakBeforeTemplateClose == R.BreakBeforeTemplateClose &&
            BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
            BreakBinaryOperations == R.BreakBinaryOperations &&
            BreakConstructorInitializers == R.BreakConstructorInitializers &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index aed86c1fb99551..4c783623afc535 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -406,6 +406,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
   }
   if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
     return true;
+  if (CurrentState.BreakBeforeClosingAngle &&
+      Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) {
+    return true;
+  }
   if (Style.Language == FormatStyle::LK_ObjC &&
       Style.ObjCBreakBeforeNestedBlockParam &&
       Current.ObjCSelectorNameParts > 1 &&
@@ -1234,6 +1238,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
         Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent;
   }
 
+  if (PreviousNonComment && PreviousNonComment->is(tok::less))
+    CurrentState.BreakBeforeClosingAngle = true;
+
   if (CurrentState.AvoidBinPacking) {
     // If we are breaking after '(', '{', '<', or this is the break after a ':'
     // to start a member initializer list in a constructor, this should not
@@ -1370,6 +1377,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
       State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
+  if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose &&
+      State.Stack.size() > 1) {
+    return State.Stack[State.Stack.size() - 2].LastSpace;
+  }
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
     return State.Stack[State.Stack.size() - 2].LastSpace;
   // Field labels in a nested type should be aligned to the brace. For example
diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h
index 18441e10a12492..88d214473396a8 100644
--- a/clang/lib/Format/ContinuationIndenter.h
+++ b/clang/lib/Format/ContinuationIndenter.h
@@ -200,14 +200,15 @@ struct ParenState {
       : Tok(Tok), Indent(Indent), LastSpace(LastSpace),
         NestedBlockIndent(Indent), IsAligned(false),
         BreakBeforeClosingBrace(false), BreakBeforeClosingParen(false),
-        AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
-        NoLineBreak(NoLineBreak), NoLineBreakInOperand(false),
-        LastOperatorWrapped(true), ContainsLineBreak(false),
-        ContainsUnwrappedBuilder(false), AlignColons(true),
-        ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false),
-        NestedBlockInlined(false), IsInsideObjCArrayLiteral(false),
-        IsCSharpGenericTypeConstraint(false), IsChainedConditional(false),
-        IsWrappedConditional(false), UnindentOperator(false) {}
+        BreakBeforeClosingAngle(false), AvoidBinPacking(AvoidBinPacking),
+        BreakBeforeParameter(false), NoLineBreak(NoLineBreak),
+        NoLineBreakInOperand(false), LastOperatorWrapped(true),
+        ContainsLineBreak(false), ContainsUnwrappedBuilder(false),
+        AlignColons(true), ObjCSelectorNameFound(false),
+        HasMultipleNestedBlocks(false), NestedBlockInlined(false),
+        IsInsideObjCArrayLiteral(false), IsCSharpGenericTypeConstraint(false),
+        IsChainedConditional(false), IsWrappedConditional(false),
+        UnindentOperator(false) {}
 
   /// \brief The token opening this parenthesis level, or nullptr if this level
   /// is opened by fake parenthesis.
@@ -280,6 +281,13 @@ struct ParenState {
   /// was a newline after the beginning left paren.
   bool BreakBeforeClosingParen : 1;
 
+  /// Whether a newline needs to be inserted before the block's closing
+  /// angle < >.
+  ///
+  /// We only want to insert a newline before the closing angle if there also
+  /// was a newline after the beginning left angle.
+  bool BreakBeforeClosingAngle : 1;
+
   /// Avoid bin packing, i.e. multiple parameters/elements on multiple
   /// lines, in this context.
   bool AvoidBinPacking : 1;
@@ -367,6 +375,8 @@ struct ParenState {
       return BreakBeforeClosingBrace;
     if (BreakBeforeClosingParen != Other.BreakBeforeClosingParen)
       return BreakBeforeClosingParen;
+    if (BreakBeforeClosingAngle != Other.BreakBeforeClosingAngle)
+      return BreakBeforeClosingAngle;
     if (QuestionColumn != Other.QuestionColumn)
       return QuestionColumn < Other.QuestionColumn;
     if (AvoidBinPacking != Other.AvoidBinPacking)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index ee52972ce66f4a..d6aa80dd8e3aef 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1000,6 +1000,7 @@ template <> struct MappingTraits<FormatStyle> {
     IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
     IO.mapOptional("BreakBeforeInlineASMColon",
                    Style.BreakBeforeInlineASMColon);
+    IO.mapOptional("BreakBeforeTemplateClose", Style.BreakBeforeTemplateClose);
     IO.mapOptional("BreakBeforeTernaryOperators",
                    Style.BreakBeforeTernaryOperators);
     IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations);
@@ -1514,6 +1515,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
   LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
   LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
   LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
+  LLVMStyle.BreakBeforeTemplateClose = false;
   LLVMStyle.BreakBeforeTernaryOperators = true;
   LLVMStyle.BreakBinaryOperations = FormatStyle::BBO_Never;
   LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index bc5239209f3aab..c9908515833bad 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6254,7 +6254,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
     return false;
 
   if (Right.is(TT_TemplateCloser))
-    return false;
+    return Right.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose;
   if (Right.is(tok::r_square) && Right.MatchingParen &&
       Right.MatchingParen->is(TT_LambdaLSquare)) {
     return false;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 7fc7492271668b..39f4ea49719600 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -162,6 +162,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
   CHECK_PARSE_BOOL(BinPackArguments);
   CHECK_PARSE_BOOL(BreakAdjacentStringLiterals);
   CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
+  CHECK_PARSE_BOOL(BreakBeforeTemplateClose);
   CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
   CHECK_PARSE_BOOL(BreakStringLiterals);
   CHECK_PARSE_BOOL(CompactNamespaces);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 250e51b5421664..07205b010575de 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11077,6 +11077,137 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
       Style);
 }
 
+TEST_F(FormatTest, BreakBeforeTemplateClose) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
+  Style.ColumnLimit = 0;
+  verifyNoChange("template <typename Foo>\n"
+                 "void foo() {}",
+                 Style);
+  verifyNoChange("template <\n"
+                 "    typename Foo,\n"
+                 "    typename Bar>\n"
+                 "void foo() {}",
+                 Style);
+  // when BreakBeforeTemplateClose is off, this line break is removed:
+  verifyFormat("template <\n"
+               "    typename Foo,\n"
+               "    typename Bar>\n"
+               "void foo() {}",
+               "template <\n"
+               "    typename Foo,\n"
+               "    typename Bar\n"
+               ">\n"
+               "void foo() {}",
+               Style);
+  Style.BreakBeforeTemplateClose = true;
+  // BreakBeforeTemplateClose should NOT force multiline templates
+  verifyNoChange("template <typename Foo>\n"
+                 "void foo() {}",
+                 Style);
+  verifyNoChange("template <typename Foo, typename Bar>\n"
+                 "void foo() {}",
+                 Style);
+  // it should allow a line break:
+  verifyNoChange("template <\n"
+                 "    typename Foo\n"
+                 ">\n"
+                 "void foo() {}",
+                 Style);
+  verifyNoChange("template <\n"
+                 "    typename Foo,\n"
+                 "    typename Bar\n"
+                 ">\n"
+                 "void foo() {}",
+                 Style);
+  // it should add a line break if not already present:
+  verifyFormat("template <\n"
+               "    typename Foo\n"
+               ">\n"
+               "void foo() {}",
+               "template <\n"
+               "    typename Foo>\n"
+               "void foo() {}",
+               Style);
+  verifyFormat("template <\n"
+               "    typename Foo,\n"
+               "    typename Bar\n"
+               ">\n"
+               "void foo() {}",
+               "template <\n"
+               "    typename Foo,\n"
+               "    typename Bar>\n"
+               "void foo() {}",
+               Style);
+  // when within an indent scope, the > should be placed appropriately:
+  verifyFormat("struct Baz {\n"
+               "  template <\n"
+               "      typename Foo,\n"
+               "      typename Bar\n"
+               "  >\n"
+               "  void foo() {}\n"
+               "};",
+               "struct Baz {\n"
+               "  template <\n"
+               "      typename Foo,\n"
+               "      typename Bar>\n"
+               "  void foo() {}\n"
+               "};",
+               Style);
+
+  // now test that it handles the cases when the column limit forces wrapping
+  Style.ColumnLimit = 40;
+  // when the column limit allows it, the template should be combined back into
+  // one line:
+  verifyFormat("template <typename Foo, typename Bar>\n"
+               "void foo() {}",
+               "template <\n"
+               "    typename Foo,\n"
+               "    typename Bar\n"
+               ">\n"
+               "void foo() {}",
+               Style);
+  // but not when the name is looong
+  verifyFormat("template <\n"
+               "    typename Foo,\n"
+               "    typename Barrrrrrrrrrrrrrrrrrrrrrrrrr\n"
+               ">\n"
+               "void foo() {}",
+               Style);
+  verifyFormat("template <\n"
+               "    typename Fooooooooooooooooooooooooooo,\n"
+               "    typename Bar\n"
+               ">\n"
+               "void foo() {}",
+               Style);
+  // additionally, long names should be split in one step:
+  verifyFormat(
+      "template <\n"
+      "    typename Foo,\n"
+      "    typename Barrrrrrrrrrrrrrrrrrrrrrrrrr\n"
+      ">\n"
+      "void foo() {}",
+      "template <typename Foo, typename Barrrrrrrrrrrrrrrrrrrrrrrrrr>\n"
+      "void foo() {}",
+      Style);
+  verifyFormat(
+      "template <\n"
+      "    typename Fooooooooooooooooooooooooooo,\n"
+      "    typename Bar\n"
+      ">\n"
+      "void foo() {}",
+      "template <typename Fooooooooooooooooooooooooooo, typename Bar>\n"
+      "void foo() {}",
+      Style);
+  // even when there is only one long name:
+  verifyFormat("template <\n"
+               "    typename Fooooooooooooooooooooooooooo\n"
+               ">\n"
+               "void foo() {}",
+               "template <typename Fooooooooooooooooooooooooooo>\n"
+               "void foo() {}",
+               Style);
+}
+
 TEST_F(FormatTest, WrapsTemplateParameters) {
   FormatStyle Style = getLLVMStyle();
   Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;

>From 212e444426a2d194df996909a40ad0e0fc681d98 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Fri, 6 Dec 2024 20:36:41 -0700
Subject: [PATCH 02/13] add test case

---
 clang/lib/Format/ContinuationIndenter.cpp |  6 +++---
 clang/lib/Format/TokenAnnotator.cpp       |  2 +-
 clang/unittests/Format/FormatTest.cpp     | 20 ++++++++++++++++++++
 3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 4c783623afc535..377234e29d9ea4 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -406,8 +406,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
   }
   if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
     return true;
-  if (CurrentState.BreakBeforeClosingAngle &&
-      Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) {
+  if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser) &&
+      Style.BreakBeforeTemplateClose) {
     return true;
   }
   if (Style.Language == FormatStyle::LK_ObjC &&
@@ -1377,7 +1377,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
       State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
-  if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose &&
+  if (Current.is(TT_TemplateCloser) && Style.BreakBeforeTemplateClose &&
       State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index c9908515833bad..ecb41827cad48c 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6254,7 +6254,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
     return false;
 
   if (Right.is(TT_TemplateCloser))
-    return Right.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose;
+    return Style.BreakBeforeTemplateClose;
   if (Right.is(tok::r_square) && Right.MatchingParen &&
       Right.MatchingParen->is(TT_LambdaLSquare)) {
     return false;
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 07205b010575de..ea00d95447bf8a 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11154,6 +11154,26 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                "};",
                Style);
 
+  // test from issue #80049
+  verifyFormat(
+      "void foo() {\n"
+      "  using type = std::remove_cv_t<\n"
+      "      add_common_cv_reference<\n"
+      "          std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
+      "          T0,\n"
+      "          T1\n"
+      "      >\n"
+      "  >;\n"
+      "}\n",
+      "void foo() {\n"
+      "  using type = std::remove_cv_t<\n"
+      "      add_common_cv_reference<\n"
+      "          std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
+      "          T0,\n"
+      "          T1>>;\n"
+      "}\n",
+      Style);
+
   // now test that it handles the cases when the column limit forces wrapping
   Style.ColumnLimit = 40;
   // when the column limit allows it, the template should be combined back into

>From 3927d411eeece27521e1a4034d01012c84beaf4b Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sun, 8 Dec 2024 21:21:18 -0800
Subject: [PATCH 03/13] more tests

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

diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index ea00d95447bf8a..4aabf13e9008f5 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11174,6 +11174,32 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
       "}\n",
       Style);
 
+  // test lambda goes to next line:
+  verifyFormat("void foo() {\n"
+               "  auto lambda = []<\n"
+               "                    typename T\n"
+               "                >(T t) {\n"
+               "  };\n"
+               "}\n",
+               "void foo() {\n"
+               "  auto lambda = []<\n"
+               "  typename T>(T t){\n"
+               "  };\n"
+               "}\n",
+               Style);
+
+  // test template usage goes to next line:
+  verifyFormat("void foo() {\n"
+               "  myFunc<\n"
+               "      T\n"
+               "  >();\n"
+               "}\n",
+               "void foo() {\n"
+               "  myFunc<\n"
+               "  T>();\n"
+               "}\n",
+               Style);
+
   // now test that it handles the cases when the column limit forces wrapping
   Style.ColumnLimit = 40;
   // when the column limit allows it, the template should be combined back into
@@ -11226,6 +11252,44 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                "template <typename Fooooooooooooooooooooooooooo>\n"
                "void foo() {}",
                Style);
+  // test lambda goes to next line if the type is looong:
+  verifyFormat(
+      "void foo() {\n"
+      // in this case, breaking "typename Looong" onto the next line would
+      // actually exceed the column limit by even more. same goes for "auto
+      // lambda = []<\n" because then the continuation indent would be all the
+      // way to the "[". therefore, this is correct for the column limited case:
+      "  auto lambda =\n"
+      "      []<typename Loooooooooooooooooooooooooooooooooong\n"
+      "      >(T t) {};\n"
+      // for completeness, let's also make sure it's willing to break if and
+      // when doing so is helpful. if we put something long into the square
+      // brackets, now it's worth it:
+      "  auto lambda =\n"
+      "      [looooooooooooooong]<\n"
+      "          typename Loooooooooooooooooooooooooooooooooong\n"
+      "      >(T t) {};\n"
+      "}\n",
+      Style);
+  // test that if the type is NOT long, it pulls it back into one line:
+  verifyFormat("void foo() {\n"
+               "  auto lambda = []<typename T>(T t) {};\n"
+               "}\n",
+               "void foo() {\n"
+               "  auto lambda = []<\n"
+               "                    typename T\n"
+               "                  >(T t) {};\n"
+               "}\n",
+               Style);
+
+  // test template usage goes to next line only if the type is looong:
+  verifyFormat("void foo() { myFunc<T>(); }\n", Style);
+  verifyFormat("void foo() {\n"
+               "  myFunc<\n"
+               "      Loooooooooooooooooooooooooooooooooooooooong\n"
+               "  >();\n"
+               "}\n",
+               Style);
 }
 
 TEST_F(FormatTest, WrapsTemplateParameters) {

>From 2c3a64c8f32a5c43887db4d107a4142490898c20 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sat, 21 Dec 2024 17:21:28 -0800
Subject: [PATCH 04/13] more tests

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

diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 4aabf13e9008f5..548bda4f774670 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11187,6 +11187,42 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                "  };\n"
                "}\n",
                Style);
+  // with no column limit, two parameters can go on the same line:
+  verifyFormat("void foo() {\n"
+               "  auto lambda = []<\n"
+               "                    typename T, typename Foo\n"
+               "                >(T t) {\n"
+               "  };\n"
+               "}\n",
+               "void foo() {\n"
+               "  auto lambda = []<\n"
+               "  typename T, typename Foo>(T t){\n"
+               "  };\n"
+               "}\n",
+               Style);
+  // or on different lines:
+  verifyFormat("void foo() {\n"
+               "  auto lambda = []<\n"
+               "                    typename T,\n"
+               "                    typename Foo\n"
+               "                >(T t) {\n"
+               "  };\n"
+               "}\n",
+               "void foo() {\n"
+               "  auto lambda = []<\n"
+               "  typename T,\n"
+               "  typename Foo>(T t){\n"
+               "  };\n"
+               "}\n",
+               Style);
+
+  // same line with no column limit
+  verifyFormat("void foo() {\n"
+               "  auto lambda = []<typename "
+               "Looooooooooooooooooooooooooooong>("
+               "Looooooooooooooooooooooooooooong t) {};\n"
+               "}\n",
+               Style);
 
   // test template usage goes to next line:
   verifyFormat("void foo() {\n"
@@ -11269,6 +11305,30 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
       "      [looooooooooooooong]<\n"
       "          typename Loooooooooooooooooooooooooooooooooong\n"
       "      >(T t) {};\n"
+      "  auto lambda =\n"
+      "      []<typename T,\n"
+      "         typename Loooooooooooooooooooooooooooooooooong\n"
+      "      >(T t) {};\n"
+      // nested:
+      "  auto lambda =\n"
+      "      []<template <typename, typename>\n"
+      "         typename Looooooooooooooooooong\n"
+      "      >(T t) {};\n"
+      // nested with long capture:
+      "  auto lambda =\n"
+      "      [loooooooooooooooooooong]<\n"
+      "          template <typename, typename>\n"
+      "          typename Looooooooooooooooooong\n"
+      "      >(T t) {};\n"
+      // nested, with long name and long captures:
+      "  auto lambda =\n"
+      "      [loooooooooooooooooooong]<\n"
+      "          template <\n"
+      "              typename Foooooooooooooooo,\n"
+      "              typename\n"
+      "          >\n"
+      "          typename T\n"
+      "      >(T t) {};\n"
       "}\n",
       Style);
   // test that if the type is NOT long, it pulls it back into one line:

>From 19bc40e7d824804ebcd9839cb2155a704d368e36 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sat, 11 Jan 2025 01:37:04 -0800
Subject: [PATCH 05/13] address comments

---
 clang/unittests/Format/FormatTest.cpp | 98 +++++++++++++--------------
 1 file changed, 46 insertions(+), 52 deletions(-)

diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 840ca703254705..cd968fc719f407 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11118,16 +11118,9 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
 
 TEST_F(FormatTest, BreakBeforeTemplateClose) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
+  // Begin with tests covering the case where there is no constraint on the column limit.
   Style.ColumnLimit = 0;
-  verifyNoChange("template <typename Foo>\n"
-                 "void foo() {}",
-                 Style);
-  verifyNoChange("template <\n"
-                 "    typename Foo,\n"
-                 "    typename Bar>\n"
-                 "void foo() {}",
-                 Style);
-  // when BreakBeforeTemplateClose is off, this line break is removed:
+  // When BreakBeforeTemplateClose is turned off, the line break that it adds shall be removed:
   verifyFormat("template <\n"
                "    typename Foo,\n"
                "    typename Bar>\n"
@@ -11139,14 +11132,15 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                "void foo() {}",
                Style);
   Style.BreakBeforeTemplateClose = true;
-  // BreakBeforeTemplateClose should NOT force multiline templates
+  // BreakBeforeTemplateClose should NOT force template declarations onto multiple lines.
+  // Use verifyNoChange since ColumnLimit = 0.
   verifyNoChange("template <typename Foo>\n"
                  "void foo() {}",
                  Style);
   verifyNoChange("template <typename Foo, typename Bar>\n"
                  "void foo() {}",
                  Style);
-  // it should allow a line break:
+  // It should allow a line break, even when the typename is short:
   verifyNoChange("template <\n"
                  "    typename Foo\n"
                  ">\n"
@@ -11158,7 +11152,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                  ">\n"
                  "void foo() {}",
                  Style);
-  // it should add a line break if not already present:
+  // It should add a line break before > if not already present:
   verifyFormat("template <\n"
                "    typename Foo\n"
                ">\n"
@@ -11177,7 +11171,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                "    typename Bar>\n"
                "void foo() {}",
                Style);
-  // when within an indent scope, the > should be placed appropriately:
+  // When within an indent scope, the > should be placed accordingly:
   verifyFormat("struct Baz {\n"
                "  template <\n"
                "      typename Foo,\n"
@@ -11193,7 +11187,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                "};",
                Style);
 
-  // test from issue #80049
+  // Test from issue #80049:
   verifyFormat(
       "void foo() {\n"
       "  using type = std::remove_cv_t<\n"
@@ -11203,91 +11197,91 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
       "          T1\n"
       "      >\n"
       "  >;\n"
-      "}\n",
+      "}",
       "void foo() {\n"
       "  using type = std::remove_cv_t<\n"
       "      add_common_cv_reference<\n"
       "          std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
       "          T0,\n"
       "          T1>>;\n"
-      "}\n",
+      "}",
       Style);
 
-  // test lambda goes to next line:
+  // Test lambda goes to next line:
   verifyFormat("void foo() {\n"
                "  auto lambda = []<\n"
                "                    typename T\n"
                "                >(T t) {\n"
                "  };\n"
-               "}\n",
+               "}",
                "void foo() {\n"
                "  auto lambda = []<\n"
                "  typename T>(T t){\n"
                "  };\n"
-               "}\n",
+               "}",
                Style);
-  // with no column limit, two parameters can go on the same line:
+  // With no column limit, two parameters can go on the same line:
   verifyFormat("void foo() {\n"
                "  auto lambda = []<\n"
                "                    typename T, typename Foo\n"
                "                >(T t) {\n"
                "  };\n"
-               "}\n",
+               "}",
                "void foo() {\n"
                "  auto lambda = []<\n"
                "  typename T, typename Foo>(T t){\n"
                "  };\n"
-               "}\n",
+               "}",
                Style);
-  // or on different lines:
+  // Or on different lines:
   verifyFormat("void foo() {\n"
                "  auto lambda = []<\n"
                "                    typename T,\n"
                "                    typename Foo\n"
                "                >(T t) {\n"
                "  };\n"
-               "}\n",
+               "}",
                "void foo() {\n"
                "  auto lambda = []<\n"
                "  typename T,\n"
                "  typename Foo>(T t){\n"
                "  };\n"
-               "}\n",
+               "}",
                Style);
 
-  // same line with no column limit
+  // Note that this is the same line (no \n):
   verifyFormat("void foo() {\n"
                "  auto lambda = []<typename "
                "Looooooooooooooooooooooooooooong>("
                "Looooooooooooooooooooooooooooong t) {};\n"
-               "}\n",
+               "}",
                Style);
 
-  // test template usage goes to next line:
+  // Test template usage goes to next line too:
   verifyFormat("void foo() {\n"
                "  myFunc<\n"
                "      T\n"
                "  >();\n"
-               "}\n",
+               "}",
                "void foo() {\n"
                "  myFunc<\n"
                "  T>();\n"
-               "}\n",
+               "}",
                Style);
 
-  // now test that it handles the cases when the column limit forces wrapping
+  // Now test that it handles the cases when the column limit forces wrapping.
   Style.ColumnLimit = 40;
-  // when the column limit allows it, the template should be combined back into
+  // When the column limit allows it, the template should be combined back into
   // one line:
   verifyFormat("template <typename Foo, typename Bar>\n"
                "void foo() {}",
                "template <\n"
                "    typename Foo,\n"
                "    typename Bar\n"
-               ">\n"
+               ">"
                "void foo() {}",
                Style);
-  // but not when the name is looong
+  // But not when the name is looong:
   verifyFormat("template <\n"
                "    typename Foo,\n"
                "    typename Barrrrrrrrrrrrrrrrrrrrrrrrrr\n"
@@ -11300,7 +11294,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                ">\n"
                "void foo() {}",
                Style);
-  // additionally, long names should be split in one step:
+  // Additionally, long names should be split in one step:
   verifyFormat(
       "template <\n"
       "    typename Foo,\n"
@@ -11319,7 +11313,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
       "template <typename Fooooooooooooooooooooooooooo, typename Bar>\n"
       "void foo() {}",
       Style);
-  // even when there is only one long name:
+  // Even when there is only one long name:
   verifyFormat("template <\n"
                "    typename Fooooooooooooooooooooooooooo\n"
                ">\n"
@@ -11327,18 +11321,18 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                "template <typename Fooooooooooooooooooooooooooo>\n"
                "void foo() {}",
                Style);
-  // test lambda goes to next line if the type is looong:
+  // Test lambda goes to next line if the type is looong:
   verifyFormat(
       "void foo() {\n"
-      // in this case, breaking "typename Looong" onto the next line would
-      // actually exceed the column limit by even more. same goes for "auto
+      // In this case, breaking "typename Looong" onto the next line would
+      // actually exceed the column limit by even more. Same goes for "auto
       // lambda = []<\n" because then the continuation indent would be all the
-      // way to the "[". therefore, this is correct for the column limited case:
+      // way to the "[". Therefore, this is correct for the column limited case:
       "  auto lambda =\n"
       "      []<typename Loooooooooooooooooooooooooooooooooong\n"
       "      >(T t) {};\n"
-      // for completeness, let's also make sure it's willing to break if and
-      // when doing so is helpful. if we put something long into the square
+      // For completeness, let's also make sure it's willing to break if and
+      // when doing so is helpful. If we put something long into the square
       // brackets, now it's worth it:
       "  auto lambda =\n"
       "      [looooooooooooooong]<\n"
@@ -11348,18 +11342,18 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
       "      []<typename T,\n"
       "         typename Loooooooooooooooooooooooooooooooooong\n"
       "      >(T t) {};\n"
-      // nested:
+      // Nested:
       "  auto lambda =\n"
       "      []<template <typename, typename>\n"
       "         typename Looooooooooooooooooong\n"
       "      >(T t) {};\n"
-      // nested with long capture:
+      // Nested with long capture:
       "  auto lambda =\n"
       "      [loooooooooooooooooooong]<\n"
       "          template <typename, typename>\n"
       "          typename Looooooooooooooooooong\n"
       "      >(T t) {};\n"
-      // nested, with long name and long captures:
+      // Nested, with long name and long captures:
       "  auto lambda =\n"
       "      [loooooooooooooooooooong]<\n"
       "          template <\n"
@@ -11368,26 +11362,26 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
       "          >\n"
       "          typename T\n"
       "      >(T t) {};\n"
-      "}\n",
+      "}",
       Style);
-  // test that if the type is NOT long, it pulls it back into one line:
+  // Test that if the type is NOT long, it pulls it back into one line:
   verifyFormat("void foo() {\n"
                "  auto lambda = []<typename T>(T t) {};\n"
-               "}\n",
+               "}",
                "void foo() {\n"
                "  auto lambda = []<\n"
                "                    typename T\n"
                "                  >(T t) {};\n"
-               "}\n",
+               "}",
                Style);
 
-  // test template usage goes to next line only if the type is looong:
-  verifyFormat("void foo() { myFunc<T>(); }\n", Style);
+  // Test template usage goes to next line only if the type is looong:
+  verifyFormat("void foo() { myFunc<T>(); }", Style);
   verifyFormat("void foo() {\n"
                "  myFunc<\n"
                "      Loooooooooooooooooooooooooooooooooooooooong\n"
                "  >();\n"
-               "}\n",
+               "}",
                Style);
 }
 

>From f75268ab23d20be2d96999a9f62d283fa300a825 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sat, 11 Jan 2025 22:35:07 -0800
Subject: [PATCH 06/13] address comments

---
 clang/docs/ClangFormatStyleOptions.rst     |  4 ++--
 clang/docs/ReleaseNotes.rst                |  2 +-
 clang/include/clang/Format/Format.h        |  4 ++--
 clang/lib/Format/ContinuationIndenter.cpp  |  4 ++--
 clang/lib/Format/Format.cpp                |  5 +++--
 clang/lib/Format/TokenAnnotator.cpp        |  2 +-
 clang/unittests/Format/ConfigParseTest.cpp |  2 +-
 clang/unittests/Format/FormatTest.cpp      | 17 ++++++++++-------
 8 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 96c27e85e0d342..ca92a073b41e45 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3421,9 +3421,9 @@ the configuration (without a prefix: ``Auto``).
 
 
 
-.. _BreakBeforeTemplateClose:
+.. _BreakBeforeTemplateCloser:
 
-**BreakBeforeTemplateClose** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateClose>`
+**BreakBeforeTemplateCloser** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateCloser>`
   If ``true``, a line break will be placed before the ``>`` in a multiline
   template declaration.
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92503c929acf39..ffc74108025f6f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1136,7 +1136,7 @@ clang-format
 - Adds ``VariableTemplates`` option.
 - Adds support for bash globstar in ``.clang-format-ignore``.
 - Adds ``WrapNamespaceBodyWithEmptyLines`` option.
-- Adds ``BreakBeforeTemplateClose`` option.
+- Adds ``BreakBeforeTemplateCloser`` option.
 
 libclang
 --------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index da287e5b65cc5f..5132e38ea02ec6 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2269,7 +2269,7 @@ struct FormatStyle {
   ///        typename Baz>
   /// \endcode
   /// \version 20
-  bool BreakBeforeTemplateClose;
+  bool BreakBeforeTemplateCloser;
 
   /// If ``true``, ternary operators will be placed after line breaks.
   /// \code
@@ -5252,7 +5252,7 @@ struct FormatStyle {
            BreakBeforeBraces == R.BreakBeforeBraces &&
            BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations &&
            BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon &&
-           BreakBeforeTemplateClose == R.BreakBeforeTemplateClose &&
+           BreakBeforeTemplateCloser == R.BreakBeforeTemplateCloser &&
            BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
            BreakBinaryOperations == R.BreakBinaryOperations &&
            BreakConstructorInitializers == R.BreakConstructorInitializers &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 0c6348bc416f5b..8e7f0d88f81742 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -407,7 +407,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
   if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
     return true;
   if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser) &&
-      Style.BreakBeforeTemplateClose) {
+      Style.BreakBeforeTemplateCloser) {
     return true;
   }
   if (Style.Language == FormatStyle::LK_ObjC &&
@@ -1378,7 +1378,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
       State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
-  if (Current.is(TT_TemplateCloser) && Style.BreakBeforeTemplateClose &&
+  if (Current.is(TT_TemplateCloser) && Style.BreakBeforeTemplateCloser &&
       State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 2229455d45a4ad..e421880d4cf34c 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1014,7 +1014,8 @@ template <> struct MappingTraits<FormatStyle> {
     IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
     IO.mapOptional("BreakBeforeInlineASMColon",
                    Style.BreakBeforeInlineASMColon);
-    IO.mapOptional("BreakBeforeTemplateClose", Style.BreakBeforeTemplateClose);
+    IO.mapOptional("BreakBeforeTemplateCloser",
+                   Style.BreakBeforeTemplateCloser);
     IO.mapOptional("BreakBeforeTernaryOperators",
                    Style.BreakBeforeTernaryOperators);
     IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations);
@@ -1533,7 +1534,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
   LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
   LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
   LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
-  LLVMStyle.BreakBeforeTemplateClose = false;
+  LLVMStyle.BreakBeforeTemplateCloser = false;
   LLVMStyle.BreakBeforeTernaryOperators = true;
   LLVMStyle.BreakBinaryOperations = FormatStyle::BBO_Never;
   LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index f33ad347436314..98c0c09811b9b5 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6325,7 +6325,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
     return false;
 
   if (Right.is(TT_TemplateCloser))
-    return Style.BreakBeforeTemplateClose;
+    return Style.BreakBeforeTemplateCloser;
   if (Right.is(tok::r_square) && Right.MatchingParen &&
       Right.MatchingParen->is(TT_LambdaLSquare)) {
     return false;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 8a0afc50c7b17d..ead9662ba54801 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -166,7 +166,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
   CHECK_PARSE_BOOL(BinPackArguments);
   CHECK_PARSE_BOOL(BreakAdjacentStringLiterals);
   CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
-  CHECK_PARSE_BOOL(BreakBeforeTemplateClose);
+  CHECK_PARSE_BOOL(BreakBeforeTemplateCloser);
   CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
   CHECK_PARSE_BOOL(BreakStringLiterals);
   CHECK_PARSE_BOOL(CompactNamespaces);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index cd968fc719f407..da0df0134568f6 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11116,11 +11116,13 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
       Style);
 }
 
-TEST_F(FormatTest, BreakBeforeTemplateClose) {
+TEST_F(FormatTest, BreakBeforeTemplateCloser) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
-  // Begin with tests covering the case where there is no constraint on the column limit.
+  // Begin with tests covering the case where there is no constraint on the
+  // column limit.
   Style.ColumnLimit = 0;
-  // When BreakBeforeTemplateClose is turned off, the line break that it adds shall be removed:
+  // When BreakBeforeTemplateCloser is turned off, the line break that it adds
+  // shall be removed:
   verifyFormat("template <\n"
                "    typename Foo,\n"
                "    typename Bar>\n"
@@ -11131,9 +11133,10 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                ">\n"
                "void foo() {}",
                Style);
-  Style.BreakBeforeTemplateClose = true;
-  // BreakBeforeTemplateClose should NOT force template declarations onto multiple lines.
-  // Use verifyNoChange since ColumnLimit = 0.
+
+  Style.BreakBeforeTemplateCloser = true;
+  // BreakBeforeTemplateCloser should NOT force template declarations onto
+  // multiple lines. Use verifyNoChange since ColumnLimit = 0.
   verifyNoChange("template <typename Foo>\n"
                  "void foo() {}",
                  Style);
@@ -11278,7 +11281,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
                "template <\n"
                "    typename Foo,\n"
                "    typename Bar\n"
-               ">"
+               ">\n"
                "void foo() {}",
                Style);
   // But not when the name is looong:

>From 130428887e534cc3bfdfeec5846df2fd1e939667 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sat, 11 Jan 2025 22:47:45 -0800
Subject: [PATCH 07/13] address comments

---
 clang/unittests/Format/FormatTest.cpp | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index da0df0134568f6..b01139ebb8864c 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11136,14 +11136,15 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
 
   Style.BreakBeforeTemplateCloser = true;
   // BreakBeforeTemplateCloser should NOT force template declarations onto
-  // multiple lines. Use verifyNoChange since ColumnLimit = 0.
-  verifyNoChange("template <typename Foo>\n"
-                 "void foo() {}",
-                 Style);
-  verifyNoChange("template <typename Foo, typename Bar>\n"
-                 "void foo() {}",
-                 Style);
-  // It should allow a line break, even when the typename is short:
+  // multiple lines.
+  verifyFormat("template <typename Foo>\n"
+               "void foo() {}",
+               Style);
+  verifyFormat("template <typename Foo, typename Bar>\n"
+               "void foo() {}",
+               Style);
+  // It should allow a line break, even when the typename is short.
+  // verifyNoChange is needed because the default behavior is one line.
   verifyNoChange("template <\n"
                  "    typename Foo\n"
                  ">\n"

>From 9277a685c7a0199fff20677759d663254de9189f Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sun, 12 Jan 2025 12:08:16 -0800
Subject: [PATCH 08/13] switch from bool to enum

---
 clang/docs/ClangFormatStyleOptions.rst     | 42 +++++++++++++--------
 clang/include/clang/Format/Format.h        | 43 +++++++++++++---------
 clang/lib/Format/ContinuationIndenter.cpp  |  5 ++-
 clang/lib/Format/Format.cpp                | 11 +++++-
 clang/lib/Format/TokenAnnotator.cpp        |  2 +-
 clang/unittests/Format/ConfigParseTest.cpp |  7 +++-
 clang/unittests/Format/FormatTest.cpp      |  2 +-
 7 files changed, 74 insertions(+), 38 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index ca92a073b41e45..6df9c8028e7dd6 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3423,24 +3423,36 @@ the configuration (without a prefix: ``Auto``).
 
 .. _BreakBeforeTemplateCloser:
 
-**BreakBeforeTemplateCloser** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateCloser>`
-  If ``true``, a line break will be placed before the ``>`` in a multiline
-  template declaration.
+**BreakBeforeTemplateCloser** (``BreakBeforeTemplateCloserStyle``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateCloser>`
+  The style of when a line break will be placed before the ``>`` that closes
+  a template.
 
-  .. code-block:: c++
+  Possible values:
+
+  * ``BBTCS_Never`` (in configuration: ``Never``)
+    Never break before a template closer.
+
+    .. code-block:: c++
+
+       template <typename Foo, typename Bar>
+
+       template <
+           typename Foo,
+           typename Bar>
+
+  * ``BBTCS_Multiline`` (in configuration: ``Multiline``)
+    Break before a template closer if the template spans more than one line.
+
+    .. code-block:: c++
+
+       template <typename Foo, typename Bar>
+
+       template <
+           typename Foo,
+           typename Bar
+       >
 
-     true:
-     template <
-         typename Foo,
-         typename Bar,
-         typename Baz
-     >
 
-     false:
-     template <
-         typename Foo,
-         typename Bar,
-         typename Baz>
 
 .. _BreakBeforeTernaryOperators:
 
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 5132e38ea02ec6..d5706a807b0dae 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2252,24 +2252,33 @@ struct FormatStyle {
   /// \version 16
   BreakBeforeInlineASMColonStyle BreakBeforeInlineASMColon;
 
-  /// If ``true``, a line break will be placed before the ``>`` in a multiline
-  /// template declaration.
-  /// \code
-  ///    true:
-  ///    template <
-  ///        typename Foo,
-  ///        typename Bar,
-  ///        typename Baz
-  ///    >
-  ///
-  ///    false:
-  ///    template <
-  ///        typename Foo,
-  ///        typename Bar,
-  ///        typename Baz>
-  /// \endcode
+  /// Different styles for whether to break before a template closer.
+  enum BreakBeforeTemplateCloserStyle : int8_t {
+    /// Never break before a template closer.
+    /// \code
+    ///    template <typename Foo, typename Bar>
+    ///
+    ///    template <
+    ///        typename Foo,
+    ///        typename Bar>
+    /// \endcode
+    BBTCS_Never,
+    /// Break before a template closer if the template spans more than one line.
+    /// \code
+    ///    template <typename Foo, typename Bar>
+    ///
+    ///    template <
+    ///        typename Foo,
+    ///        typename Bar
+    ///    >
+    /// \endcode
+    BBTCS_Multiline,
+  };
+
+  /// The style of when a line break will be placed before the ``>`` that closes
+  /// a template.
   /// \version 20
-  bool BreakBeforeTemplateCloser;
+  BreakBeforeTemplateCloserStyle BreakBeforeTemplateCloser;
 
   /// If ``true``, ternary operators will be placed after line breaks.
   /// \code
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 8e7f0d88f81742..b3beb43793c259 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -407,7 +407,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
   if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
     return true;
   if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser) &&
-      Style.BreakBeforeTemplateCloser) {
+      Style.BreakBeforeTemplateCloser == FormatStyle::BBTCS_Multiline) {
     return true;
   }
   if (Style.Language == FormatStyle::LK_ObjC &&
@@ -1378,7 +1378,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
       State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
-  if (Current.is(TT_TemplateCloser) && Style.BreakBeforeTemplateCloser &&
+  if (Current.is(TT_TemplateCloser) &&
+      Style.BreakBeforeTemplateCloser != FormatStyle::BBTCS_Never &&
       State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index e421880d4cf34c..30a0d7b1a5d2c4 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -256,6 +256,15 @@ struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> {
   }
 };
 
+template <>
+struct ScalarEnumerationTraits<FormatStyle::BreakBeforeTemplateCloserStyle> {
+  static void enumeration(IO &IO,
+                          FormatStyle::BreakBeforeTemplateCloserStyle &Value) {
+    IO.enumCase(Value, "Never", FormatStyle::BBTCS_Never);
+    IO.enumCase(Value, "Multiline", FormatStyle::BBTCS_Multiline);
+  }
+};
+
 template <>
 struct ScalarEnumerationTraits<FormatStyle::BreakBinaryOperationsStyle> {
   static void enumeration(IO &IO,
@@ -1534,7 +1543,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
   LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
   LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
   LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
-  LLVMStyle.BreakBeforeTemplateCloser = false;
+  LLVMStyle.BreakBeforeTemplateCloser = FormatStyle::BBTCS_Never;
   LLVMStyle.BreakBeforeTernaryOperators = true;
   LLVMStyle.BreakBinaryOperations = FormatStyle::BBO_Never;
   LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 98c0c09811b9b5..dcc9469aac6774 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6325,7 +6325,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
     return false;
 
   if (Right.is(TT_TemplateCloser))
-    return Style.BreakBeforeTemplateCloser;
+    return Style.BreakBeforeTemplateCloser != FormatStyle::BBTCS_Never;
   if (Right.is(tok::r_square) && Right.MatchingParen &&
       Right.MatchingParen->is(TT_LambdaLSquare)) {
     return false;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index ead9662ba54801..785c0901c720fc 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -166,7 +166,6 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
   CHECK_PARSE_BOOL(BinPackArguments);
   CHECK_PARSE_BOOL(BreakAdjacentStringLiterals);
   CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
-  CHECK_PARSE_BOOL(BreakBeforeTemplateCloser);
   CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
   CHECK_PARSE_BOOL(BreakStringLiterals);
   CHECK_PARSE_BOOL(CompactNamespaces);
@@ -424,6 +423,12 @@ TEST(ConfigParseTest, ParsesConfiguration) {
   CHECK_PARSE("BreakBeforeBinaryOperators: true", BreakBeforeBinaryOperators,
               FormatStyle::BOS_All);
 
+  Style.BreakBeforeTemplateCloser = FormatStyle::BBTCS_Never;
+  CHECK_PARSE("BreakBeforeTemplateCloser: Multiline", BreakBeforeTemplateCloser,
+              FormatStyle::BBTCS_Multiline);
+  CHECK_PARSE("BreakBeforeTemplateCloser: Never", BreakBeforeTemplateCloser,
+              FormatStyle::BBTCS_Never);
+
   Style.BreakBinaryOperations = FormatStyle::BBO_Never;
   CHECK_PARSE("BreakBinaryOperations: OnePerLine", BreakBinaryOperations,
               FormatStyle::BBO_OnePerLine);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index b01139ebb8864c..6b51c26c8ee03d 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11134,7 +11134,7 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                "void foo() {}",
                Style);
 
-  Style.BreakBeforeTemplateCloser = true;
+  Style.BreakBeforeTemplateCloser = FormatStyle::BBTCS_Multiline;
   // BreakBeforeTemplateCloser should NOT force template declarations onto
   // multiple lines.
   verifyFormat("template <typename Foo>\n"

>From 09528826ffc9f7b783d043c4447419cfd9a6ff38 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Mon, 13 Jan 2025 10:09:40 -0800
Subject: [PATCH 09/13] switch from multiline to blockindent

---
 clang/docs/ClangFormatStyleOptions.rst     | 10 +++-
 clang/include/clang/Format/Format.h        | 11 ++++-
 clang/lib/Format/ContinuationIndenter.cpp  |  2 +-
 clang/lib/Format/Format.cpp                |  2 +-
 clang/unittests/Format/ConfigParseTest.cpp |  4 +-
 clang/unittests/Format/FormatTest.cpp      | 54 ++++++++++++++++++++--
 6 files changed, 70 insertions(+), 13 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 6df9c8028e7dd6..3e6feadf597005 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3436,17 +3436,23 @@ the configuration (without a prefix: ``Auto``).
 
        template <typename Foo, typename Bar>
 
+       template <typename Foo,
+                 typename Bar>
+
        template <
            typename Foo,
            typename Bar>
 
-  * ``BBTCS_Multiline`` (in configuration: ``Multiline``)
-    Break before a template closer if the template spans more than one line.
+  * ``BBTCS_BlockIndent`` (in configuration: ``BlockIndent``)
+    Break before a template closer if the template has broken into block indent style.
 
     .. code-block:: c++
 
        template <typename Foo, typename Bar>
 
+       template <typename Foo,
+                 typename Bar>
+
        template <
            typename Foo,
            typename Bar
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index d5706a807b0dae..0986e6e683b6d7 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2258,21 +2258,28 @@ struct FormatStyle {
     /// \code
     ///    template <typename Foo, typename Bar>
     ///
+    ///    template <typename Foo,
+    ///              typename Bar>
+    ///
     ///    template <
     ///        typename Foo,
     ///        typename Bar>
     /// \endcode
     BBTCS_Never,
-    /// Break before a template closer if the template spans more than one line.
+    /// Break before a template closer if the template has broken into block
+    /// indent style.
     /// \code
     ///    template <typename Foo, typename Bar>
     ///
+    ///    template <typename Foo,
+    ///              typename Bar>
+    ///
     ///    template <
     ///        typename Foo,
     ///        typename Bar
     ///    >
     /// \endcode
-    BBTCS_Multiline,
+    BBTCS_BlockIndent,
   };
 
   /// The style of when a line break will be placed before the ``>`` that closes
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index b3beb43793c259..1895d0d95928a5 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -407,7 +407,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
   if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
     return true;
   if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser) &&
-      Style.BreakBeforeTemplateCloser == FormatStyle::BBTCS_Multiline) {
+      Style.BreakBeforeTemplateCloser == FormatStyle::BBTCS_BlockIndent) {
     return true;
   }
   if (Style.Language == FormatStyle::LK_ObjC &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 30a0d7b1a5d2c4..bd52b5c06d5ed0 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -261,7 +261,7 @@ struct ScalarEnumerationTraits<FormatStyle::BreakBeforeTemplateCloserStyle> {
   static void enumeration(IO &IO,
                           FormatStyle::BreakBeforeTemplateCloserStyle &Value) {
     IO.enumCase(Value, "Never", FormatStyle::BBTCS_Never);
-    IO.enumCase(Value, "Multiline", FormatStyle::BBTCS_Multiline);
+    IO.enumCase(Value, "BlockIndent", FormatStyle::BBTCS_BlockIndent);
   }
 };
 
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 785c0901c720fc..45815f7286590b 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -424,8 +424,8 @@ TEST(ConfigParseTest, ParsesConfiguration) {
               FormatStyle::BOS_All);
 
   Style.BreakBeforeTemplateCloser = FormatStyle::BBTCS_Never;
-  CHECK_PARSE("BreakBeforeTemplateCloser: Multiline", BreakBeforeTemplateCloser,
-              FormatStyle::BBTCS_Multiline);
+  CHECK_PARSE("BreakBeforeTemplateCloser: BlockIndent",
+              BreakBeforeTemplateCloser, FormatStyle::BBTCS_BlockIndent);
   CHECK_PARSE("BreakBeforeTemplateCloser: Never", BreakBeforeTemplateCloser,
               FormatStyle::BBTCS_Never);
 
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 6b51c26c8ee03d..57286c5b4c0ee7 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11134,7 +11134,7 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                "void foo() {}",
                Style);
 
-  Style.BreakBeforeTemplateCloser = FormatStyle::BBTCS_Multiline;
+  Style.BreakBeforeTemplateCloser = FormatStyle::BBTCS_BlockIndent;
   // BreakBeforeTemplateCloser should NOT force template declarations onto
   // multiple lines.
   verifyFormat("template <typename Foo>\n"
@@ -11156,6 +11156,10 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                  ">\n"
                  "void foo() {}",
                  Style);
+  verifyNoChange("template <typename Foo,\n"
+                 "          typename Bar>\n"
+                 "void foo() {}",
+                 Style);
   // It should add a line break before > if not already present:
   verifyFormat("template <\n"
                "    typename Foo\n"
@@ -11285,19 +11289,31 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                ">\n"
                "void foo() {}",
                Style);
-  // But not when the name is looong:
+  // But not when the name is looong. Note that these names are exactly 1
+  // character too long for the ColumnLimit.
   verifyFormat("template <\n"
                "    typename Foo,\n"
-               "    typename Barrrrrrrrrrrrrrrrrrrrrrrrrr\n"
+               "    typename Barrrrrrrrrrrrrrrrrrrr\n"
                ">\n"
                "void foo() {}",
                Style);
+  // Note that this "Foo" is 1 character shorter than the previous "Bar" because
+  // of the comma.
   verifyFormat("template <\n"
-               "    typename Fooooooooooooooooooooooooooo,\n"
+               "    typename Foooooooooooooooooooo,\n"
                "    typename Bar\n"
                ">\n"
                "void foo() {}",
                Style);
+  // BlockIndent style is used when the ColumnLimit allows it:
+  verifyFormat("template <typename Foo,\n"
+               "          typename Barrrrrrrrrrrrrrrrrr>\n"
+               "void foo() {}",
+               Style);
+  verifyFormat("template <typename Fooooooooooooooooooo,\n"
+               "          typename Bar>\n"
+               "void foo() {}",
+               Style);
   // Additionally, long names should be split in one step:
   verifyFormat(
       "template <\n"
@@ -11346,17 +11362,32 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
       "      []<typename T,\n"
       "         typename Loooooooooooooooooooooooooooooooooong\n"
       "      >(T t) {};\n"
+      // Because this is not BlockIndent style, and the [] is empty,
+      // and the "T" is short, then the ">" is placed on the same line.
+      "  auto lambda =\n"
+      "      []<typename Loooooooooooooooooooooooooooooooooong,\n"
+      "         typename T>(T t) {};\n"
       // Nested:
       "  auto lambda =\n"
       "      []<template <typename, typename>\n"
       "         typename Looooooooooooooooooong\n"
       "      >(T t) {};\n"
-      // Nested with long capture:
+      // Same idea, the "T" is now short rather than Looong:
+      "  auto lambda =\n"
+      "      []<template <typename, typename>\n"
+      "         typename T>(T t) {};\n"
+      // Nested with long capture forces the style to block indent:
       "  auto lambda =\n"
       "      [loooooooooooooooooooong]<\n"
       "          template <typename, typename>\n"
       "          typename Looooooooooooooooooong\n"
       "      >(T t) {};\n"
+      // But *now* it stays block indented even when T is short:
+      "  auto lambda =\n"
+      "      [loooooooooooooooooooong]<\n"
+      "          template <typename, typename>\n"
+      "          typename T\n"
+      "      >(T t) {};\n"
       // Nested, with long name and long captures:
       "  auto lambda =\n"
       "      [loooooooooooooooooooong]<\n"
@@ -11366,6 +11397,13 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
       "          >\n"
       "          typename T\n"
       "      >(T t) {};\n"
+      // Allow the nested template to be on the same line:
+      "  auto lambda =\n"
+      "      [loooooooooooooooooooong]<\n"
+      "          template <typename Fooooooooo,\n"
+      "                    typename>\n"
+      "          typename T\n"
+      "      >(T t) {};\n"
       "}",
       Style);
   // Test that if the type is NOT long, it pulls it back into one line:
@@ -11387,6 +11425,12 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                "  >();\n"
                "}",
                Style);
+  // But if the type is short, we don't need block indent style:
+  verifyFormat("void foo() {\n"
+               "  myFunc<Foo, Foo, Foo, Foo, Foo, Foo,\n"
+               "         Foo, Foo>();\n"
+               "}",
+               Style);
 }
 
 TEST_F(FormatTest, WrapsTemplateParameters) {

>From ed0289fd97189a37140ddbefd93e979c0d568f27 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Mon, 13 Jan 2025 10:16:12 -0800
Subject: [PATCH 10/13] one last test

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

diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 57286c5b4c0ee7..eb1c4a02f6a2f5 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11431,6 +11431,16 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                "         Foo, Foo>();\n"
                "}",
                Style);
+  // Even a single type in the middle is enough to force it to block indent
+  // style:
+  verifyFormat("void foo() {\n"
+               "  myFunc<\n"
+               "      Foo, Foo, Foo,\n"
+               "      Foooooooooooooooooooooooooooooo,\n"
+               "      Foo, Foo, Foo, Foo\n"
+               "  >();\n"
+               "}",
+               Style);
 }
 
 TEST_F(FormatTest, WrapsTemplateParameters) {

>From 53766dd84f72c95219e604e95206970057f1b6ac Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Mon, 13 Jan 2025 15:32:45 -0800
Subject: [PATCH 11/13] rerun dump format style

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

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 3e6feadf597005..6b2dbf1edbdede 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3444,7 +3444,8 @@ the configuration (without a prefix: ``Auto``).
            typename Bar>
 
   * ``BBTCS_BlockIndent`` (in configuration: ``BlockIndent``)
-    Break before a template closer if the template has broken into block indent style.
+    Break before a template closer if the template has broken into block
+    indent style.
 
     .. code-block:: c++
 

>From fa15aca5c58a16760479fa3e53fa1286fc6adffa Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sun, 19 Jan 2025 20:38:28 -0800
Subject: [PATCH 12/13] address comments

---
 clang/lib/Format/ContinuationIndenter.cpp | 15 +++++++--------
 clang/lib/Format/ContinuationIndenter.h   |  6 +-----
 2 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 7d751caf7ddac3..e2530eeebc8602 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -407,10 +407,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
   }
   if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
     return true;
-  if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser) &&
-      Style.BreakBeforeTemplateCloser == FormatStyle::BBTCS_BlockIndent) {
+  if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser))
     return true;
-  }
   if (Style.Language == FormatStyle::LK_ObjC &&
       Style.ObjCBreakBeforeNestedBlockParam &&
       Current.ObjCSelectorNameParts > 1 &&
@@ -1240,8 +1238,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
         Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent;
   }
 
-  if (PreviousNonComment && PreviousNonComment->is(tok::less))
-    CurrentState.BreakBeforeClosingAngle = true;
+  if (PreviousNonComment && PreviousNonComment->is(TT_TemplateOpener)) {
+    CurrentState.BreakBeforeClosingAngle =
+        Style.BreakBeforeTemplateCloser == FormatStyle::BBTCS_BlockIndent;
+  }
 
   if (CurrentState.AvoidBinPacking) {
     // If we are breaking after '(', '{', '<', or this is the break after a ':'
@@ -1379,9 +1379,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
       State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
-  if (Current.is(TT_TemplateCloser) &&
-      Style.BreakBeforeTemplateCloser != FormatStyle::BBTCS_Never &&
-      State.Stack.size() > 1) {
+  if (Style.BreakBeforeTemplateCloser == FormatStyle::BBTCS_BlockIndent &&
+      Current.is(TT_TemplateCloser) && State.Stack.size() > 1) {
     return State.Stack[State.Stack.size() - 2].LastSpace;
   }
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h
index 88d214473396a8..ac354aa96f86ea 100644
--- a/clang/lib/Format/ContinuationIndenter.h
+++ b/clang/lib/Format/ContinuationIndenter.h
@@ -281,11 +281,7 @@ struct ParenState {
   /// was a newline after the beginning left paren.
   bool BreakBeforeClosingParen : 1;
 
-  /// Whether a newline needs to be inserted before the block's closing
-  /// angle < >.
-  ///
-  /// We only want to insert a newline before the closing angle if there also
-  /// was a newline after the beginning left angle.
+  /// Whether a newline needs to be inserted before a closing angle `>`.
   bool BreakBeforeClosingAngle : 1;
 
   /// Avoid bin packing, i.e. multiple parameters/elements on multiple

>From c0090c8ae6bea4091bc061601902f99903c1a89f Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Mon, 27 Jan 2025 20:57:52 -0800
Subject: [PATCH 13/13] address comments

---
 clang/lib/Format/ContinuationIndenter.cpp |   4 +
 clang/unittests/Format/FormatTest.cpp     | 165 +++++++++++-----------
 2 files changed, 84 insertions(+), 85 deletions(-)

diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index e2530eeebc8602..b2566d10e3348b 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -304,6 +304,10 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
                                    Current.closesBlockOrBlockTypeList(Style))) {
     return false;
   }
+  if (Style.BreakBeforeTemplateCloser == FormatStyle::BBTCS_BlockIndent &&
+      Current.is(TT_TemplateCloser) && !CurrentState.BreakBeforeClosingAngle) {
+    return false;
+  }
   // The opening "{" of a braced list has to be on the same line as the first
   // element if it is nested in another braced init list or function call.
   if (!Current.MustBreakBefore && Previous.is(tok::l_brace) &&
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 375f4e6adc07b8..1b4d7c0765a0ed 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11221,7 +11221,7 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
 }
 
 TEST_F(FormatTest, BreakBeforeTemplateCloser) {
-  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
+  FormatStyle Style = getLLVMStyle();
   // Begin with tests covering the case where there is no constraint on the
   // column limit.
   Style.ColumnLimit = 0;
@@ -11299,24 +11299,20 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                "};",
                Style);
 
-  // Test from issue #80049:
+  // Test from https://github.com/llvm/llvm-project/issues/80049:
   verifyFormat(
-      "void foo() {\n"
-      "  using type = std::remove_cv_t<\n"
-      "      add_common_cv_reference<\n"
-      "          std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
-      "          T0,\n"
-      "          T1\n"
-      "      >\n"
-      "  >;\n"
-      "}",
-      "void foo() {\n"
-      "  using type = std::remove_cv_t<\n"
-      "      add_common_cv_reference<\n"
-      "          std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
-      "          T0,\n"
-      "          T1>>;\n"
-      "}",
+      "using type = std::remove_cv_t<\n"
+      "    add_common_cv_reference<\n"
+      "        std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
+      "        T0,\n"
+      "        T1\n"
+      "    >\n"
+      ">;\n",
+      "using type = std::remove_cv_t<\n"
+      "    add_common_cv_reference<\n"
+      "        std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
+      "        T0,\n"
+      "        T1>>;\n",
       Style);
 
   // Test lambda goes to next line:
@@ -11363,9 +11359,7 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
 
   // Note that this is the same line (no \n):
   verifyFormat("void foo() {\n"
-               "  auto lambda = []<typename "
-               "Looooooooooooooooooooooooooooong>("
-               "Looooooooooooooooooooooooooooong t) {};\n"
+               "  auto lambda = []<typename T>(T t) {};\n"
                "}",
                Style);
 
@@ -11418,6 +11412,17 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                "          typename Bar>\n"
                "void foo() {}",
                Style);
+  // Same check for only one template parameter.
+  // Note how the first line is exactly 40 chars:
+  verifyFormat("template <typename Barrrrrrrrrrrrrrrrrr>\n"
+               "void foo() {}",
+               Style);
+  // And when one more "r" is added, it breaks properly:
+  verifyFormat("template <\n"
+               "    typename Barrrrrrrrrrrrrrrrrrr\n"
+               ">\n"
+               "void foo() {}",
+               Style);
   // Additionally, long names should be split in one step:
   verifyFormat(
       "template <\n"
@@ -11446,70 +11451,60 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
                "void foo() {}",
                Style);
   // Test lambda goes to next line if the type is looong:
-  verifyFormat(
-      "void foo() {\n"
-      // In this case, breaking "typename Looong" onto the next line would
-      // actually exceed the column limit by even more. Same goes for "auto
-      // lambda = []<\n" because then the continuation indent would be all the
-      // way to the "[". Therefore, this is correct for the column limited case:
-      "  auto lambda =\n"
-      "      []<typename Loooooooooooooooooooooooooooooooooong\n"
-      "      >(T t) {};\n"
-      // For completeness, let's also make sure it's willing to break if and
-      // when doing so is helpful. If we put something long into the square
-      // brackets, now it's worth it:
-      "  auto lambda =\n"
-      "      [looooooooooooooong]<\n"
-      "          typename Loooooooooooooooooooooooooooooooooong\n"
-      "      >(T t) {};\n"
-      "  auto lambda =\n"
-      "      []<typename T,\n"
-      "         typename Loooooooooooooooooooooooooooooooooong\n"
-      "      >(T t) {};\n"
-      // Because this is not BlockIndent style, and the [] is empty,
-      // and the "T" is short, then the ">" is placed on the same line.
-      "  auto lambda =\n"
-      "      []<typename Loooooooooooooooooooooooooooooooooong,\n"
-      "         typename T>(T t) {};\n"
-      // Nested:
-      "  auto lambda =\n"
-      "      []<template <typename, typename>\n"
-      "         typename Looooooooooooooooooong\n"
-      "      >(T t) {};\n"
-      // Same idea, the "T" is now short rather than Looong:
-      "  auto lambda =\n"
-      "      []<template <typename, typename>\n"
-      "         typename T>(T t) {};\n"
-      // Nested with long capture forces the style to block indent:
-      "  auto lambda =\n"
-      "      [loooooooooooooooooooong]<\n"
-      "          template <typename, typename>\n"
-      "          typename Looooooooooooooooooong\n"
-      "      >(T t) {};\n"
-      // But *now* it stays block indented even when T is short:
-      "  auto lambda =\n"
-      "      [loooooooooooooooooooong]<\n"
-      "          template <typename, typename>\n"
-      "          typename T\n"
-      "      >(T t) {};\n"
-      // Nested, with long name and long captures:
-      "  auto lambda =\n"
-      "      [loooooooooooooooooooong]<\n"
-      "          template <\n"
-      "              typename Foooooooooooooooo,\n"
-      "              typename\n"
-      "          >\n"
-      "          typename T\n"
-      "      >(T t) {};\n"
-      // Allow the nested template to be on the same line:
-      "  auto lambda =\n"
-      "      [loooooooooooooooooooong]<\n"
-      "          template <typename Fooooooooo,\n"
-      "                    typename>\n"
-      "          typename T\n"
-      "      >(T t) {};\n"
-      "}",
-      Style);
+  verifyFormat("void foo() {\n"
+               "  auto lambda =\n"
+               "      []<\n"
+               "          typename Loooooooooooooooooooooooooooooooooong\n"
+               "      >(T t) {};\n"
+               "  auto lambda =\n"
+               "      [looooooooooooooong]<\n"
+               "          typename Loooooooooooooooooooooooooooooooooong\n"
+               "      >(T t) {};\n"
+               "  auto lambda =\n"
+               "      []<\n"
+               "          typename T,\n"
+               "          typename Loooooooooooooooooooooooooooooooooong\n"
+               "      >(T t) {};\n"
+               // Nested:
+               "  auto lambda =\n"
+               "      []<\n"
+               "          template <typename, typename>\n"
+               "          typename Looooooooooooooooooong\n"
+               "      >(T t) {};\n"
+               // Same idea, the "T" is now short rather than Looong:
+               "  auto lambda =\n"
+               "      []<template <typename, typename>\n"
+               "         typename T>(T t) {};\n"
+               // Nested with long capture forces the style to block indent:
+               "  auto lambda =\n"
+               "      [loooooooooooooooooooong]<\n"
+               "          template <typename, typename>\n"
+               "          typename Looooooooooooooooooong\n"
+               "      >(T t) {};\n"
+               // But *now* it stays block indented even when T is short:
+               "  auto lambda =\n"
+               "      [loooooooooooooooooooong]<\n"
+               "          template <typename, typename>\n"
+               "          typename T\n"
+               "      >(T t) {};\n"
+               // Nested, with long name and long captures:
+               "  auto lambda =\n"
+               "      [loooooooooooooooooooong]<\n"
+               "          template <\n"
+               "              typename Foooooooooooooooo,\n"
+               "              typename\n"
+               "          >\n"
+               "          typename T\n"
+               "      >(T t) {};\n"
+               // Allow the nested template to be on the same line:
+               "  auto lambda =\n"
+               "      [loooooooooooooooooooong]<\n"
+               "          template <typename Fooooooooo,\n"
+               "                    typename>\n"
+               "          typename T\n"
+               "      >(T t) {};\n"
+               "}",
+               Style);
   // Test that if the type is NOT long, it pulls it back into one line:
   verifyFormat("void foo() {\n"
                "  auto lambda = []<typename T>(T t) {};\n"



More information about the cfe-commits mailing list