Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -551,6 +551,40 @@ /// \version 11 bool AllowShortEnumsOnASingleLine; + /// Allow short requires expression on a single line. + /// \code + /// true: + /// template + /// concept c = requires(T a, T b) { a + b; }; + /// + /// false: + /// template + /// concept c = requires(T a, T b) { + /// a + b; + /// }; + /// \endcode + /// \version 16 + bool AllowShortRequiresExpressionOnASingleLine; + + /// Allow short compound requirement on a single line. + /// \code + /// true: + /// template + /// concept c = requires(T x) { + /// { x + 1 } -> std::same_as; + /// }; + /// + /// false: + /// template + /// concept c = requires(T x) { + /// { + /// x + 1 + /// } -> std::same_as; + /// }; + /// \endcode + /// \version 16 + bool AllowShortCompoundRequirementOnASingleLine; + /// Different styles for merging short functions containing at most one /// statement. enum ShortFunctionStyle : int8_t { @@ -4032,6 +4066,10 @@ AllowShortCaseLabelsOnASingleLine == R.AllowShortCaseLabelsOnASingleLine && AllowShortEnumsOnASingleLine == R.AllowShortEnumsOnASingleLine && + AllowShortRequiresExpressionOnASingleLine == + R.AllowShortRequiresExpressionOnASingleLine && + AllowShortCompoundRequirementOnASingleLine == + R.AllowShortCompoundRequirementOnASingleLine && AllowShortFunctionsOnASingleLine == R.AllowShortFunctionsOnASingleLine && AllowShortIfStatementsOnASingleLine == Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -808,6 +808,10 @@ Style.AllowShortCaseLabelsOnASingleLine); IO.mapOptional("AllowShortEnumsOnASingleLine", Style.AllowShortEnumsOnASingleLine); + IO.mapOptional("AllowShortRequiresExpressionOnASingleLine", + Style.AllowShortRequiresExpressionOnASingleLine); + IO.mapOptional("AllowShortCompoundRequirementOnASingleLine", + Style.AllowShortCompoundRequirementOnASingleLine); IO.mapOptional("AllowShortFunctionsOnASingleLine", Style.AllowShortFunctionsOnASingleLine); IO.mapOptional("AllowShortIfStatementsOnASingleLine", @@ -1261,6 +1265,8 @@ LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; LLVMStyle.AllowShortCaseLabelsOnASingleLine = false; LLVMStyle.AllowShortEnumsOnASingleLine = true; + LLVMStyle.AllowShortRequiresExpressionOnASingleLine = true; + LLVMStyle.AllowShortCompoundRequirementOnASingleLine = true; LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All; Index: clang/lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- clang/lib/Format/UnwrappedLineFormatter.cpp +++ clang/lib/Format/UnwrappedLineFormatter.cpp @@ -502,6 +502,10 @@ // Try to merge records. if (TheLine->Last->is(TT_EnumLBrace)) { ShouldMerge = Style.AllowShortEnumsOnASingleLine; + } else if (TheLine->Last->is(TT_RequiresExpressionLBrace)) { + ShouldMerge = Style.AllowShortRequiresExpressionOnASingleLine; + } else if (TheLine->Last->is(TT_CompoundRequirementLBrace)) { + ShouldMerge = Style.AllowShortCompoundRequirementOnASingleLine; } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace)) { // NOTE: We use AfterClass (whereas AfterStruct exists) for both classes // and structs, but it seems that wrapping is still handled correctly Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -1085,6 +1085,12 @@ FormatTok->setBlockKind(BK_Block); const FormatToken *OpeningBrace = FormatTok; nextToken(); + + if (NextLBracesType == TT_CompoundRequirementLBrace && + !Style.AllowShortRequiresExpressionOnASingleLine) { + addUnwrappedLine(); + } + { bool SkipIndent = (Style.isJavaScript() && (isGoogScope(*Line) || isIIFE(*Line, Keywords))); @@ -1096,6 +1102,7 @@ flushComments(isOnNewLine(*FormatTok)); Line->Level -= SkipIndent ? 0 : 1; } + nextToken(); } Index: clang/unittests/Format/ConfigParseTest.cpp =================================================================== --- clang/unittests/Format/ConfigParseTest.cpp +++ clang/unittests/Format/ConfigParseTest.cpp @@ -148,6 +148,8 @@ CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine); CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine); CHECK_PARSE_BOOL(AllowShortEnumsOnASingleLine); + CHECK_PARSE_BOOL(AllowShortRequiresExpressionOnASingleLine); + CHECK_PARSE_BOOL(AllowShortCompoundRequirementOnASingleLine); CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine); CHECK_PARSE_BOOL(BinPackArguments); CHECK_PARSE_BOOL(BinPackParameters); Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -2899,6 +2899,35 @@ Style); } +TEST_F(FormatTest, ShortRequiresExpression) { + FormatStyle Style = getLLVMStyle(); + EXPECT_TRUE(Style.AllowShortRequiresExpressionOnASingleLine); + verifyFormat("template \n" + "concept c = requires(T a, T b) { a + b; };"); + Style.AllowShortRequiresExpressionOnASingleLine = false; + verifyFormat("template \n" + "concept c = requires(T a, T b) {\n" + " a + b;\n" + "};"); + // TODO: support BraceWrapping.AfterRequiresExpression. +} + +TEST_F(FormatTest, ShortCompoundRequirements) { + FormatStyle Style = getLLVMStyle(); + EXPECT_TRUE(Style.AllowShortCompoundRequirementOnASingleLine); + verifyFormat("template \n" + "concept c = requires(T x) {\n" + " { x + 1 } -> std::same_as;\n" + "};"); + Style.AllowShortCompoundRequirementOnASingleLine = false; + verifyFormat("template \n" + "concept c = requires(T x) {\n" + " {\n" + " x + 1\n" + " } -> std::same_as;\n" + "};"); +} + TEST_F(FormatTest, ShortCaseLabels) { FormatStyle Style = getLLVMStyle(); Style.AllowShortCaseLabelsOnASingleLine = true;