Subject: bug#35194: CC Mode 5.33.1 (C++//l); Indentation of C++ methods with ref-qualifiers is broken.

From: Alan Mackenzie <[email-masked]>
Date: Fri, 12 Apr 2019 13:04:58 +0000

Hello, Tau.

Thanks for taking the trouble to report this bug (or lack of a feature),
and thanks even more for cutting the test case down to an easily usable
minimum, and also thanks for the C-c C-b CC Mode configuration dump.

On Mon, Apr 08, 2019 at 15:13:25 +0300, Tau wrote:
> Methods with ref-qualifiers (& and &&) seem to get indented with
> "brace-list-intro" which, as I understand it, is used for
> initializer lists and not code blocks. It is set to
> "c-lineup-arglist-intro-after-paren" in GNU style which is the
> default.

Yes.  brace-list-info is wrong, these lines should return
defun-block-intro.

> Functions that use the auto syntax for return types and return
> a reference are affected as well.

> // Example of incorrect indentation in a program:

> #include <iostream>

> struct T {
>   void a_method() && {
> 		      std::cout << "rvalue ref\n";
>   }

>   void a_method() const& {
> 			  std::cout << "lvalue const ref\n";
>   }

[ .... ]

Would you please apply the patch below (which should apply cleanly to the
Emacs 26.1 sources), byte-compile cc-engine.el, and try it out.  Then
please either confirm to me that it fixes the problem, or say what is
still not right.  (Feel free to send me private email if you want any
help in applying the patch or byte-compiling the file.)

Unfortunately, this isn't an "important enough" bug actually to get
fixed in the Emacs-26 release branch.  It will be committed to the
master branch, which will eventually be released as Emacs 27.1.  So
please keep the patch, so that you can apply it to your copy of Emacs
26.2 which is due to be released "very soon".

Here's the patch:

diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 965886727d..e58a988a48 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -10446,7 +10446,8 @@ c-looking-at-or-maybe-in-bracelist
 		      (eq (char-after) ?\())
 		 (setq braceassignp 'c++-noassign
 		       in-paren 'in-paren))
-		((looking-at c-pre-id-bracelist-key))
+		((looking-at c-pre-id-bracelist-key)
+		 (setq braceassignp nil))
 		((looking-at c-return-key))
 		((and (looking-at c-symbol-start)
 		      (not (looking-at c-keywords-regexp)))
@@ -10488,6 +10489,8 @@ c-looking-at-or-maybe-in-bracelist
 
       (setq pos (point))
       (cond
+       ((not braceassignp)
+	nil)
        ((and after-type-id-pos
 	     (goto-char after-type-id-pos)
 	     (setq res (c-back-over-member-initializers))
@@ -10558,9 +10561,15 @@ c-looking-at-or-maybe-in-bracelist
 				     ))))
 			   nil)
 			  (t t))))))
-	  (if (and (eq braceassignp 'dontknow)
-		   (/= (c-backward-token-2 1 t lim) 0))
-	      (setq braceassignp nil)))
+	  (when (eq braceassignp 'dontknow)
+	    (cond ((and
+		    (not (eq (char-after) ?,))
+		    (save-excursion
+		      (c-backward-syntactic-ws)
+		      (eq (char-before) ?})))
+		   (setq braceassignp nil))
+		  ((/= (c-backward-token-2 1 t lim) 0)
+		   (setq braceassignp nil)))))
 
 	(cond
 	 (braceassignp
@@ -10592,9 +10601,14 @@ c-looking-at-or-maybe-in-bracelist
 		    (and (consp res)
 			 (eq (car res) after-type-id-pos))))))
 	  (cons bufpos (or in-paren inexpr-brace-list)))
-	 ((eq (char-after) ?\;)
-	  ;; Brace lists can't contain a semicolon, so we're done.
-	  ;; (setq containing-sexp nil)
+	 ((or (eq (char-after) ?\;)
+	      ;; Brace lists can't contain a semicolon, so we're done.
+	      (save-excursion
+		(c-backward-syntactic-ws)
+		(eq (char-before) ?}))
+	      ;; They also can't contain a bare }, which is probably the end
+	      ;; of a function.
+	      )
 	  nil)
 	 ((and (setq macro-start (point))
 	       (c-forward-to-cpp-define-body)

-- 
Alan Mackenzie (Nuremberg, Germany).