Skip to content

Commit

Permalink
[clang-format] Adjust requires clause wrapping (llvm#101550) (llvm#10…
Browse files Browse the repository at this point in the history
…2078)

Address llvm#101550 by adding OwnLineWithBrace option for RequiresClausePosition. This permits placing a following '{' on the same line as the requires clause.

Thus, instead of:
```
bool Foo ()
  requires(true)
{
  return true;
}
```

we have:
```
bool Foo ()
  requires(true) {
  return true;
}
```

If the function body is empty, we'll get:
```
bool Foo ()
  requires(true) {}
```

I attempted to get a line break between the open and close braces, but
failed. Perhaps that's fine -- it's rare and only happens in the empty
body case.
  • Loading branch information
urnathan authored Aug 17, 2024
1 parent 8d8f56d commit 4cf9a42
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 12 deletions.
36 changes: 31 additions & 5 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4187,7 +4187,8 @@ the configuration (without a prefix: ``Auto``).

**IndentRequiresClause** (``Boolean``) :versionbadge:`clang-format 15` :ref:`<IndentRequiresClause>`
Indent the requires clause in a template. This only applies when
``RequiresClausePosition`` is ``OwnLine``, or ``WithFollowing``.
``RequiresClausePosition`` is ``OwnLine``, ``OwnLineWithBrace``,
or ``WithFollowing``.

In clang-format 12, 13 and 14 it was named ``IndentRequires``.

Expand Down Expand Up @@ -5419,23 +5420,48 @@ the configuration (without a prefix: ``Auto``).
Possible values:

* ``RCPS_OwnLine`` (in configuration: ``OwnLine``)
Always put the ``requires`` clause on its own line.
Always put the ``requires`` clause on its own line (possibly followed by
a semicolon).

.. code-block:: c++

template <typename T>
requires C<T>
requires C<T>
struct Foo {...

template <typename T>
requires C<T>
void bar(T t)
requires C<T>;

template <typename T>
requires C<T>
void bar(T t) {...

template <typename T>
void baz(T t)
requires C<T>
requires C<T>
{...

* ``RCPS_OwnLineWithBrace`` (in configuration: ``OwnLineWithBrace``)
As with ``OwnLine``, except, unless otherwise prohibited, place a
following open brace (of a function definition) to follow on the same
line.

.. code-block:: c++

void bar(T t)
requires C<T> {
return;
}

void bar(T t)
requires C<T> {}

template <typename T>
requires C<T>
void baz(T t) {
...

* ``RCPS_WithPreceding`` (in configuration: ``WithPreceding``)
Try to put the clause together with the preceding part of a declaration.
For class templates: stick to the template declaration.
Expand Down
34 changes: 29 additions & 5 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2858,7 +2858,8 @@ struct FormatStyle {
PPDirectiveIndentStyle IndentPPDirectives;

/// Indent the requires clause in a template. This only applies when
/// ``RequiresClausePosition`` is ``OwnLine``, or ``WithFollowing``.
/// ``RequiresClausePosition`` is ``OwnLine``, ``OwnLineWithBrace``,
/// or ``WithFollowing``.
///
/// In clang-format 12, 13 and 14 it was named ``IndentRequires``.
/// \code
Expand Down Expand Up @@ -3944,22 +3945,45 @@ struct FormatStyle {
/// ``IndentRequires`` option is only used if the ``requires`` is put on the
/// start of a line.
enum RequiresClausePositionStyle : int8_t {
/// Always put the ``requires`` clause on its own line.
/// Always put the ``requires`` clause on its own line (possibly followed by
/// a semicolon).
/// \code
/// template <typename T>
/// requires C<T>
/// requires C<T>
/// struct Foo {...
///
/// template <typename T>
/// requires C<T>
/// void bar(T t)
/// requires C<T>;
///
/// template <typename T>
/// requires C<T>
/// void bar(T t) {...
///
/// template <typename T>
/// void baz(T t)
/// requires C<T>
/// requires C<T>
/// {...
/// \endcode
RCPS_OwnLine,
/// As with ``OwnLine``, except, unless otherwise prohibited, place a
/// following open brace (of a function definition) to follow on the same
/// line.
/// \code
/// void bar(T t)
/// requires C<T> {
/// return;
/// }
///
/// void bar(T t)
/// requires C<T> {}
///
/// template <typename T>
/// requires C<T>
/// void baz(T t) {
/// ...
/// \endcode
RCPS_OwnLineWithBrace,
/// Try to put the clause together with the preceding part of a declaration.
/// For class templates: stick to the template declaration.
/// For function templates: stick to the template declaration.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
switch (Style.RequiresClausePosition) {
case FormatStyle::RCPS_OwnLine:
case FormatStyle::RCPS_WithFollowing:
case FormatStyle::RCPS_OwnLineWithBrace:
return CurrentState.Indent;
default:
break;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ struct ScalarEnumerationTraits<FormatStyle::RequiresClausePositionStyle> {
static void enumeration(IO &IO,
FormatStyle::RequiresClausePositionStyle &Value) {
IO.enumCase(Value, "OwnLine", FormatStyle::RCPS_OwnLine);
IO.enumCase(Value, "OwnLineWithBrace", FormatStyle::RCPS_OwnLineWithBrace);
IO.enumCase(Value, "WithPreceding", FormatStyle::RCPS_WithPreceding);
IO.enumCase(Value, "WithFollowing", FormatStyle::RCPS_WithFollowing);
IO.enumCase(Value, "SingleLine", FormatStyle::RCPS_SingleLine);
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5681,6 +5681,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (Right.is(TT_RequiresClause)) {
switch (Style.RequiresClausePosition) {
case FormatStyle::RCPS_OwnLine:
case FormatStyle::RCPS_OwnLineWithBrace:
case FormatStyle::RCPS_WithFollowing:
return true;
default:
Expand All @@ -5699,11 +5700,13 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
(Style.BreakTemplateDeclarations == FormatStyle::BTDS_Leave &&
Right.NewlinesBefore > 0);
}
if (Left.ClosesRequiresClause && Right.isNot(tok::semi)) {
if (Left.ClosesRequiresClause) {
switch (Style.RequiresClausePosition) {
case FormatStyle::RCPS_OwnLine:
case FormatStyle::RCPS_WithPreceding:
return true;
return Right.isNot(tok::semi);
case FormatStyle::RCPS_OwnLineWithBrace:
return !Right.isOneOf(tok::semi, tok::l_brace);
default:
break;
}
Expand Down
83 changes: 83 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25857,7 +25857,90 @@ TEST_F(FormatTest, RequiresClausesPositions) {
"}",
Style);

Style.RequiresClausePosition = FormatStyle::RCPS_OwnLineWithBrace;
Style.IndentRequiresClause = true;

verifyFormat("template <typename T>\n"
" requires(Foo<T> && std::trait<T>)\n"
"struct Bar;",
Style);

verifyFormat("template <typename T>\n"
" requires(Foo<T> && std::trait<T>)\n"
"class Bar {\n"
"public:\n"
" Bar(T t);\n"
" bool baz();\n"
"};",
Style);

verifyFormat(
"template <typename T>\n"
" requires requires(T &&t) {\n"
" typename T::I;\n"
" requires(F<typename T::I> && std::trait<typename T::I>);\n"
" }\n"
"Bar(T) -> Bar<typename T::I>;",
Style);

verifyFormat("template <typename T>\n"
" requires(Foo<T> && std::trait<T>)\n"
"constexpr T MyGlobal;",
Style);

verifyFormat("template <typename T>\n"
" requires Foo<T> && requires(T t) {\n"
" { t.baz() } -> std::same_as<bool>;\n"
" requires std::same_as<T::Factor, int>;\n"
" }\n"
"inline int bar(T t) {\n"
" return t.baz() ? T::Factor : 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
"inline int bar(T t)\n"
" requires Foo<T> && requires(T t) {\n"
" { t.baz() } -> std::same_as<bool>;\n"
" requires std::same_as<T::Factor, int>;\n"
" } {\n"
" return t.baz() ? T::Factor : 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
" requires F<T>\n"
"int bar(T t) {\n"
" return 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
"int bar(T t)\n"
" requires F<T> {\n"
" return 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
"int S::bar(T t) &&\n"
" requires F<T> {\n"
" return 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
"int bar(T t)\n"
" requires F<T>;",
Style);

verifyFormat("template <typename T>\n"
"int bar(T t)\n"
" requires F<T> {}",
Style);

Style.RequiresClausePosition = FormatStyle::RCPS_SingleLine;
Style.IndentRequiresClause = false;
verifyFormat("template <typename T> requires Foo<T> struct Bar {};\n"
"template <typename T> requires Foo<T> void bar() {}\n"
"template <typename T> void bar() requires Foo<T> {}\n"
Expand Down

0 comments on commit 4cf9a42

Please sign in to comment.