Subject: bug#53605: CC Mode 5.35.1 (C++//l); C++11 string literal operator mishighlighted

From: Alan Mackenzie <[email-masked]>
Date: Sun, 30 Jan 2022 15:42:03 +0000

Hello again, Richard.

On Fri, Jan 28, 2022 at 14:53:20 +0000, Richard Copley wrote:
> Package: cc-mode
> Hi Alan,

> The code below (which is valid since C++11) is mishighlighted,
> with the open-paren after "_opcode" in font-lock-warning face
> and the subsequent characters in font-lock-string-face. This is
> unstable: inserting and deleting a character before the open-
> paren fixes the highlighting, and [M-x normal-mode RET] breaks
> it again.

> <<END
> #include <cstddef>
> int operator""_opcode(const char *p, std::size_t size) {
>   return 0;
> }
> END

Yes.  Please try out the following patch, and confirm that it has fixed
the problem (or let me know what is still not right).  It's actually a
small patch, just binding `case-fold-search' to nil in a function, but
reindenting the entire function.

As I said earlier, the r""_opcode( was getting confused for R""_opcode(,
which would be a valid raw string delimiter.

Thanks!

diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 3a3413dc36..957a0b8a7c 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -798,43 +798,44 @@ c-common-init
 `c-basic-common-init' for details.  It's only optional to be
 compatible with old code; callers should always specify it."
 
-  (unless mode
-    ;; Called from an old third party package.  The fallback is to
-    ;; initialize for C.
-    (c-init-language-vars-for 'c-mode))
-
-  (c-basic-common-init mode c-default-style)
-  (when mode
-    ;; Only initialize font locking if we aren't called from an old package.
-    (c-font-lock-init))
-
-  ;; Starting a mode is a sort of "change".  So call the change functions...
-  (save-restriction
-    (widen)
-    (setq c-new-BEG (point-min))
-    (setq c-new-END (point-max))
-    (save-excursion
-      (let (before-change-functions after-change-functions)
-	(mapc (lambda (fn)
-		(funcall fn (point-min) (point-max)))
-	      c-get-state-before-change-functions)
-	(mapc (lambda (fn)
-		(funcall fn (point-min) (point-max)
-			 (- (point-max) (point-min))))
-	      c-before-font-lock-functions))))
-
-  (set (make-local-variable 'outline-regexp) "[^#\n\^M]")
-  (set (make-local-variable 'outline-level) 'c-outline-level)
-  (set (make-local-variable 'add-log-current-defun-function)
-       (lambda ()
-	 (or (c-cpp-define-name) (car (c-defun-name-and-limits nil)))))
-  (let ((rfn (assq mode c-require-final-newline)))
-    (when rfn
-      (if (boundp 'mode-require-final-newline)
-          (and (cdr rfn)
-               (set (make-local-variable 'require-final-newline)
-                    mode-require-final-newline))
-        (set (make-local-variable 'require-final-newline) (cdr rfn))))))
+  (let (case-fold-search)
+    (unless mode
+      ;; Called from an old third party package.  The fallback is to
+      ;; initialize for C.
+      (c-init-language-vars-for 'c-mode))
+
+    (c-basic-common-init mode c-default-style)
+    (when mode
+      ;; Only initialize font locking if we aren't called from an old package.
+      (c-font-lock-init))
+
+    ;; Starting a mode is a sort of "change".  So call the change functions...
+    (save-restriction
+      (widen)
+      (setq c-new-BEG (point-min))
+      (setq c-new-END (point-max))
+      (save-excursion
+	(let (before-change-functions after-change-functions)
+	  (mapc (lambda (fn)
+		  (funcall fn (point-min) (point-max)))
+		c-get-state-before-change-functions)
+	  (mapc (lambda (fn)
+		  (funcall fn (point-min) (point-max)
+			   (- (point-max) (point-min))))
+		c-before-font-lock-functions))))
+
+    (set (make-local-variable 'outline-regexp) "[^#\n\^M]")
+    (set (make-local-variable 'outline-level) 'c-outline-level)
+    (set (make-local-variable 'add-log-current-defun-function)
+	 (lambda ()
+	   (or (c-cpp-define-name) (car (c-defun-name-and-limits nil)))))
+    (let ((rfn (assq mode c-require-final-newline)))
+      (when rfn
+	(if (boundp 'mode-require-final-newline)
+            (and (cdr rfn)
+		 (set (make-local-variable 'require-final-newline)
+                      mode-require-final-newline))
+          (set (make-local-variable 'require-final-newline) (cdr rfn)))))))
 
 (defun c-count-cfss (lv-alist)
   ;; LV-ALIST is an alist like `file-local-variables-alist'.  Count how many

[ .... ]

-- 
Alan Mackenzie (Nuremberg, Germany).