Subject: bug#62386: CC Mode 5.35.2 (C++//l); C++ concept indentation

From: Michael Welsh Duggan <[email-masked]>
Date: Fri, 07 Apr 2023 12:00:13 -0400

Alan Mackenzie <[email-masked]> writes:

> Hello, Michael.
>
> On Tue, Mar 28, 2023 at 10:45:54 -0400, Michael Welsh Duggan wrote:
>> 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();
>
> I think I've now got these corrected.  The coding was much more difficult
> than I'd anticipated, with me spending several days in total confusion.
> The last thing which threw me off was the realisation that the
> expressions in the concept clause need not be "primary" expressions, i.e.
> something like !foo<T> is valid.  This is not the case with requires
> clauses, where only "primary" expressions are permitted.
>
>> 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.
>
> Thanks, you've just got to love the C++ Standards Committee.  ;-)
>
>> https://en.cppreference.com/w/cpp/language/constraints
>> https://en.cppreference.com/w/cpp/language/requires
>
> Thanks again, I've had those pages in my web browser cache for quite some
> time, now.
>
> Here's the latest version of the patch.  Please do the usual with it, and
> let me know how it goes.  Thanks!

Much, much better!  I have only one niggling nit left, and this one
doesn't bother me nearly as much as the others.  The nit is that opening
parentheses don't seem to open up a new indention context anymore.
(That's my internal mental terminology, not necessary what it used by
cc-mode.)

Before:

  template <typename T>
  requires (OctetLike<T>
            || (std::rank_v<T> == 1 && std::extent_v<T> == 0
                && OctetLike<std::remove_extent_t<T>>))
  Chunk(std::shared_ptr<T> const & p, length_t size)
  : data_{p, octet_cast(p.get())},
    size_{size}
  {}

After:

  template <typename T>
  requires (OctetLike<T>
    || (std::rank_v<T> == 1 && std::extent_v<T> == 0
    && OctetLike<std::remove_extent_t<T>>))
  Chunk(std::shared_ptr<T> const & p, length_t size)
    : data_{p, octet_cast(p.get())},
      size_{size}
  {}

-- 
Michael Welsh Duggan
([email-masked])