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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits