Subject: bug#51692: 29.0.50; High CPU in c++ mode. Type finder?

From: Alan Mackenzie <[email-masked]>
Date: Thu, 11 Nov 2021 20:00:43 +0000

Hello, David, Zhiwei, Yuri, and Lars.

On Mon, Nov 08, 2021 at 13:00:06 -0600, David Koppelman wrote:

> Load the attached file into a buffer:

> ./src/emacs --no-init d.cc

> Emacs will use 100% CPU on a core while the buffer is visible. CPU usage
> goes to normal when switching to another buffer. The attached file is a
> reduced version of a much larger file. (The larger file experiences the
> high CPU usage only while a certain portion of the code is visible.)

Yes, there is a bug here.  CC Mode is expected to use a high amount of
CPU time (but not 100%) for a few seconds after starting C (etc.) Mode,
or for a few minutes after starting Emacs when there's a desktop with a
lot of CC Mode files in it.

However, with C++ files (and likely Java files, too), a problem with
templates caused this 100% usage.

I'm hoping the following patch will fix it.  Could you (plural) please
apply this patch to the Emacs master branch, byte compile the two
amended files, then load the fixed CC Mode into your Emacs.  Then please
try it out with your real files.  (If anybody wants any help with the
patching or byte compiling, feel free to send me personal email.)

Then please report back to the bug list confirming that the bug is
fixed, or telling me what's still not right.

Thank you!

diff -r 05fd00cb5937 cc-engine.el
--- a/cc-engine.el	Sat Oct 30 15:57:26 2021 +0000
+++ b/cc-engine.el	Thu Nov 11 18:47:47 2021 +0000
@@ -6838,6 +6838,13 @@
 (defvar c-found-types nil)
 (make-variable-buffer-local 'c-found-types)
 
+;; Dynamically bound variable that instructs `c-forward-type' to
+;; record the ranges of types that only are found.  Behaves otherwise
+;; like `c-record-type-identifiers'.  Also when this variable is non-nil,
+;; `c-fontify-new-found-type' doesn't get called (yet) for the purported
+;; type.
+(defvar c-record-found-types nil)
+
 (defsubst c-clear-found-types ()
   ;; Clears `c-found-types'.
   (setq c-found-types
@@ -6851,7 +6858,10 @@
   (let ((type (c-syntactic-content from to c-recognize-<>-arglists)))
     (unless (gethash type c-found-types)
       (puthash type t c-found-types)
-      (when (and (eq (string-match c-symbol-key type) 0)
+      (when (and (not c-record-found-types) ; Only call `c-fontify-new-fount-type'
+					; when we haven't "bound" c-found-types
+					; to itself in c-forward-<>-arglist.
+		 (eq (string-match c-symbol-key type) 0)
 		 (eq (match-end 0) (length type)))
 	(c-fontify-new-found-type type)))))
 
@@ -8248,11 +8258,6 @@
 	   (setq c-record-ref-identifiers
 		 (cons range c-record-ref-identifiers))))))
 
-;; Dynamically bound variable that instructs `c-forward-type' to
-;; record the ranges of types that only are found.  Behaves otherwise
-;; like `c-record-type-identifiers'.
-(defvar c-record-found-types nil)
-
 (defmacro c-forward-keyword-prefixed-id (type)
   ;; Used internally in `c-forward-keyword-clause' to move forward
   ;; over a type (if TYPE is 'type) or a name (otherwise) which
@@ -8480,6 +8485,11 @@
 		(c-forward-<>-arglist-recur all-types)))
 	(progn
 	  (when (consp c-record-found-types)
+	    (let ((cur c-record-found-types))
+	      (while (consp (car-safe cur))
+		(c-fontify-new-found-type
+		 (buffer-substring-no-properties (caar cur) (cdar cur)))
+		(setq cur (cdr cur))))
 	    (setq c-record-type-identifiers
 		  ;; `nconc' doesn't mind that the tail of
 		  ;; `c-record-found-types' is t.
@@ -9203,6 +9213,12 @@
 
 		(when (and (eq res t)
 			   (consp c-record-found-types))
+		  ;; Cause the confirmed types to get fontified.
+		  (let ((cur c-record-found-types))
+		    (while (consp (car-safe cur))
+		      (c-fontify-new-found-type
+		       (buffer-substring-no-properties (caar cur) (cdar cur)))
+		      (setq cur (cdr cur))))
 		  ;; Merge in the ranges of any types found by the second
 		  ;; `c-forward-type'.
 		  (setq c-record-type-identifiers
diff -r 05fd00cb5937 cc-fonts.el
--- a/cc-fonts.el	Sat Oct 30 15:57:26 2021 +0000
+++ b/cc-fonts.el	Thu Nov 11 18:47:47 2021 +0000
@@ -105,6 +105,7 @@
 (cc-bytecomp-defun c-font-lock-objc-method)
 (cc-bytecomp-defun c-font-lock-invalid-string)
 (cc-bytecomp-defun c-before-context-fl-expand-region)
+(cc-bytecomp-defun c-font-lock-fontify-region)
 
 
 ;; Note that font-lock in XEmacs doesn't expand face names as
@@ -2431,6 +2432,7 @@
 (defun c-force-redisplay (start end)
   ;; Force redisplay immediately.  This assumes `font-lock-support-mode' is
   ;; 'jit-lock-mode.  Set the variable `c-re-redisplay-timer' to nil.
+  (save-excursion (c-font-lock-fontify-region start end))
   (jit-lock-force-redisplay (copy-marker start) (copy-marker end))
   (setq c-re-redisplay-timer nil))
 
@@ -2458,7 +2460,6 @@
 	    (dolist (win-boundary window-boundaries)
 	      (when (and (< (match-beginning 0) (cdr win-boundary))
 			 (> (match-end 0) (car win-boundary))
-			 (c-get-char-property (match-beginning 0) 'fontified)
 			 (not c-re-redisplay-timer))
 		(setq c-re-redisplay-timer
 		      (run-with-timer 0 nil #'c-force-redisplay

-- 
Alan Mackenzie (Nuremberg, Germany).