bug#61144: CC Mode 5.35.2 (C/*l); Incorrect fontification (but different from last time)
Alan Mackenzie <[email protected]> Mon, 30 Jan 2023 21:53:11 +0000
| Newsgroups | gmane.emacs.cc-mode.general |
|---|---|
| Message-ID | <Y9g8R1VdaPxPvBrN@ACM> |
Hello, Po.
On Sun, Jan 29, 2023 at 19:00:47 +0800, Po Lu via CC-Mode-help wrote:
> Package: cc-mode
> Emacs : GNU Emacs 30.0.50 (build 41, x86_64-pc-linux-gnu)
> of 2023-01-29
> Package: CC Mode 5.35.2 (C/*l)
> Buffer Style: gnu
> c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties category-properties 1-bit)
> Insert the following text in a C Mode buffer:
> static sfnt_f26dot6
> sfnt_mul_f26dot6 (sfnt_f26dot6 a, sfnt_f26dot6 b)
> {
> #ifdef INT64_MAX
> return (sfnt_f26dot6) ((int64_t) a * b + (1 << 5) >> 6);
> #else
> int negative;
> unsigned short al, bl, ah, bh;
> unsigned int lowlong, midlong, hilong;
> negative = 0;
> /* Compensate for complement and determine if the result will be
> negative. */
> if (a < 0)
> {
> a = -a;
> negative = 1;
> }
> if (b < 0)
> {
> b = -b;
> negative ^= true;
> }
> /* Load low and high words from A and B. */
> al = a & 0xffff;
> bl = b & 0xffff;
> ah = a >> 16;
> bh = b >> 16;
> /* Multiply the various bits separately. */
> midlong = (unsigned int) al * bh;
> #endif
> }
> In ``al * bh'', al is fontified as a type, and bh an identifier.
Yes. foo * bar is a difficult case, since it can either be a
multiplication or a declaration of bar as a pointer to foo. There is no
reliable way to distinguish these two cases without a full parser. No
doubt c-ts-mode will do better here.
In another similar case, I have disambiguated these with "whitespace
asymmetry" - If there's WS both before and after the "*" or neither,
it's treated as a multiplication. Otherwise it's a declaration.
I've extended this heuristic to treat the case in your test file. Would
you try out the attached patch, please (it applies cleanly to the master
branch). I would be in favour of putting the patch into the release
branch, but given the patch is ~90 lines long, Eli might object.
Anyhow, please try it out, and let me know what you think about it.
Thanks!
[ .... ]
--
Alan Mackenzie (Nuremberg, Germany).
diff.20230130.diff
(text/plain, 3.3 KB)
diff -r 15a49bc02b66 cc-engine.el --- a/cc-engine.el Mon Jan 30 19:39:13 2023 +0000 +++ b/cc-engine.el Mon Jan 30 21:39:55 2023 +0000 @@ -10167,6 +10167,24 @@ ;; This identifier is bound only in the inner let. '(setq start id-start)))) +(defmacro c-fdoc-assymetric-space-about-asterisk () + ;; We've got a "*" at `id-start' between two identifiers, the first at + ;; `type-start'. Return non-nil when there is either whitespace between the + ;; first id and the "*" or between the "*" and the second id, but not both. + `(let ((space-before-id + (save-excursion + (goto-char id-start) ; Position of "*". + (and (> (skip-chars-forward "* \t\n\r") 0) + (memq (char-before) '(?\ ?\t ?\n ?\r))))) + (space-after-type + (save-excursion + (goto-char type-start) + (and (c-forward-type nil t) + (or (eolp) + (memq (char-after) '(?\ ?\t))))))) + (not (eq (not space-before-id) + (not space-after-type))))) + (defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end &optional inside-macro) ;; Move forward over a declaration or a cast if at the start of one. @@ -11185,19 +11203,25 @@ ;; CASE 16 (when (and got-prefix-before-parens at-type - (or at-decl-end (looking-at "=[^=]")) (memq context '(nil top)) (or (not got-suffix) at-decl-start)) ;; Got something like "foo * bar;". Since we're not inside ;; an arglist it would be a meaningless expression because ;; the result isn't used. We therefore choose to recognize - ;; it as a declaration. We only allow a suffix (which makes - ;; the construct look like a function call) when - ;; `at-decl-start' provides additional evidence that we do - ;; have a declaration. + ;; it as a declaration when there's "symmetrical WS" around + ;; the "*" or the flag `c-assymetry-fontification-flag' is + ;; not set. We only allow a suffix (which makes the + ;; construct look like a function call) when `at-decl-start' + ;; provides additional evidence that we do have a + ;; declaration. (setq maybe-expression t) - (throw 'at-decl-or-cast t)) + (when (or (not c-asymmetry-fontification-flag) + (looking-at "=[^=]") + (c-fdoc-assymetric-space-about-asterisk)) + (when (eq at-type 'maybe) + (setq unsafe-maybe t)) + (throw 'at-decl-or-cast t))) ;; CASE 17 (when (and (or got-suffix-after-parens @@ -11216,24 +11240,12 @@ got-prefix-before-parens at-type (or (not got-suffix) - at-decl-start)) - (let ((space-before-id - (save-excursion - (goto-char id-start) ; Position of "*". - (and (> (skip-chars-forward "* \t\n\r") 0) - (memq (char-before) '(?\ ?\t ?\n ?\r))))) - (space-after-type - (save-excursion - (goto-char type-start) - (and (c-forward-type nil t) - (or (eolp) - (memq (char-after) '(?\ ?\t))))))) - (when (not (eq (not space-before-id) - (not space-after-type))) - (when (eq at-type 'maybe) - (setq unsafe-maybe t)) - (setq maybe-expression t) - (throw 'at-decl-or-cast t))))) + at-decl-start) + (c-fdoc-assymetric-space-about-asterisk)) + (when (eq at-type 'maybe) + (setq unsafe-maybe t)) + (setq maybe-expression t) + (throw 'at-decl-or-cast t))) ;; CASE 18 (when (and at-decl-end