Reported by: Mauro Aranda <maurooaranda <at> gmail.com>
Date: Sat, 27 Apr 2019 16:12:02 UTC
Severity: normal
Found in version 26.2.50
Done: Alan Mackenzie <acm <at> muc.de>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Alan Mackenzie <acm <at> muc.de> To: Mauro Aranda <maurooaranda <at> gmail.com> Cc: 35454 <at> debbugs.gnu.org Subject: bug#35454: 26.2.50; CC-Mode fontification fails inside macro Date: Wed, 1 May 2019 21:02:30 +0000
Hello again, Mauro. On Sat, Apr 27, 2019 at 20:36:46 +0000, Alan Mackenzie wrote: > On Sat, Apr 27, 2019 at 12:57:05 -0300, Mauro Aranda wrote: > > Hello. > > Steps to reproduce: > > 1) emacs -Q > > 2) Open up a new .c file: > > C-x C-f test.c > > 3) Type this text: > > #define FOO \ > > /* Some comms. */ \ > > struct foobar my_foo; \ > > struct foobar my_bar; > > The first struct foobar after the comment is not fontified as the second > > one. That is, the second foobar has face font-lock-type-face, and > > my_bar has face font-lock-variable-name-face, but the first foobar and > > my_foo don't get those face values. > > I actually bumped into this issue while visiting the emacs source file > > src/editfns.c. In that file, search for "#define EXTRA_CONTEXT_FIELDS" > > and the problem should be evident. > Thanks! I can reproduce this easily, and will look into it in the next > day or two. Please try out the patch below. On my system, it corrects the fontification in both your test file and editfns.c. > Of interest is the fact that if FOO is given an empty argument list > (i.e. one writes > #define FOO() \ > ... > ), the bug doesn't happen. > > I can reproduce it with the latest Emacs 26, as well as with the latest > > master: > > Repository revision: 8dc00b2f1e6523c634df3e24379afbe712a32b27 > > Repository branch: master diff -r 9d58d1e3ab27 cc-engine.el --- a/cc-engine.el Sat Apr 27 17:07:23 2019 +0000 +++ b/cc-engine.el Wed May 01 20:46:40 2019 +0000 @@ -5668,7 +5668,10 @@ (setq cfd-re-match cfd-limit) nil) ((c-got-face-at - (if (setq cfd-re-match (match-end 1)) + (if (setq cfd-re-match + (or (match-end 1) + (and c-dposr-cpp-macro-depth + (match-end (1+ c-dposr-cpp-macro-depth))))) ;; Matched the end of a token preceding a decl spot. (progn (goto-char cfd-re-match) @@ -5679,15 +5682,19 @@ c-literal-faces) ;; Pseudo match inside a comment or string literal. Skip out ;; of comments and string literals. - (while (progn - (unless - (and (match-end 1) - (c-got-face-at (1- (point)) c-literal-faces) - (not (c-got-face-at (point) c-literal-faces))) - (goto-char (c-next-single-property-change - (point) 'face nil cfd-limit))) - (and (< (point) cfd-limit) - (c-got-face-at (point) c-literal-faces)))) + (while + (progn + (unless + (and + (or (match-end 1) + (and c-dposr-cpp-macro-depth + (match-end (1+ c-dposr-cpp-macro-depth)))) + (c-got-face-at (1- (point)) c-literal-faces) + (not (c-got-face-at (point) c-literal-faces))) + (goto-char (c-next-single-property-change + (point) 'face nil cfd-limit))) + (and (< (point) cfd-limit) + (c-got-face-at (point) c-literal-faces)))) t) ; Continue the loop over pseudo matches. ((and c-opt-identifier-concat-key (match-string 1) diff -r 9d58d1e3ab27 cc-langs.el --- a/cc-langs.el Sat Apr 27 17:07:23 2019 +0000 +++ b/cc-langs.el Wed May 01 20:46:40 2019 +0000 @@ -964,6 +964,14 @@ (c-lang-defvar c-opt-cpp-macro-define-id (c-lang-const c-opt-cpp-macro-define-id)) +(c-lang-defconst c-anchored-hash-define-no-parens + ;; Regexp matching everything up to the end of a cpp define which has no + ;; argument parentheses. Or nil in languages which don't have them. + t (if (c-lang-const c-opt-cpp-macro-define) + (concat (c-lang-const c-anchored-cpp-prefix) + (c-lang-const c-opt-cpp-macro-define) + "[ \t]+\\(\\sw\\|_\\)+\\([^(a-zA-Z0-9_]\\|$\\)"))) + (c-lang-defconst c-cpp-expr-directives "List of cpp directives (without the prefix) that are followed by an expression." @@ -1578,7 +1586,7 @@ t (concat (c-lang-const c-comment-start-regexp) "\\|" (if (memq 'gen-string-delim c-emacs-features) - "\"|" + "\"\\|\\s|" "\""))) (c-lang-defvar c-literal-start-regexp (c-lang-const c-literal-start-regexp)) @@ -3152,24 +3160,40 @@ ;; token that might precede such a construct, e.g. ';', '}' or '{'. ;; It's built from `c-decl-prefix-re'. ;; - ;; If the first submatch did not match, the match of the whole - ;; regexp is taken to be at the first token in the declaration. - ;; `c-decl-start-re' is not checked in this case. + ;; If the first submatch did not match, we have either a #define construct + ;; without parentheses or the match of the whole regexp is taken to be at + ;; the first token in the declaration. `c-decl-start-re' is not checked in + ;; these cases. ;; ;; Design note: The reason the same regexp is used to match both ;; tokens that precede declarations and start them is to avoid an ;; extra regexp search from the previous declaration spot in ;; `c-find-decl-spots'. Users of `c-find-decl-spots' also count on - ;; that it finds all declaration/cast/label starts in approximately + ;; it finding all declaration/cast/label starts in approximately ;; linear order, so we can't do the searches in two separate passes. - t (if (c-lang-const c-decl-start-kwds) - (concat (c-lang-const c-decl-prefix-re) - "\\|" - (c-make-keywords-re t (c-lang-const c-decl-start-kwds))) - (c-lang-const c-decl-prefix-re))) + t (cond + ((and (c-lang-const c-decl-start-kwds) + (c-lang-const c-anchored-hash-define-no-parens)) + (concat (c-lang-const c-decl-prefix-re) + "\\|" (c-lang-const c-anchored-hash-define-no-parens) + "\\|" (c-make-keywords-re t (c-lang-const c-decl-start-kwds)))) + ((c-lang-const c-decl-start-kwds) + (concat (c-lang-const c-decl-prefix-re) + "\\|" (c-make-keywords-re t (c-lang-const c-decl-start-kwds)))) + ((c-lang-const c-anchored-hash-define-no-parens) + (concat (c-lang-const c-decl-prefix-re) + "\\|" (c-lang-const c-anchored-hash-define-no-parens))) + (t (c-lang-const c-decl-prefix-re)))) (c-lang-defvar c-decl-prefix-or-start-re (c-lang-const c-decl-prefix-or-start-re)) +(c-lang-defconst c-dposr-cpp-macro-depth + ;; The match number of `c-anchored-hash-define-no-parens''s first match + ;; within `c-decl-prefix-or-start-re', or nil if there is no such component. + t (if (c-lang-const c-anchored-hash-define-no-parens) + (1+ (regexp-opt-depth (c-lang-const c-decl-prefix-re))))) +(c-lang-defvar c-dposr-cpp-macro-depth (c-lang-const c-dposr-cpp-macro-depth)) + (c-lang-defconst c-cast-parens ;; List containing the paren characters that can open a cast, or nil in ;; languages without casts. > > Best regards, > > Mauro. -- Alan Mackenzie (Nuremberg, Germany).
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.