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

Previous Next

Package: cc-mode;

Reported by: Tau <tau <at> ea7aba.be>

Date: Mon, 8 Apr 2019 14:19:02 UTC

Severity: normal

Done: Alan Mackenzie <acm <at> muc.de>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 35194 in the body.
You can then email your comments to 35194 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to help-debbugs <at> gnu.org:
bug#35194; Package debbugs.gnu.org. (Mon, 08 Apr 2019 14:19:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Tau <tau <at> ea7aba.be>:
New bug report received and forwarded. Copy sent to help-debbugs <at> gnu.org. (Mon, 08 Apr 2019 14:19:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Tau <tau <at> ea7aba.be>
To: submit <at> debbugs.gnu.org
Subject: CC Mode 5.33.1 (C++//l); Indentation of C++ methods with
 ref-qualifiers is broken.
Date: Mon, 8 Apr 2019 15:13:25 +0300
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.

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";
  }

  void this_gets_properly_indented() const {
    std::cout << "without a ref-qualifier\n";
  }

  auto this_too() && -> void {
    std::cout << "rvalue ref; '->' notation\n";
  }

  auto this_breaks_again() -> T& {
				  return *this;
  }
};

int main() {
  T x;

  T().a_method();
  x.a_method();
}

Emacs  : GNU Emacs 26.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version
3.22.30) of 2018-07-05
Package: CC Mode 5.33.1 (C++//l)
Buffer Style: gnu
c-emacs-features: (pps-extended-state col-0-paren posix-char-classes
gen-string-delim gen-comment-delim syntax-properties 1-bit)

current state:
==============
(setq
 c-basic-offset 2
 c-comment-only-line-offset '(0 . 0)
 c-indent-comment-alist '((anchored-comment column . 0) (end-block
space . 1) (cpp-end-block space . 2))
 c-indent-comments-syntactically-p nil
 c-block-comment-prefix ""
 c-comment-prefix-regexp '((pike-mode . "//+!?\\|\\**") (awk-mode .
"#+") (other . "//+\\|\\**"))
 c-doc-comment-style '((java-mode . javadoc) (pike-mode . autodoc)
(c-mode . gtkdoc)) c-cleanup-list '(scope-operator)
 c-hanging-braces-alist '((substatement-open before after)
(arglist-cont-nonempty)) c-hanging-colons-alist nil
 c-hanging-semi&comma-criteria '(c-semi&comma-inside-parenlist)
 c-backslash-column 48
 c-backslash-max-column 72
 c-special-indent-hook '(c-gnu-impose-minimum)
 c-label-minimum-indentation 1
 c-offsets-alist '((inexpr-class . +)
		   (inexpr-statement . +)
		   (lambda-intro-cont . +)
		   (inlambda . c-lineup-inexpr-block)
		   (template-args-cont c-lineup-template-args +)
		   (incomposition . +)
		   (inmodule . +)
		   (innamespace . +)
		   (inextern-lang . +)
		   (composition-close . 0)
		   (module-close . 0)
		   (namespace-close . 0)
		   (extern-lang-close . 0)
		   (composition-open . 0)
		   (module-open . 0)
		   (namespace-open . 0)
		   (extern-lang-open . 0)
		   (objc-method-call-cont
		    c-lineup-ObjC-method-call-colons
		    c-lineup-ObjC-method-call
		    +
		    )
		   (objc-method-args-cont . c-lineup-ObjC-method-args)
		   (objc-method-intro . [0])
		   (friend . 0)
		   (cpp-define-intro c-lineup-cpp-define +)
		   (cpp-macro-cont . +)
		   (cpp-macro . [0])
		   (inclass . +)
		   (stream-op . c-lineup-streamop)
		   (arglist-cont-nonempty c-lineup-gcc-asm-reg
c-lineup-arglist) (arglist-cont c-lineup-gcc-asm-reg 0)
		   (comment-intro c-lineup-knr-region-comment
c-lineup-comment) (catch-clause . 0)
		   (else-clause . 0)
		   (do-while-closure . 0)
		   (access-label . -)
		   (case-label . 0)
		   (substatement . +)
		   (statement-case-intro . +)
		   (statement . 0)
		   (brace-entry-open . 0)
		   (brace-list-entry . c-lineup-under-anchor)
		   (brace-list-close . 0)
		   (block-close . 0)
		   (block-open . 0)
		   (inher-cont . c-lineup-multi-inher)
		   (inher-intro . +)
		   (member-init-cont . c-lineup-multi-inher)
		   (member-init-intro . +)
		   (annotation-var-cont . +)
		   (annotation-top-cont . 0)
		   (topmost-intro . 0)
		   (knr-argdecl . 0)
		   (func-decl-cont . +)
		   (inline-close . 0)
		   (class-close . 0)
		   (class-open . 0)
		   (defun-block-intro . +)
		   (defun-close . 0)
		   (defun-open . 0)
		   (c . c-lineup-C-comments)
		   (string . c-lineup-dont-change)
		   (topmost-intro-cont
		    first
		    c-lineup-topmost-intro-cont
		    c-lineup-gnu-DEFUN-intro-cont
		    )
		   (brace-list-intro .
c-lineup-arglist-intro-after-paren) (brace-list-open . +)
		   (inline-open . 0)
		   (arglist-close . c-lineup-arglist)
		   (arglist-intro . c-lineup-arglist-intro-after-paren)
		   (statement-cont . +)
		   (statement-case-open . +)
		   (label . 0)
		   (substatement-label . 0)
		   (substatement-open . +)
		   (knr-argdecl-intro . 5)
		   (statement-block-intro . +)
		   )
 c-buffer-is-cc-mode 'c++-mode
 c-tab-always-indent t
 c-syntactic-indentation t
 c-syntactic-indentation-in-macros t
 c-ignore-auto-fill '(string cpp code)
 c-auto-align-backslashes t
 c-backspace-function 'backward-delete-char-untabify
 c-delete-function 'delete-char
 c-electric-pound-behavior nil
 c-default-style '((java-mode . "java") (awk-mode . "awk") (other .
"gnu")) c-enable-xemacs-performance-kludge-p nil
 c-old-style-variable-behavior nil
 defun-prompt-regexp nil
 tab-width 8
 comment-column 32
 parse-sexp-ignore-comments t
 parse-sexp-lookup-properties t
 auto-fill-function nil
 comment-multi-line t
 comment-start-skip "\\(//+\\|/\\*+\\)\\s *"
 fill-prefix nil
 fill-column 70
 paragraph-start "[ 	]*\\(//+\\|\\**\\)[ 	]*$\\|^\f"
 adaptive-fill-mode t
 adaptive-fill-regexp
"[ 	]*\\(//+\\|\\**\\)[ 	]*\\([ 	]*\\([-–!|#%;>*·•‣⁃◦]+[ 	]*\\)*\\)" )





bug reassigned from package 'debbugs.gnu.org' to 'cc-mode'. Request was from Glenn Morris <rgm <at> gnu.org> to control <at> debbugs.gnu.org. (Mon, 08 Apr 2019 16:11:02 GMT) Full text and rfc822 format available.

Information forwarded to bug-cc-mode <at> gnu.org:
bug#35194; Package cc-mode. (Mon, 08 Apr 2019 16:19:02 GMT) Full text and rfc822 format available.

Message #10 received at 35194 <at> debbugs.gnu.org (full text, mbox):

From: Glenn Morris <rgm <at> gnu.org>
To: 35194 <at> debbugs.gnu.org
Cc: Tau <tau <at> ea7aba.be>
Subject: Re: bug#35194: CC Mode 5.33.1 (C++//l);
 Indentation of C++ methods with ref-qualifiers is broken.
Date: Mon, 08 Apr 2019 12:18:11 -0400
Report reassigned to cc-mode.

(It seems that cc-mode users not infrequently report bugs from mail
clients that don't support X- headers. So I suggest also putting "Package:
cc-mode" at the start of the message body in c-submit-bug-report.)


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.
>
> 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";
>   }
>
>   void this_gets_properly_indented() const {
>     std::cout << "without a ref-qualifier\n";
>   }
>
>   auto this_too() && -> void {
>     std::cout << "rvalue ref; '->' notation\n";
>   }
>
>   auto this_breaks_again() -> T& {
> 				  return *this;
>   }
> };
>
> int main() {
>   T x;
>
>   T().a_method();
>   x.a_method();
> }
>
> Emacs  : GNU Emacs 26.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version
> 3.22.30) of 2018-07-05
> Package: CC Mode 5.33.1 (C++//l)
> Buffer Style: gnu
> c-emacs-features: (pps-extended-state col-0-paren posix-char-classes
> gen-string-delim gen-comment-delim syntax-properties 1-bit)
>
> current state:
> ==============
> (setq
>  c-basic-offset 2
>  c-comment-only-line-offset '(0 . 0)
>  c-indent-comment-alist '((anchored-comment column . 0) (end-block
> space . 1) (cpp-end-block space . 2))
>  c-indent-comments-syntactically-p nil
>  c-block-comment-prefix ""
>  c-comment-prefix-regexp '((pike-mode . "//+!?\\|\\**") (awk-mode .
> "#+") (other . "//+\\|\\**"))
>  c-doc-comment-style '((java-mode . javadoc) (pike-mode . autodoc)
> (c-mode . gtkdoc)) c-cleanup-list '(scope-operator)
>  c-hanging-braces-alist '((substatement-open before after)
> (arglist-cont-nonempty)) c-hanging-colons-alist nil
>  c-hanging-semi&comma-criteria '(c-semi&comma-inside-parenlist)
>  c-backslash-column 48
>  c-backslash-max-column 72
>  c-special-indent-hook '(c-gnu-impose-minimum)
>  c-label-minimum-indentation 1
>  c-offsets-alist '((inexpr-class . +)
> 		   (inexpr-statement . +)
> 		   (lambda-intro-cont . +)
> 		   (inlambda . c-lineup-inexpr-block)
> 		   (template-args-cont c-lineup-template-args +)
> 		   (incomposition . +)
> 		   (inmodule . +)
> 		   (innamespace . +)
> 		   (inextern-lang . +)
> 		   (composition-close . 0)
> 		   (module-close . 0)
> 		   (namespace-close . 0)
> 		   (extern-lang-close . 0)
> 		   (composition-open . 0)
> 		   (module-open . 0)
> 		   (namespace-open . 0)
> 		   (extern-lang-open . 0)
> 		   (objc-method-call-cont
> 		    c-lineup-ObjC-method-call-colons
> 		    c-lineup-ObjC-method-call
> 		    +
> 		    )
> 		   (objc-method-args-cont . c-lineup-ObjC-method-args)
> 		   (objc-method-intro . [0])
> 		   (friend . 0)
> 		   (cpp-define-intro c-lineup-cpp-define +)
> 		   (cpp-macro-cont . +)
> 		   (cpp-macro . [0])
> 		   (inclass . +)
> 		   (stream-op . c-lineup-streamop)
> 		   (arglist-cont-nonempty c-lineup-gcc-asm-reg
> c-lineup-arglist) (arglist-cont c-lineup-gcc-asm-reg 0)
> 		   (comment-intro c-lineup-knr-region-comment
> c-lineup-comment) (catch-clause . 0)
> 		   (else-clause . 0)
> 		   (do-while-closure . 0)
> 		   (access-label . -)
> 		   (case-label . 0)
> 		   (substatement . +)
> 		   (statement-case-intro . +)
> 		   (statement . 0)
> 		   (brace-entry-open . 0)
> 		   (brace-list-entry . c-lineup-under-anchor)
> 		   (brace-list-close . 0)
> 		   (block-close . 0)
> 		   (block-open . 0)
> 		   (inher-cont . c-lineup-multi-inher)
> 		   (inher-intro . +)
> 		   (member-init-cont . c-lineup-multi-inher)
> 		   (member-init-intro . +)
> 		   (annotation-var-cont . +)
> 		   (annotation-top-cont . 0)
> 		   (topmost-intro . 0)
> 		   (knr-argdecl . 0)
> 		   (func-decl-cont . +)
> 		   (inline-close . 0)
> 		   (class-close . 0)
> 		   (class-open . 0)
> 		   (defun-block-intro . +)
> 		   (defun-close . 0)
> 		   (defun-open . 0)
> 		   (c . c-lineup-C-comments)
> 		   (string . c-lineup-dont-change)
> 		   (topmost-intro-cont
> 		    first
> 		    c-lineup-topmost-intro-cont
> 		    c-lineup-gnu-DEFUN-intro-cont
> 		    )
> 		   (brace-list-intro .
> c-lineup-arglist-intro-after-paren) (brace-list-open . +)
> 		   (inline-open . 0)
> 		   (arglist-close . c-lineup-arglist)
> 		   (arglist-intro . c-lineup-arglist-intro-after-paren)
> 		   (statement-cont . +)
> 		   (statement-case-open . +)
> 		   (label . 0)
> 		   (substatement-label . 0)
> 		   (substatement-open . +)
> 		   (knr-argdecl-intro . 5)
> 		   (statement-block-intro . +)
> 		   )
>  c-buffer-is-cc-mode 'c++-mode
>  c-tab-always-indent t
>  c-syntactic-indentation t
>  c-syntactic-indentation-in-macros t
>  c-ignore-auto-fill '(string cpp code)
>  c-auto-align-backslashes t
>  c-backspace-function 'backward-delete-char-untabify
>  c-delete-function 'delete-char
>  c-electric-pound-behavior nil
>  c-default-style '((java-mode . "java") (awk-mode . "awk") (other .
> "gnu")) c-enable-xemacs-performance-kludge-p nil
>  c-old-style-variable-behavior nil
>  defun-prompt-regexp nil
>  tab-width 8
>  comment-column 32
>  parse-sexp-ignore-comments t
>  parse-sexp-lookup-properties t
>  auto-fill-function nil
>  comment-multi-line t
>  comment-start-skip "\\(//+\\|/\\*+\\)\\s *"
>  fill-prefix nil
>  fill-column 70
>  paragraph-start "[ 	]*\\(//+\\|\\**\\)[ 	]*$\\|^\f"
>  adaptive-fill-mode t
>  adaptive-fill-regexp
> "[ 	]*\\(//+\\|\\**\\)[ 	]*\\([ 	]*\\([-–!|#%;>*·•‣⁃◦]+[ 	]*\\)*\\)" )




Information forwarded to bug-cc-mode <at> gnu.org:
bug#35194; Package cc-mode. (Fri, 12 Apr 2019 13:06:01 GMT) Full text and rfc822 format available.

Message #13 received at 35194 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: Tau <tau <at> ea7aba.be>
Cc: 35194 <at> debbugs.gnu.org
Subject: Re: bug#35194: CC Mode 5.33.1 (C++//l); Indentation of C++ methods
 with ref-qualifiers is broken.
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).




Information forwarded to bug-cc-mode <at> gnu.org:
bug#35194; Package cc-mode. (Fri, 12 Apr 2019 16:29:02 GMT) Full text and rfc822 format available.

Message #16 received at 35194 <at> debbugs.gnu.org (full text, mbox):

From: Tau <tau <at> ea7aba.be>
To: Alan Mackenzie <acm <at> muc.de>
Cc: 35194 <at> debbugs.gnu.org
Subject: Re: bug#35194: CC Mode 5.33.1 (C++//l); Indentation of C++ methods
 with ref-qualifiers is broken.
Date: Fri, 12 Apr 2019 19:27:59 +0300
On Fri, 12 Apr 2019 13:04:58 +0000
Alan Mackenzie wrote:
> 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.

Hi, Alan. Awesome job! I have applied the patch and tested it on a few
C++ files. Everything looks good now.




Reply sent to Alan Mackenzie <acm <at> muc.de>:
You have taken responsibility. (Fri, 12 Apr 2019 20:20:02 GMT) Full text and rfc822 format available.

Notification sent to Tau <tau <at> ea7aba.be>:
bug acknowledged by developer. (Fri, 12 Apr 2019 20:20:02 GMT) Full text and rfc822 format available.

Message #21 received at 35194-done <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: Tau <tau <at> ea7aba.be>
Cc: 35194-done <at> debbugs.gnu.org
Subject: Re: bug#35194: CC Mode 5.33.1 (C++//l); Indentation of C++ methods
 with ref-qualifiers is broken.
Date: Fri, 12 Apr 2019 20:19:45 +0000
Hello again, Tau.

On Fri, Apr 12, 2019 at 19:27:59 +0300, Tau wrote:
> On Fri, 12 Apr 2019 13:04:58 +0000
> Alan Mackenzie wrote:
> > 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.

> Hi, Alan. Awesome job! I have applied the patch and tested it on a few
> C++ files. Everything looks good now.

Thanks for the testing!

Just as a matter of interest, Emacs 26.2 was released this afternoon
(European time).

I've committed the patch to the Emacs master branch, and standalone CC
Mode.  I'm closing the bug.

-- 
Alan Mackenzie (Nuremberg, Germany).




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Sat, 11 May 2019 11:24:05 GMT) Full text and rfc822 format available.

This bug report was last modified 4 years and 351 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.