Subject: Re: bug#45560: 27.1; add-change-log-entry erroneously removes "const" from function name

From: Alan Mackenzie <[email-masked]>
Date: Fri, 1 Jan 2021 16:20:25 +0000

Hello, Lars and Tom

On Thu, Dec 31, 2020 at 06:09:21 +0100, Lars Ingebrigtsen wrote:
> Tom Tromey <[email-masked]> writes:

> > Put this into a .c file:
> >
> > void
> > const_ref ()
> > {
> > }
> >
> > Now, put point inside the braces and M-x add-change-log-entry.
> >
> > For me the resulting ChangeLog looks like:
> >
> > 2020-12-30  Tom Tromey  <[email-masked]>
> >
> > 	* q.c (_ref): 

> Debugging this, it looks like this is down to

> (c-defun-name-1)

> returning "_ref" if called in the const_ref function, so I've added Alan
> to the CCs. 

Yes, there was a regular expression recognising "const" where it
shouldn't have.  It was a regexp with many discordant, conflicting
requirements, so I had to "split it in two" to get it working properly.

Please try the following patch out, which shouldn't be at all
controversial, and let me know whether it fixes everything.  Thanks!

diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 7444f0f805..60e85fc085 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -9021,14 +9021,15 @@ c-forward-declarator
 		    (c-forward-noise-clause))
 		   ((and (looking-at c-type-decl-prefix-key)
 			 (if (and (c-major-mode-is 'c++-mode)
-				  (match-beginning 3))
+				  (match-beginning 4)) ; Was 3 - 2021-01-01
 			     ;; If the third submatch matches in C++ then
 			     ;; we're looking at an identifier that's a
 			     ;; prefix only if it specifies a member pointer.
 			     (progn
 			       (setq id-start (point))
 			       (c-forward-name)
-			       (if (looking-at "\\(::\\)")
+			       (if (save-match-data
+				     (looking-at "\\(::\\)"))
 				   ;; We only check for a trailing "::" and
 				   ;; let the "*" that should follow be
 				   ;; matched in the next round.
@@ -9038,13 +9039,15 @@ c-forward-declarator
 				 (setq got-identifier t)
 				 nil))
 			   t))
-		    (if (looking-at c-type-decl-operator-prefix-key)
+		    (if (save-match-data
+			  (looking-at c-type-decl-operator-prefix-key))
 			(setq decorated t))
 		    (if (eq (char-after) ?\()
 			(progn
 			  (setq paren-depth (1+ paren-depth))
 			  (forward-char))
-		      (goto-char (match-end 1)))
+		      (goto-char (or (match-end 1)
+				     (match-end 2))))
 		    (c-forward-syntactic-ws)
 		    t)))
 
@@ -9721,14 +9724,15 @@ c-forward-decl-or-cast-1
 	      (setq after-paren-pos (point))))
 	(while (and (looking-at c-type-decl-prefix-key)
 		    (if (and (c-major-mode-is 'c++-mode)
-			     (match-beginning 3))
+			     (match-beginning 4))
 			;; If the third submatch matches in C++ then
 			;; we're looking at an identifier that's a
 			;; prefix only if it specifies a member pointer.
 			(when (progn (setq pos (point))
 				     (setq got-identifier (c-forward-name)))
 			  (setq name-start pos)
-			  (if (looking-at "\\(::\\)")
+			  (if (save-match-data
+				(looking-at "\\(::\\)"))
 			      ;; We only check for a trailing "::" and
 			      ;; let the "*" that should follow be
 			      ;; matched in the next round.
@@ -9749,7 +9753,8 @@ c-forward-decl-or-cast-1
 	    (when (save-match-data
 		    (looking-at c-type-decl-operator-prefix-key))
 	      (setq got-function-name-prefix t))
-	    (goto-char (match-end 1)))
+	    (goto-char (or (match-end 1)
+			   (match-end 2))))
 	  (c-forward-syntactic-ws)))
 
       (setq got-parens (> paren-depth 0))
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index c3cd81e1e8..9577f55e87 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -3433,41 +3433,47 @@ c-populate-syntax-table
   t (c-make-bare-char-alt (c-lang-const c-block-prefix-disallowed-chars) t))
 (c-lang-defvar c-block-prefix-charset (c-lang-const c-block-prefix-charset))
 
-(c-lang-defconst c-type-decl-prefix-key
-  "Regexp matching any declarator operator that might precede the
-identifier in a declaration, e.g. the \"*\" in \"char *argv\".  This
-regexp should match \"(\" if parentheses are valid in declarators.
-The end of the first submatch is taken as the end of the operator.
-Identifier syntax is in effect when this is matched (see
-`c-identifier-syntax-table')."
+(c-lang-defconst c-type-decl-prefix-keywords-key
+  ;; Regexp matching any keyword operator that might precede the identifier in
+  ;; a declaration, e.g. "const" or nil.  It doesn't test there is no "_"
+  ;; following the keyword.
   t (if (or (c-lang-const c-type-modifier-kwds) (c-lang-const c-modifier-kwds))
-        (concat
+	(concat
 	 (regexp-opt (c--delete-duplicates
 		      (append (c-lang-const c-type-modifier-kwds)
 			      (c-lang-const c-modifier-kwds))
 		      :test 'string-equal)
 		     t)
-	 "\\>")
-      ;; Default to a regexp that never matches.
-      regexp-unmatchable)
+	 "\\>")))
+
+(c-lang-defconst c-type-decl-prefix-key
+  "Regexp matching any declarator operator that might precede the
+identifier in a declaration, e.g. the \"*\" in \"char *argv\".  This
+regexp should match \"(\" if parentheses are valid in declarators.
+The operator found is either the first submatch (if it is not a
+keyword) or the second submatch (if it is)."
+  t (if (c-lang-const c-type-decl-prefix-keywords-key)
+	(concat "\\(\\`a\\`\\)\\|"	; 1 - will never match.
+		(c-lang-const c-type-decl-prefix-keywords-key) ; 2
+		"\\([^_]\\|$\\)")			       ; 3
+      regexp-unmatchable) ;; Default to a regexp that never matches.
   ;; Check that there's no "=" afterwards to avoid matching tokens
   ;; like "*=".
-  (c objc) (concat "\\("
+  (c objc) (concat "\\("		; 1
 		   "[*(]"
-		   "\\|"
-		   (c-lang-const c-type-decl-prefix-key)
-		   "\\)"
-		   "\\([^=]\\|$\\)")
-  c++  (concat "\\("
+		   "\\)\\|"
+		   (c-lang-const c-type-decl-prefix-keywords-key) ; 2
+		   "\\([^=_]\\|$\\)")	; 3
+  c++  (concat "\\("			; 1
 	       "&&"
 	       "\\|"
 	       "\\.\\.\\."
 	       "\\|"
 	       "[*(&~]"
+	       "\\)\\|\\("				      ; 2
+	       (c-lang-const c-type-decl-prefix-keywords-key) ; 3
 	       "\\|"
-	       (c-lang-const c-type-decl-prefix-key)
-	       "\\|"
-	       (concat "\\("   ; 3
+	       (concat "\\("   ; 4
 		       ;; If this matches there's special treatment in
 		       ;; `c-font-lock-declarators' and
 		       ;; `c-font-lock-declarations' that check for a
@@ -3475,8 +3481,9 @@ c-populate-syntax-table
 		       (c-lang-const c-identifier-start)
 		       "\\)")
 	       "\\)"
-	       "\\([^=]\\|$\\)")
+	       "\\([^=_]\\|$\\)")	; 5
   pike "\\(\\*\\)\\([^=]\\|$\\)")
+
 (c-lang-defvar c-type-decl-prefix-key (c-lang-const c-type-decl-prefix-key)
   'dont-doc)

> -- 
> (domestic pets only, the antidote for overdose, milk.)
>    bloggy blog: http://lars.ingebrigtsen.no

-- 
Alan Mackenzie (Nuremberg, Germany).