Subject: Re: bug#56841: Emacs-28 C Mode: Fontification errors when arglist closing ) is on next line

From: Bill Sacks <[email-masked]>
Date: Mon, 22 Aug 2022 10:08:48 -0600

Thank you very much for this fix, Alan. I have now tested it both with 
my test case and in more realistic code, and it seems to fix the issues 
I was encountering – thank you!

Sorry for the delay on getting back to you about this.

Bill

Alan Mackenzie wrote on 8/2/22 1:30 PM:
> Hello again, Bill.
>
> On Sat, Jul 30, 2022 at 17:14:43 +0300, Eli Zaretskii wrote:
>>> Cc: Bill Sacks <[email-masked]>
>>> Date: Sat, 30 Jul 2022 13:05:24 +0000
>>> From: Alan Mackenzie <[email-masked]>
>>> 1. Start emacs -Q.
>>> 2. Insert the following file in C Mode:
>>> void myfunc(
>>>    ) {
>>> }
>>> 3. In line 2 (the first blank line) type "<TAB>int somevar".
>>> 4. Note that somevar is not fontified.  This is a bug, given that the
>>>    arglist to myfunc is terminated with a ) on line 3.
>>> 5. Do something (e.g. typing M-x) to cause a redisplay.  somevar gets
>>>    its correct face.
>>> 6. Note that any insertion or deletion in L2 causes somevar to lose its
>>>    fontification.  This is a bug.
>>> 7. (After 6).  Move point onto somevar and do C-u C-x =.  This shows
>>>    that the face text property is set on the character despite the face
>>>    not appearing on the screen.
> This bug, although the symptoms were similar to the other bug you
> reported, was an entirely different bug, more difficult to fix.
>
> I now have a patch for it, and would ask you to apply the patch to your
> Emacs 28.1 and byte compile the files in it, as before.  (As before,
> help is available from me by private email.)  Then please test it on
> your actual C code and let us know how it went.  Thanks!
>
>
>
> diff -r e4e62074b8a6 cc-engine.el
> --- a/cc-engine.el	Sat Jul 30 09:15:53 2022 +0000
> +++ b/cc-engine.el	Tue Aug 02 19:14:15 2022 +0000
> @@ -9576,7 +9576,7 @@
>   	 (or (= paren-depth 0)
>   	     (c-safe (goto-char (scan-lists (point) 1 paren-depth))))
>   
> -	 (<= (point) limit)
> +	 (< (point) limit)
>   
>   	 ;; Skip over any trailing bit, such as "__attribute__".
>   	 (progn
> diff -r e4e62074b8a6 cc-mode.el
> --- a/cc-mode.el	Sat Jul 30 09:15:53 2022 +0000
> +++ b/cc-mode.el	Tue Aug 02 19:14:15 2022 +0000
> @@ -2412,49 +2412,59 @@
>         (and (/= new-pos pos) new-pos))))
>   
>   (defun c-fl-decl-end (pos)
> -  ;; If POS is inside a declarator, return the end of the token that follows
> -  ;; the declarator, otherwise return nil.  POS being in a literal does not
> -  ;; count as being in a declarator (on pragmatic grounds).  POINT is not
> -  ;; preserved.
> +  ;; If POS is inside a declarator, return the position of the end of the
> +  ;; paren pair that terminates it, or of the end of the token that follows
> +  ;; the declarator, otherwise return nil.  If there is no such token, the end
> +  ;; of the last token in the buffer is used.  POS being in a literal is now
> +  ;; (2022-07) handled correctly.  POINT is not preserved.
>     (goto-char pos)
>     (let ((lit-start (c-literal-start))
>   	(lim (c-determine-limit 1000))
>   	enclosing-attribute pos1)
> -    (unless lit-start
> -      (c-backward-syntactic-ws
> -       lim)
> -      (when (setq enclosing-attribute (c-enclosing-c++-attribute))
> -	(goto-char (car enclosing-attribute))) ; Only happens in C++ Mode.
> -      (when (setq pos1 (c-on-identifier))
> -	(goto-char pos1)
> -	(let ((lim (save-excursion
> -		     (and (c-beginning-of-macro)
> -			  (progn (c-end-of-macro) (point))))))
> -	  (and (c-forward-declarator lim)
> -	       (if (eq (char-after) ?\()
> -		   (and
> -		    (c-go-list-forward nil lim)
> -		    (progn (c-forward-syntactic-ws lim)
> -			   (not (eobp)))
> -		    (progn
> -		      (if (looking-at c-symbol-char-key)
> -			  ;; Deal with baz (foo((bar)) type var), where
> -			  ;; foo((bar)) is not semantically valid.  The result
> -			  ;; must be after var).
> -			  (and
> -			   (goto-char pos)
> -			   (setq pos1 (c-on-identifier))
> -			   (goto-char pos1)
> -			   (progn
> -			     (c-backward-syntactic-ws lim)
> -			     (eq (char-before) ?\())
> -			   (c-fl-decl-end (1- (point))))
> -			(c-backward-syntactic-ws lim)
> -			(point))))
> -		 (and (progn (c-forward-syntactic-ws lim)
> -			     (not (eobp)))
> +    (if lit-start
> +	(goto-char lit-start))
> +    (c-backward-syntactic-ws lim)
> +    (when (setq enclosing-attribute (c-enclosing-c++-attribute))
> +      (goto-char (car enclosing-attribute)) ; Only happens in C++ Mode.
> +      (c-backward-syntactic-ws lim))
> +    (while (and (> (point) lim)
> +		(memq (char-before) '(?\[ ?\()))
> +      (backward-char)
> +      (c-backward-syntactic-ws lim))
> +    (when (setq pos1 (c-on-identifier))
> +      (goto-char pos1)
> +      (let ((lim (save-excursion
> +		   (and (c-beginning-of-macro)
> +			(progn (c-end-of-macro) (point))))))
> +	(and (c-forward-declarator lim)
> +	     (if (and (eq (char-after) ?\()
> +		      (c-go-list-forward nil lim))
> +		 (and
> +		  (progn (c-forward-syntactic-ws lim)
> +			 (not (eobp)))
> +		  (progn
> +		    (if (looking-at c-symbol-char-key)
> +			;; Deal with baz (foo((bar)) type var), where
> +			;; foo((bar)) is not semantically valid.  The result
> +			;; must be after var).
> +			(and
> +			 (goto-char pos)
> +			 (setq pos1 (c-on-identifier))
> +			 (goto-char pos1)
> +			 (progn
> +			   (c-backward-syntactic-ws lim)
> +			   (eq (char-before) ?\())
> +			 (c-fl-decl-end (1- (point))))
>   		      (c-backward-syntactic-ws lim)
> -		      (point)))))))))
> +		      (point))))
> +	       (if (progn (c-forward-syntactic-ws lim)
> +			  (not (eobp)))
> +		   (c-forward-over-token)
> +		 (let ((lit-start (c-literal-start)))
> +		   (when lit-start
> +		       (goto-char lit-start))
> +		   (c-backward-syntactic-ws)))
> +	       (and (>= (point) pos) (point))))))))
>   
>   (defun c-change-expand-fl-region (_beg _end _old-len)
>     ;; Expand the region (c-new-BEG c-new-END) to an after-change font-lock
>
>