[PATCH] D113319: [clang-format] Improve require and concept handling
Arthur O'Dwyer via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 3 13:50:15 PST 2021
Quuxplusone added inline comments.
================
Comment at: clang/docs/ClangFormatStyleOptions.rst:3424
+ templates or between template and function delcarations. In case of
+ after the function delcaration it tries to stick to this.
+
----------------
`s/delca/decla/g`
`s/Preceeding/Preceding/g`
================
Comment at: clang/docs/ClangFormatStyleOptions.rst:3464-3483
+ * ``RCPS_TwoLines`` (in configuration: ``TwoLines``)
+ The clause always gets its own line, and the content of the clause go
+ into the next line with some indentation.
+
+ .. code-block:: c++
+
+ template<typename T>
----------------
This option strikes me as actively harmful; I think you should remove it from the PR completely. Nobody does this today and nobody should do it in the future either.
================
Comment at: clang/include/clang/Format/Format.h:2504-2505
- /// Indent the requires clause in a template
+ /// Indent the requires clause in a template, this only applies if the
+ /// ``requires`` is at the beginning of a line.
/// \code
----------------
Comma-splice. But I don't think you need to change this comment at all. It's obvious that "indent" applies only to constructs at the left side of the (logical) source line.
================
Comment at: clang/include/clang/Format/Format.h:3130-3136
+ /// \brief The position of the ``requires`` clause for class templates.
+ /// \version 14
+ RequiresClausePositionStyle RequiresClausePositionForClasses;
+
+ /// \brief The position of the ``requires`` clause for function templates.
+ /// \version 14
+ RequiresClausePositionStyle RequiresClausePositionForFunctions;
----------------
What about for variable templates? What about for alias templates? What about for deduction guides?
It makes sense to me to have //one// option for this. It doesn't make sense to have 2, 3, or 4. Having 5 feels insane. So, I think you should just have one option that applies consistently to all `requires`-clauses everywhere in the code.
================
Comment at: clang/lib/Format/Format.cpp:1213
+ // This is open for discussions! When will LLVM adapt C++20?
+ LLVMStyle.RequiresClausePositionForClasses = FormatStyle::RCPS_OwnLine;
+ LLVMStyle.RequiresClausePositionForFunctions = FormatStyle::RCPS_OwnLine;
----------------
HazardyKnusperkeks wrote:
> What are your opinions on that?
+1 `RequiresClausePosition=OwnLine`, but also `IndentRequires=true`.
================
Comment at: clang/unittests/Format/FormatTest.cpp:22288-22291
+ verifyFormat("template <typename T>\n"
+ "concept C = ((false || foo()) && C2<T>) || "
+ "(std::trait<T>::value && Baz) ||\n "
+ " sizeof(T) >= 6;");
----------------
Nit: I was initially very confused by the formatting here, until I realized that lines 22289 and 22290 are two lines //physically// but represent one single line in the //test case//. Strongly recommend eliminating the gratuitous line break.
================
Comment at: clang/unittests/Format/FormatTest.cpp:22374-22378
+ "template <typename T>\n"
+ "concept C = decltype([]() { return std::true_type{}; }())::value &&\n"
+ " requires(T t) {\n"
+ " t.bar();\n"
+ "} && sizeof(T) <= 8;");
----------------
This looks wrong. Current:
```
template <typename T>\n"
concept C = decltype([]() { return std::true_type{}; }())::value &&
requires(T t) {
t.bar();
} && sizeof(T) <= 8;
```
but should be:
```
template <typename T>\n"
concept C = decltype([]() { return std::true_type{}; }())::value &&
requires(T t) {
t.bar();
} && sizeof(T) <= 8;
```
(assuming that all the relevant indent-widths are set to `2`).
================
Comment at: clang/unittests/Format/FormatTest.cpp:22597
+ verifyFormat("template <std::semiregular F, std::semiregular... Args>\n"
+ "requires(std::invocable<F, std::invoke_result_t<Args>...>)\n"
+ "struct constant;",
----------------
Currently:
```
template <std::semiregular F, std::semiregular... Args>
requires(std::invocable<F, std::invoke_result_t<Args>...>)
struct constant;
```
Should be:
```
template <std::semiregular F, std::semiregular... Args>
requires (std::invocable<F, std::invoke_result_t<Args>...>)
struct constant;
```
(notice the extra single space). Add a TODO comment and ship it anyway?
================
Comment at: clang/unittests/Format/FormatTest.cpp:22643
verifyFormat("template <typename T>\n"
- "concept Context = Traits<typename T::traits_type> or\n"
- " Interface<typename T::interface_type> or\n"
- " Request<typename T::request_type> or\n"
- " Response<typename T::response_type> or\n"
- " ContextExtension<typename T::extension_type> or\n"
- " ::std::is_copy_constructable<T> or "
- "::std::is_move_constructable<T> or\n"
- " requires (T c) {\n"
- " { c.response; } -> Response;\n"
- "} or requires (T c) {\n"
- " { c.request; } -> Request;\n"
- "}\n",
+ "requires requires(T t) {\n"
+ " typename T::Bar;\n"
----------------
Data point: libc++ has a mix of `requires (T t) { }` and `requires(T t) { }`. Am I correct that clang-format is not yet smart enough to have a meaningful opinion about this particular whitespace?
I would bet that two years ago I was doing `requires(T t) { }`, but these days `requires (T t) { }` is much more natural to me.
================
Comment at: clang/unittests/Format/FormatTest.cpp:22715-22717
+ " typename T::Bar;\n"
+ " { t.bar() } -> std::same_as<bool>;\n"
+ "}\n"
----------------
HazardyKnusperkeks wrote:
> Should these lines be indented because requires is indented, or not?
> Should these lines be indented because requires is indented, or not?
================
Comment at: clang/unittests/Format/FormatTest.cpp:22715-22717
+ " typename T::Bar;\n"
+ " { t.bar() } -> std::same_as<bool>;\n"
+ "}\n"
----------------
Quuxplusone wrote:
> HazardyKnusperkeks wrote:
> > Should these lines be indented because requires is indented, or not?
> > Should these lines be indented because requires is indented, or not?
>
>
Yes.
```
template<typename T>
requires requires (T t) {
typename T::Bar;
{ t.bar(); } -> std::same_as<bool>;
}
class Foo {
};
```
(And in general it would be nice to simplify all of these test cases: lines 22707–22709, 22719–22721, etc. definitely aren't needed, and I even question whether line 22716 is germane to the point of this test case. Ideally, each test case will regression-test a single specific functionality or codepath, with no unnecessary digressions.)
================
Comment at: clang/unittests/Format/FormatTest.cpp:22812-22814
+ verifyFormat("template <std::semiregular F, std::semiregular... Args>\n"
+ " requires true struct constant;",
+ Style);
----------------
This result of `RequiresClausePosition=SingleLine, IndentRequires=true` feels bizarre to me. I'm 99% sure that `RequiresClausePosition=SingleLine` should implicitly disable `IndentRequires`, because `IndentRequires` applies only to requires-clauses at the beginning of a logical source line, and with `SingleLine` a requires-clause is //never// at the beginning of a logical source line.
The fact that this `requires` keyword accidentally fell at the beginning of a //physical// source line should be completely irrelevant to the algorithm.
We should test a progression that looks like
```
template<VeryLongName F> requires
true struct S;
template<VeryLongName123456789 F>
requires true struct S;
template<VeryLongName1234567890 F
> requires true struct S;
```
(But also, `SingleLine` is a bad style and it would be cool to just not support it at all. Nobody should use it.)
================
Comment at: clang/unittests/Format/FormatTest.cpp:23268-23270
+ return;
+ FormatStyle Style = getLLVMStyle();
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
----------------
(1) That `return` on line 23268 is sneaky. 😛
(2) LLVM style should certainly set `IndentRequires=true`, so this test shouldn't pass without some modification to line 23273.
================
Comment at: clang/unittests/Format/FormatTest.cpp:23441
+ "void func(T) {}");
+ verifyFormat("template <tyename T>\n"
+ "requires requires(T &&t) {\n"
----------------
`s/tyename/typename/g`
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D113319/new/
https://reviews.llvm.org/D113319
More information about the cfe-commits
mailing list