Add handling of the C11 _Generic construct to C Mode

This fixes bug #61481.

* lisp/progmodes/cc-engine.el (c-guess-basic-syntax): Add a new CASE 6 for
_Generic.

* lisp/progmodes/cc-fonts.el (c-fontify-types-and-refs): Use `let*' rather
than `let'.
(c-get-fontification-context): Add the new result `generic', and add handling
to determine it.
(c-font-lock-declarations): Call c-font-lock-c11-generic-clause when needed.
(c-font-lock-c11-generic-clause): New function.

* lisp/progmodes/cc-langs.el (c-generic-kwds, c-generic-key): New lang
constants/variable.
This commit is contained in:
Alan Mackenzie 2023-02-17 09:14:10 +00:00
parent 23089f1cf2
commit d4346a7cc7
3 changed files with 101 additions and 13 deletions

View file

@ -14911,7 +14911,49 @@ comment at the start of cc-engine.el for more info."
(c-add-syntax 'topmost-intro-cont (c-point 'boi)))
))
;; (CASE 6 has been removed.)
;; ((Old) CASE 6 has been removed.)
;; CASE 6: line is within a C11 _Generic expression.
((and c-generic-key
(eq (char-after containing-sexp) ?\()
(progn (setq tmp-pos (c-safe-scan-lists
containing-sexp 1 0
(min (+ (point) 2000) (point-max))))
t)
(save-excursion
(and
(progn (goto-char containing-sexp)
(zerop (c-backward-token-2)))
(looking-at c-generic-key)
(progn (goto-char (1+ containing-sexp))
(c-syntactic-re-search-forward
"," indent-point 'bound t t))
(setq placeholder (point)))))
(let ((res (c-syntactic-re-search-forward
"[,:)]"
(or tmp-pos (min (+ (point) 2000) (point-max)))
'bound t t)))
(cond
((and res
(eq (char-before) ?\))
(save-excursion
(backward-char)
(c-backward-syntactic-ws indent-point)
(eq (point) indent-point)))
(c-add-stmt-syntax
'arglist-close (list containing-sexp) t
(c-most-enclosing-brace paren-state indent-point) paren-state))
((or (not res)
(eq (char-before) ?\)))
(backward-char)
(c-syntactic-skip-backward "^,:" containing-sexp t)
(c-add-syntax (if (eq (char-before) ?:)
'statement-case-intro
'case-label)
(1+ containing-sexp)))
(t (c-add-syntax (if (eq (char-before) ?:)
'case-label
'statement-case-intro)
(1+ containing-sexp))))))
;; CASE 7: line is an expression, not a statement. Most
;; likely we are either in a function prototype or a function

View file

@ -259,14 +259,14 @@
(defmacro c-fontify-types-and-refs (varlist &rest body)
(declare (indent 1) (debug let*))
;; Like `let', but additionally activates `c-record-type-identifiers'
;; Like `let*', but additionally activates `c-record-type-identifiers'
;; and `c-record-ref-identifiers', and fontifies the recorded ranges
;; accordingly on exit.
;;
;; This function does hidden buffer changes.
`(let ((c-record-type-identifiers t)
c-record-ref-identifiers
,@varlist)
`(let* ((c-record-type-identifiers t)
c-record-ref-identifiers
,@varlist)
(prog1 (progn ,@body)
(c-fontify-recorded-types-and-refs))))
@ -1219,6 +1219,7 @@ casts and declarations are fontified. Used on level 2 and higher."
;; inside a function declaration arglist).
;; '<> In an angle bracket arglist.
;; 'arglist Some other type of arglist.
;; 'generic In a C11 _Generic construct.
;; 'top Some other context and point is at the top-level (either
;; outside any braces or directly inside a class or namespace,
;; etc.)
@ -1345,6 +1346,15 @@ casts and declarations are fontified. Used on level 2 and higher."
(c-back-over-member-initializers)))
(c-put-char-property (1- match-pos) 'c-type 'c-not-decl)
(cons 'not-decl nil))
;; In a C11 _Generic construct.
((and c-generic-key
(eq (char-before match-pos) ?,)
(save-excursion
(and (c-go-up-list-backward match-pos
(max (- (point) 2000) (point-min)))
(zerop (c-backward-token-2))
(looking-at c-generic-key))))
(cons 'generic nil))
;; At start of a declaration inside a declaration paren.
((save-excursion
(goto-char match-pos)
@ -1616,13 +1626,16 @@ casts and declarations are fontified. Used on level 2 and higher."
(c-forward-syntactic-ws))
;; Now analyze the construct.
(if (eq context 'not-decl)
(progn
(setq decl-or-cast nil)
(if (c-syntactic-re-search-forward
"," (min limit (point-max)) 'at-limit t)
(c-put-char-property (1- (point)) 'c-type 'c-not-decl))
nil)
(cond
((eq context 'not-decl)
(setq decl-or-cast nil)
(if (c-syntactic-re-search-forward
"," (min limit (point-max)) 'at-limit t)
(c-put-char-property (1- (point)) 'c-type 'c-not-decl))
nil)
((eq context 'generic)
(c-font-lock-c11-generic-clause))
(t
(setq decl-or-cast
(c-forward-decl-or-cast-1
match-pos context last-cast-end inside-macro))
@ -1683,7 +1696,7 @@ casts and declarations are fontified. Used on level 2 and higher."
context
(or toplev (nth 4 decl-or-cast))))
(t t))))
(t t)))))
;; It was a false alarm. Check if we're in a label (or other
;; construct with `:' except bitfield) instead.
@ -1713,6 +1726,28 @@ casts and declarations are fontified. Used on level 2 and higher."
nil))))
(defun c-font-lock-c11-generic-clause ()
;; Fontify a type inside the C11 _Generic clause. Point will be at the
;; type and will be left at the next comma of the clause (if any) or the
;; closing parenthesis, if any, or at the end of the type, otherwise.
;; The return value is always nil.
(c-fontify-types-and-refs
((here (point))
(type-type (c-forward-type t))
(c-promote-possible-types (if (eq type-type 'maybe) 'just-one t))
(pos (point)) pos1)
(when (and type-type (eq (char-after) ?:))
(goto-char here)
(c-forward-type t)) ; Fontify the type.
(cond
((c-syntactic-re-search-forward "," nil t t t)
(backward-char))
((and (setq pos1 (c-up-list-forward))
(eq (char-before pos1) ?\)))
(goto-char (1- pos1)))
(t (goto-char pos))))
nil)
(defun c-font-lock-enum-body (limit)
;; Fontify the identifiers of each enum we find by searching forward.
;;

View file

@ -3085,6 +3085,17 @@ Keywords here should also be in `c-block-stmt-1-kwds'."
t (c-make-keywords-re t (c-lang-const c-block-stmt-2-kwds)))
(c-lang-defvar c-block-stmt-2-key (c-lang-const c-block-stmt-2-key))
(c-lang-defconst c-generic-kwds
"The keyword \"_Generic\" which introduces a C11 generic statement."
t nil
c '("_Generic"))
(c-lang-defconst c-generic-key
;; Regexp matching the keyword(s) in `c-generic-kwds'.
t (if (c-lang-const c-generic-kwds)
(c-make-keywords-re t (c-lang-const c-generic-kwds))))
(c-lang-defvar c-generic-key (c-lang-const c-generic-key))
(c-lang-defconst c-block-stmt-kwds
;; Union of `c-block-stmt-1-kwds' and `c-block-stmt-2-kwds'.
t (c--delete-duplicates (append (c-lang-const c-block-stmt-1-kwds)