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

>From 1caf823165b16f6701993d586df51d5cdbf0885e Mon Sep 17 00:00:00 2001
From: Leijurv <leij...@gmail.com>
Date: Fri, 29 Nov 2024 21:54:36 -0600
Subject: [PATCH 1/8] [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 <leij...@gmail.com>
Date: Fri, 6 Dec 2024 20:36:41 -0700
Subject: [PATCH 2/8] 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 <leij...@gmail.com>
Date: Sun, 8 Dec 2024 21:21:18 -0800
Subject: [PATCH 3/8] 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 <leij...@gmail.com>
Date: Sat, 21 Dec 2024 17:21:28 -0800
Subject: [PATCH 4/8] 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 <leij...@gmail.com>
Date: Sat, 11 Jan 2025 01:37:04 -0800
Subject: [PATCH 5/8] 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 <leij...@gmail.com>
Date: Sat, 11 Jan 2025 22:35:07 -0800
Subject: [PATCH 6/8] 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 <leij...@gmail.com>
Date: Sat, 11 Jan 2025 22:47:45 -0800
Subject: [PATCH 7/8] 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 <leij...@gmail.com>
Date: Sun, 12 Jan 2025 12:08:16 -0800
Subject: [PATCH 8/8] 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"

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

Reply via email to