bug#62386: CC Mode 5.35.2 (C++//l); C++ concept indentation
Michael Welsh Duggan <[email protected]> Tue, 28 Mar 2023 10:45:54 -0400
| Newsgroups | gmane.emacs.cc-mode.general |
|---|---|
| Message-ID | <[email protected]> |
Alan Mackenzie <[email protected]> writes: > Hello, Michael. > > On Fri, Mar 24, 2023 at 14:58:28 -0400, Michael Welsh Duggan wrote: >> Alan Mackenzie <[email protected]> writes: > >> > On Wed, Mar 22, 2023 at 11:58:32 -0400, Michael Welsh Duggan wrote: >> >> Package: cc-mode > >> >> Given a concept definition like: > >> >> template <typename T> >> >> concept Foo = >> >> Bar<T> >> >> && requires (T t) { >> >> { t + t } -> std::same_as<T>; >> >> } >> >> && something_else; > >> >> This is how it actually indents in cc-mode: > >> >> template <typename T> >> >> concept Foo = >> >> Bar<T> >> >> && requires (T t) { >> >> { t + t } -> std::same_as<T>; >> >> } >> >> && something_else; > >> >> I would expect "Bar<T>" to be statement-cont, but it is >> >> topmost-intro-cont instead. The indentation of "{ t + t }" isn't offset >> >> properly with respect to the "requires" clause, and the closing brace is >> >> way out of line. > >> [...] > >> > I've made an attempt to improve the indentation of code like your test >> > case. Would you please try it out and let me know how well it solves >> > the problem. Thanks! > >> Better for that test case and a few others. Here's a few test outliers >> as indented by cc: > > OK. It is apparent that the former "approximate" solution for concepts > and requireses wasn't adequate, and that deeper, more rigorous analysis > was needed. I've attempted this, and the results are in the patch in > this post. They mostly indent your test cases to very close to how you'd > like them to be. > > There's one test in particular that is slightly different, namely: > > [ .... ] > >> template <typename T> >> requires >> (requires (T t) { ++t; } >> && Baz<T>) >> int foo(); > > Here, I haven't managed to align the && under the requires. Rather it is > aligned underneath the (. CC Mode currently has no syntactic symbols for > this kind of alignment, but there might be one or two line-up functions > which could do the trick. (I haven't actually searched for one). > >> The latter of these is especially interesting because TAB on the "&& >> Baz<T>)" section causes an "End of buffer" signal. > > I never found out why this was happening. It's not happening any more. > > Here's the patch. Please try it out on your real code, and let me know > how well it solves the bug. Thanks! Found one strange real code case and one very strange constructed test case: class Chunk { template <typename T, typename D> requires (OctetLike<T> || (std::rank_v<T> == 1 && OctetLike<std::remove_extent_t<T>>)) Chunk(std::unique_ptr<T, D> && p, length_t size) : size_{size} { auto ptr = p.get(); data_ = {std::shared_ptr<T>{std::move(p)}, octet_cast(ptr)}; } }; The case above comes from some actual code I have been writing. The strange bit is that the Chunk constructor is indented once more than intended. template <typename T> requires requires (T t) { { ++t; } } && std::is_integral<T> int foo(); This has a few problems with it. The "{ ++t; }" should be indented with respect to the "requires (T t)" portion. The "&& std::is_integral<T>" should be at the same level as that requires. And "int foo()" is indented one level too far. Just in case you didn't know, in this latter case, the first "requires" introduces an associated constraint, and the second evaluates a requirement as a requires expression. https://en.cppreference.com/w/cpp/language/constraints https://en.cppreference.com/w/cpp/language/requires -- Michael Welsh Duggan ([email protected])