Subject: Re: bug#61481: CC Mode 5.35.2 (C/*l); _Generic unsupported

From: Alan Mackenzie <[email-masked]>
Date: Thu, 16 Feb 2023 13:15:36 +0000

Hello, Po.

On Mon, Feb 13, 2023 at 23:25:43 +0800, Po Lu via CC-Mode-help wrote:
> Package: cc-mode

> 2011 Standard C has a feature that works like `switch', except on the
> type of an expression and with different syntax.

Yuck!  How on Earth did something like this get included in the
standard?  It's not used often (I wasn't aware of it until three days
ago), it's wholly unlike anything else in C, and just takes up effort
from compiler and editor maintainers.

> Today, I had to figure out how to port some code written with that in
> mind to ANSI C, and surprisingly enough, found that CC Mode does not
> support that feature at all.

:-)

> Code making use of _Generic looks more or less like this:

> {
>   const char *typename = _Generic ((expr),
> 				   const char *:
> 				     "const char *",
> 				   int:
> 				     "int",
> 				   unsigned long:
> 				     "unsigned long"
> 				   default:
> 				     NULL);
> }

> where `typename' is set to an appropriate value based on the type of the
> expression ``expr''.

> CC Mode already works remarkably well, but it should be taught to indent
> the cases separately from the values.

Thanks!

I've made a first patch for this, which is fairly crude.  It handles
only the indentation, not the fontification, which will be more
difficult.

Would you please try out the attached patch, and let me know how well it
does the job.  Thanks!

[ .... ]

-- 
Alan Mackenzie (Nuremberg, Germany).

diff -r 97e4c3437e75 cc-engine.el
--- a/cc-engine.el	Sun Feb 05 17:48:26 2023 +0000
+++ b/cc-engine.el	Thu Feb 16 13:13:59 2023 +0000
@@ -14927,7 +14927,31 @@
 	  (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) ?\()
+	     (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 ((delim ?,))
+	  (goto-char placeholder)
+	  (while
+	      (and (c-syntactic-re-search-forward ":" indent-point 'bound t t)
+		   (setq delim ?:)
+		   (c-syntactic-re-search-forward
+		    "," indent-point 'bound t t)
+		   (setq delim ?,)))
+	  (c-add-syntax (if (eq delim ?,)
+			    'case-label
+			  'statement-case-intro)
+			containing-sexp)))
 
        ;; CASE 7: line is an expression, not a statement.  Most
        ;; likely we are either in a function prototype or a function
diff -r 97e4c3437e75 cc-langs.el
--- a/cc-langs.el	Sun Feb 05 17:48:26 2023 +0000
+++ b/cc-langs.el	Thu Feb 16 13:13:59 2023 +0000
@@ -3071,6 +3071,28 @@
   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-generic-default-kwds
+  "The keyword \"default\" used in a C11 generic statement."
+  t nil
+  c '("default"))
+
+(c-lang-defconst c-generic-default-key
+  ;; Regexp matching the keyword(s) in `c-generic-default-kwds'.
+  t (if (c-lang-const c-generic-default-kwds)
+	(c-make-keywords-re t (c-lang-const c-generic-default-kwds))))
+(c-lang-defvar c-generic-default-key (c-lang-const c-generic-default-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)