Subject: bug#52863: CC Mode 5.35.1 (ObjC//l); CC mode locks up on nsterm.m

From: Alan Mackenzie <[email-masked]>
Date: Thu, 30 Dec 2021 09:19:20 +0000

Hello, Po.

Thanks for the bug report.

On Wed, Dec 29, 2021 at 10:32:30 +0800, Po Lu wrote:
> Package: cc-mode

> In emacs -Q, open src/nsterm.m on master, then say:

>   M-g g 750 RET M-v

> Emacs will proceeed to freeze for a while.  If a second M-v is pressed
> after that freeze finishes, Emacs gets hopelessly wedged.  This seems to
> be a variant of a problem I reported earlier, but must be caused by
> something different, seeing as the type finder code has been removed.

It is indeed a variant of the problem you reported on 2021-11-28.  What
is happening is that CC Mode is "finding" the type "margins", which
isn't a type at all.  But it's entering this "type" into c-found-types
and refontifying it throughout the buffer, only later to remove that
"type" from the list.  When the buffer position is around L710, this
also causes rapid redrawing of the screen.

The following patch should fix the problem.  Would you try it out,
please, and confirm that it actually fixes the bug.  Thanks!

diff -r 99fc8bc9358e cc-engine.el
--- a/cc-engine.el	Wed Dec 29 18:50:38 2021 +0000
+++ b/cc-engine.el	Thu Dec 30 09:11:17 2021 +0000
@@ -9954,6 +9954,10 @@
 	;; Set when we have encountered a keyword (e.g. "extern") which
 	;; causes the following declaration to be treated as though top-level.
 	make-top
+	;; A list of found types in this declaration.  This is an association
+	;; list, the car being the buffer position, the cdr being the
+	;; identifier.
+	found-type-list
 	;; Save `c-record-type-identifiers' and
 	;; `c-record-ref-identifiers' since ranges are recorded
 	;; speculatively and should be thrown away if it turns out
@@ -10023,10 +10027,17 @@
 		;; If the previous identifier is a found type we
 		;; record it as a real one; it might be some sort of
 		;; alias for a prefix like "unsigned".
-		(save-excursion
-		  (goto-char type-start)
-		  (let ((c-promote-possible-types t))
-		    (c-forward-type))))
+		;; We postpone entering the new found type into c-found-types
+		;; until we are sure of it, thus preventing rapid alternation
+		;; of the fontification of the token throughout the buffer.
+		(push (cons type-start
+			    (buffer-substring-no-properties
+			     type-start
+			     (save-excursion
+			       (goto-char type-start)
+			       (c-end-of-token)
+			       (point))))
+		      found-type-list))
 
 	      ;; Signal a type declaration for "struct foo {".
 	      (when (and backup-at-type-decl
@@ -10272,13 +10283,10 @@
 		   (when (eq at-type 'found)
 		     ;; Remove the ostensible type from the found types list.
 		     (when type-start
-		       (c-unfind-type
-			(buffer-substring-no-properties
-			 type-start
-			 (save-excursion
-			   (goto-char type-start)
-			   (c-end-of-token)
-			   (point)))))
+		       (let ((discard-t (assq type-start found-type-list)))
+			 (when discard-t
+			   (setq found-type-list
+				 (remq discard-t found-type-list)))))
 		     t))
 	       ;; The token which we assumed to be a type is actually the
 	       ;; identifier, and we have no explicit type.
@@ -10892,6 +10900,14 @@
 	;; interactive refontification.
 	(c-put-c-type-property (point) 'c-decl-arg-start))
 
+      ;; Enter all the found types into `c-found-types'.
+      (when found-type-list
+	(save-excursion
+	  (let ((c-promote-possible-types t))
+	    (dolist (ft found-type-list)
+	      (goto-char (car ft))
+	      (c-forward-type)))))
+
       ;; Record the type's coordinates in `c-record-type-identifiers' for
       ;; later fontification.
       (when (and c-record-type-identifiers at-type ;; (not (eq at-type t))

> Thanks.

> Emacs  : GNU Emacs 29.0.50 (build 472, x86_64-pc-linux-gnu, GTK+ Version 3.24.30, cairo version 1.17.4)
>  of 2021-12-29
> Package: CC Mode 5.35.1 (ObjC//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)

[ .... ]

-- 
Alan Mackenzie (Nuremberg, Germany).