Subject: Re: bug#56362: CC Mode 5.35.1 (C++//l); Highlight for C++20 keywords

From: Alan Mackenzie <[email-masked]>
Date: Wed, 7 Sep 2022 13:01:24 +0000

Hello, Zhiwei.

First of all, sorry that it's taken me two months to reply.

Secondly, thanks for taking the trouble to submit this bug.  I have fixed
the problems, partly, but I still have a lot of work to do to bring CC
Mode up to the C++20 standard.  In particular, "concepts" and "requires"
will need a lot doing.  I hope to do this work in the coming weeks.

I have included a patch for these problems below; could you please test
this patch on your CC Mode and your real C++ source files, and let me
know how it goes.  As I said, it is not perfect, but it should be better
than it was.  If you want any help with the patching or byte compiling of
CC Mode, feel free to send me private email.

For the problems you raised:

On Sun, Jul 03, 2022 at 03:12:28 +0800, Zhiwei Chen wrote:
> Package: cc-mode

> See the comments.

> #+begin_src C++
> #if __has_include(<bits/stdc++.h>)
> #include <bits/stdc++.h>
> #endif

> #include <cstdint>
> #include <concepts>

> // no highlight for consteval keyword
> consteval int sqr(int x) {
>     return x * x;
> }

Now fixed.

> // no highlight for constinit keyword
> constinit int four = sqr(16);

Now fixed.

> class Foo {
> public:
>     // <=> highlights wrong
>     auto operator<=>(const Foo&) const = default;

Now fixed.

> private:
>     // no highlight for alignas keyword
>     alignas(alignof(std::uint64_t)) int val_;
> };

Now fixed.  It's also worth noting that "alignas" in a struct/class:

    class alignas(64) Foo { ..... }

should now fontify correctly.

> template <typename T>
> requires std::integral<T> // 'requires' occasionally has a font-lock-type-face
> T add(T a, T b) {
>     return a + b;
> }

Here's where I still need to make "requires" work properly.  I've
temporarily make "requires" and "concept" C++ keywords, but in the above
piece of code, "T add(T a, T b) {" is not correctly fontified.  But
"requires" should now always be fontified as a keyword.

> int main() {
>     const char8_t c1 = 0; // char8_t is missing in `c-primitive-type-kwds'. cc-langs.el L2205

>     return 0;
> }
> #+end_src

char8_t is now in c-primitive-type-kwds.

> Emacs  : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.34, cairo version 1.17.6)
>  of 2022-07-02
> Package: CC Mode 5.35.1 (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 1-bit)

[ CC Mode configuration appreciated, but snipped ]

Here's the patch:

diff -r 87af98f62eec cc-langs.el
--- a/cc-langs.el	Wed Aug 31 18:28:12 2022 +0000
+++ b/cc-langs.el	Wed Sep 07 12:38:20 2022 +0000
@@ -1301,6 +1301,10 @@
 		  ,@(when (c-major-mode-is 'java-mode)
 		      '(">>>")))
 
+      ;; The C++ "spaceship" operator.
+      ,@(when (c-major-mode-is 'c++-mode)
+	  `((left-assoc "<=>")))
+
       ;; Relational.
       (left-assoc "<" ">" "<=" ">="
 		  ,@(when (c-major-mode-is 'java-mode)
@@ -1414,7 +1418,7 @@
 	 "^" "??'" "xor" "&" "bitand" "|" "??!" "bitor" "~" "??-" "compl"
 	 "!" "=" "<" ">" "+=" "-=" "*=" "/=" "%=" "^="
 	 "??'=" "xor_eq" "&=" "and_eq" "|=" "??!=" "or_eq"
-	 "<<" ">>" ">>=" "<<=" "==" "!=" "not_eq" "<=" ">="
+	 "<<" ">>" ">>=" "<<=" "==" "!=" "not_eq" "<=>" "<=" ">="
 	 "&&" "and" "||" "??!??!" "or" "++" "--" "," "->*" "->"
 	 "()" "[]" "<::>" "??(??)")
   ;; These work like identifiers in Pike.
@@ -1535,8 +1539,10 @@
   "List of all arithmetic operators, including \"+=\", etc."
   ;; Note: in the following, there are too many operators for AWK and IDL.
   t (append (c-lang-const c-assignment-operators)
-	    '("+" "-" "*" "/" "%"
+	    `("+" "-" "*" "/" "%"
 	      "<<" ">>"
+	      ,@(if (c-major-mode-is 'c++-mode)
+		    '("<=>"))
 	      "<" ">" "<=" ">="
 	      "==" "!="
 	      "&" "^" "|"
@@ -2187,7 +2193,7 @@
 	'("_Bool" "_Complex" "_Imaginary") ; Conditionally defined in C99.
 	(c-lang-const c-primitive-type-kwds))
   c++  (append
-	'("bool" "wchar_t" "char16_t" "char32_t")
+	'("bool" "wchar_t" "char8_t" "char16_t" "char32_t")
 	(c-lang-const c-primitive-type-kwds))
   ;; Objective-C extends C, but probably not the new stuff in C99.
   objc (append
@@ -2580,8 +2586,8 @@
   t    nil
   (c c++) '("extern" "inline" "register" "static")
   c    (append '("auto") (c-lang-const c-modifier-kwds))
-  c++  (append '("constexpr" "explicit" "friend" "mutable" "template"
-		 "thread_local" "virtual")
+  c++  (append '("consteval" "constexpr" "constinit" "explicit" "friend"
+		 "mutable" "template" "thread_local" "virtual")
 	       ;; "using" is now handled specially (2020-09-14).
 	       (c-lang-const c-modifier-kwds))
   objc '("auto" "bycopy" "byref" "extern" "in" "inout" "oneway" "out" "static")
@@ -2655,7 +2661,8 @@
   (c c++) '(;; GCC extension.
 	    "__attribute__"
 	    ;; MSVC extension.
-	    "__declspec"))
+	    "__declspec")
+  c++ (append (c-lang-const c-decl-hangon-kwds) '("alignas")))
 
 (c-lang-defconst c-decl-hangon-key
   ;; Adorned regexp matching `c-decl-hangon-kwds'.
@@ -2880,7 +2887,7 @@
 	    "__attribute__"
 	    ;; MSVC extension.
 	    "__declspec")
-  c++ (append (c-lang-const c-paren-nontype-kwds) '("noexcept")))
+  c++ (append (c-lang-const c-paren-nontype-kwds) '("noexcept" "alignas")))
 
 (c-lang-defconst c-paren-nontype-key
   t (c-make-keywords-re t (c-lang-const c-paren-nontype-kwds)))
@@ -3256,11 +3263,17 @@
 (c-lang-defconst c-keywords
   ;; All keywords as a list.
   t (c--delete-duplicates
-     (c-lang-defconst-eval-immediately
-      `(append ,@(mapcar (lambda (kwds-lang-const)
-			   `(c-lang-const ,kwds-lang-const))
-			 c-kwds-lang-consts)
-	       nil))
+     (append				; Temporary, 2022-09-07
+      (c-lang-defconst-eval-immediately
+       `(append ,@(mapcar (lambda (kwds-lang-const)
+			    `(c-lang-const ,kwds-lang-const))
+			  c-kwds-lang-consts)
+		nil))
+      ;; Temporary addition for C++ until concepts have been worked out properly.
+      ;; 2022-09-07.
+      `(,@(if (c-major-mode-is 'c++-mode)
+	      '("concept" "requires")))
+      nil)
      :test 'string-equal))
 
 (c-lang-defconst c-keywords-regexp

-- 
Alan Mackenzie (Nuremberg, Germany).