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