HazardyKnusperkeks created this revision.
HazardyKnusperkeks added reviewers: MyDeveloperDay, krasimir, curdeius.
HazardyKnusperkeks added a project: clang-format.
HazardyKnusperkeks requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Before this patch the require clause between function and template declaration 
was written in the same line as the function. I can't believe this is what 
anyone wants.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113319

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/lib/Format/UnwrappedLineParser.cpp
  clang/lib/Format/UnwrappedLineParser.h
  clang/unittests/Format/FormatTest.cpp

Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -22288,6 +22288,114 @@
                "requires (std::invocable<F, std::invoke_result_t<Args>...>) "
                "struct constant;",
                Style);
+
+  verifyFormat("template <typename T> void func(T);");
+
+  verifyFormat("template <typename T>\n"
+               "requires std::signed_integral<T> && std::signed_integral<T>\n"
+               "void func(T);");
+  verifyFormat("template <typename T>\n"
+               "requires(std::is_integral_v<T> && std::is_signed_v<T>)\n"
+               "void func(T);");
+  verifyFormat("template <tyename T>\n"
+               "requires requires(T &&t) {\n"
+               "  typename T::size_type;\n"
+               "  { t.size() } -> std::same_as<typename T::size_type>;\n"
+               "}\n"
+               "func(T);");
+
+  verifyFormat("template <typename T>\n"
+               "requires std::signed_integral<T> && std::signed_integral<T>\n"
+               "void func(T) {}");
+  verifyFormat("template <typename T>\n"
+               "requires(std::is_integral_v<T> && std::is_signed_v<T>)\n"
+               "void func(T) {}");
+  verifyFormat("template <tyename T>\n"
+               "requires requires(T &&t) {\n"
+               "  typename T::size_type;\n"
+               "  { t.size() } -> std::same_as<typename T::size_type>;\n"
+               "}\n"
+               "func(T) {}");
+
+  verifyFormat(
+      "template <typename T> void func(T) requires std::signed_integral<T>;");
+  verifyFormat("template <typename T>\n"
+               "void func(T) requires std::signed_integral<T> && "
+               "std::signed_integral<T>;");
+  verifyFormat(
+      "template <typename T>\n"
+      "void func(T) requires(std::is_integral_v<T> && std::is_signed_v<T>);");
+  verifyFormat("template <typename T> void func(T) requires requires(T &&t) {\n"
+               "  typename T::size_type;\n"
+               "  { t.size() } -> std::same_as<typename T::size_type>;\n"
+               "};");
+
+  verifyFormat(
+      "template <typename T> void func(T) requires std::signed_integral<T> {}");
+  verifyFormat("template <typename T>\n"
+               "void func(T) requires std::signed_integral<T> && "
+               "std::signed_integral<T> {}");
+  verifyFormat(
+      "template <typename T>\n"
+      "void func(T) requires(std::is_integral_v<T> && std::is_signed_v<T>) {}");
+  verifyFormat("template <typename T> void func(T) requires requires(T &&t) {\n"
+               "  typename T::size_type;\n"
+               "  { t.size() } -> std::same_as<typename T::size_type>;\n"
+               "}\n"
+               "{}");
+
+  Style = getLLVMStyle();
+  Style.IndentRequires = true;
+
+  verifyFormat("template <typename T>\n"
+               "  requires std::signed_integral<T> && std::signed_integral<T>\n"
+               "void func(T);",
+               Style);
+  verifyFormat("template <typename T>\n"
+               "  requires(std::is_integral_v<T> && std::is_signed_v<T>)\n"
+               "void func(T);",
+               Style);
+  verifyFormat("template <tyename T>\n"
+               "  requires requires(T &&t) {\n"
+               "    typename T::size_type;\n"
+               "    { t.size() } -> std::same_as<typename T::size_type>;\n"
+               "  }\n"
+               "func(T);",
+               Style);
+
+  verifyFormat("template <typename T>\n"
+               "  requires std::signed_integral<T> && std::signed_integral<T>\n"
+               "void func(T) {}",
+               Style);
+  verifyFormat("template <typename T>\n"
+               "  requires(std::is_integral_v<T> && std::is_signed_v<T>)\n"
+               "void func(T) {}",
+               Style);
+  verifyFormat("template <tyename T>\n"
+               "  requires requires(T &&t) {\n"
+               "    typename T::size_type;\n"
+               "    { t.size() } -> std::same_as<typename T::size_type>;\n"
+               "  }\n"
+               "func(T) {}",
+               Style);
+
+  verifyFormat(
+      "template <typename T> void func(T) requires std::signed_integral<T> {}",
+      Style);
+  verifyFormat("template <typename T>\n"
+               "void func(T) requires std::signed_integral<T> && "
+               "std::signed_integral<T> {}",
+               Style);
+  verifyFormat(
+      "template <typename T>\n"
+      "void func(T) requires(std::is_integral_v<T> && std::is_signed_v<T>) {}",
+      Style);
+  verifyFormat("template <typename T> void func(T) requires requires(T &&t) {\n"
+               "  typename T::size_type;\n"
+               "  { t.size() } -> std::same_as<typename T::size_type>;\n"
+               "}\n"
+               "{}",
+               Style);
 }
 
 TEST_F(FormatTest, StatementAttributeLikeMacros) {
Index: clang/lib/Format/UnwrappedLineParser.h
===================================================================
--- clang/lib/Format/UnwrappedLineParser.h
+++ clang/lib/Format/UnwrappedLineParser.h
@@ -117,7 +117,7 @@
   bool parseStructLike();
   void parseConcept();
   void parseRequires();
-  void parseRequiresExpression(unsigned int OriginalLevel);
+  void parseRequiresClauseOrExpression(unsigned int OriginalLevel);
   void parseConstraintExpression(unsigned int OriginalLevel);
   void parseJavaEnumBody();
   // Parses a record (aka class) as a top level element. If ParseAsExpr is true,
Index: clang/lib/Format/UnwrappedLineParser.cpp
===================================================================
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -2436,17 +2436,27 @@
     return;
   nextToken();
   if (FormatTok->Tok.is(tok::kw_requires)) {
+    FormatTok->setType(TT_RequiresExpression);
     nextToken();
-    parseRequiresExpression(Line->Level);
+    parseRequiresClauseOrExpression(Line->Level);
   } else {
     parseConstraintExpression(Line->Level);
   }
 }
 
-void UnwrappedLineParser::parseRequiresExpression(unsigned int OriginalLevel) {
-  // requires (R range)
+void UnwrappedLineParser::parseRequiresClauseOrExpression(
+    unsigned int OriginalLevel) {
+  // requires (R range) or requires (trait1_v<T> && trait2_v<T>)
+  assert(FormatTok->Previous && FormatTok->Previous->is(tok::kw_requires));
   if (FormatTok->Tok.is(tok::l_paren)) {
+    bool ParsingClause = FormatTok->Previous->is(TT_RequiresClause);
     parseParens();
+    if (ParsingClause &&
+        !FormatTok->Tok.isOneOf(tok::comment, tok::kw_struct, tok::kw_class,
+                                tok::kw_union, tok::l_brace, tok::semi)) {
+      // Only break if we start a function.
+      addUnwrappedLine();
+    }
     if (Style.IndentRequires && OriginalLevel != Line->Level) {
       addUnwrappedLine();
       --Line->Level;
@@ -2480,7 +2490,8 @@
       nextToken();
     }
     if (FormatTok->Tok.is(tok::kw_requires)) {
-      parseRequiresExpression(OriginalLevel);
+      FormatTok->setType(TT_RequiresExpression);
+      parseRequiresClauseOrExpression(OriginalLevel);
     }
     if (FormatTok->Tok.is(tok::less)) {
       parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false,
@@ -2526,15 +2537,26 @@
   assert(FormatTok->Tok.is(tok::kw_requires) && "'requires' expected");
 
   unsigned OriginalLevel = Line->Level;
-  if (FormatTok->Previous && FormatTok->Previous->is(tok::greater)) {
-    addUnwrappedLine();
-    if (Style.IndentRequires) {
-      Line->Level++;
+  bool SetClause = false;
+  if (FormatTok->Previous) {
+    if (FormatTok->Previous->is(tok::greater)) {
+      FormatTok->setType(TT_RequiresClause);
+      SetClause = true;
+      addUnwrappedLine();
+      if (Style.IndentRequires) {
+        Line->Level++;
+      }
+    } else if (FormatTok->Previous->is(tok::r_paren)) {
+      FormatTok->setType(TT_RequiresClause);
+      SetClause = true;
     }
   }
+  if (!SetClause)
+    FormatTok->setType(TT_RequiresExpression);
+
   nextToken();
 
-  parseRequiresExpression(OriginalLevel);
+  parseRequiresClauseOrExpression(OriginalLevel);
 }
 
 bool UnwrappedLineParser::parseEnum() {
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -251,7 +251,8 @@
       Contexts.back().IsExpression = false;
     } else if (Left->Previous &&
                (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_while,
-                                        tok::l_paren, tok::comma) ||
+                                        tok::l_paren, tok::comma,
+                                        TT_RequiresClause) ||
                 Left->Previous->isIf() ||
                 Left->Previous->is(TT_BinaryOperator))) {
       // static_assert, if and while usually contain expressions.
@@ -1415,7 +1416,8 @@
             TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator,
             TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral,
             TT_UntouchableMacroFunc, TT_ConstraintJunctions,
-            TT_StatementAttributeLikeMacro))
+            TT_StatementAttributeLikeMacro, TT_RequiresClause,
+            TT_RequiresExpression))
       CurrentToken->setType(TT_Unknown);
     CurrentToken->Role.reset();
     CurrentToken->MatchingParen = nullptr;
Index: clang/lib/Format/FormatToken.h
===================================================================
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -95,6 +95,8 @@
   TYPE(PureVirtualSpecifier)                                                   \
   TYPE(RangeBasedForLoopColon)                                                 \
   TYPE(RegexLiteral)                                                           \
+  TYPE(RequiresClause)                                                         \
+  TYPE(RequiresExpression)                                                     \
   TYPE(SelectorName)                                                           \
   TYPE(StartOfName)                                                            \
   TYPE(StatementAttributeLikeMacro)                                            \
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to