Subject: bug#24377: 25.1; CC-Mode (C++) uses font-lock-type-face for ordinary variable

From: Alan Mackenzie <[email-masked]>
Date: 13 Sep 2016 18:35:14 -0000

Hello, Bastian.

In article <[email-masked]> you wrote:

> This piece of C++ code is wrongly fontified by CC-Mode:

> int b = 5;
> int a = (b*3);

> Reproduce as follows:

> 1) emacs -Q
> 2) Open file "test.C"
> 3) Paste snippet in buffer
> 4) Place cursor over "b" in second line
> 5) M-x describe-face -> font-lock-type-face

> This appears to be correlated with the presence of the opening
> parentheses and the '*' character, because:

> 1) int a = b*3;
> does not have this problem

> 2) "b" gets fontified incorrectly after entering the '*' character:
> int a = (b*

Thanks for this bug report, and thanks even more for taking the trouble
to reduce the test case to just two lines.

> In GNU Emacs 25.1.2 (x86_64-unknown-linux-gnu, GTK+ Version 2.24.30)
>  of 2016-08-30 built on beischer-w520
> Repository revision: 17197d0ae9eac100b56078b2a48964b29710b76e
> Windowing system distributor 'The X.Org Foundation', version 11.0.11804000
> Configured using:
>  'configure --prefix=/usr --sysconfdir=/etc --libexecdir=/usr/lib
>  --localstatedir=/var --mandir=/usr/share/man --with-gameuser=:games
>  --with-sound=alsa --with-xft --with-modules --with-x-toolkit=gtk2
>  --with-gconf --without-gsettings 'CFLAGS=-march=native -O2 -pipe
>  -fstack-protector-strong' CPPFLAGS=-D_FORTIFY_SOURCE=2
>  LDFLAGS=-Wl,-O1,--sort-common,--as-needed,-z,relro'

[ .... ]

Yes, the CC Mode fontification code was confusing the "*" with an
indirection operator, such as you might get in "int (*b) (....);"

The solution seems to be to recognise the case where an arithmetic
operator (including "=") precedes the open parenthesis.  This is what the
following patch does.  Would you please try out this patch on real code,
and let me know whether the problem is completely fixed, and if not,
what's still going wrong.  Thanks!

After applying the patch, plese recompile all of CC Mode, since the
change is partly in Lisp macros, which need to propagate to other files.

Here's the patch:

diff -r 9ff65a2d07bd cc-fonts.el
--- a/cc-fonts.el	Sun Sep 11 20:46:35 2016 +0000
+++ b/cc-fonts.el	Tue Sep 13 18:22:17 2016 +0000
@@ -1310,6 +1310,13 @@
 		     ;; multiline declaration.
 		     (c-put-char-property (1- match-pos)
 					  'c-type 'c-decl-arg-start))
+		    ;; Got an open paren preceded by an arith operator.
+		    ((and (eq (char-before match-pos) ?\()
+			  (save-excursion
+			    (and (zerop (c-backward-token-2 2))
+				 (looking-at c-arithmetic-op-regexp))))
+		     (setq context nil
+			   c-restricted-<>-arglists nil))
 		    (t (setq context 'arglist
 			     c-restricted-<>-arglists t))))
 
diff -r 9ff65a2d07bd cc-langs.el
--- a/cc-langs.el	Sun Sep 11 20:46:35 2016 +0000
+++ b/cc-langs.el	Tue Sep 13 18:22:17 2016 +0000
@@ -1231,6 +1231,22 @@
 (c-lang-defvar c-assignment-op-regexp
   (c-lang-const c-assignment-op-regexp))
 
+(c-lang-defconst c-arithmetic-operators
+  "List of all arithmetic operators, including \"+=\", etc."
+  ;; Note: in the following, there are too many operators for AWK and IDL.
+  t (append (c-lang-const c-assignment-operators)
+	    '("+" "-" "*" "/" "%"
+	      "<<" ">>"
+	      "<" ">" "<=" ">="
+	      "==" "!="
+	      "&" "^" "|"
+	      "&&" "||")))
+
+(c-lang-defconst c-arithmetic-op-regexp
+  t (c-make-keywords-re nil
+      (c-lang-const c-arithmetic-operators)))
+(c-lang-defvar c-arithmetic-op-regexp (c-lang-const c-arithmetic-op-regexp))
+
 (c-lang-defconst c-:$-multichar-token-regexp
   ;; Regexp matching all tokens ending in ":" which are longer than one char.
   ;; Currently (2016-01-07) only used in C++ Mode.

-- 
Alan Mackenzie (Nuremberg, Germany).