diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -117,8 +117,10 @@ bool parseStructLike(); void parseConcept(); void parseRequires(); - void parseRequiresExpression(unsigned int OriginalLevel); - void parseConstraintExpression(unsigned int OriginalLevel); + void parseRequiresExpression(unsigned int OriginalLevel, + bool InTrailingRequire = false); + void parseConstraintExpression(unsigned int OriginalLevel, + bool InTrailingRequire = false); void parseJavaEnumBody(); // Parses a record (aka class) as a top level element. If ParseAsExpr is true, // parses the record as a child block, i.e. if the class declaration is an diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2547,7 +2547,8 @@ } } -void UnwrappedLineParser::parseRequiresExpression(unsigned int OriginalLevel) { +void UnwrappedLineParser::parseRequiresExpression(unsigned int OriginalLevel, + bool InTrailingRequire) { // requires (R range) if (FormatTok->Tok.is(tok::l_paren)) { parseParens(); @@ -2564,12 +2565,12 @@ parseBlock(); addUnwrappedLine(); } else { - parseConstraintExpression(OriginalLevel); + parseConstraintExpression(OriginalLevel, InTrailingRequire); } } -void UnwrappedLineParser::parseConstraintExpression( - unsigned int OriginalLevel) { +void UnwrappedLineParser::parseConstraintExpression(unsigned int OriginalLevel, + bool InTrailingRequire) { // requires Id && Id || Id while ( FormatTok->isOneOf(tok::identifier, tok::kw_requires, tok::coloncolon)) { @@ -2609,10 +2610,13 @@ return; } if (!FormatTok->Tok.isOneOf(tok::ampamp, tok::pipepipe)) { - if (FormatTok->Previous && - !FormatTok->Previous->isOneOf(tok::identifier, tok::kw_requires, - tok::coloncolon)) { - addUnwrappedLine(); + if (FormatTok->Previous) { + bool AddLine = + !FormatTok->Previous->isOneOf(tok::identifier, tok::kw_requires, + tok::coloncolon) && + !(InTrailingRequire && FormatTok->Previous->is(tok::r_brace)); + if (AddLine) + addUnwrappedLine(); } if (Style.IndentRequires && OriginalLevel != Line->Level) { --Line->Level; @@ -2630,7 +2634,9 @@ assert(FormatTok->Tok.is(tok::kw_requires) && "'requires' expected"); unsigned OriginalLevel = Line->Level; - if (FormatTok->Previous && FormatTok->Previous->is(tok::greater)) { + bool InTrailingRequire = + !(FormatTok->Previous && FormatTok->Previous->is(tok::greater)); + if (!InTrailingRequire) { addUnwrappedLine(); if (Style.IndentRequires) { Line->Level++; @@ -2638,7 +2644,7 @@ } nextToken(); - parseRequiresExpression(OriginalLevel); + parseRequiresExpression(OriginalLevel, InTrailingRequire); } bool UnwrappedLineParser::parseEnum() { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -16914,6 +16914,49 @@ Style); } +TEST_F(FormatTest, AttachBraceBreaking) { + FormatStyle BraceStyle = getLLVMStyle(); + BraceStyle.BreakBeforeBraces = FormatStyle::BS_Attach; + verifyFormat("namespace a {\n" + "class A {\n" + " void f() {\n" + " if (true) {\n" + " a();\n" + " b();\n" + " } else {\n" + " a();\n" + " }\n" + " }\n" + " void g() { return; }\n" + "};\n" + "struct B {\n" + " int x;\n" + "};\n" + "} // namespace a\n", + BraceStyle); + verifyFormat("enum X {\n" + " Y = 0,\n" + "}\n", + BraceStyle); + verifyFormat("struct S {\n" + " int Type;\n" + " union {\n" + " int x;\n" + " double y;\n" + " } Value;\n" + " class C {\n" + " MyFavoriteType Value;\n" + " } Class;\n" + "}\n", + BraceStyle); + // https://llvm.org/PR48968 + verifyFormat("void f() requires requires { a; } {\n" + " a();\n" + " b();\n" + "}\n", + BraceStyle); +} + TEST_F(FormatTest, LinuxBraceBreaking) { FormatStyle LinuxBraceStyle = getLLVMStyle(); LinuxBraceStyle.BreakBeforeBraces = FormatStyle::BS_Linux; @@ -17348,6 +17391,13 @@ " }\n" "}\n", BreakBeforeBraceShortIfs); + // https://llvm.org/PR48968 + verifyFormat("void f() requires requires { a; }\n" + "{\n" + " a();\n" + " b();\n" + "}\n", + BreakBeforeBraceShortIfs); } TEST_F(FormatTest, WhitesmithsBraceBreaking) { @@ -22483,6 +22533,15 @@ "}", Style); + // https://llvm.org/PR48968 + verifyFormat("void f() requires requires {\n" + " a;\n" + "} {\n" + " a();\n" + " b();\n" + "}\n", + Style); + verifyFormat( "template int g(T i) requires Concept1 && Concept2 {\n" " //...\n"