From: Alan Mackenzie Date: Thu, 1 May 2025 16:12:18 +0000 (+0000) Subject: Implement C23 features: X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=a75f48cdac6c3d09140f52f29cdf205c6e39c8be;p=emacs.git Implement C23 features: Improve the handling of #error and #warning in C and C++ Modes. * lisp/progmodes/cc-engine.el (c-looking-at-c++-attribute) (c-enclosing-c++-attribute, c-forward-sws, c-backward-sws): Handle attributes in C as they have been handled in C++. (c-forward-align-clause-throw-if-invalid): New macro. (c-forward-type): Handle alignas, alignof, and _BitInt, putting a catch block around most of the function to catch invalid uses of these new keywords. (c-in-id-arglist): New function. (c-forward-decl-or-cast-1): Recognize a "maybe" type identifier as a type in arglists when there is no parameter identifier associated with it. * lisp/progmodes/cc-fonts.el (c-font-lock-cpp-messages): New function. (c-cpp-matchers): Move the handling of "invalid" comment delimiters outside of the block handling CPP directives. Remove the inline handling of #error and #warning, using the new function c-font-lock-cpp-messages instead. (c-get-fontification-context): Handle alignof, alignas, _BitInt. (c-font-lock-declarations): Adapt fontification of K&R parameters to the C23 nameless parameter scheme. * lisp/progmodes/cc-langs.el (c-has-quoted-numbers) (c-stmt-boundary-skip-chars) (c-recognize-post-brace-list-type-p, c-modifier-kwds) (c-constant-kwds): Handle C the same as the existing C++ handling. (c-cpp-message-directives-re, noncontinued-line-end) (c-cpp-messages-re, c-cpp-message-match-no): New c-lang-consts/vars. (c-cpp-include-directives): New directive embed. (c-cpp-expr-directives): New directives elifdef, elifndef. (c-primitive-type-kwds): New types, _Decimal*, bool, char*_t, nullptr_t. (c-typeof-kwds): New keyword typeof_unqual. (c-type-with-paren-kwds, c-type-with-paren-key): New c-lang-const/vars. (c-type-modifier-with-parens-kwds) (c-type-modifier-with-parens-key, c-type-internal-paren-kwds) (c-type-internal-paren-key): New c-lang-const/vars. (c-type-modifier-prefix-kwds, c-type-start-kwds): Amend with the above new c-lang-consts. (c-no-type-with-equals-kwds, c-no-type-with-equals-key): New c-lang-const/vars. (c-modifier-kwds): Add constexpr, auto, and thread_local to the C value. (c-paren-nontype-kwds): Add static_assert to the C value. (c-constant-kwds): Add nullptr to the C value. (c-regular-keywords-regexp): Include c-type-with-paren-kwds. (c-recognize-nameless-type-decls): New c-lang-const/var. * lisp/progmodes/cc-mode.el (c-leave-cc-mode-mode): Also clear c-digit-separator properties. (cherry picked from commit 8ddb8b0e45f150a5866c86af8ed2054b792761ff) --- diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index c52ecd8291b..29b412f903a 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -84,8 +84,9 @@ ;; 'syntax-table ;; Used to modify the syntax of some characters. It is used to ;; mark the "<" and ">" of angle bracket parens with paren syntax, to -;; "hide" obtrusive characters in preprocessor lines, and to mark C++ -;; raw strings to enable their fontification. +;; "hide" obtrusive characters in preprocessor lines, to mark C++ raw +;; strings to enable their fontification, and to mark syntactically +;; wrong single quotes, again for their fontification. ;; ;; This property is used on single characters and is therefore ;; always treated as front and rear nonsticky (or start and end open @@ -142,9 +143,14 @@ ;; Put on the brace which introduces a brace list and on the commas ;; which separate the elements within it. ;; -;; 'c-typedef This property is applied to the first character of a -;; "typedef" keyword. It's value is a list of the identifiers that -;; the "typedef" declares as types. +;; 'c-digit-separator +;; Used for digit separators in numeric literals, where it gets set +;; with the value t. +;; +;; 'c-typedef +;; This property is applied to the first character of a "typedef" +;; keyword. It's value is a list of the identifiers that the "typedef" +;; declares as types. ;; ;; 'c-awk-NL-prop ;; Used in AWK mode to mark the various kinds of newlines. See @@ -713,11 +719,11 @@ comment at the start of cc-engine.el for more info." (defmacro c-looking-at-c++-attribute () - ;; If we're in C++ Mode, and point is at the [[ introducing an attribute, - ;; return the position of the end of the attribute, otherwise return nil. - ;; The match data are NOT preserved over this macro. + ;; If we're in C or C++ Mode, and point is at the [[ introducing an + ;; attribute, return the position of the end of the attribute, otherwise + ;; return nil. The match data are NOT preserved over this macro. `(and - (c-major-mode-is 'c++-mode) + (c-major-mode-is '(c-mode c++-mode)) (looking-at "\\[\\[") (save-excursion (and @@ -1511,7 +1517,7 @@ comment at the start of cc-engine.el for more info." ;; In a string/comment? ((setq lit-range (c-literal-limits from)) (goto-char (cdr lit-range))) - ;; Skip over a C++ attribute? + ;; Skip over a C or C++ attribute? ((eq (char-after) ?\[) (if (setq attr-end (c-looking-at-c++-attribute)) (goto-char attr-end) @@ -1946,11 +1952,11 @@ comment at the start of cc-engine.el for more info." (defvar c-sws-lit-limits nil) (defun c-enclosing-c++-attribute () - ;; If we're in C++ Mode, and point is within a correctly balanced [[ ... ]] - ;; attribute structure, return a cons of its starting and ending positions. - ;; Otherwise, return nil. + ;; If we're in C or C++ Mode, and point is within a correctly balanced [[ + ;; ... ]] attribute structure, return a cons of its starting and ending + ;; positions. Otherwise, return nil. (and - (c-major-mode-is 'c++-mode) + (c-major-mode-is '(c-mode c++-mode)) (save-excursion (let ((lim (max (- (point) 200) (point-min))) cand) @@ -2139,7 +2145,7 @@ comment at the start of cc-engine.el for more info." (when (or (looking-at c-syntactic-ws-start) (and c-opt-cpp-prefix (looking-at c-noise-macro-name-re)) - (and (c-major-mode-is 'c++-mode) + (and (c-major-mode-is '(c-mode c++-mode)) (looking-at "\\[\\[")) (looking-at c-doc-line-join-re)) @@ -2397,7 +2403,7 @@ comment at the start of cc-engine.el for more info." (re-search-backward doc-line-join-here (c-point 'bopl) t)) (and - (c-major-mode-is 'c++-mode) + (c-major-mode-is '(c-mode c++-mode)) (eq (char-before) ?\]) (eq (char-before (1- (point))) ?\]) (save-excursion @@ -2570,7 +2576,7 @@ comment at the start of cc-engine.el for more info." (goto-char next-rung-pos) t) - ((and (c-major-mode-is 'c++-mode) + ((and (c-major-mode-is '(c-mode c++-mode)) (eq (char-before) ?\]) (eq (char-before (1- (point))) ?\]) (save-excursion @@ -8626,15 +8632,35 @@ multi-line strings (but not C++, for example)." (goto-char here) nil))) +(defmacro c-forward-align-clause-throw-if-invalid (throw-tag) + ;; If we are at a `c-type-modifier-with-parens-key' keyword, try to go + ;; forward over the clause it introduces, and return t. If the clause is + ;; ill formed (or absent), move point to START, set RES to nil, and throw + ;; nil to the tag THROW-TAG. Otherwise, return nil. The match data are + ;; preserved. + ;; This macro is intended only for use withing `c-forward-type'. + `(if (save-match-data + (looking-at c-type-modifier-with-parens-key)) + (if (and (zerop (c-forward-token-2)) + (eq (char-after) ?\() + (c-safe (c-go-list-forward)) + (eq (char-before) ?\)) + (setq pos (point)) + (progn (c-forward-syntactic-ws) t)) + t + (setq res nil) + (goto-char start) + (throw ,throw-tag nil)) + nil)) + (defun c-forward-keyword-clause (match &optional stop-at-end) - ;; Submatch MATCH in the current match data is assumed to surround a - ;; token. If it's a keyword, move over it and any immediately - ;; following clauses associated with it, stopping either at the start - ;; of the next token, or (when STOP-AT-END is non-nil) at the end - ;; of the clause. t is returned in that case, otherwise the point - ;; stays and nil is returned. The kind of clauses that are - ;; recognized are those specified by `c-type-list-kwds', - ;; `c-ref-list-kwds', `c-colon-type-list-kwds', + ;; Submatch MATCH in the current match data is assumed to surround a token. + ;; If it's a keyword, move over it and, if present, over any immediately + ;; following clauses associated with it, stopping either at the start of the + ;; next token, or (when STOP-AT-END is non-nil) at the end of the clause. t + ;; is returned in that case, otherwise the point stays and nil is returned. + ;; The kind of clauses that are recognized are those specified by + ;; `c-type-list-kwds', `c-ref-list-kwds', `c-colon-type-list-kwds', ;; `c-paren-nontype-kwds', `c-paren-type-kwds', `c-<>-type-kwds', ;; `c-<>-arglist-kwds', and `c-protection-kwds'. ;; @@ -9321,7 +9347,7 @@ multi-line strings (but not C++, for example)." ;; o - 'found if it's a type that matches one in `c-found-types'; ;; o - 'maybe if it's an identifier that might be a type; ;; o - 'decltype if it's a decltype(variable) declaration; - or - ;; o - 'no-id if "auto" precluded parsing a type identifier (C++) + ;; o - 'no-id if "auto" precluded parsing a type identifier (C or C++) ;; or the type int was implicit (C). ;; o - nil if it can't be a type (the point isn't moved then). ;; @@ -9342,327 +9368,370 @@ multi-line strings (but not C++, for example)." (c-forward-syntactic-ws)) (let ((start (point)) pos res name-res id-start id-end id-range - post-prefix-pos prefix-end-pos) + post-prefix-pos prefix-end-pos equals-makes-type) ;; Skip leading type modifiers. If any are found we know it's a ;; prefix of a type. - (when c-maybe-typeless-specifier-re - (while (looking-at c-maybe-typeless-specifier-re) - (save-match-data - (when (looking-at c-no-type-key) - (setq res 'no-id))) + (catch 'type-error + (when c-maybe-typeless-specifier-re + (while (looking-at c-maybe-typeless-specifier-re) + (save-match-data + (when (looking-at c-no-type-key) + (setq res 'no-id)) + (when (looking-at c-no-type-with-equals-key) + (setq equals-makes-type t))) + (if (c-forward-align-clause-throw-if-invalid 'type-error) + (setq prefix-end-pos pos) + (goto-char (match-end 1)) + (setq prefix-end-pos (point)) + (setq pos (point)) + (c-forward-syntactic-ws) + (or (eq res 'no-id) + (setq res 'prefix))))) + (setq post-prefix-pos (point)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + (cond + ((looking-at c-typeof-key) ; e.g. C++'s "decltype". (goto-char (match-end 1)) - (setq prefix-end-pos (point)) (setq pos (point)) (c-forward-syntactic-ws) - (or (eq res 'no-id) - (setq res 'prefix)))) - (setq post-prefix-pos (point)) + (setq res (and (eq (char-after) ?\() + (c-safe (c-forward-sexp)) + 'decltype)) + (if res + (progn + (setq pos (point)) + (c-forward-syntactic-ws)) + (goto-char start))) - (cond - ((looking-at c-typeof-key) ; e.g. C++'s "decltype". - (goto-char (match-end 1)) - (setq pos (point)) - (c-forward-syntactic-ws) - (setq res (and (eq (char-after) ?\() - (c-safe (c-forward-sexp)) - 'decltype)) - (if res - (progn - (setq pos (point)) - (c-forward-syntactic-ws)) - (goto-char start))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ((looking-at c-type-prefix-key) ; e.g. "struct", "class", but NOT - ; "typedef". - (goto-char (match-end 1)) - (setq pos (point)) - (c-forward-syntactic-ws) + ((looking-at c-type-prefix-key) ; e.g. "struct", "class", but NOT + ; "typedef". + (goto-char (match-end 1)) + (setq pos (point)) + (c-forward-syntactic-ws) - (while (cond - ((looking-at c-decl-hangon-key) - (c-forward-keyword-clause 1 t) - (setq pos (point)) - (c-forward-syntactic-ws)) - ((looking-at c-pack-key) - (goto-char (match-end 1)) - (setq pos (point)) - (c-forward-syntactic-ws)) - ((and c-opt-cpp-prefix - (looking-at c-noise-macro-with-parens-name-re)) - (c-forward-noise-clause t) - (setq pos (point)) - (c-forward-syntactic-ws)))) + (while (cond + ((looking-at c-decl-hangon-key) + (c-forward-keyword-clause 1 t) + (setq pos (point)) + (c-forward-syntactic-ws)) + ((looking-at c-pack-key) + (goto-char (match-end 1)) + (setq pos (point)) + (c-forward-syntactic-ws)) + ((and c-opt-cpp-prefix + (looking-at c-noise-macro-with-parens-name-re)) + (c-forward-noise-clause t) + (setq pos (point)) + (c-forward-syntactic-ws)))) - (setq id-start (point)) - (setq name-res (c-forward-name t)) - (setq pos (point)) - (setq res (not (null name-res))) - (when (eq name-res t) - ;; With some keywords the name can be used without the prefix, so we - ;; add the name to `c-found-types' when this is the case. - (when (save-excursion - (goto-char post-prefix-pos) - (looking-at c-self-contained-typename-key)) - (c-add-type id-start - (point))) - (when (and c-record-type-identifiers - c-last-identifier-range) - (c-record-type-id c-last-identifier-range))) - (c-forward-syntactic-ws) - (when (and brace-block-too - (memq res '(t nil)) - (eq (char-after) ?\{) - (save-excursion - (c-safe - (progn (c-forward-sexp) - (setq pos (point)))))) - (goto-char pos) + (setq id-start (point)) + (setq name-res (c-forward-name t)) + (setq pos (point)) + (setq res (not (null name-res))) + (when (eq name-res t) + ;; With some keywords the name can be used without the prefix, so we + ;; add the name to `c-found-types' when this is the case. + (when (save-excursion + (goto-char post-prefix-pos) + (looking-at c-self-contained-typename-key)) + (c-add-type id-start + (point))) + (when (and c-record-type-identifiers + c-last-identifier-range) + (c-record-type-id c-last-identifier-range))) (c-forward-syntactic-ws) - (setq res t)) - (unless res (goto-char start))) ; invalid syntax + (when (and brace-block-too + (memq res '(t nil)) + (eq (char-after) ?\{) + (save-excursion + (c-safe + (progn (c-forward-sexp) + (setq pos (point)))))) + (goto-char pos) + (c-forward-syntactic-ws) + (setq res t)) + (unless res (goto-char start))) ; invalid syntax - ((and - (not (eq res 'no-id)) - (progn - (setq pos nil) - (while (and c-opt-cpp-prefix - (looking-at c-noise-macro-with-parens-name-re)) - (c-forward-noise-clause)) - (if (looking-at c-identifier-start) - (save-excursion - (setq id-start (point) - name-res (c-forward-name t)) - (when name-res - (setq id-end (point) - id-range c-last-identifier-range)))) - (and (cond ((looking-at c-primitive-type-key) - (setq res t)) - ((c-with-syntax-table c-identifier-syntax-table - (looking-at c-known-type-key)) - (setq res 'known))) - (or (not id-end) - (>= (save-excursion - (save-match-data - (goto-char (match-end 1)) - (setq pos (point)) - (c-forward-syntactic-ws) - pos)) - id-end) - (setq res nil))))) - ;; Looking at a primitive or known type identifier. We've - ;; checked for a name first so that we don't go here if the - ;; known type match only is a prefix of another name. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (setq id-end (match-end 1)) + ((looking-at c-type-with-paren-key) ; C's "_BitInt". + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (if (and (eq (char-after) ?\() + (c-go-list-forward nil (min (+ (point) 500) (point-max))) + (eq (char-before) ?\))) + (progn + (setq pos (point)) + (c-forward-syntactic-ws) + (setq res t)) + (goto-char start) + (setq res nil))) ; invalid syntax. - (when (and c-record-type-identifiers - (or c-promote-possible-types (eq res t))) - (c-record-type-id (cons (match-beginning 1) (match-end 1)))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (cond - ((and c-opt-type-component-key + ((and + (not (eq res 'no-id)) + (not (and equals-makes-type + (save-excursion + (and (zerop (c-forward-token-2)) + (looking-at "=\\([^=]\\|$\\)"))) + (setq res 'no-id))) + (progn + (setq pos nil) + (while (and c-opt-cpp-prefix + (looking-at c-noise-macro-with-parens-name-re)) + (c-forward-noise-clause)) + (if (looking-at c-identifier-start) + (save-excursion + (setq id-start (point) + name-res (c-forward-name t)) + (when name-res + (setq id-end (point) + id-range c-last-identifier-range)))) + (and (cond ((looking-at c-primitive-type-key) + (setq res t)) + ((c-with-syntax-table c-identifier-syntax-table + (looking-at c-known-type-key)) + (setq res 'known))) + (or (not id-end) + (>= (save-excursion + (save-match-data + (goto-char (match-end 1)) + (setq pos (point)) + (c-forward-syntactic-ws) + pos)) + id-end) + (setq res nil))))) + ;; Looking at a primitive or known type identifier. We've + ;; checked for a name first so that we don't go here if the + ;; known type match only is a prefix of another name. + + (setq id-end (match-end 1)) + + (when (and c-record-type-identifiers + (or c-promote-possible-types (eq res t))) + (c-record-type-id (cons (match-beginning 1) (match-end 1)))) + + (cond + ((and c-opt-type-component-key (save-match-data (looking-at c-opt-type-component-key))) ;; There might be more keywords for the type. - (let (safe-pos) - (c-forward-keyword-clause 1 t) + (let (safe-pos) + (c-forward-keyword-clause 1 t) + (while (progn + (setq safe-pos (point)) + (c-forward-syntactic-ws) + (looking-at c-opt-type-component-key)) + (when (and c-record-type-identifiers + (looking-at c-primitive-type-key)) + (c-record-type-id (cons (match-beginning 1) + (match-end 1)))) + (or (c-forward-align-clause-throw-if-invalid 'type-error) + (c-forward-keyword-clause 1 t))) + (if (looking-at c-primitive-type-key) + (progn + (when c-record-type-identifiers + (c-record-type-id (cons (match-beginning 1) + (match-end 1)))) + (c-forward-keyword-clause 1 t) + (setq res t) + (while (progn + (setq safe-pos (point)) + (c-forward-syntactic-ws) + (looking-at c-opt-type-component-key)) + (c-forward-keyword-clause 1 t))) + (goto-char safe-pos) + (setq res 'prefix)) + (setq pos (point)))) + ((save-match-data (c-forward-keyword-clause 1 t)) (while (progn - (setq safe-pos (point)) + (setq pos (point)) (c-forward-syntactic-ws) - (looking-at c-opt-type-component-key)) - (when (and c-record-type-identifiers - (looking-at c-primitive-type-key)) - (c-record-type-id (cons (match-beginning 1) - (match-end 1)))) - (c-forward-keyword-clause 1 t)) - (if (looking-at c-primitive-type-key) - (progn - (when c-record-type-identifiers - (c-record-type-id (cons (match-beginning 1) - (match-end 1)))) - (c-forward-keyword-clause 1 t) - (setq res t) - (while (progn - (setq safe-pos (point)) - (c-forward-syntactic-ws) - (looking-at c-opt-type-component-key)) - (c-forward-keyword-clause 1 t))) - (goto-char safe-pos) - (setq res 'prefix)) - (setq pos (point)))) - ((save-match-data (c-forward-keyword-clause 1 t)) - (while (progn - (setq pos (point)) - (c-forward-syntactic-ws) - (and c-opt-type-component-key - (looking-at c-opt-type-component-key))) - (c-forward-keyword-clause 1 t))) - (pos (goto-char pos)) - (t (goto-char (match-end 1)) - (setq pos (point)))) - (c-forward-syntactic-ws)) - - ((and (eq name-res t) - (eq res 'prefix) - (c-major-mode-is 'c-mode) - (save-excursion - (goto-char id-end) - (setq pos (point)) - (c-forward-syntactic-ws) - (and (not (looking-at c-symbol-start)) - (or - (not (looking-at c-type-decl-prefix-key)) - (and (eq (char-after) ?\() - (not (save-excursion - (c-forward-declarator)))))))) - ;; A C specifier followed by an implicit int, e.g. - ;; "register count;" - (goto-char prefix-end-pos) - (setq pos (point)) - (unless stop-at-end + (and c-opt-type-component-key + (looking-at c-opt-type-component-key))) + (or (c-forward-align-clause-throw-if-invalid 'type-error) + (c-forward-keyword-clause 1 t)))) + (pos (goto-char pos)) + (t (goto-char (match-end 1)) + (setq pos (point)))) (c-forward-syntactic-ws)) - (setq res 'no-id)) - (name-res - (cond ((eq name-res t) - ;; A normal identifier. - (goto-char id-end) - (setq pos (point)) - (c-forward-syntactic-ws) - (if (or res c-promote-possible-types) - (progn - (when (not (eq c-promote-possible-types 'just-one)) - (c-add-type id-start id-end)) - (when (and c-record-type-identifiers id-range) - (c-record-type-id id-range)) - (unless res - (setq res 'found)) - (when (eq res 'prefix) - (setq res t))) - (setq res (if (c-check-qualified-type id-start) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + ((and (eq name-res t) + (eq res 'prefix) + (c-major-mode-is 'c-mode) + (save-excursion + (goto-char id-end) + (setq pos (point)) + (c-forward-syntactic-ws) + (and (not (looking-at c-symbol-start)) + (or + (not (looking-at c-type-decl-prefix-key)) + (and (eq (char-after) ?\() + (not (save-excursion + (c-forward-declarator)))))))) + ;; A C specifier followed by an implicit int, e.g. + ;; "register count;" + (goto-char prefix-end-pos) + (setq pos (point)) + (unless stop-at-end + (c-forward-syntactic-ws)) + (setq res 'no-id)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + (name-res + (cond ((eq name-res t) + ;; A normal identifier. + (goto-char id-end) + (setq pos (point)) + (c-forward-syntactic-ws) + (if (or res c-promote-possible-types) + (progn + (when (not (eq c-promote-possible-types 'just-one)) + (c-add-type id-start id-end)) + (when (and c-record-type-identifiers id-range) + (c-record-type-id id-range)) + (unless res + (setq res 'found)) + (when (eq res 'prefix) + (setq res t))) + (setq res (if (c-check-qualified-type id-start) + ;; It's an identifier that has been used as + ;; a type somewhere else. + 'found + ;; It's an identifier that might be a type. + 'maybe)))) + ((eq name-res 'template) + ;; A template is sometimes a type. + (goto-char id-end) + (setq pos (point)) + (c-forward-syntactic-ws) + (setq res + (if (eq (char-after) ?\() + (if (c-check-qualified-type id-start) ;; It's an identifier that has been used as ;; a type somewhere else. 'found ;; It's an identifier that might be a type. - 'maybe)))) - ((eq name-res 'template) - ;; A template is sometimes a type. - (goto-char id-end) - (setq pos (point)) - (c-forward-syntactic-ws) - (setq res - (if (eq (char-after) ?\() - (if (c-check-qualified-type id-start) - ;; It's an identifier that has been used as - ;; a type somewhere else. - 'found - ;; It's an identifier that might be a type. - 'maybe) - t))) - (t - ;; Otherwise it's an operator identifier, which is not a type. - (goto-char start) - (setq res nil)))) - - ((eq res 'prefix) - ;; Deal with "extern "C" foo_t my_foo;" - (setq res nil))) - - (when (not (memq res '(nil no-id))) - ;; Skip trailing type modifiers. If any are found we know it's - ;; a type. - (when c-opt-type-modifier-key - (while (looking-at c-opt-type-modifier-key) ; e.g. "const", "volatile" + 'maybe) + t))) + (t + ;; Otherwise it's an operator identifier, which is not a type. + (goto-char start) + (setq res nil)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + ((eq res 'prefix) + ;; Deal with "extern "C" foo_t my_foo;" + (setq res nil))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + (when (not (memq res '(nil no-id))) + ;; Skip trailing type modifiers. If any are found we know it's + ;; a type. + (when c-opt-type-modifier-key + (while (looking-at c-opt-type-modifier-key) ; e.g. "const", "volatile" + (unless (c-forward-align-clause-throw-if-invalid 'type-error) + (goto-char (match-end 1)) + (setq pos (point)) + (c-forward-syntactic-ws) + (setq res t)))) + + ;; Step over any type suffix operator. Do not let the existence + ;; of these alter the classification of the found type, since + ;; these operators typically are allowed in normal expressions + ;; too. + (when c-opt-type-suffix-key ; e.g. "..." + (while (looking-at c-opt-type-suffix-key) + (goto-char (match-end 1)) + (setq pos (point)) + (c-forward-syntactic-ws))) + + ;; Skip any "WS" identifiers (e.g. "final" or "override" in C++) + (while (looking-at c-type-decl-suffix-ws-ids-key) (goto-char (match-end 1)) (setq pos (point)) (c-forward-syntactic-ws) - (setq res t))) - - ;; Step over any type suffix operator. Do not let the existence - ;; of these alter the classification of the found type, since - ;; these operators typically are allowed in normal expressions - ;; too. - (when c-opt-type-suffix-key ; e.g. "..." - (while (looking-at c-opt-type-suffix-key) - (goto-char (match-end 1)) + (setq res t)) + + (when c-opt-type-concat-key ; Only/mainly for pike. + ;; Look for a trailing operator that concatenates the type + ;; with a following one, and if so step past that one through + ;; a recursive call. Note that we don't record concatenated + ;; types in `c-found-types' - it's the component types that + ;; are recorded when appropriate. (setq pos (point)) - (c-forward-syntactic-ws))) - - ;; Skip any "WS" identifiers (e.g. "final" or "override" in C++) - (while (looking-at c-type-decl-suffix-ws-ids-key) - (goto-char (match-end 1)) - (setq pos (point)) - (c-forward-syntactic-ws) - (setq res t)) - - (when c-opt-type-concat-key ; Only/mainly for pike. - ;; Look for a trailing operator that concatenates the type - ;; with a following one, and if so step past that one through - ;; a recursive call. Note that we don't record concatenated - ;; types in `c-found-types' - it's the component types that - ;; are recorded when appropriate. - (setq pos (point)) - (let* ((c-promote-possible-types (or (memq res '(t known)) - c-promote-possible-types)) - ;; If we can't promote then set `c-record-found-types' so that - ;; we can merge in the types from the second part afterwards if - ;; it turns out to be a known type there. - (c-record-found-types (and c-record-type-identifiers - (not c-promote-possible-types))) - subres) - (if (and (looking-at c-opt-type-concat-key) + (let* ((c-promote-possible-types (or (memq res '(t known)) + c-promote-possible-types)) + ;; If we can't promote then set `c-record-found-types' so that + ;; we can merge in the types from the second part afterwards if + ;; it turns out to be a known type there. + (c-record-found-types (and c-record-type-identifiers + (not c-promote-possible-types))) + subres) + (if (and (looking-at c-opt-type-concat-key) - (progn - (goto-char (match-end 1)) - (c-forward-syntactic-ws) - (setq subres (c-forward-type nil t)) - (setq pos (point)))) - - (progn - ;; If either operand certainly is a type then both are, but we - ;; don't let the existence of the operator itself promote two - ;; uncertain types to a certain one. - (cond ((eq res t)) - ((eq subres t) - (unless (eq name-res 'template) - (c-add-type id-start id-end)) - (when (and c-record-type-identifiers id-range) - (c-record-type-id id-range)) - (setq res t)) - ((eq res 'known)) - ((eq subres 'known) - (setq res 'known)) - ((eq res 'found)) - ((eq subres 'found) - (setq res 'found)) - (t - (setq res 'maybe))) - - (when (and (eq res t) - (consp c-record-found-types)) - ;; Cause the confirmed types to get fontified. - (let ((cur c-record-found-types)) - (while (consp (car-safe cur)) - (c-fontify-new-found-type - (buffer-substring-no-properties (caar cur) (cdar cur))) - (setq cur (cdr cur)))) - ;; Merge in the ranges of any types found by the second - ;; `c-forward-type'. - (setq c-record-type-identifiers - ;; `nconc' doesn't mind that the tail of - ;; `c-record-found-types' is t. - (nconc c-record-found-types - c-record-type-identifiers))))))) + (progn + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (setq subres (c-forward-type nil t)) + (setq pos (point)))) - (goto-char pos) - (unless stop-at-end - (c-forward-syntactic-ws)) + (progn + ;; If either operand certainly is a type then both are, but we + ;; don't let the existence of the operator itself promote two + ;; uncertain types to a certain one. + (cond ((eq res t)) + ((eq subres t) + (unless (eq name-res 'template) + (c-add-type id-start id-end)) + (when (and c-record-type-identifiers id-range) + (c-record-type-id id-range)) + (setq res t)) + ((eq res 'known)) + ((eq subres 'known) + (setq res 'known)) + ((eq res 'found)) + ((eq subres 'found) + (setq res 'found)) + (t + (setq res 'maybe))) + + (when (and (eq res t) + (consp c-record-found-types)) + ;; Cause the confirmed types to get fontified. + (let ((cur c-record-found-types)) + (while (consp (car-safe cur)) + (c-fontify-new-found-type + (buffer-substring-no-properties (caar cur) (cdar cur))) + (setq cur (cdr cur)))) + ;; Merge in the ranges of any types found by the second + ;; `c-forward-type'. + (setq c-record-type-identifiers + ;; `nconc' doesn't mind that the tail of + ;; `c-record-found-types' is t. + (nconc c-record-found-types + c-record-type-identifiers))))))) - (when (and c-record-found-types (memq res '(known found)) id-range) - (setq c-record-found-types - (cons id-range c-record-found-types)))) + (goto-char pos) + (unless stop-at-end + (c-forward-syntactic-ws)) + (when (and c-record-found-types (memq res '(known found)) id-range) + (setq c-record-found-types + (cons id-range c-record-found-types))))) ;;(message "c-forward-type %s -> %s: %s" start (point) res) res)) @@ -9998,6 +10067,32 @@ point unchanged and return nil." (and (zerop (c-forward-token-2)) ; over "requires". (c-forward-constraint-clause limit stop-at-end))) +(defun c-in-id-arglist () + ;; If point is inside a paren delimited non-empty arglist, all of whose + ;; arguments are identifiers, return a cons of the start and (after) the end + ;; of the arglist. Otherwise return nil. + (let* ((paren-state (c-parse-state)) + (enclosing-paren-pos (c-most-enclosing-brace paren-state))) + (save-excursion + (and + enclosing-paren-pos + (eq (char-after enclosing-paren-pos) ?\() + (progn + (goto-char (1+ enclosing-paren-pos)) + (c-forward-syntactic-ws) + (catch 'in-arglist + (while + (and + (c-on-identifier) + (zerop (c-forward-token-2)) + (progn + (when (eq (char-after) ?\)) + (throw 'in-arglist + (cons enclosing-paren-pos (1+ (point))))) + (eq (char-after) ?\,)) + (zerop (c-forward-token-2)))) + nil)))))) + (defun c-forward-decl-arglist (not-top id-in-parens &optional limit) ;; Point is at an open parenthesis, assumed to be the arglist of a function ;; declaration. Move over this arglist and following syntactic whitespace, @@ -11276,10 +11371,13 @@ This function might do hidden buffer changes." ;; style declarations and parenthesis style initializers ;; aren't allowed then the single identifier must be a ;; type, else we require that it's known or found - ;; (primitive types are handled above). + ;; (primitive types are handled above). We also allow + ;; 'maybe types when nameless types can be in arglists. (or (and (not c-recognize-knr-p) (not c-recognize-paren-inits)) - (memq at-type '(known found)))) + (memq at-type '(known found)) + (and c-recognize-nameless-type-decls + (eq at-type 'maybe)))) ((eq context '<>) ;; Inside a template arglist. Accept known and found ;; types; other identifiers could just as well be diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index ac5a32f704f..eca249ee2f6 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -521,6 +521,29 @@ (c-put-font-lock-face (car elem) (cdr elem) c-reference-face-name)))) +(defun c-font-lock-cpp-messages (limit) + ;; Font lock #error and #warning messages between point and LIMIT. + ;; Always return nil to prevent a further call to this function. + ;; The position of point at the end of this function is random. + (while + (and (< (point) limit) + (re-search-forward c-cpp-messages-re limit t)) + (let ((beg (match-beginning c-cpp-message-match-no)) + (end (match-end c-cpp-message-match-no))) + (c-put-font-lock-string-face beg end) + ;; We replace '(1) (punctuation) syntax-table text properties on ' by + ;; '(3) (symbol), so that these characters won't later get the warning + ;; face. + (goto-char beg) + (while (and + (< (point) end) + (c-search-forward-char-property-with-value-on-char + 'syntax-table '(1) ?\' end)) + (c-put-char-property ;; -trim-caches + (1- (point)) 'syntax-table '(3))) + (goto-char end))) + nil) + (c-lang-defconst c-cpp-matchers "Font lock matchers for preprocessor directives and purely lexical stuff. Used on level 1 and higher." @@ -529,28 +552,20 @@ stuff. Used on level 1 and higher." ;; sets `font-lock-type-face' in languages where ;; `c-recognize-<>-arglists' is set. - t `(,@(when (c-lang-const c-opt-cpp-prefix) + t `(;; Fontify "invalid" comment delimiters + ,@(when (and (c-lang-const c-block-comment-starter) + (c-lang-const c-line-comment-starter)) + `(c-maybe-font-lock-wrong-style-comments)) + ,@(when (c-lang-const c-opt-cpp-prefix) (let* ((noncontinued-line-end "\\(\\=\\|\\(\\=\\|[^\\]\\)[\n\r]\\)") (ncle-depth (regexp-opt-depth noncontinued-line-end)) (sws-depth (c-lang-const c-syntactic-ws-depth)) (nsws-depth (c-lang-const c-nonempty-syntactic-ws-depth))) - `(;; Fontify "invalid" comment delimiters - ,@(when (and (c-lang-const c-block-comment-starter) - (c-lang-const c-line-comment-starter)) - `(c-maybe-font-lock-wrong-style-comments)) - - ;; The stuff after #error and #warning is a message, so + `(;; The stuff after #error and #warning is a message, so ;; fontify it as a string. ,@(when (c-lang-const c-cpp-message-directives) - (let* ((re (c-make-keywords-re 'appendable ; nil - (c-lang-const c-cpp-message-directives))) - (re-depth (regexp-opt-depth re))) - `((,(concat noncontinued-line-end - (c-lang-const c-opt-cpp-prefix) - re - "\\s +\\(.*\\)$") - ,(+ ncle-depth re-depth 1) font-lock-string-face t)))) + '(c-font-lock-cpp-messages)) ;; Fontify filenames in #include <...> as strings. ,@(when (c-lang-const c-cpp-include-directives) @@ -1219,22 +1234,29 @@ casts and declarations are fontified. Used on level 2 and higher." ;; characters it allows within the list. (let ((type (and (> match-pos (point-min)) (c-get-char-property (1- match-pos) 'c-type))) - id-pos) + id-pos tok-end-pos) (cond ;; Are we just after something like "(foo((bar))" ? ((and (eq (char-before match-pos) ?\)) (c-go-list-backward match-pos) (progn (c-backward-syntactic-ws) - (and (setq id-pos (c-on-identifier)) - (goto-char id-pos) - (progn - (c-backward-syntactic-ws) - (eq (char-before) ?\())))) - (c-get-fontification-context (point) not-front-decl toplev)) + (setq tok-end-pos (point)) + (cond + ((and (setq id-pos (c-on-identifier)) + (goto-char id-pos) + (progn + (c-backward-syntactic-ws) + (eq (char-before) ?\())) + (c-get-fontification-context (point) not-front-decl toplev)) + ((progn + (goto-char tok-end-pos) + (and (zerop (c-backward-token-2)) + (looking-at c-type-internal-paren-key))) + (cons 'not-decl nil)))))) ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?< ?{))) (cons (and toplev 'top) nil)) - ;; A control flow expression or a decltype + ;; A control flow expression or a decltype, etc. ((and (eq (char-before match-pos) ?\() (save-excursion (goto-char match-pos) @@ -1246,7 +1268,8 @@ casts and declarations are fontified. Used on level 2 and higher." (cons nil nil)) ((or (looking-at c-block-stmt-2-key) (looking-at c-block-stmt-1-2-key) - (looking-at c-typeof-key)) + (looking-at c-typeof-key) + (looking-at c-type-internal-paren-key)) (cons nil t)) (t nil))))) ;; Near BOB. @@ -1531,8 +1554,8 @@ casts and declarations are fontified. Used on level 2 and higher." ;; `parse-sexp-lookup-properties' (when it exists). (parse-sexp-lookup-properties (cc-eval-when-compile - (boundp 'parse-sexp-lookup-properties)) - )) + (boundp 'parse-sexp-lookup-properties))) + list-bounds) ;; Below we fontify a whole declaration even when it crosses the limit, ;; to avoid gaps when jit/lazy-lock fontifies the file a block at a @@ -1622,6 +1645,24 @@ casts and declarations are fontified. Used on level 2 and higher." nil) ((eq context 'generic) (c-font-lock-c11-generic-clause)) + + ;; K&R parameters. + ((and + c-recognize-knr-p + (or toplev inside-macro) + (eq context 'decl) + (setq list-bounds (c-in-id-arglist)) + (save-excursion + (goto-char (car list-bounds)) + (and (zerop (c-backward-token-2)) + (eq (point) (c-on-identifier)))) + (save-excursion + (goto-char (cdr list-bounds)) + (c-forward-syntactic-ws) + (not (memq (char-after) '(?\; ?{ ?\? ?: ?\,))))) + ;; Nothing to fontify. + (goto-char (cdr list-bounds))) + (t (setq decl-or-cast (c-forward-decl-or-cast-1 @@ -2371,7 +2412,10 @@ on level 2 only and so aren't combined with `c-complex-decl-matchers'." ;; Fontify basic types. ,(let ((re (c-make-keywords-re nil - (c-lang-const c-primitive-type-kwds)))) + (cl-delete-duplicates + (append (c-lang-const c-primitive-type-kwds) + (c-lang-const c-type-with-paren-kwds)) + :test #'equal)))) (if (c-major-mode-is 'pike-mode) ;; No symbol is a keyword after "->" in Pike. `(,(concat "\\(\\=.?\\|[^>]\\|[^-]>\\)" diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 17fb51aaeac..772b09e1f97 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -835,7 +835,7 @@ there be copies of the opener contained in the multi-line string." (c-lang-defconst c-has-quoted-numbers "Whether the language has numbers quoted like 4'294'967'295." t nil - c++ t) + (c c++) t) (c-lang-defvar c-has-quoted-numbers (c-lang-const c-has-quoted-numbers)) (c-lang-defconst c-has-compound-literals @@ -1172,11 +1172,37 @@ string message." '("error")) (c c++ objc pike) '("error" "warning")) +(c-lang-defconst c-cpp-message-directives-re + ;; Appendable regexp matching any of the tokens in `c-cpp-message-directives'. + t (c-make-keywords-re 'appendable (c-lang-const c-cpp-message-directives))) + +(c-lang-defconst noncontinued-line-end + t "\\(\\=\\|\\(\\=\\|[^\\]\\)[\n\r]\\)") +(c-lang-defconst ncle-depth + t (regexp-opt-depth (c-lang-const noncontinued-line-end))) + +(c-lang-defconst c-cpp-messages-re + ;; Regexp to match a #error or #warning construct. See + ;; `c-cpp-message-directives'. + t (if (c-lang-const c-cpp-message-directives) + (concat (c-lang-const noncontinued-line-end) + (c-lang-const c-opt-cpp-prefix) + (c-lang-const c-cpp-message-directives-re) + "\\s +\\(\\(\\\\\\(\\\\?\n\\|.\\)\\|[^\n]\\)*\\)$"))) +(c-lang-defvar c-cpp-messages-re (c-lang-const c-cpp-messages-re)) + +(c-lang-defconst c-cpp-message-match-no + t (if (c-lang-const c-cpp-messages-re) + (+ 1 (c-lang-const ncle-depth) + (regexp-opt-depth (c-lang-const c-cpp-message-directives-re))))) +(c-lang-defvar c-cpp-message-match-no (c-lang-const c-cpp-message-match-no)) + (c-lang-defconst c-cpp-include-directives "List of cpp directives (without the prefix) that are followed by a file name in angle brackets or quotes." t (if (c-lang-const c-opt-cpp-prefix) '("include")) + c '("include" "embed") objc '("include" "import")) (c-lang-defconst c-cpp-include-key @@ -1235,7 +1261,8 @@ definition, or nil if the language doesn't have any." "List of cpp directives (without the prefix) that are followed by an expression." t (if (c-lang-const c-opt-cpp-prefix) - '("if" "elif"))) + '("if" "elif" + "elifdef" "elifndef"))) (c-lang-defconst c-cpp-expr-intro-re "Regexp which matches the start of a CPP directive which contains an @@ -1751,9 +1778,10 @@ This doesn't count the merely contextual bits of the regexp match." (c-lang-const c-opt-cpp-symbol) ; usually # (substring (c-lang-const c-stmt-delim-chars) 1)) ; ";{}?:" (c-lang-const c-stmt-delim-chars)) - c++ (concat (substring (c-lang-const c-stmt-boundary-skip-chars) 0 1) ; "^" - "[" - (substring (c-lang-const c-stmt-boundary-skip-chars) 1))) ; ";{}?:" + (c c++) (concat + (substring (c-lang-const c-stmt-boundary-skip-chars) 0 1) ; "^" + "[" + (substring (c-lang-const c-stmt-boundary-skip-chars) 1))) ; ";{}?:" (c-lang-defvar c-stmt-boundary-skip-chars (c-lang-const c-stmt-boundary-skip-chars)) @@ -2250,7 +2278,7 @@ This works in Emacs >= 25.1." ;; `c-kwds-lang-consts' list below and used to build `c-keywords' etc. (c-lang-defconst c-primitive-type-kwds - "Primitive type keywords. As opposed to the other keyword lists, the + "Primitive type keywords. As opposed to most other keyword lists, the keywords listed here are fontified with the type face instead of the keyword face. @@ -2265,10 +2293,12 @@ the appropriate place for that." t '("char" "double" "float" "int" "long" "short" "signed" "unsigned" "void") c (append - '("_Bool" "_Complex" "_Imaginary") ; Conditionally defined in C99. + '("_Bool" "_Complex" "_Imaginary" ;) Conditionally defined in C99. + "_Decimal32" "_Decimal64" "_Decimal128" + "bool" "char8_t" "char16_t" "char32_t" "nullptr_t") (c-lang-const c-primitive-type-kwds)) c++ (append - '("bool" "wchar_t" "char8_t" "char16_t" "char32_t") + '("bool" "wchar_t" "char8_t" "char16_t" "char32_t" "nullptr_t") (c-lang-const c-primitive-type-kwds)) ;; Objective-C extends C, but probably not the new stuff in C99. objc (append @@ -2327,7 +2357,7 @@ of a variable declaration." "Keywords followed by a parenthesized expression, which stands for the type of that expression." t nil - c '("typeof") ; longstanding GNU C(++) extension. + c '("typeof" "typeof_unqual") c++ '("decltype" "typeof")) (c-lang-defconst c-typeof-key @@ -2357,6 +2387,16 @@ used in declarations without the keyword." (c-lang-defvar c-self-contained-typename-key (c-lang-const c-self-contained-typename-key)) +(c-lang-defconst c-type-with-paren-kwds + "Keywords followed by a parenthesis expression, which form types." + t nil + c '("_BitInt")) + +(c-lang-defconst c-type-with-paren-key + "Adorned regexp which matches an element of `c-type-with-paren-kwds'." + t (c-make-keywords-re t (c-lang-const c-type-with-paren-kwds))) +(c-lang-defvar c-type-with-paren-key (c-lang-const c-type-with-paren-key)) + (c-lang-defconst c-type-prefix-kwds "Keywords where the following name - if any - is a type name, and where the keyword together with the symbol works as a type in @@ -2375,6 +2415,31 @@ on one of the `*-decl-kwds' lists." t (c-make-keywords-re t (c-lang-const c-type-prefix-kwds))) (c-lang-defvar c-type-prefix-key (c-lang-const c-type-prefix-key)) +(c-lang-defconst c-type-modifier-with-parens-kwds + "Keywords which have parenthesis expressions which modify a type. +They can appear anywhere in the type. Not included here are kwds which +stand in place of a type, namely those in `c-no-type-kwds'." + t nil + c '("alignof" "alignas" "_Alignas" "_Alignof")) + +(c-lang-defconst c-type-modifier-with-parens-key + ;; Adorned regexp matching `c-type-modifier-with-parens-kwds'. + t (c-make-keywords-re t (c-lang-const c-type-modifier-with-parens-kwds))) +(c-lang-defvar c-type-modifier-with-parens-key + (c-lang-const c-type-modifier-with-parens-key)) + +(c-lang-defconst c-type-internal-paren-kwds + ;; Keywords which can be followed by a parenthesis expression inside a type + ;; specification. + t (append (c-lang-const c-type-with-paren-kwds) + (c-lang-const c-type-modifier-with-parens-kwds))) + +(c-lang-defconst c-type-internal-paren-key + ;; Adorned regexp matching any member of `c-type-internal-paren-kwds'. + t (c-make-keywords-re t (c-lang-const c-type-internal-paren-kwds))) +(c-lang-defvar c-type-internal-paren-key + (c-lang-const c-type-internal-paren-key)) + (c-lang-defconst c-type-modifier-prefix-kwds "Type modifier keywords which can appear in front of a type. These can also occur almost anywhere in types but they don't build a type of @@ -2386,6 +2451,7 @@ fontified with the keyword face and not the type face." objc '("const" "volatile") java '("final") t (append (c-lang-const c-no-type-kwds) + (c-lang-const c-type-modifier-with-parens-kwds) (c-lang-const c-type-modifier-prefix-kwds))) (c-lang-defconst c-opt-type-modifier-prefix-key @@ -2427,7 +2493,8 @@ the type face." ;; or a complete type). t (c--delete-duplicates (append (c-lang-const c-primitive-type-kwds) (c-lang-const c-type-prefix-kwds) - (c-lang-const c-type-modifier-kwds)) + (c-lang-const c-type-modifier-kwds) + (c-lang-const c-type-with-paren-kwds)) :test 'string-equal)) (c-lang-defconst c-type-decl-suffix-ws-ids-kwds @@ -2539,7 +2606,7 @@ and precede the opening brace." "Set to t when we recognize a colon and then a type after an enum, e.g., enum foo : int { A, B, C };" t nil - c++ t) + (c c++) t) (c-lang-defvar c-recognize-post-brace-list-type-p (c-lang-const c-recognize-post-brace-list-type-p)) @@ -2644,6 +2711,17 @@ will be handled." t (c-make-keywords-re t (c-lang-const c-no-type-kwds))) (c-lang-defvar c-no-type-key (c-lang-const c-no-type-key)) +(c-lang-defconst c-no-type-with-equals-kwds + "Keywords after which no type is needed when there's an = sign." + t nil + c '("auto")) + +(c-lang-defconst c-no-type-with-equals-key + ;; Regexp mathing an entry from `c-no-type-with-equals-kwds'. + t (c-make-keywords-re t (c-lang-const c-no-type-with-equals-kwds))) +(c-lang-defvar c-no-type-with-equals-key + (c-lang-const c-no-type-with-equals-key)) + (c-lang-defconst c-typeless-decl-kwds "Keywords introducing declarations where the (first) identifier \(declarator) follows directly after the keyword, without any type. @@ -2750,10 +2828,12 @@ If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', `c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses will be handled." t nil - (c c++) '("extern" "inline" "register" "static") - c (append '("auto") (c-lang-const c-modifier-kwds)) - c++ (append '("consteval" "constexpr" "constinit" "explicit" - "friend" "mutable" "template" "thread_local" "virtual") + (c c++) '("constexpr" "extern" "inline" "register" + "static" "thread_local") + c (append '("auto" "_Thread_local") + (c-lang-const c-modifier-kwds)) + c++ (append '("consteval" "constinit" "explicit" + "friend" "mutable" "template" "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") @@ -3061,7 +3141,9 @@ contain type identifiers." (c c++) '(;; GCC extension. "__attribute__" ;; MSVC extension. - "__declspec") + "__declspec" + "static_assert") + c (append (c-lang-const c-paren-nontype-kwds) '("_Static_assert")) c++ (append (c-lang-const c-paren-nontype-kwds) '("noexcept" "alignas"))) (c-lang-defconst c-paren-nontype-key @@ -3337,11 +3419,9 @@ not really template operators." (c-lang-defconst c-constant-kwds "Keywords for constants." t nil - c '("NULL" ;; Not a keyword, but practically works as one. - "false" "true") ; Defined in C99. - c++ (append - '("nullptr") - (c-lang-const c-constant-kwds c)) + (c c++) '("NULL" ;; Not a keyword, but practically works as one. + "false" "true" ; Defined in C99. + "nullptr") objc '("nil" "Nil" "YES" "NO" "IBAction" "IBOutlet" "NS_DURING" "NS_HANDLER" "NS_ENDHANDLER") idl '("TRUE" "FALSE") @@ -3618,7 +3698,8 @@ Note that Java specific rules are currently applied to tell this from t (c-make-keywords-re t (c--set-difference (c-lang-const c-keywords) (append (c-lang-const c-primitive-type-kwds) - (c-lang-const c-constant-kwds)) + (c-lang-const c-constant-kwds) + (c-lang-const c-type-with-paren-kwds)) :test 'string-equal))) (c-lang-defvar c-regular-keywords-regexp (c-lang-const c-regular-keywords-regexp)) @@ -4237,6 +4318,13 @@ This is only used in c++-mode." (c-lang-defvar c-pre-brace-non-bracelist-key (c-lang-const c-pre-brace-non-bracelist-key)) +(c-lang-defconst c-recognize-nameless-type-decls + "Non-nil means a type may be used in an arglist without an identifier." + t nil + c t) +(c-lang-defvar c-recognize-nameless-type-decls + (c-lang-const c-recognize-nameless-type-decls)) + (c-lang-defconst c-recognize-typeless-decls "Non-nil means function declarations without return type should be recognized. That can introduce an ambiguity with parenthesized macro diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index d500fb29959..e559265d295 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -194,6 +194,8 @@ (c-clear-char-properties (point-min) (point-max) 'c-is-sws) (c-clear-char-properties (point-min) (point-max) 'c-in-sws) (c-clear-char-properties (point-min) (point-max) 'c-type) + (if c-has-quoted-numbers + (c-clear-char-properties (point-min) (point-max) 'c-digit-separator)) (if (c-major-mode-is 'awk-mode) (c-clear-char-properties (point-min) (point-max) 'c-awk-NL-prop)))) (setq c-buffer-is-cc-mode nil))) @@ -2583,7 +2585,7 @@ with // and /*, not more generic line and block comments." (goto-char (car ml-delim))) (c-backward-syntactic-ws lim) (when (setq enclosing-attribute (c-enclosing-c++-attribute)) - (goto-char (car enclosing-attribute)) ; Only happens in C++ Mode. + (goto-char (car enclosing-attribute)) ; Only happens in C or C++ Mode. (c-backward-syntactic-ws lim)) (while (and (> (point) lim) (memq (char-before) '(?\[ ?\()))