Subject: Re: bug#22486: CC Mode 5.33 (C++/l); Bad indentation in a hideous C++ struct

From: Michael Welsh Duggan <[email-masked]>
Date: Fri, 05 Feb 2016 14:01:52 -0500

Alan Mackenzie <[email-masked]> writes:

> Hello, Michael.
>
> On Thu, Jan 28, 2016 at 03:37:07PM -0500, Michael Welsh Duggan wrote:
>> In the following C++ snippet:
>
>> template <typename Arg, typename... Args>
>> struct ArgListMatcher<Arg, Args...> :
>>     ArgListMatcher<MakeIndices<CountRef<Arg>::value>,
>>                    MakeIndices<sizeof...(Args) - CountRef<Arg>::value, CountRef<Arg>::value>,
>>                        Arg, Args...>    <============================
>> {
>>   using Parent = ArgListMatcher<
>>     MakeIndices<CountRef<Arg>::value>,
>>     MakeIndices<sizeof...(Args) + 1 - CountRef<Arg>::value,
>>                 CountRef<Arg>::value>, Arg, Args...>;
>>   using Parent::ArgListMatcher;
>> };
>
>> Starting with "template" as the first line, the lines' contexts are
>> listed as:
>
>> syntax: ((topmost-intro 1)), indent: 0
>> syntax: ((topmost-intro-cont 1)), indent: 0
>> syntax: ((inher-intro 1)), indent: 4
>> syntax: ((template-args-cont 1 99)), indent: 19
>> syntax: ((member-init-intro 154)), indent: 23  <=====================
>> syntax: ((defun-open 1)), indent: 0
>
>> All of these seem reasonable save for member-init-intro, which I
>> expected to be template-args-cont.
>
> Also noticeable here is that some of the <...> pairs are not marked with
> paren syntax by CC Mode.  Further analysis shows that these are the pairs
> with arithmetic operators (- and +) inside them.
>
> If the - operator in line 4 is replaced by a comma, then line 5 gets
> correctly recognised as template-args-cont.  (No, I'm not suggesting this
> as a workaround.  :-)

Yeah.  You're going to see arithmetic operators in template parameter
lists a lot more due to the way variadic templates are handled.  (They
basically are type-matched recursively via partial template
specialization.)

> CC Mode currently uses the presence of things like + and - and other
> things which "can't [couldn't] be inside templates" as a heuristic to
> distingish template delimiters from less-than and greater-than.  [On a
> personal note, it seems like the designers of C++ are lacking taste; they
> just don't know where to stop.  C++'s syntax is ambiguous and highly
> context dependent.  It seems like those designers are determined that
> only editors attached to a compiler's syntax tree are to be practical for
> C++.]

No arguments with your parenthetical.  Though I expect some of the C++
designers are the types to use vi and manually indent everything to
their taste.

> Would it, perhaps, be feasible to detect the ... operator as an
> indication that +, -, (?etc.) are permissible inside template delimiters?
> Is it true that ... only exists inside either a variadic parameter list
> or template delimiters?

Nope, sorry.  Functions can use the ... as well.  Here's an example,
compilable with g++ -std=c++11:

  #include <iostream>
  
  int sum()
  {
      return 0;
  }
  
  template<typename... T>
  int sum(int first, T... rest)
  {
      return first + sum(rest...);
  }
  
  int sum2()
  {
      return 0;
  }
  
  template<typename... T>
  int sum2(int first, T... rest)
  {
      return first + sum2(1 + rest...);
  }
  
  int main()
  {
      std::cout << sum(1, 2, 3, 4) << std::endl;  /* outputs 10 */
      std::cout << sum2(1, 2, 3, 4) << std::endl; /* outputs 16 */
  }

sum(1, 2, 3, 4) turns into (1 + 2 + 3 + 4 + 0), whereas sum2(1, 2, 3, 4)
turns into (1 + 3 + 5 + 7 + 0).  This is because of the sum(rest...) and
sum2(1 + rest...) expansions.

sum(rest...) turns into sum(rest0, rest1, ..., restn)
sum(1 + rest...) turns into sum (1 + rest0, 1 + rest1, ..., 1 + restn)

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