]> git.eshelyaron.com Git - emacs.git/commitdiff
Add handling of the C11 _Generic construct to C Mode
authorAlan Mackenzie <acm@muc.de>
Fri, 17 Feb 2023 09:14:10 +0000 (09:14 +0000)
committerAlan Mackenzie <acm@muc.de>
Fri, 17 Feb 2023 09:14:10 +0000 (09:14 +0000)
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.

lisp/progmodes/cc-engine.el
lisp/progmodes/cc-fonts.el
lisp/progmodes/cc-langs.el

index 1899b522ab0395b4f63c043de47a66160b65dd79..f8ae49c42ddcc698408dcaddc814d3a17f0e5365 100644 (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
index c220d8d8789ac69e97c41cdea46c6ca94e894f13..4ec21af1b25f02d6ac360012031f754f3e838daf 100644 (file)
 
   (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.
   ;;
index daa23bd14fac9f757ebe6678cf574af58912f8fe..61f81f09b3e9ec652174e97c4480d50f787005c4 100644 (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)