Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:ymarkovitch:devel
emacs
emacs-cc-mode-master.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File emacs-cc-mode-master.patch of Package emacs
diff --git a/lisp/progmodes/cc-align.el b/lisp/progmodes/cc-align.el index 37e40d039cc..fbbb81b6f10 100644 --- a/lisp/progmodes/cc-align.el +++ b/lisp/progmodes/cc-align.el @@ -940,6 +940,16 @@ Works with: template-args-cont." (zerop (c-forward-token-2 1 nil (c-point 'eol)))) (vector (current-column))))) +(defun c-lineup-template-args-indented-from-margin (_langelem) + "Indent a template argument line `c-basic-offset' from the margin +of the line with the containing <. + +Works with: template-args-cont." + (save-excursion + (goto-char (c-langelem-2nd-pos c-syntactic-element)) + (back-to-indentation) + (vector (+ (current-column) c-basic-offset)))) + (defun c-lineup-ObjC-method-call (langelem) "Line up selector args as Emacs Lisp mode does with function args: Go to the position right after the message receiver, and if you are at diff --git a/lisp/progmodes/cc-awk.el b/lisp/progmodes/cc-awk.el index 9798f397491..e299f4fa8d2 100644 --- a/lisp/progmodes/cc-awk.el +++ b/lisp/progmodes/cc-awk.el @@ -754,14 +754,14 @@ (if (eq (char-after beg) ?_) (setq beg (1+ beg))) ;; First put the properties on the delimiters. - (cond ((eq end (point-max)) ; string/regexp terminated by EOB - (c-put-char-property beg 'syntax-table '(15))) ; (15) = "string fence" - ((/= (char-after beg) (char-after end)) ; missing end delimiter - (c-put-char-property beg 'syntax-table '(15)) - (c-put-char-property end 'syntax-table '(15))) - ((eq (char-after beg) ?/) ; Properly bracketed regexp - (c-put-char-property beg 'syntax-table '(7)) ; (7) = "string" - (c-put-char-property end 'syntax-table '(7))) + (cond ((eq end (point-max)) ; string/regexp terminated by EOB + (c-put-string-fence beg)) + ((/= (char-after beg) (char-after end)) ; missing end delimiter + (c-put-string-fence beg) + (c-put-string-fence end)) + ((eq (char-after beg) ?/) ; Properly bracketed regexp + (c-put-char-property beg 'syntax-table '(7)) ; (7) = "string" + (c-put-char-property end 'syntax-table '(7))) (t)) ; Properly bracketed string: Nothing to do. ;; Now change the properties of any escaped "s in the string to punctuation. (save-excursion diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index 8dc0714dacf..7cd6cb0dda0 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -4909,7 +4909,8 @@ If a fill prefix is specified, it overrides all the above." (setq c-lit-limits (c-literal-limits nil nil t))) (unless c-lit-type (setq c-lit-type (c-literal-type c-lit-limits))) - (if (memq (cond ((c-query-and-set-macro-start) 'cpp) + (if (memq (cond ((memq c-lit-type '(c c++ string)) c-lit-type) + ((c-query-and-set-macro-start) 'cpp) ((null c-lit-type) 'code) (t c-lit-type)) c-ignore-auto-fill) @@ -5144,6 +5145,41 @@ details." (goto-char here) (delete-char 1)))) + + +;; Text conversion support. + +(defun c-post-text-conversion () + "Notice that the character `last-command-event' has been inserted. +If said character is an electric character such as `*' or `{', delete +it, then call the appropriate CC Mode function to electrically insert +it again." + (cond ((eq last-command-event ?#) + (delete-char -1) + (c-electric-pound nil) t) + ((memq last-command-event '(?{ ?})) + (delete-char -1) + (c-electric-brace nil) t) + ((memq last-command-event '(?\( ?\))) + (delete-char -1) + (c-electric-paren nil) t) + ((eq last-command-event ?*) + (delete-char -1) + (c-electric-star nil) t) + ((eq last-command-event ?/) + (delete-char -1) + (c-electric-slash nil) t) + ((memq last-command-event '(?\; ?,)) + (delete-char -1) + (c-electric-semi&comma nil) t) + ((eq last-command-event ?:) + (delete-char -1) + (c-electric-colon nil) t) + ((memq last-command-event '(?> ?<)) + (delete-char -1) + (c-electric-lt-gt nil) t))) + + (cc-provide 'cc-cmds) diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index 8fe3d653636..f84d95dbc94 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -425,11 +425,14 @@ to it is returned. This function does not modify the point or the mark." (defvar lookup-syntax-properties) ;XEmacs. (defmacro c-is-escaped (pos) - ;; Are there an odd number of backslashes before POS? + ;; Is the character following POS escaped? (declare (debug t)) `(save-excursion (goto-char ,pos) - (not (zerop (logand (skip-chars-backward "\\\\") 1))))) + (if (and c-escaped-newline-takes-precedence + (memq (char-after) '(?\n ?\r))) + (eq (char-before) ?\\) + (not (zerop (logand (skip-chars-backward "\\\\") 1)))))) (defmacro c-will-be-escaped (pos beg end) ;; Will the character after POS be escaped after the removal of (BEG END)? @@ -437,13 +440,23 @@ to it is returned. This function does not modify the point or the mark." (declare (debug t)) `(save-excursion (let ((-end- ,end) + (-pos- ,pos) count) - (goto-char ,pos) - (setq count (skip-chars-backward "\\\\" -end-)) - (when (eq (point) -end-) - (goto-char ,beg) - (setq count (+ count (skip-chars-backward "\\\\")))) - (not (zerop (logand count 1)))))) + (if (and c-escaped-newline-takes-precedence + (memq (char-after -pos-) '(?\n ?\r))) + (eq (char-before (if (eq -pos- -end-) + ,beg + -pos-)) + ?\\) + (goto-char -pos-) + (setq count + (if (> -pos- -end-) + (skip-chars-backward "\\\\" -end-) + 0)) + (when (eq (point) -end-) + (goto-char ,beg) + (setq count (+ count (skip-chars-backward "\\\\")))) + (not (zerop (logand count 1))))))) (defmacro c-will-be-unescaped (beg) ;; Would the character after BEG be unescaped? @@ -720,9 +733,10 @@ various buffer change hooks." (defmacro c-forward-syntactic-ws (&optional limit) "Forward skip over syntactic whitespace. -Syntactic whitespace is defined as whitespace characters, comments, -and preprocessor directives. However if point starts inside a comment -or preprocessor directive, the content of it is not treated as +Syntactic whitespace is defined as whitespace characters with +whitespace (or comment-end) syntax, comments, and preprocessor +directives. However if point starts inside a comment or +preprocessor directive, the content of it is not treated as whitespace. LIMIT sets an upper limit of the forward movement, if specified. If @@ -742,9 +756,10 @@ comment at the start of cc-engine.el for more info." (defmacro c-backward-syntactic-ws (&optional limit) "Backward skip over syntactic whitespace. -Syntactic whitespace is defined as whitespace characters, comments, -and preprocessor directives. However if point starts inside a comment -or preprocessor directive, the content of it is not treated as +Syntactic whitespace is defined as whitespace characters with +whitespace (or comment-end) syntax, comments, and preprocessor +directives. However if point starts inside a comment or +preprocessor directive, the content of it is not treated as whitespace. LIMIT sets a lower limit of the backward movement, if specified. If @@ -912,7 +927,8 @@ be after it." (when dest (goto-char dest) t))) (defmacro c-beginning-of-defun-1 () - ;; Wrapper around beginning-of-defun. + ;; Wrapper around beginning-of-defun. Note that the return value from this + ;; macro has no significance. ;; ;; NOTE: This function should contain the only explicit use of ;; beginning-of-defun in CC Mode. Eventually something better than @@ -925,44 +941,49 @@ be after it." ;; `c-parse-state'. `(progn - (if (and ,(fboundp 'buffer-syntactic-context-depth) - c-enable-xemacs-performance-kludge-p) - ,(when (fboundp 'buffer-syntactic-context-depth) - ;; XEmacs only. This can improve the performance of - ;; c-parse-state to between 3 and 60 times faster when - ;; braces are hung. It can also degrade performance by - ;; about as much when braces are not hung. - '(let (beginning-of-defun-function end-of-defun-function - pos) - (while (not pos) - (save-restriction - (widen) - (setq pos (c-safe-scan-lists - (point) -1 (buffer-syntactic-context-depth)))) - (cond - ((bobp) (setq pos (point-min))) - ((not pos) - (let ((distance (skip-chars-backward "^{"))) - ;; unbalanced parenthesis, while invalid C code, - ;; shouldn't cause an infloop! See unbal.c - (when (zerop distance) - ;; Punt! - (beginning-of-defun) - (setq pos (point))))) - ((= pos 0)) - ((not (eq (char-after pos) ?{)) - (goto-char pos) - (setq pos nil)) - )) - (goto-char pos))) - ;; Emacs, which doesn't have buffer-syntactic-context-depth - (let (beginning-of-defun-function end-of-defun-function) - (beginning-of-defun))) - ;; if defun-prompt-regexp is non-nil, b-o-d won't leave us at the - ;; open brace. - (and defun-prompt-regexp - (looking-at defun-prompt-regexp) - (goto-char (match-end 0))))) + (while + (progn + (if (and ,(fboundp 'buffer-syntactic-context-depth) + c-enable-xemacs-performance-kludge-p) + ,(when (fboundp 'buffer-syntactic-context-depth) + ;; XEmacs only. This can improve the performance of + ;; c-parse-state to between 3 and 60 times faster when + ;; braces are hung. It can also degrade performance by + ;; about as much when braces are not hung. + '(let (beginning-of-defun-function end-of-defun-function + pos) + (while (not pos) + (save-restriction + (widen) + (setq pos (c-safe-scan-lists + (point) -1 (buffer-syntactic-context-depth)))) + (cond + ((bobp) (setq pos (point-min))) + ((not pos) + (let ((distance (skip-chars-backward "^{"))) + ;; unbalanced parenthesis, while invalid C code, + ;; shouldn't cause an infloop! See unbal.c + (when (zerop distance) + ;; Punt! + (beginning-of-defun) + (setq pos (point))))) + ((= pos 0)) + ((not (eq (char-after pos) ?{)) + (goto-char pos) + (setq pos nil)) + )) + (goto-char pos))) + ;; Emacs, which doesn't have buffer-syntactic-context-depth + (let (beginning-of-defun-function end-of-defun-function) + (beginning-of-defun))) + (and (not (bobp)) + ;; if defun-prompt-regexp is non-nil, b-o-d won't leave us at + ;; the open brace. + defun-prompt-regexp + (looking-at (concat defun-prompt-regexp "\\s(")) + (or (not (eq (char-before (match-end 0)) ?{)) + (progn (goto-char (1- (match-end 0))) + nil))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1089,6 +1110,38 @@ continuations." (eq (char-before) ?\\))) (backward-char)))) +(defmacro c-skip-ws-chars-forward (string &optional lim) + ;; Move point forward, stopping before a char which isn't in STRING, or a + ;; char whose syntax isn't whitespace or comment-end, or at pos LIM. + ;; Note that \n usually has comment-end syntax. + ;; + ;; Returns the distance traveled, either zero or positive. + (declare (debug t)) + `(let ((-lim- ,lim) + (here (point)) + count) + (setq count (skip-chars-forward ,string -lim-)) + (when (> count 0) + (goto-char here) + (setq count (skip-syntax-forward " >" (+ here count)))) + count)) + +(defmacro c-skip-ws-chars-backward (string &optional lim) + ;; Move point backward, stopping after a char which isn't in STRING, or a + ;; char whose syntax isn't whitespace or comment-end, or at pos LIM. Note + ;; that \n usually has comment-end syntax. + ;; + ;; Returns the distance traveled, either zero or negative. + (declare (debug t)) + `(let ((-lim- ,lim) + (here (point)) + count) + (setq count (skip-chars-backward ,string -lim-)) + (when (< count 0) + (goto-char here) + (setq count (skip-syntax-backward " >" (+ here count)))) + count)) + (eval-and-compile (defvar c-langs-are-parametric nil)) @@ -1195,6 +1248,17 @@ MODE is either a mode symbol or a list of mode symbols." `((setq c-syntax-table-hwm (min c-syntax-table-hwm -pos-)))) (put-text-property -pos- (1+ -pos-) ',property ,value)))) +(defmacro c-put-string-fence (pos) + ;; Put the string-fence syntax-table text property at POS. + ;; Since the character there cannot then count as syntactic whitespace, + ;; clear the properties `c-is-sws' and `c-in-sws' (see functions + ;; `c-forward-sws' and `c-backward-sws' in cc-engine.el for details). + (declare (debug t)) + `(let ((-pos- ,pos)) + (c-put-char-property -pos- 'syntax-table '(15)) + (c-clear-char-property -pos- 'c-is-sws) + (c-clear-char-property -pos- 'c-in-sws))) + (eval-and-compile ;; Constant to decide at compilation time whether to use category ;; properties. Currently (2010-03) they're available only on GNU @@ -1284,6 +1348,21 @@ MODE is either a mode symbol or a list of mode symbols." pos) (most-positive-fixnum)))) +(defmacro c-put-char-properties (from to property value) + ;; Put the given PROPERTY with the given VALUE on the characters between + ;; FROM and TO. PROPERTY is assumed to be constant. The return value is + ;; undefined. + ;; + ;; This macro does hidden buffer changes. + (declare (debug t)) + (setq property (eval property)) + `(let ((-from- ,from)) + (progn + ,@(when (and (fboundp 'syntax-ppss) + (eq `,property 'syntax-table)) + `((setq c-syntax-table-hwm (min c-syntax-table-hwm -from-)))) + (put-text-property -from- ,to ',property ,value)))) + (defmacro c-clear-char-properties (from to property) ;; Remove all the occurrences of the given property in the given ;; region that has been put with `c-put-char-property'. PROPERTY is @@ -1379,7 +1458,8 @@ isn't found, return nil; point is then left undefined." value) (t (let ((place (c-next-single-property-change (point) ,property nil -limit-))) - (when place + (when (and place + (< place -limit-)) (goto-char (1+ place)) (c-get-char-property place ,property))))))) @@ -1846,9 +1926,9 @@ with value CHAR in the region [FROM to)." '(looking-at "\\([;#]\\|\\'\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s$\\|\\s<\\|\\s>\\|\\s!\\)") '(or (looking-at - "\\([;#]\\|\\'\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s$\\|\\s<\\|\\s>\\)" + "\\([;#]\\|\\'\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s$\\|\\s<\\|\\s>\\)") (let ((prop (c-get-char-property (point) 'syntax-table))) - (equal prop '(14))))))) ; '(14) is generic comment delimiter. + (equal prop '(14)))))) ; '(14) is generic comment delimiter. (defsubst c-intersect-lists (list alist) diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 8a954c4c14e..ea4ee3d7b7c 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -146,11 +146,6 @@ ;; "typedef" keyword. It's value is a list of the identifiers that ;; the "typedef" declares as types. ;; -;; 'c-<>-c-types-set -;; This property is set on an opening angle bracket, and indicates that -;; any "," separators within the template/generic expression have been -;; marked with a 'c-type property value 'c-<>-arg-sep (see above). -;; ;; 'c-awk-NL-prop ;; Used in AWK mode to mark the various kinds of newlines. See ;; cc-awk.el. @@ -981,10 +976,10 @@ comment at the start of cc-engine.el for more info." (point-min))) (widen) - (if (save-excursion - (and (c-beginning-of-macro) - (/= (point) start))) - (setq macro-start (point))) + (save-excursion + (if (and (c-beginning-of-macro) + (/= (point) start)) + (setq macro-start (point)))) ;; Try to skip back over unary operator characters, to register ;; that we've moved. @@ -1651,7 +1646,7 @@ This function does not do any hidden buffer changes." ;; comment, but XEmacs doesn't. We depend on the Emacs ;; behavior (which also is symmetric). (if (and (eolp) (elt (parse-partial-sexp start (point)) 7)) - (condition-case nil (forward-char 1))) + (forward-char 1)) t)))) @@ -2135,7 +2130,7 @@ comment at the start of cc-engine.el for more info." ;; Skip simple ws and do a quick check on the following character to see ;; if it's anything that can't start syntactic ws, so we can bail out ;; early in the majority of cases when there just are a few ws chars. - (skip-chars-forward " \t\n\r\f\v") + (c-skip-ws-chars-forward " \t\n\r\f\v") (when (or (looking-at c-syntactic-ws-start) (and c-opt-cpp-prefix (looking-at c-noise-macro-name-re)) @@ -2185,7 +2180,7 @@ comment at the start of cc-engine.el for more info." rung-pos (point) (point-max)) (setq rung-pos (point)) - (and (> (skip-chars-forward " \t\n\r\f\v") 0) + (and (> (c-skip-ws-chars-forward " \t\n\r\f\v") 0) (not (eobp)))) ;; We'll loop here if there is simple ws after the last rung. @@ -2251,7 +2246,7 @@ comment at the start of cc-engine.el for more info." (and c-opt-cpp-prefix (looking-at c-opt-cpp-start) (setq macro-start (point)) - (progn (skip-chars-backward " \t") + (progn (c-skip-ws-chars-backward " \t") (bolp)) (or (bobp) (progn (backward-char) @@ -2291,7 +2286,7 @@ comment at the start of cc-engine.el for more info." ;; We've searched over a piece of non-white syntactic ws. See if this ;; can be cached. (setq next-rung-pos (point)) - (skip-chars-forward " \t\n\r\f\v") + (c-skip-ws-chars-forward " \t\n\r\f\v") (setq rung-end-pos (min (1+ (point)) (point-max))) (if (or @@ -2388,7 +2383,7 @@ comment at the start of cc-engine.el for more info." ;; bail out early in the majority of cases when there just are a few ws ;; chars. Newlines are complicated in the backward direction, so we can't ;; skip over them. - (skip-chars-backward " \t\f") + (c-skip-ws-chars-backward " \t\f") (when (and (not (bobp)) (save-excursion (or (and @@ -2416,7 +2411,7 @@ comment at the start of cc-engine.el for more info." (setq simple-ws-beg (or attr-end ; After attribute. (match-end 1) ; Noise macro, etc. (match-end 0))) ; c-syntactic-ws-end - (skip-chars-backward " \t\n\r\f\v") + (c-skip-ws-chars-backward " \t\n\r\f\v") (if (setq rung-is-marked (text-property-any (point) (min (1+ rung-pos) (point-max)) 'c-is-sws t)) @@ -2453,10 +2448,10 @@ comment at the start of cc-engine.el for more info." (point) rung-pos (point-min)) (setq rung-pos (point)) - (if (and (< (min (skip-chars-backward " \t\f\v") + (if (and (< (min (c-skip-ws-chars-backward " \t\f\v") (progn (setq simple-ws-beg (point)) - (skip-chars-backward " \t\n\r\f\v"))) + (c-skip-ws-chars-backward " \t\n\r\f\v"))) 0) (setq rung-is-marked (text-property-any (point) rung-pos @@ -2536,7 +2531,7 @@ comment at the start of cc-engine.el for more info." ;; the macro, and then `simple-ws-beg' must be kept on the ;; same side of those comments. (goto-char simple-ws-beg) - (skip-chars-backward " \t\n\r\f\v") + (c-skip-ws-chars-backward " \t\n\r\f\v") (if (eq (char-before) ?\\) (forward-char)) (forward-line 1) @@ -2549,7 +2544,7 @@ comment at the start of cc-engine.el for more info." t))) ((/= (save-excursion - (skip-chars-forward " \t\n\r\f\v" simple-ws-beg) + (c-skip-ws-chars-forward " \t\n\r\f\v" simple-ws-beg) (setq next-rung-pos (point))) simple-ws-beg) ;; Skipped over comments. Must put point at the end of @@ -2586,7 +2581,7 @@ comment at the start of cc-engine.el for more info." ;; We've searched over a piece of non-white syntactic ws. See if this ;; can be cached. (setq next-rung-pos (point)) - (skip-chars-backward " \t\f\v") + (c-skip-ws-chars-backward " \t\f\v") (if (or ;; Cache if we started either from a marked rung or from a @@ -2596,7 +2591,7 @@ comment at the start of cc-engine.el for more info." ;; Cache if there's a marked rung in the encountered simple ws. (save-excursion - (skip-chars-backward " \t\n\r\f\v") + (c-skip-ws-chars-backward " \t\n\r\f\v") (text-property-any (point) (min (1+ next-rung-pos) (point-max)) 'c-is-sws t))) @@ -2677,6 +2672,7 @@ comment at the start of cc-engine.el for more info." (progn (goto-char beg) (c-skip-ws-forward end+1) (eq (point) end+1)))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; We maintain a sopisticated cache of positions which are in a literal, @@ -5915,19 +5911,21 @@ comment at the start of cc-engine.el for more info." (cond ((> pos start) ; Nothing but literals base) - ((> base (point-min)) + ((and + (> base (point-min)) + (> (- base try-size) (point-min))) ; prevent infinite recursion. (c-determine-limit how-far-back base (* 2 try-size) org-start)) (t base))) ((>= count how-far-back) (c-determine-limit-no-macro - (+ (car elt) (- count how-far-back)) - org-start)) + (+ (car elt) (- count how-far-back)) + org-start)) ((eq base (point-min)) (point-min)) ((> base (- start try-size)) ; Can only happen if we hit point-min. (c-determine-limit-no-macro - (car elt) - org-start)) + (car elt) + org-start)) (t (c-determine-limit (- how-far-back count) base (* 2 try-size) org-start)))))) @@ -6170,12 +6168,18 @@ comment at the start of cc-engine.el for more info." (cons (point) (cons bound-<> s))))) +(defvar c-record-type-identifiers) ; Specially for `c-brace-stack-at'. + (defun c-brace-stack-at (here) ;; Given a buffer position HERE, Return the value of the brace stack there. (save-excursion (save-restriction (widen) - (let ((c c-bs-cache) + (let (c-record-type-identifiers ; In case `c-forward-<>-arglist' would + ; otherwise record identifiers outside + ; of the restriction in force before + ; this function. + (c c-bs-cache) (can-use-prev (<= c-bs-prev-pos c-bs-cache-limit)) elt stack pos npos high-elt) ;; Trim the cache to take account of buffer changes. @@ -6241,6 +6245,9 @@ comment at the start of cc-engine.el for more info." ;; prefix". The declaration prefix is the earlier of `cfd-prop-match' and ;; `cfd-re-match'. `cfd-match-pos' is set to the decl prefix. ;; + ;; The variables which this macro should set for `c-find-decl-spots' are + ;; `cfd-match-pos' and `cfd-continue-pos'. + ;; ;; This macro might do hidden buffer changes. '(progn @@ -6583,11 +6590,17 @@ comment at the start of cc-engine.el for more info." ;; and so we can continue the search from this point. If we ;; didn't hit `c-find-decl-syntactic-pos' then we're now in ;; the right spot to begin searching anyway. - (if (and (eq (point) c-find-decl-syntactic-pos) - c-find-decl-match-pos) - (setq cfd-match-pos c-find-decl-match-pos - cfd-continue-pos syntactic-pos) - + (cond + ((and (eq (point) c-find-decl-syntactic-pos) + c-find-decl-match-pos) + (setq cfd-match-pos c-find-decl-match-pos + cfd-continue-pos syntactic-pos)) + ((save-excursion (c-beginning-of-macro)) + ;; The `c-backward-syntactic-ws' ~40 lines up failed to find non + ;; syntactic-ws and hit its limit, leaving us in a macro. + (setq cfd-match-pos cfd-start-pos + cfd-continue-pos cfd-start-pos)) + (t (setq c-find-decl-syntactic-pos syntactic-pos) (when (if (bobp) @@ -6605,7 +6618,7 @@ comment at the start of cc-engine.el for more info." (c-find-decl-prefix-search)) ; sets cfd-continue-pos (setq c-find-decl-match-pos (and (< cfd-match-pos cfd-start-pos) - cfd-match-pos))))) ; end of `cond' + cfd-match-pos)))))) ; end of `cond' ;; Advance `cfd-continue-pos' if it's before the start position. ;; The closest continue position that might have effect at or @@ -7027,8 +7040,8 @@ comment at the start of cc-engine.el for more info." ;; POS (default point) is at a < character. If it is both marked ;; with open/close paren syntax-table property, and has a matching > ;; (also marked) which is after LIM, remove the property both from - ;; the current > and its partner. Return t when this happens, nil - ;; when it doesn't. + ;; the current > and its partner. Return the position after the > + ;; when this happens, nil when it doesn't. (save-excursion (if pos (goto-char pos) @@ -7042,15 +7055,15 @@ comment at the start of cc-engine.el for more info." c->-as-paren-syntax)) ; should always be true. (c-unmark-<->-as-paren (1- (point))) (c-unmark-<->-as-paren pos) - (c-truncate-lit-pos-cache pos)) - t))) + (c-truncate-lit-pos-cache pos) + (point))))) (defun c-clear->-pair-props-if-match-before (lim &optional pos) ;; POS (default point) is at a > character. If it is both marked ;; with open/close paren syntax-table property, and has a matching < ;; (also marked) which is before LIM, remove the property both from - ;; the current < and its partner. Return t when this happens, nil - ;; when it doesn't. + ;; the current < and its partner. Return the position of the < when + ;; this happens, nil when it doesn't. (save-excursion (if pos (goto-char pos) @@ -7064,8 +7077,8 @@ comment at the start of cc-engine.el for more info." c-<-as-paren-syntax)) ; should always be true. (c-unmark-<->-as-paren (point)) (c-truncate-lit-pos-cache (point)) - (c-unmark-<->-as-paren pos)) - t))) + (c-unmark-<->-as-paren pos) + (point))))) ;; Set by c-common-init in cc-mode.el. (defvar c-new-BEG) @@ -7073,7 +7086,48 @@ comment at the start of cc-engine.el for more info." ;; Set by c-before-change-check-raw-strings. (defvar c-old-END-literality) -(defun c-before-change-check-<>-operators (beg end) +(defun c-end-of-literal (pt-s pt-search) + ;; If a literal is open in the `c-semi-pp-to-literal' state PT-S, return the + ;; end point of this literal (or point-max) assuming PT-S is valid at + ;; PT-SEARCH. Otherwise, return nil. + (when (car (cddr pt-s)) ; Literal start + (let ((lit-type (cadr pt-s)) + (lit-beg (car (cddr pt-s))) + ml-end-re + ) + (save-excursion + (cond + ((eq lit-type 'string) + (if (and c-ml-string-opener-re + (c-ml-string-opener-at-or-around-point lit-beg)) + (progn + (setq ml-end-re + (funcall c-make-ml-string-closer-re-function + (match-string 1))) + (goto-char (max (- pt-search (1- (length ml-end-re))) + (point-min))) + (re-search-forward ml-end-re nil 'stay)) + ;; For an ordinary string, we can't use `parse-partial-sexp' since + ;; not all syntax-table properties have yet been set. + (goto-char pt-search) + (re-search-forward + "\\(?:\\\\\\(?:.\\|\n\\)\\|[^\"\n\\]\\)*[\"\n]" nil 'stay))) + ((memq lit-type '(c c++)) + ;; To work around a bug in parse-partial-sexp, where effect is given + ;; to the syntax of a backslash, even the the scan starts with point + ;; just after it. + (if (and (eq (char-before pt-search) ?\\) + (eq (char-after pt-search) ?\n)) + (progn + (c-put-char-property (1- pt-search) 'syntax-table '(1)) + (parse-partial-sexp pt-search (point-max) nil nil (car pt-s) + 'syntax-table) + (c-clear-char-property (1- pt-search) 'syntax-table)) + (parse-partial-sexp pt-search (point-max) nil nil (car pt-s) + 'syntax-table)))) + (point))))) + +(defun c-unmark-<>-around-region (beg end &optional old-len) ;; Unmark certain pairs of "< .... >" which are currently marked as ;; template/generic delimiters. (This marking is via syntax-table text ;; properties), and expand the (c-new-BEG c-new-END) region to include all @@ -7087,66 +7141,196 @@ comment at the start of cc-engine.el for more info." ;; enclose a brace or semicolon, so we use these as bounds on the ;; region we must work on. ;; + ;; The buffer is widened, and point is undefined, both at entry and exit. + ;; + ;; FIXME!!! This routine ignores the possibility of macros entirely. + ;; 2010-01-29. + + (when (> end beg) + ;; Extend the region (BEG END) to deal with any complicating literals. + (let* ((lit-search-beg (if (memq (char-before beg) '(?/ ?*)) + (1- beg) beg)) + (lit-search-end (if (memq (char-after end) '(?/ ?*)) + (1+ end) end)) + ;; Note we can't use c-full-pp-to-literal here, since we haven't + ;; yet applied syntax-table properties to ends of lines, etc. + (lit-search-beg-s (c-semi-pp-to-literal lit-search-beg)) + (beg-literal-beg (car (cddr lit-search-beg-s))) + (lit-search-end-s (c-semi-pp-to-literal lit-search-end)) + (end-literal-beg (car (cddr lit-search-end-s))) + (beg-literal-end (c-end-of-literal lit-search-beg-s lit-search-beg)) + (end-literal-end (c-end-of-literal lit-search-end-s lit-search-end)) + new-beg new-end search-region) + + ;; Determine any new end of literal resulting from the insertion/deletion. + (setq search-region + (if (and (eq beg-literal-beg end-literal-beg) + (eq beg-literal-end end-literal-end)) + (if beg-literal-beg + nil + (cons beg + (max end + (or beg-literal-end (point-min)) + (or end-literal-end (point-min))))) + (cons (or beg-literal-beg beg) + (max end + (or beg-literal-end (point-min)) + (or end-literal-end (point-min)))))) + + (when search-region + ;; If we've just inserted text, mask its syntaxes temporarily so that + ;; they won't interfere with the undoing of the properties on the <s + ;; and >s. + (c-save-buffer-state (syn-tab-settings syn-tab-value + swap-open-string-ends) + (unwind-protect + (progn + (when old-len + ;; Special case: If a \ has just been inserted into a + ;; string, escaping or unescaping a LF, temporarily swap + ;; the LF's syntax-table text property with that of the + ;; former end of the open string. + (goto-char end) + (when (and (eq (cadr lit-search-beg-s) 'string) + (not (eq beg-literal-end end-literal-end)) + (skip-chars-forward "\\\\") + (eq (char-after) ?\n) + (not (zerop (skip-chars-backward "\\\\")))) + (setq swap-open-string-ends t) + (if (c-get-char-property (1- beg-literal-end) + 'syntax-table) + (progn + (c-clear-char-property (1- beg-literal-end) + 'syntax-table) + (c-put-string-fence (1- end-literal-end))) + (c-put-string-fence (1- beg-literal-end)) + (c-clear-char-property (1- end-literal-end) + 'syntax-table))) + + ;; Save current settings of the 'syntax-table property in + ;; (BEG END), then splat these with the punctuation value. + (goto-char beg) + (while (setq syn-tab-value + (c-search-forward-non-nil-char-property + 'syntax-table end)) + (when (not (c-get-char-property (1- (point)) 'category)) + (push (cons (1- (point)) syn-tab-value) + syn-tab-settings))) + + (c-put-char-properties beg end 'syntax-table '(1)) + ;; If an open string's opener has just been neutralized, + ;; do the same to the terminating LF. + (when (and end-literal-end + (eq (char-before end-literal-end) ?\n) + (equal (c-get-char-property + (1- end-literal-end) 'syntax-table) + '(15))) + (push (cons (1- end-literal-end) '(15)) syn-tab-settings) + (c-put-char-property (1- end-literal-end) 'syntax-table + '(1)))) + + (let + ((beg-lit-start (progn (goto-char beg) (c-literal-start))) + beg-limit end-limit <>-pos) + ;; Locate the earliest < after the barrier before the + ;; changed region, which isn't already marked as a paren. + (goto-char (or beg-lit-start beg)) + (setq beg-limit (c-determine-limit 5000)) + + ;; Remove the syntax-table/category properties from each pertinent <...> + ;; pair. Firstly, the ones with the < before beg and > after beg.... + (goto-char (cdr search-region)) + (while (progn (c-syntactic-skip-backward "^;{}<" beg-limit) + (eq (char-before) ?<)) + (c-backward-token-2) + (when (eq (char-after) ?<) + (when (setq <>-pos (c-clear-<-pair-props-if-match-after + (car search-region))) + (setq new-end <>-pos)) + (setq new-beg (point)))) + + ;; ...Then the ones with < before end and > after end. + (goto-char (car search-region)) + (setq end-limit (c-determine-+ve-limit 5000)) + (while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end) + (eq (char-before) ?>)) + (when (eq (char-before) ?>) + (if (and (looking-at c->-op-cont-regexp) + (not (eq (char-after) ?>))) + (goto-char (match-end 0)) + (when + (and (setq <>-pos + (c-clear->-pair-props-if-match-before + (cdr search-region) + (1- (point)))) + (or (not new-beg) + (< <>-pos new-beg))) + (setq new-beg <>-pos)) + (when (or (not new-end) (> (point) new-end)) + (setq new-end (point)))))))) + + (when old-len + (c-clear-char-properties beg end 'syntax-table) + (dolist (elt syn-tab-settings) + (if (cdr elt) + (c-put-char-property (car elt) 'syntax-table (cdr elt))))) + ;; Swap the '(15) syntax-table property on open string LFs back + ;; again. + (when swap-open-string-ends + (if (c-get-char-property (1- beg-literal-end) + 'syntax-table) + (progn + (c-clear-char-property (1- beg-literal-end) + 'syntax-table) + (c-put-string-fence (1- end-literal-end))) + (c-put-string-fence (1- beg-literal-end)) + (c-clear-char-property (1- end-literal-end) + 'syntax-table))))) + ;; Extend the fontification region, if needed. + (and new-beg + (< new-beg c-new-BEG) + (setq c-new-BEG new-beg)) + (and new-end + (> new-end c-new-END) + (setq c-new-END new-end)))))) + +(defun c-before-change-check-<>-operators (beg end) + ;; When we're deleting text, unmark certain pairs of "< .... >" which are + ;; currently marked as template/generic delimiters. (This marking is via + ;; syntax-table text properties), and expand the (c-new-BEG c-new-END) + ;; region to include all unmarked < and > operators within the certain + ;; bounds (see below). + ;; + ;; These pairs are those which are in the current "statement" (i.e., + ;; the region between the {, }, or ; before BEG and the one after + ;; END), and which enclose any part of the interval (BEG END). + ;; Also unmark a < or > which is about to become part of a multi-character + ;; operator, e.g. <=. + ;; + ;; Note that in C++ (?and Java), template/generic parens cannot + ;; enclose a brace or semicolon, so we use these as bounds on the + ;; region we must work on. + ;; ;; This function is called from before-change-functions (via ;; c-get-state-before-change-functions). Thus the buffer is widened, ;; and point is undefined, both at entry and exit. ;; ;; FIXME!!! This routine ignores the possibility of macros entirely. ;; 2010-01-29. - (when (and (or (> end beg) - (and (> c-<-pseudo-digraph-cont-len 0) - (goto-char beg) - (progn - (skip-chars-backward - "^<" (max (- (point) c-<-pseudo-digraph-cont-len) - (point-min))) - (eq (char-before) ?<)) - (looking-at c-<-pseudo-digraph-cont-regexp))) - (or - (progn - (goto-char beg) - (search-backward "<" (max (- (point) 1024) (point-min)) t)) - (progn - (goto-char end) - (search-forward ">" (min (+ (point) 1024) (point-max)) t)))) - (save-excursion - (c-save-buffer-state - ((beg-lit-start (progn (goto-char beg) (c-literal-start))) - (end-lit-limits (progn (goto-char end) (c-literal-limits))) - new-beg new-end beg-limit end-limit) - ;; Locate the earliest < after the barrier before the changed region, - ;; which isn't already marked as a paren. - (goto-char (or beg-lit-start beg)) - (setq beg-limit (c-determine-limit 512)) - - ;; Remove the syntax-table/category properties from each pertinent <...> - ;; pair. Firstly, the ones with the < before beg and > after beg.... - (while (progn (c-syntactic-skip-backward "^;{}<" beg-limit) - (eq (char-before) ?<)) - (c-backward-token-2) - (when (eq (char-after) ?<) - (c-clear-<-pair-props-if-match-after beg) - (setq new-beg (point)))) - (c-forward-syntactic-ws) - - ;; ...Then the ones with < before end and > after end. - (goto-char (if end-lit-limits (cdr end-lit-limits) end)) - (setq end-limit (c-determine-+ve-limit 512)) - (while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end) - (eq (char-before) ?>)) - (c-end-of-current-token) - (when (eq (char-before) ?>) - (c-clear->-pair-props-if-match-before end (1- (point))) - (setq new-end (point)))) - (c-backward-syntactic-ws) - - ;; Extend the fontification region, if needed. - (and new-beg - (< new-beg c-new-BEG) - (setq c-new-BEG new-beg)) - (and new-end - (> new-end c-new-END) - (setq c-new-END new-end)))))) + (when (> end beg) + ;; Cope with removing (beg end) coalescing a < or > with, say, an = sign. + (goto-char beg) + (let ((ch (char-before))) + (if (and (memq ch '(?< ?>)) + (c-get-char-property (1- (point)) 'syntax-table) + (progn + (goto-char end) + (looking-at (if (eq ch ?<) + c-<-op-cont-regexp + c->-op-cont-regexp))) + (or (eq ch ?<) + (not (eq (char-after) ?>)))) + (c-unmark-<>-around-region (1- beg) beg))))) (defun c-after-change-check-<>-operators (beg end) ;; This is called from `after-change-functions' when @@ -7186,29 +7370,38 @@ comment at the start of cc-engine.el for more info." (c-clear-<>-pair-props) (forward-char))))))) +(defun c-<>-get-restricted () + ;; With point at the < at the start of the purported <>-arglist, determine + ;; the value of `c-restricted-<>-arglists' to use for the call of + ;; `c-forward-<>-arglist' starting there. + (save-excursion + (c-backward-token-2) + (and (not (looking-at c-opt-<>-sexp-key)) + (progn (c-backward-syntactic-ws) ; to ( or , + (and (memq (char-before) '(?\( ?,)) ; what about <? + (not (eq (c-get-char-property (point) 'c-type) + 'c-decl-arg-start))))))) + (defun c-restore-<>-properties (_beg _end _old-len) ;; This function is called as an after-change function. It restores the ;; category/syntax-table properties on template/generic <..> pairs between ;; c-new-BEG and c-new-END. It may do hidden buffer changes. - (c-save-buffer-state ((c-parse-and-markup-<>-arglists t) - c-restricted-<>-arglists lit-limits) + (c-save-buffer-state ((c-parse-and-markup-<>-arglists t) lit-limits) (goto-char c-new-BEG) (if (setq lit-limits (c-literal-limits)) (goto-char (cdr lit-limits))) (while (and (< (point) c-new-END) - (c-syntactic-re-search-forward "<" c-new-END 'bound)) - (backward-char) - (save-excursion - (c-backward-token-2) - (setq c-restricted-<>-arglists - (and (not (looking-at c-opt-<>-sexp-key)) - (progn (c-backward-syntactic-ws) ; to ( or , - (and (memq (char-before) '(?\( ?,)) ; what about <? - (not (eq (c-get-char-property (point) 'c-type) - 'c-decl-arg-start))))))) - (or (c-forward-<>-arglist nil) - (c-forward-over-token-and-ws) - (goto-char c-new-END))))) + (c-syntactic-re-search-forward "[<>]" c-new-END 'bound)) + (if (eq (char-before) ?<) + (progn + (backward-char) + (let ((c-restricted-<>-arglists (c-<>-get-restricted))) + (or (c-forward-<>-arglist nil) + (c-forward-over-token-and-ws) + (goto-char c-new-END)))) + (save-excursion + (when (c-backward-<>-arglist nil nil #'c-<>-get-restricted) + (setq c-new-BEG (min c-new-BEG (point))))))))) ;; Handling of CC Mode multi-line strings. @@ -7360,13 +7553,13 @@ multi-line strings (but not C++, for example)." (defun c-ml-string-opener-intersects-region (&optional start finish) ;; If any part of the region [START FINISH] is inside an ml-string opener, - ;; return a dotted list of the start, end and double-quote position of that - ;; opener. That list will not include any "context characters" before or - ;; after the opener. If an opener is found, the match-data will indicate - ;; it, with (match-string 1) being the entire delimiter, and (match-string - ;; 2) the "main" double-quote. Otherwise, the match-data is undefined. - ;; Both START and FINISH default to point. FINISH may not be at an earlier - ;; buffer position than START. + ;; return a dotted list of the start, end and double-quote position of the + ;; first such opener. That list will not include any "context characters" + ;; before or after the opener. If an opener is found, the match-data will + ;; indicate it, with (match-string 1) being the entire delimiter, and + ;; (match-string 2) the "main" double-quote. Otherwise, the match-data is + ;; undefined. Both START and FINISH default to point. FINISH may not be at + ;; an earlier buffer position than START. (let ((here (point)) found) (or finish (setq finish (point))) (or start (setq start (point))) @@ -7390,7 +7583,10 @@ multi-line strings (but not C++, for example)." ;; If POSITION (default point) is at or inside an ml string opener, return a ;; dotted list of the start and end of that opener, and the position of the ;; double-quote in it. That list will not include any "context characters" - ;; before or after the opener. + ;; before or after the opener. If an opener is found, the match-data will + ;; indicate it, with (match-string 1) being the entire delimiter, and + ;; (match-string 2) the "main" double-quote. Otherwise, the match-data is + ;; undefined. (let ((here (point)) found) (or position (setq position (point))) @@ -7402,7 +7598,7 @@ multi-line strings (but not C++, for example)." c-ml-string-opener-re (min (+ position c-ml-string-max-opener-len) (point-max)) 'bound)) - (<= (match-end 1) position))) + (< (match-end 1) position))) (prog1 (and found (<= (match-beginning 1) position) @@ -7746,7 +7942,7 @@ multi-line strings (but not C++, for example)." (insert (nth 3 (car state)))) ((eq (nth 3 (car state)) t) (insert ?\") - (c-put-char-property end 'syntax-table '(15)))) + (c-put-string-fence end))) (c-truncate-lit-pos-cache end) ;; ....ensure c-new-END extends right to the end of the about ;; to be un-stringed raw string.... @@ -7991,7 +8187,7 @@ multi-line strings (but not C++, for example)." (goto-char (cadr end-delim)) t) (c-put-char-property (cddr delim) 'syntax-table '(1)) - (c-put-char-property (1- (cadr delim)) 'syntax-table '(15)) + (c-put-string-fence (1- (cadr delim))) (c-truncate-lit-pos-cache (1- (cddr delim))) (when bound ;; In a CPP construct, we try to apply a generic-string @@ -8021,10 +8217,10 @@ multi-line strings (but not C++, for example)." (cadr delim) t)) (if (match-beginning 10) (progn - (c-put-char-property (match-beginning 10) 'syntax-table '(15)) + (c-put-string-fence (match-beginning 10)) (c-truncate-lit-pos-cache (match-beginning 10))) (c-put-char-property (match-beginning 5) 'syntax-table '(1)) - (c-put-char-property (1+ (match-beginning 5)) 'syntax-table '(15)) + (c-put-string-fence (1+ (match-beginning 5))) (c-truncate-lit-pos-cache (match-beginning 5)))) (goto-char bound)) nil)) @@ -8288,10 +8484,17 @@ multi-line strings (but not C++, for example)." (setq c-record-ref-identifiers (cons range c-record-ref-identifiers)))))) -(defmacro c-forward-keyword-prefixed-id (type) +(defmacro c-forward-keyword-prefixed-id (type &optional stop-at-end) ;; Used internally in `c-forward-keyword-clause' to move forward ;; over a type (if TYPE is 'type) or a name (otherwise) which ;; possibly is prefixed by keywords and their associated clauses. + ;; Point should be at the type/name or a preceding keyword at the start of + ;; the macro, and it is left at the first token following the type/name, + ;; or (when STOP-AT-END is non-nil) immediately after that type/name. + ;; + ;; Note that both parameters are evaluated at compile time, not run time, + ;; so they must be constants. + ;; ;; Try with a type/name first to not trip up on those that begin ;; with a keyword. Return t if a known or found type is moved ;; over. The point is clobbered if nil is returned. If range @@ -8300,51 +8503,84 @@ multi-line strings (but not C++, for example)." ;; ;; This macro might do hidden buffer changes. (declare (debug t)) - `(let (res) + `(let (res pos) (setq c-last-identifier-range nil) (while (if (setq res ,(if (eq type 'type) - '(c-forward-type) - '(c-forward-name))) - nil - (cond ((looking-at c-keywords-regexp) - (c-forward-keyword-clause 1)) - ((and c-opt-cpp-prefix - (looking-at c-noise-macro-with-parens-name-re)) - (c-forward-noise-clause))))) + `(c-forward-type nil ,stop-at-end) + `(c-forward-name ,stop-at-end))) + (progn + (setq pos (point)) + nil) + (and + (cond ((looking-at c-keywords-regexp) + (c-forward-keyword-clause 1 t)) + ((and c-opt-cpp-prefix + (looking-at c-noise-macro-with-parens-name-re)) + (c-forward-noise-clause t))) + (progn + (setq pos (point)) + (c-forward-syntactic-ws) + t)))) (when (memq res '(t known found prefix maybe)) (when c-record-type-identifiers - ,(if (eq type 'type) - '(c-record-type-id c-last-identifier-range) - '(c-record-ref-id c-last-identifier-range))) + ,(if (eq type 'type) + '(c-record-type-id c-last-identifier-range) + '(c-record-ref-id c-last-identifier-range))) + (when pos + (goto-char pos) + ,(unless stop-at-end + `(c-forward-syntactic-ws))) t))) -(defmacro c-forward-id-comma-list (type update-safe-pos) +(defmacro c-forward-id-comma-list (type update-safe-pos &optional stop-at-end) ;; Used internally in `c-forward-keyword-clause' to move forward ;; over a comma separated list of types or names using - ;; `c-forward-keyword-prefixed-id'. + ;; `c-forward-keyword-prefixed-id'. Point should start at the first token + ;; after the already scanned type/name, or (if STOP-AT-END is non-nil) + ;; immediately after that type/name. Point is left either before or + ;; after the whitespace following the last type/name in the list, depending + ;; on whether STOP-AT-END is non-nil or nil. The return value is without + ;; significance. + ;; + ;; Note that all three parameters are evaluated at compile time, not run + ;; time, so they must be constants. ;; ;; This macro might do hidden buffer changes. (declare (debug t)) - `(while (and (progn - ,(when update-safe-pos - '(setq safe-pos (point))) - (eq (char-after) ?,)) - (progn - (forward-char) - (c-forward-syntactic-ws) - (c-forward-keyword-prefixed-id ,type))))) + `(let ((pos (point))) + (while (and (progn + ,(when update-safe-pos + `(setq safe-pos (point))) + (setq pos (point)) + (c-forward-syntactic-ws) + (eq (char-after) ?,)) + (progn + (forward-char) + (setq pos (point)) + (c-forward-syntactic-ws) + (c-forward-keyword-prefixed-id ,type t)))) + (goto-char pos) + ,(unless stop-at-end + `(c-forward-syntactic-ws)))) -(defun c-forward-noise-clause () +(defun c-forward-noise-clause (&optional stop-at-end) ;; Point is at a c-noise-macro-with-parens-names macro identifier. Go ;; forward over this name, any parenthesis expression which follows it, and - ;; any syntactic WS, ending up at the next token or EOB. If there is an + ;; any syntactic WS, ending up either at the next token or EOB or (when + ;; STOP-AT-END is non-nil) directly after the clause. If there is an ;; unbalanced paren expression, leave point at it. Always Return t. - (or (zerop (c-forward-token-2)) - (goto-char (point-max))) - (if (and (eq (char-after) ?\() - (c-go-list-forward)) + (let (pos) + (or (c-forward-over-token) + (goto-char (point-max))) + (setq pos (point)) + (c-forward-syntactic-ws) + (when (and (eq (char-after) ?\() + (c-go-list-forward)) + (setq pos (point))) + (goto-char pos) + (unless stop-at-end (c-forward-syntactic-ws)) - t) + t)) (defun c-forward-noise-clause-not-macro-decl (maybe-parens) ;; Point is at a noise macro identifier, which, when MAYBE-PARENS is @@ -8378,11 +8614,12 @@ multi-line strings (but not C++, for example)." (goto-char here) nil))) -(defun c-forward-keyword-clause (match) +(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 at the start of - ;; the next token. t is returned in that case, otherwise the point + ;; 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', @@ -8412,19 +8649,23 @@ multi-line strings (but not C++, for example)." (when kwd-sym (goto-char (match-end match)) - (c-forward-syntactic-ws) (setq safe-pos (point)) + (c-forward-syntactic-ws) (cond ((and (c-keyword-member kwd-sym 'c-type-list-kwds) - (c-forward-keyword-prefixed-id type)) + (c-forward-keyword-prefixed-id type t)) ;; There's a type directly after a keyword in `c-type-list-kwds'. - (c-forward-id-comma-list type t)) + (setq safe-pos (point)) + (c-forward-syntactic-ws) + (c-forward-id-comma-list type t t)) ((and (c-keyword-member kwd-sym 'c-ref-list-kwds) - (c-forward-keyword-prefixed-id ref)) + (c-forward-keyword-prefixed-id ref t)) ;; There's a name directly after a keyword in `c-ref-list-kwds'. - (c-forward-id-comma-list ref t)) + (setq safe-pos (point)) + (c-forward-syntactic-ws) + (c-forward-id-comma-list ref t t)) ((and (c-keyword-member kwd-sym 'c-paren-any-kwds) (eq (char-after) ?\()) @@ -8444,20 +8685,20 @@ multi-line strings (but not C++, for example)." (goto-char (match-end 0))))) (goto-char pos) - (c-forward-syntactic-ws) - (setq safe-pos (point)))) + (setq safe-pos (point))) + (c-forward-syntactic-ws)) ((and (c-keyword-member kwd-sym 'c-<>-sexp-kwds) (eq (char-after) ?<) (c-forward-<>-arglist (c-keyword-member kwd-sym 'c-<>-type-kwds))) - (c-forward-syntactic-ws) - (setq safe-pos (point))) + (setq safe-pos (point)) + (c-forward-syntactic-ws)) ((and (c-keyword-member kwd-sym 'c-nonsymbol-sexp-kwds) (not (looking-at c-symbol-start)) (c-safe (c-forward-sexp) t)) - (c-forward-syntactic-ws) - (setq safe-pos (point))) + (setq safe-pos (point)) + (c-forward-syntactic-ws)) ((and (c-keyword-member kwd-sym 'c-protection-kwds) (or (null c-post-protection-token) @@ -8467,8 +8708,8 @@ multi-line strings (but not C++, for example)." (not (c-end-of-current-token)))))) (if c-post-protection-token (goto-char (match-end 0))) - (c-forward-syntactic-ws) - (setq safe-pos (point)))) + (setq safe-pos (point)) + (c-forward-syntactic-ws))) (when (c-keyword-member kwd-sym 'c-colon-type-list-kwds) (if (eq (char-after) ?:) @@ -8477,8 +8718,10 @@ multi-line strings (but not C++, for example)." (progn (forward-char) (c-forward-syntactic-ws) - (when (c-forward-keyword-prefixed-id type) - (c-forward-id-comma-list type t))) + (when (c-forward-keyword-prefixed-id type t) + (setq safe-pos (point)) + (c-forward-syntactic-ws) + (c-forward-id-comma-list type t t))) ;; Not at the colon, so stop here. But the identifier ;; ranges in the type list later on should still be ;; recorded. @@ -8488,15 +8731,18 @@ multi-line strings (but not C++, for example)." ;; this one, we move forward to the colon following the ;; clause matched above. (goto-char safe-pos) + (c-forward-syntactic-ws) (c-forward-over-colon-type-list)) (progn (c-forward-syntactic-ws) - (c-forward-keyword-prefixed-id type)) + (c-forward-keyword-prefixed-id type t)) ;; There's a type after the `c-colon-type-list-re' match ;; after a keyword in `c-colon-type-list-kwds'. (c-forward-id-comma-list type nil)))) (goto-char safe-pos) + (unless stop-at-end + (c-forward-syntactic-ws)) t))) ;; cc-mode requires cc-fonts. @@ -8578,11 +8824,9 @@ multi-line strings (but not C++, for example)." ;; List that collects the positions after the argument ;; separating ',' in the arglist. arg-start-pos) - ;; If the '<' has paren open syntax then we've marked it as an angle - ;; bracket arglist before, so skip to the end. - (if (and syntax-table-prop-on-< - (or (not c-parse-and-markup-<>-arglists) - (c-get-char-property (point) 'c-<>-c-types-set))) + (if (and (not c-parse-and-markup-<>-arglists) + syntax-table-prop-on-<) + (progn (forward-char) (if (and (c-go-up-list-forward) @@ -8679,7 +8923,6 @@ multi-line strings (but not C++, for example)." (c-unmark-<->-as-paren (point))))) (c-mark-<-as-paren start) (c-mark->-as-paren (1- (point))) - (c-put-char-property start 'c-<>-c-types-set t) (c-truncate-lit-pos-cache start)) (setq res t) nil)) ; Exit the loop. @@ -8762,7 +9005,7 @@ multi-line strings (but not C++, for example)." (if res (or c-record-found-types t))))) -(defun c-backward-<>-arglist (all-types &optional limit) +(defun c-backward-<>-arglist (all-types &optional limit restricted-function) ;; The point is assumed to be directly after a ">". Try to treat it ;; as the close paren of an angle bracket arglist and move back to ;; the corresponding "<". If successful, the point is left at @@ -8771,7 +9014,12 @@ multi-line strings (but not C++, for example)." ;; `c-forward-<>-arglist'. ;; ;; If the optional LIMIT is given, it bounds the backward search. - ;; It's then assumed to be at a syntactically relevant position. + ;; It's then assumed to be at a syntactically relevant position. If + ;; RESTRICTED-FUNCTION is non-nil, it should be a function taking no + ;; arguments, called with point at a < at the start of a purported + ;; <>-arglist, which will return the value of + ;; `c-restricted-<>-arglists' to be used in the `c-forward-<>-arglist' + ;; call starting at that <. ;; ;; This is a wrapper around `c-forward-<>-arglist'. See that ;; function for more details. @@ -8807,7 +9055,11 @@ multi-line strings (but not C++, for example)." t (backward-char) - (let ((beg-pos (point))) + (let ((beg-pos (point)) + (c-restricted-<>-arglists + (if restricted-function + (funcall restricted-function) + c-restricted-<>-arglists))) (if (c-forward-<>-arglist all-types) (cond ((= (point) start) ;; Matched the arglist. Break the while. @@ -8827,11 +9079,12 @@ multi-line strings (but not C++, for example)." (/= (point) start)))) -(defun c-forward-name () - ;; Move forward over a complete name if at the beginning of one, - ;; stopping at the next following token. A keyword, as such, - ;; doesn't count as a name. If the point is not at something that - ;; is recognized as a name then it stays put. +(defun c-forward-name (&optional stop-at-end) + ;; Move forward over a complete name if at the beginning of one, stopping + ;; either at the next following token or (when STOP-AT-END is non-nil) at + ;; the end of the name. A keyword, as such, doesn't count as a name. If + ;; the point is not at something that is recognized as a name then it stays + ;; put. ;; ;; A name could be something as simple as "foo" in C or something as ;; complex as "X<Y<class A<int>::B, BIT_MAX >> b>, ::operator<> :: @@ -8853,7 +9106,7 @@ multi-line strings (but not C++, for example)." ;; ;; This function might do hidden buffer changes. - (let ((pos (point)) (start (point)) res id-start id-end + (let ((pos (point)) pos2 pos3 (start (point)) res id-start id-end ;; Turn off `c-promote-possible-types' here since we might ;; call `c-forward-<>-arglist' and we don't want it to promote ;; every suspect thing in the arglist to a type. We're @@ -8895,7 +9148,7 @@ multi-line strings (but not C++, for example)." (c-forward-syntactic-ws lim+) (cond ((eq (char-before id-end) ?e) ;; Got "... ::template". - (let ((subres (c-forward-name))) + (let ((subres (c-forward-name t))) (when subres (setq pos (point) res subres)))) @@ -8907,7 +9160,7 @@ multi-line strings (but not C++, for example)." (and (eq (c-forward-token-2) 0) (not (eq (char-after) ?\()))))) ;; Got a cast operator. - (when (c-forward-type) + (when (c-forward-type nil t) (setq pos (point) res 'operator) ;; Now we should match a sequence of either @@ -8931,8 +9184,8 @@ multi-line strings (but not C++, for example)." (forward-char) t))))) (while (progn - (c-forward-syntactic-ws lim+) (setq pos (point)) + (c-forward-syntactic-ws lim+) (and (<= (point) lim+) (looking-at c-opt-type-modifier-key))) @@ -8947,30 +9200,34 @@ multi-line strings (but not C++, for example)." ;; operator"" has an (?)optional tag after it. (progn (goto-char (match-end 0)) + (setq pos2 (point)) (c-forward-syntactic-ws lim+) (when (c-on-identifier) - (c-forward-token-2 1 nil lim+))) - (goto-char (match-end 0)) - (c-forward-syntactic-ws lim+)) - (setq pos (point) + (c-forward-over-token nil lim+))) + (goto-char (match-end 0)) + (setq pos2 (point)) + (c-forward-syntactic-ws lim+)) + (setq pos pos2 res 'operator))) nil) ;; `id-start' is equal to `id-end' if we've jumped over ;; an identifier that doesn't end with a symbol token. - ;; That can occur e.g. for Java import directives on the + ;; That can occur e.g. for Java import directives of the ;; form "foo.bar.*". (when (and id-start (/= id-start id-end)) (setq c-last-identifier-range (cons id-start id-end))) (goto-char id-end) + (setq pos (point)) (c-forward-syntactic-ws lim+) - (setq pos (point) - res t))) + (setq res t))) (progn (goto-char pos) + (c-forward-syntactic-ws lim+) + (setq pos3 (point)) (when (or c-opt-identifier-concat-key c-recognize-<>-arglists) @@ -8981,7 +9238,6 @@ multi-line strings (but not C++, for example)." ;; cases with tricky syntactic whitespace that aren't ;; covered in `c-identifier-key'. (goto-char (match-end 0)) - (c-forward-syntactic-ws lim+) t) ((and c-recognize-<>-arglists @@ -8993,11 +9249,12 @@ multi-line strings (but not C++, for example)." ;; `lim+'. (setq lim+ (c-determine-+ve-limit 500)) + (setq pos2 (point)) (c-forward-syntactic-ws lim+) (unless (eq (char-after) ?\() (setq c-last-identifier-range nil) - (c-add-type start (1+ pos))) - (setq pos (point)) + (c-add-type start (1+ pos3))) + (setq pos pos2) (if (and c-opt-identifier-concat-key (looking-at c-opt-identifier-concat-key)) @@ -9007,7 +9264,7 @@ multi-line strings (but not C++, for example)." (progn (when (and c-record-type-identifiers id-start) (c-record-ref-id (cons id-start id-end))) - (forward-char 2) + (goto-char (match-end 0)) (c-forward-syntactic-ws lim+) t) @@ -9019,11 +9276,14 @@ multi-line strings (but not C++, for example)." ))))) (goto-char pos) + (unless stop-at-end + (c-forward-syntactic-ws lim+)) res)) -(defun c-forward-type (&optional brace-block-too) +(defun c-forward-type (&optional brace-block-too stop-at-end) ;; Move forward over a type spec if at the beginning of one, - ;; stopping at the next following token. The keyword "typedef" + ;; stopping at the next following token (if STOP-AT-END is nil) or + ;; at the end of the type spec (otherwise). The keyword "typedef" ;; isn't part of a type spec here. ;; ;; BRACE-BLOCK-TOO, when non-nil, means move over the brace block in @@ -9062,7 +9322,7 @@ 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) + post-prefix-pos prefix-end-pos) ;; Skip leading type modifiers. If any are found we know it's a ;; prefix of a type. @@ -9072,6 +9332,8 @@ multi-line strings (but not C++, for example)." (when (looking-at c-no-type-key) (setq res 'no-id))) (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)))) @@ -9080,32 +9342,41 @@ multi-line strings (but not C++, for example)." (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 - (c-forward-syntactic-ws) + (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) (while (cond ((looking-at c-decl-hangon-key) - (c-forward-keyword-clause 1)) + (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)))) + (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 name-res (c-forward-name)) (setq res (not (null name-res))) (when (eq name-res t) ;; With some keywords the name can be used without the prefix, so we @@ -9113,21 +9384,21 @@ multi-line strings (but not C++, for example)." (when (save-excursion (goto-char post-prefix-pos) (looking-at c-self-contained-typename-key)) - (c-add-type pos (save-excursion - (c-backward-syntactic-ws) - (point)))) + (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) - (c-forward-syntactic-ws) (setq pos (point)))))) (goto-char pos) + (c-forward-syntactic-ws) (setq res t)) (unless res (goto-char start))) ; invalid syntax @@ -9141,7 +9412,7 @@ multi-line strings (but not C++, for example)." (if (looking-at c-identifier-start) (save-excursion (setq id-start (point) - name-res (c-forward-name)) + name-res (c-forward-name t)) (when name-res (setq id-end (point) id-range c-last-identifier-range)))) @@ -9154,8 +9425,9 @@ multi-line strings (but not C++, for example)." (>= (save-excursion (save-match-data (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws) - (setq pos (point)))) + pos)) id-end) (setq res nil))))) ;; Looking at a primitive or known type identifier. We've @@ -9168,62 +9440,86 @@ multi-line strings (but not C++, for example)." (or c-promote-possible-types (eq res t))) (c-record-type-id (cons (match-beginning 1) (match-end 1)))) - (if (and c-opt-type-component-key + (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) - (while (progn - (setq safe-pos (point)) - (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)) - (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) - (setq res t)) - (goto-char safe-pos) - (setq res 'prefix))) - (unless (save-match-data (c-forward-keyword-clause 1)) - (if pos - (goto-char pos) - (goto-char (match-end 1)) - (c-forward-syntactic-ws))))) + (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)))) + (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)) - (not (looking-at c-type-decl-prefix-key))))) + (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 id-start) + (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 (save-excursion - (goto-char id-end) - (c-backward-syntactic-ws) - (point)))) + (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))) + (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. @@ -9233,6 +9529,7 @@ multi-line strings (but not C++, for example)." ((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) ?\() @@ -9258,6 +9555,7 @@ multi-line strings (but not C++, for example)." (when c-opt-type-modifier-key (while (looking-at c-opt-type-modifier-key) ; e.g. "const", "volatile" (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws) (setq res t))) @@ -9268,11 +9566,13 @@ multi-line strings (but not C++, for example)." (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)) @@ -9296,7 +9596,8 @@ multi-line strings (but not C++, for example)." (progn (goto-char (match-end 1)) (c-forward-syntactic-ws) - (setq subres (c-forward-type)))) + (setq subres (c-forward-type nil t)) + (setq pos (point)))) (progn ;; If either operand certainly is a type then both are, but we @@ -9332,9 +9633,11 @@ multi-line strings (but not C++, for example)." ;; `nconc' doesn't mind that the tail of ;; `c-record-found-types' is t. (nconc c-record-found-types - c-record-type-identifiers)))) + c-record-type-identifiers))))))) - (goto-char pos)))) + (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 @@ -9373,19 +9676,24 @@ multi-line strings (but not C++, for example)." (setq ,ps (cdr ,ps))))) (defun c-forward-over-compound-identifier () - ;; Go over a possibly compound identifier, such as C++'s Foo::Bar::Baz, - ;; returning that identifier (with any syntactic WS removed). Return nil if - ;; we're not at an identifier. - (when (c-on-identifier) + ;; Go over a possibly compound identifier (but not any following + ;; whitespace), such as C++'s Foo::Bar::Baz, returning that identifier (with + ;; any syntactic WS removed). Return nil if we're not at an identifier, in + ;; which case point is not moved. + (when + (eq (c-on-identifier) + (point)) (let ((consolidated "") (consolidated-:: "") - start end) + (here (point)) + start end end-token) (while (progn (setq start (point)) (c-forward-over-token) (setq consolidated (concat consolidated-:: - (buffer-substring-no-properties start (point)))) + (buffer-substring-no-properties start (point))) + end-token (point)) (c-forward-syntactic-ws) (and c-opt-identifier-concat-key (looking-at c-opt-identifier-concat-key) @@ -9400,7 +9708,9 @@ multi-line strings (but not C++, for example)." (concat consolidated (buffer-substring-no-properties start end)))))))) (if (equal consolidated "") - nil + (progn (goto-char here) + nil) + (goto-char end-token) consolidated)))) (defun c-back-over-compound-identifier () @@ -9573,13 +9883,16 @@ point unchanged and return nil." ;; Handling of large scale constructs like statements and declarations. -(defun c-forward-primary-expression (&optional limit) - ;; Go over the primary expression (if any) at point, moving to the next - ;; token and return non-nil. If we're not at a primary expression leave - ;; point unchanged and return nil. +(defun c-forward-primary-expression (&optional limit stop-at-end) + ;; Go over the primary expression (if any) at point, and unless STOP-AT-END + ;; is non-nil, move to the next token then return non-nil. If we're not at + ;; a primary expression leave point unchanged and return nil. ;; ;; Note that this function is incomplete, handling only those cases expected ;; to be common in a C++20 requires clause. + ;; + ;; Note also that (...) is not recognized as a primary expression if the + ;; next token is an open brace. (let ((here (point)) (c-restricted-<>-arglists t) (c-parse-and-markup-<>-arglists nil) @@ -9587,28 +9900,38 @@ point unchanged and return nil." (if (cond ((looking-at c-constant-key) (goto-char (match-end 1)) - (c-forward-syntactic-ws limit) + (unless stop-at-end (c-forward-syntactic-ws limit)) t) ((eq (char-after) ?\() (and (c-go-list-forward (point) limit) (eq (char-before) ?\)) - (progn (c-forward-syntactic-ws limit) - t))) + (let ((after-paren (point))) + (c-forward-syntactic-ws limit) + (prog1 + (not (eq (char-after) ?{)) + (when stop-at-end + (goto-char after-paren)))))) ((c-forward-over-compound-identifier) - (c-forward-syntactic-ws limit) - (while (cond - ((looking-at "<") - (prog1 - (c-forward-<>-arglist nil) - (c-forward-syntactic-ws limit))) - ((looking-at c-opt-identifier-concat-key) - (and - (zerop (c-forward-token-2 1 nil limit)) - (prog1 - (c-forward-over-compound-identifier) - (c-forward-syntactic-ws limit)))))) - t) - ((looking-at c-fun-name-substitute-key) ; "requires" + (let ((after-id (point))) + (c-forward-syntactic-ws limit) + (while (cond + ((and + (looking-at "<") + (prog1 + (and + (c-forward-<>-arglist nil) + (setq after-id (point))))) + (c-forward-syntactic-ws limit)) + ((looking-at c-opt-identifier-concat-key) + (and + (zerop (c-forward-token-2 1 nil limit)) + (prog1 + (c-forward-over-compound-identifier) + (c-forward-syntactic-ws limit)))))) + (goto-char after-id))) + ((and + (looking-at c-fun-name-substitute-key) ; "requires" + (not (eq (char-after (match-end 0)) ?_))) (goto-char (match-end 1)) (c-forward-syntactic-ws limit) (and @@ -9621,36 +9944,47 @@ point unchanged and return nil." (and (c-go-list-forward (point) limit) (eq (char-before) ?})) (progn - (c-forward-syntactic-ws limit) + (unless stop-at-end (c-forward-syntactic-ws limit)) t)))) t (goto-char here) nil))) -(defun c-forward-c++-requires-clause (&optional limit) - ;; Point is at the keyword "requires". Move forward over the requires - ;; clause to the next token after it and return non-nil. If there is no - ;; valid requires clause at point, leave point unmoved and return nil. +(defun c-forward-constraint-clause (&optional limit stop-at-end) + ;; Point is at the putative start of a constraint clause. Move to its end + ;; (when STOP-AT-END is non-zero) or the token after that (otherwise) and + ;; return non-nil. Return nil without moving if we fail to find a + ;; constraint. (let ((here (point)) final-point) (or limit (setq limit (point-max))) - (if (and - (zerop (c-forward-token-2 1 nil limit)) ; over "requires". - (prog1 - (c-forward-primary-expression limit) - (setq final-point (point)) - (while - (and (looking-at "\\(?:&&\\|||\\)") - (progn (goto-char (match-end 0)) - (c-forward-syntactic-ws limit) - (and (< (point) limit) - (c-forward-primary-expression limit)))) - (setq final-point (point))))) - (progn (goto-char final-point) - t) + (if (c-forward-primary-expression limit t) + (progn + (setq final-point (point)) + (c-forward-syntactic-ws limit) + (while + (and (looking-at "\\(?:&&\\|||\\)") + (<= (match-end 0) limit) + (progn (goto-char (match-end 0)) + (c-forward-syntactic-ws limit) + (and (<= (point) limit))) + (c-forward-primary-expression limit t) + (setq final-point (point)))) + (goto-char final-point) + (or stop-at-end (c-forward-syntactic-ws limit)) + t) (goto-char here) nil))) +(defun c-forward-c++-requires-clause (&optional limit stop-at-end) + ;; Point is at the keyword "requires". Move forward over the requires + ;; clause to its end (if STOP-AT-END is non-nil) or the next token after it + ;; (otherwise) and return non-nil. If there is no valid requires clause at + ;; point, leave point unmoved and return nil. + (or limit (setq limit (point-max))) + (and (zerop (c-forward-token-2)) ; over "requires". + (c-forward-constraint-clause limit stop-at-end))) + (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, @@ -9737,7 +10071,7 @@ point unchanged and return nil." ;; (e.g. "," or ";" or "}"). (let ((here (point)) id-start id-end brackets-after-id paren-depth decorated - got-init arglist double-double-quote) + got-init arglist double-double-quote pos) (or limit (setq limit (point-max))) (if (and (< (point) limit) @@ -9771,6 +10105,7 @@ point unchanged and return nil." (eq (char-after (1+ (point))) ?\")) (setq double-double-quote t)) (goto-char (match-end 0)) + (setq pos (point)) (c-forward-syntactic-ws limit) (setq got-identifier t) nil) @@ -9783,7 +10118,10 @@ point unchanged and return nil." ;; prefix only if it specifies a member pointer. (progn (setq id-start (point)) - (when (c-forward-name) + (when (c-forward-name t) + (setq pos (point)) + (c-forward-syntactic-ws limit) + (if (save-match-data (looking-at "\\(::\\)")) ;; We only check for a trailing "::" and @@ -9812,10 +10150,12 @@ point unchanged and return nil." (setq id-start (point))) (cond ((or got-identifier - (c-forward-name)) - (save-excursion - (c-backward-syntactic-ws) - (setq id-end (point)))) + (c-forward-name t)) + (setq id-end + (or pos + (point))) + (c-forward-syntactic-ws limit) + t) (accept-anon (setq id-start nil id-end nil) t) @@ -9846,7 +10186,9 @@ point unchanged and return nil." ((looking-at c-type-decl-suffix-key) (cond ((save-match-data - (looking-at c-fun-name-substitute-key)) + (and + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_)))) (c-forward-c++-requires-clause)) ((eq (char-after) ?\() (if (c-forward-decl-arglist not-top decorated limit) @@ -9883,7 +10225,11 @@ point unchanged and return nil." (prog1 (setq found (c-syntactic-re-search-forward - "[;:,]\\|\\(=\\|\\s(\\)" + ;; Consider making the next regexp a + ;; c-lang-defvar (2023-07-04). + (if (c-major-mode-is 'objc-mode) + "\\(?:@end\\)\\|[;:,]\\|\\(=\\|[[(]\\)" + "[;:,]\\|\\(=\\|\\s(\\)") limit 'limit t)) (setq got-init (and found (match-beginning 1)))) @@ -10060,6 +10406,24 @@ This function might do hidden buffer changes." ;; This identifier is bound only in the inner let. '(setq start id-start)))) +(defmacro c-fdoc-assymetric-space-about-asterisk () + ;; We've got a "*" at `id-start' between two identifiers, the first at + ;; `type-start'. Return non-nil when there is either whitespace between the + ;; first id and the "*" or between the "*" and the second id, but not both. + `(let ((space-before-id + (save-excursion + (goto-char id-start) ; Position of "*". + (and (> (skip-chars-forward "* \t\n\r") 0) + (memq (char-before) '(?\ ?\t ?\n ?\r))))) + (space-after-type + (save-excursion + (goto-char type-start) + (and (c-forward-type nil t) + (or (eolp) + (memq (char-after) '(?\ ?\t))))))) + (not (eq (not space-before-id) + (not space-after-type))))) + (defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end &optional inside-macro) ;; Move forward over a declaration or a cast if at the start of one. @@ -10282,7 +10646,9 @@ This function might do hidden buffer changes." (when (and (c-major-mode-is 'c++-mode) (c-keyword-member kwd-sym 'c-<>-sexp-kwds) (save-match-data - (looking-at c-fun-name-substitute-key))) + (and + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_))))) (c-forward-c++-requires-clause)) (setq kwd-clause-end (point)))) ((and c-opt-cpp-prefix @@ -10477,6 +10843,10 @@ This function might do hidden buffer changes." got-parens ;; True if there is a terminated argument list. got-arglist + ;; True when `got-arglist' and the token after the end of the + ;; arglist is an opening brace. Used only when we have a + ;; suspected typeless function name. + got-stmt-block ;; True if there is an identifier in the declarator. got-identifier ;; True if we find a number where an identifier was expected. @@ -10569,11 +10939,11 @@ This function might do hidden buffer changes." (or got-identifier (and (looking-at c-identifier-start) (setq pos (point)) - (setq got-identifier (c-forward-name)) + (setq got-identifier (c-forward-name t)) (save-excursion - (c-backward-syntactic-ws) (c-simple-skip-symbol-backward) (setq identifier-start (point))) + (progn (c-forward-syntactic-ws) t) (setq name-start pos)) (when (looking-at "[0-9]") (setq got-number t)) ; We probably have an arithmetic expression. @@ -10629,10 +10999,16 @@ This function might do hidden buffer changes." (setq got-arglist t)) t) (when (cond + ((and (eq (char-after) ?\() + (c-safe (c-forward-sexp 1) t)) + (when (eq (char-before) ?\)) + (setq got-arglist t))) ((save-match-data (looking-at "\\s(")) (c-safe (c-forward-sexp 1) t)) ((save-match-data - (looking-at c-fun-name-substitute-key)) ; C++ requires + (and + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_)))) ; C++ requires (c-forward-c++-requires-clause)) (t (goto-char (match-end 1)) t)) @@ -10641,6 +11017,11 @@ This function might do hidden buffer changes." (setq got-suffix-after-parens (match-beginning 0))) (setq got-suffix t)))) + ((and got-arglist + (eq (char-after) ?{)) + (setq got-stmt-block t) + nil) + (t ;; No suffix matched. We might have matched the ;; identifier as a type and the open paren of a @@ -10709,9 +11090,17 @@ This function might do hidden buffer changes." (not (memq context '(arglist decl)))) (or (and new-style-auto (looking-at c-auto-ops-re)) - (and (or maybe-typeless backup-maybe-typeless) - (not got-prefix) - at-type))) + (and (not got-prefix) + at-type + (or maybe-typeless backup-maybe-typeless + ;; Do we have a (typeless) constructor? + (and got-stmt-block + (save-excursion + (goto-char type-start) + (and + (looking-at c-identifier-key) + (c-directly-in-class-called-p + (match-string 0))))))))) ;; Have found no identifier but `c-typeless-decl-kwds' has ;; matched so we know we're inside a declaration. The ;; preceding type must be the identifier instead. @@ -10796,8 +11185,7 @@ This function might do hidden buffer changes." type-start (progn (goto-char type-start) - (c-forward-type) - (c-backward-syntactic-ws) + (c-forward-type nil t) (point))))))))) ;; Got a declaration of the form "foo bar (gnu);" or "bar ;; (gnu);" where we've recognized "bar" as the type and "gnu" @@ -11081,19 +11469,25 @@ This function might do hidden buffer changes." ;; CASE 16 (when (and got-prefix-before-parens at-type - (or at-decl-end (looking-at "=[^=]")) (memq context '(nil top)) (or (not got-suffix) at-decl-start)) ;; Got something like "foo * bar;". Since we're not inside ;; an arglist it would be a meaningless expression because ;; the result isn't used. We therefore choose to recognize - ;; it as a declaration. We only allow a suffix (which makes - ;; the construct look like a function call) when - ;; `at-decl-start' provides additional evidence that we do - ;; have a declaration. + ;; it as a declaration when there's "symmetrical WS" around + ;; the "*" or the flag `c-asymmetry-fontification-flag' is + ;; not set. We only allow a suffix (which makes the + ;; construct look like a function call) when `at-decl-start' + ;; provides additional evidence that we do have a + ;; declaration. (setq maybe-expression t) - (throw 'at-decl-or-cast t)) + (when (or (not c-asymmetry-fontification-flag) + (looking-at "=\\([^=]\\|$\\)\\|;") + (c-fdoc-assymetric-space-about-asterisk)) + (when (eq at-type 'maybe) + (setq unsafe-maybe t)) + (throw 'at-decl-or-cast t))) ;; CASE 17 (when (and (or got-suffix-after-parens @@ -11112,25 +11506,12 @@ This function might do hidden buffer changes." got-prefix-before-parens at-type (or (not got-suffix) - at-decl-start)) - (let ((space-before-id - (save-excursion - (goto-char id-start) ; Position of "*". - (and (> (skip-chars-forward "* \t\n\r") 0) - (memq (char-before) '(?\ ?\t ?\n ?\r))))) - (space-after-type - (save-excursion - (goto-char type-start) - (and (c-forward-type) - (progn (c-backward-syntactic-ws) t) - (or (eolp) - (memq (char-after) '(?\ ?\t))))))) - (when (not (eq (not space-before-id) - (not space-after-type))) - (when (eq at-type 'maybe) - (setq unsafe-maybe t)) - (setq maybe-expression t) - (throw 'at-decl-or-cast t))))) + at-decl-start) + (c-fdoc-assymetric-space-about-asterisk)) + (when (eq at-type 'maybe) + (setq unsafe-maybe t)) + (setq maybe-expression t) + (throw 'at-decl-or-cast t))) ;; CASE 18 (when (and at-decl-end @@ -11895,11 +12276,14 @@ comment at the start of cc-engine.el for more info." ;; Each time around the following checks one ;; declaration (which may contain several identifiers). (while (and - (consp (setq decl-or-cast - (c-forward-decl-or-cast-1 - after-prec-token - nil ; Or 'arglist ??? - nil))) + (not (eq (char-after) ?{)) + (or + (consp (setq decl-or-cast + (c-forward-decl-or-cast-1 + after-prec-token + nil ; Or 'arglist ??? + nil))) + (throw 'knr nil)) (memq (char-after) '(?\; ?\,)) (goto-char (car decl-or-cast)) (save-excursion @@ -12243,31 +12627,27 @@ comment at the start of cc-engine.el for more info." (let ((open-brace (point)) kwd-start first-specifier-pos) (c-syntactic-skip-backward c-block-prefix-charset limit t) - (when (and c-recognize-<>-arglists - (eq (char-before) ?>)) - ;; Could be at the end of a template arglist. - (let ((c-parse-and-markup-<>-arglists t)) - (while (and - (c-backward-<>-arglist nil limit) - (progn - (c-syntactic-skip-backward c-block-prefix-charset limit t) - (eq (char-before) ?>)))))) - - ;; Skip back over noise clauses. - (while (and - c-opt-cpp-prefix - (eq (char-before) ?\)) - (let ((after-paren (point))) - (if (and (c-go-list-backward) - (progn (c-backward-syntactic-ws) - (c-simple-skip-symbol-backward)) - (or (looking-at c-paren-nontype-key) - (looking-at c-noise-macro-with-parens-name-re))) - (progn - (c-syntactic-skip-backward c-block-prefix-charset limit t) - t) - (goto-char after-paren) - nil)))) + (while + (or + ;; Could be after a template arglist.... + (and c-recognize-<>-arglists + (eq (char-before) ?>) + (let ((c-parse-and-markup-<>-arglists t)) + (c-backward-<>-arglist nil limit))) + ;; .... or after a noise clause with parens. + (and c-opt-cpp-prefix + (let ((after-paren (point))) + (if (eq (char-before) ?\)) + (and + (c-go-list-backward) + (eq (char-after) ?\() + (progn (c-backward-syntactic-ws) + (c-simple-skip-symbol-backward)) + (or (looking-at c-paren-nontype-key) ; e.g. __attribute__ + (looking-at c-noise-macro-with-parens-name-re))) + (goto-char after-paren) + nil)))) + (c-syntactic-skip-backward c-block-prefix-charset limit t)) ;; Note: Can't get bogus hits inside template arglists below since they ;; have gotten paren syntax above. @@ -12277,10 +12657,18 @@ comment at the start of cc-engine.el for more info." ;; The `c-decl-block-key' search continues from there since ;; we know it can't match earlier. (if goto-start - (when (c-syntactic-re-search-forward c-symbol-start - open-brace t t) - (goto-char (setq first-specifier-pos (match-beginning 0))) - t) + (progn + (while + (and + (c-syntactic-re-search-forward c-symbol-start + open-brace t t) + (goto-char (match-beginning 0)) + (if (or (looking-at c-noise-macro-name-re) + (looking-at c-noise-macro-with-parens-name-re)) + (c-forward-noise-clause) + (setq first-specifier-pos (match-beginning 0)) + nil))) + first-specifier-pos) t) (cond @@ -12349,34 +12737,39 @@ comment at the start of cc-engine.el for more info." (goto-char first-specifier-pos) (while (< (point) kwd-start) - (if (looking-at c-symbol-key) - ;; Accept any plain symbol token on the ground that - ;; it's a specifier masked through a macro (just - ;; like `c-forward-decl-or-cast-1' skip forward over - ;; such tokens). - ;; - ;; Could be more restrictive wrt invalid keywords, - ;; but that'd only occur in invalid code so there's - ;; no use spending effort on it. - (let ((end (match-end 0)) - (kwd-sym (c-keyword-sym (match-string 0)))) - (unless - (and kwd-sym - ;; Moving over a protection kwd and the following - ;; ":" (in C++ Mode) to the next token could take - ;; us all the way up to `kwd-start', leaving us - ;; no chance to update `first-specifier-pos'. - (not (c-keyword-member kwd-sym 'c-protection-kwds)) - (c-forward-keyword-clause 0)) - (goto-char end) - (c-forward-syntactic-ws))) - + (cond + ((or (looking-at c-noise-macro-name-re) + (looking-at c-noise-macro-with-parens-name-re)) + (c-forward-noise-clause)) + ((looking-at c-symbol-key) + ;; Accept any plain symbol token on the ground that + ;; it's a specifier masked through a macro (just + ;; like `c-forward-decl-or-cast-1' skips forward over + ;; such tokens). + ;; + ;; Could be more restrictive wrt invalid keywords, + ;; but that'd only occur in invalid code so there's + ;; no use spending effort on it. + (let ((end (match-end 0)) + (kwd-sym (c-keyword-sym (match-string 0)))) + (unless + (and kwd-sym + ;; Moving over a protection kwd and the following + ;; ":" (in C++ Mode) to the next token could take + ;; us all the way up to `kwd-start', leaving us + ;; no chance to update `first-specifier-pos'. + (not (c-keyword-member kwd-sym 'c-protection-kwds)) + (c-forward-keyword-clause 0)) + (goto-char end) + (c-forward-syntactic-ws)))) + + ((c-syntactic-re-search-forward c-symbol-start + kwd-start 'move t) ;; Can't parse a declaration preamble and is still ;; before `kwd-start'. That means `first-specifier-pos' ;; was in some earlier construct. Search again. - (if (c-syntactic-re-search-forward c-symbol-start - kwd-start 'move t) - (goto-char (setq first-specifier-pos (match-beginning 0))) + (goto-char (setq first-specifier-pos (match-beginning 0)))) + (t ;; Got no preamble before the block declaration keyword. (setq first-specifier-pos kwd-start)))) @@ -12401,7 +12794,8 @@ comment at the start of cc-engine.el for more info." (looking-at c-class-key)) (goto-char (match-end 1)) (c-forward-syntactic-ws) - (looking-at name)))))) + (and (looking-at c-identifier-key) + (string= (match-string 0) name))))))) (defun c-search-uplist-for-classkey (paren-state) ;; Check if the closest containing paren sexp is a declaration @@ -12625,11 +13019,19 @@ comment at the start of cc-engine.el for more info." (defvar c-laomib-cache nil) (make-variable-buffer-local 'c-laomib-cache) -(defun c-laomib-get-cache (containing-sexp) - ;; Get an element from `c-laomib-cache' matching CONTAINING-SEXP. +(defun c-laomib-get-cache (containing-sexp start) + ;; Get an element from `c-laomib-cache' matching CONTAINING-SEXP, and which + ;; is suitable for start position START. ;; Return that element or nil if one wasn't found. - (let ((elt (assq containing-sexp c-laomib-cache))) - (when elt + (let ((ptr c-laomib-cache) + elt) + (while + (and ptr + (setq elt (car ptr)) + (or (not (eq (car elt) containing-sexp)) + (< start (car (cddr elt))))) + (setq ptr (cdr ptr))) + (when ptr ;; Move the fetched `elt' to the front of the cache. (setq c-laomib-cache (delq elt c-laomib-cache)) (push elt c-laomib-cache) @@ -12641,18 +13043,26 @@ comment at the start of cc-engine.el for more info." ;; the components of the new element (see comment for `c-laomib-cache'). ;; The return value is of no significance. (when lim - (let ((old-elt (assq lim c-laomib-cache)) - ;; (elt (cons containing-sexp (cons start nil))) + (let (old-elt (new-elt (list lim start end result)) big-ptr (cur-ptr c-laomib-cache) - togo (size 0) cur-size - ) - (if old-elt (setq c-laomib-cache (delq old-elt c-laomib-cache))) + togo (size 0) cur-size) + + ;; If there is an elt which overlaps with the new element, remove it. + (while + (and cur-ptr + (setq old-elt (car cur-ptr)) + (or (not (eq (car old-elt) lim)) + (not (and (> start (car (cddr old-elt))) + (<= start (cadr old-elt)))))) + (setq cur-ptr (cdr cur-ptr))) + (when (and cur-ptr old-elt) + (setq c-laomib-cache (delq old-elt c-laomib-cache))) (while (>= (length c-laomib-cache) 4) ;; We delete the least recently used elt which doesn't enclose START, - ;; or.. + ;; or ... (dolist (elt c-laomib-cache) (if (or (<= start (cadr elt)) (> start (car (cddr elt)))) @@ -12660,8 +13070,10 @@ comment at the start of cc-engine.el for more info." ;; ... delete the least recently used elt which isn't the biggest. (when (not togo) + (setq cur-ptr c-laomib-cache) (while (cdr cur-ptr) - (setq cur-size (- (nth 2 (cadr cur-ptr)) (car (cadr cur-ptr)))) + (setq cur-size (- (cadr (cadr cur-ptr)) + (car (cddr (cadr cur-ptr))))) (when (> cur-size size) (setq size cur-size big-ptr cur-ptr)) @@ -12763,7 +13175,9 @@ comment at the start of cc-engine.el for more info." in-paren 'in-paren)) ((looking-at c-pre-brace-non-bracelist-key) (setq braceassignp nil)) - ((looking-at c-fun-name-substitute-key) + ((and + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_))) (setq braceassignp nil)) ((looking-at c-return-key)) ((and (looking-at c-symbol-start) @@ -12778,7 +13192,8 @@ comment at the start of cc-engine.el for more info." ;; Have we a requires with a parenthesis list? (when (save-excursion (and (zerop (c-backward-token-2 1 nil lim)) - (looking-at c-fun-name-substitute-key))) + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_)))) (setq braceassignp nil)) nil) (t nil)) @@ -12850,7 +13265,7 @@ comment at the start of cc-engine.el for more info." (goto-char pos) (when (eq braceassignp 'dontknow) (let* ((cache-entry (and containing-sexp - (c-laomib-get-cache containing-sexp))) + (c-laomib-get-cache containing-sexp pos))) (lim2 (or (cadr cache-entry) lim)) sub-bassign-p) (if cache-entry @@ -12872,6 +13287,8 @@ comment at the start of cc-engine.el for more info." ) (setq braceassignp (nth 3 cache-entry)) (goto-char (nth 2 cache-entry))) + (c-laomib-put-cache containing-sexp + start (point) sub-bassign-p) (setq braceassignp sub-bassign-p))) (t)) @@ -13109,6 +13526,120 @@ comment at the start of cc-engine.el for more info." (t nil))) (goto-char here)))) +(defun c-forward-concept-fragment (&optional limit stop-at-end) + ;; Are we currently at the "concept" keyword in a concept construct? If so + ;; we return the position of the first constraint expression following the + ;; "=" sign and move forward over the constraint. Otherwise we return nil. + ;; LIMIT is a forward search limit. + (let ((here (point))) + (if + (and + (looking-at c-equals-nontype-decl-key) ; "concept" + (goto-char (match-end 0)) + (progn (c-forward-syntactic-ws limit) + (not (looking-at c-keywords-regexp))) + (looking-at c-identifier-key) + (goto-char (match-end 0)) + (progn (c-forward-syntactic-ws limit) + (looking-at c-operator-re)) + (equal (match-string 0) "=") + (goto-char (match-end 0))) + (prog1 + (progn (c-forward-syntactic-ws limit) + (point)) + (c-forward-constraint-clause limit stop-at-end)) + (goto-char here) + nil))) + +(defun c-looking-at-concept (&optional limit) + ;; Are we currently at the start of a concept construct? I.e. at the + ;; "template" keyword followed by the construct? If so, we return a cons of + ;; the position of "concept" and the position of the first constraint + ;; expression following the "=" sign, otherwise we return nil. LIMIT is a + ;; forward search limit. + (save-excursion + (let (conpos) + (and (looking-at c-pre-concept-<>-key) + (goto-char (match-end 1)) + (< (point) limit) + (progn (c-forward-syntactic-ws limit) + (eq (char-after) ?<)) + (let ((c-parse-and-markup-<>-arglists t) + c-restricted-<>-arglists) + (c-forward-<>-arglist nil)) + (< (point) limit) + (progn (c-forward-syntactic-ws limit) + (looking-at c-equals-nontype-decl-key)) ; "concept" + (setq conpos (match-beginning 0)) + (goto-char (match-end 0)) + (< (point) limit) + (c-syntactic-re-search-forward + "=" limit t t) + (goto-char (match-end 0)) + (<= (point) limit) + (progn (c-forward-syntactic-ws limit) + (cons conpos (point))))))) + +(defun c-in-requires-or-at-end-of-clause (&optional pos) + ;; Is POS (default POINT) in a C++ "requires" expression or "requires" + ;; clause or at the end of a "requires" clause? If so return a cons + ;; (POSITION . END) where POSITION is that of the "requires" keyword, and + ;; END is `expression' if POS is in an expression, nil if it's in a clause + ;; or t if it's at the end of a clause. "End of a clause" means just after + ;; the non syntactic WS on the line where the clause ends. + ;; + ;; Note we can't use `c-beginning-of-statement-1' in this function because + ;; of this function's use in `c-at-vsemi-p' for C++ Mode. + (save-excursion + (if pos (goto-char pos) (setq pos (point))) + (let ((limit (max (- (point) 2000) (point-min))) + found-req req-pos found-clause res pe-start pe-end + ) + (while ; Loop around syntactically significant "requires" keywords. + (progn + (while + (and + (setq found-req (re-search-backward + c-fun-name-substitute-key + limit t)) ; Fast! + (or (not (setq found-req + (not (eq (char-after (match-end 0)) ?_)))) + (not (setq found-req (not (c-in-literal))))))) ; Slow! + (setq req-pos (point)) + (cond + ((not found-req) ; No "requires" found + nil) + ((save-excursion ; A primary expression `pos' is in + (setq pe-end nil) + (while (and (setq pe-start (point)) + (< (point) pos) + (c-forward-primary-expression nil t) + (setq pe-end (point)) + (progn (c-forward-syntactic-ws) + (looking-at "&&\\|||")) + (c-forward-over-token-and-ws))) + pe-end) + (if (<= pe-end pos) + t ; POS is not in a primary expression. + (setq res (cons pe-start 'expression)) + nil)) + ((progn + (goto-char req-pos) + (if (looking-at c-fun-name-substitute-key) + (setq found-clause (c-forward-c++-requires-clause nil t)) + (and (c-forward-concept-fragment) + (setq found-clause (point)))) + nil)) + ((and found-clause (>= (point) pos)) + (setq res (cons req-pos (eq (point) pos))) + nil) + (found-clause ; We found a constraint clause, but it did not + ; extend far enough forward to reach POS. + (c-go-up-list-backward req-pos limit)) + (t (goto-char req-pos) + t)))) + res))) + (defun c-looking-at-inexpr-block (lim containing-sexp &optional check-at-end) ;; Return non-nil if we're looking at the beginning of a block ;; inside an expression. The value returned is actually a cons of @@ -13305,6 +13836,19 @@ comment at the start of cc-engine.el for more info." (looking-at c-pre-lambda-tokens-re))) (not (c-in-literal)))) +(defun c-c++-vsemi-p (&optional pos) + ;; C++ Only - Is there a "virtual semicolon" at POS or point? + ;; (See cc-defs.el for full details of "virtual semicolons".) + ;; + ;; This is true when point is at the last non syntactic WS position on the + ;; line, and either there is a "macro with semicolon" just before it (see + ;; `c-at-macro-vsemi-p') or there is a "requires" clause which ends there. + (let (res) + (cond + ((setq res (c-in-requires-or-at-end-of-clause pos)) + (and res (eq (cdr res) t))) + ((c-at-macro-vsemi-p))))) + (defun c-at-macro-vsemi-p (&optional pos) ;; Is there a "virtual semicolon" at POS or point? ;; (See cc-defs.el for full details of "virtual semicolons".) @@ -13640,7 +14184,8 @@ comment at the start of cc-engine.el for more info." (defun c-add-class-syntax (symbol containing-decl-open containing-decl-start - containing-decl-kwd) + containing-decl-kwd + &rest args) ;; The inclass and class-close syntactic symbols are added in ;; several places and some work is needed to fix everything. ;; Therefore it's collected here. @@ -13655,7 +14200,7 @@ comment at the start of cc-engine.el for more info." ;; Ought to use `c-add-stmt-syntax' instead of backing up to boi ;; here, but we have to do like this for compatibility. (back-to-indentation) - (c-add-syntax symbol (point)) + (apply #'c-add-syntax symbol (point) args) (if (and (c-keyword-member containing-decl-kwd 'c-inexpr-class-kwds) (/= containing-decl-start (c-point 'boi containing-decl-start))) @@ -13689,9 +14234,10 @@ comment at the start of cc-engine.el for more info." ;; CASE B.1: class-open ((save-excursion (and (eq (char-after) ?{) - (c-looking-at-decl-block t) + (setq placeholder (c-looking-at-decl-block t)) (setq beg-of-same-or-containing-stmt (point)))) - (c-add-syntax 'class-open beg-of-same-or-containing-stmt)) + (c-add-syntax 'class-open beg-of-same-or-containing-stmt + (c-point 'boi placeholder))) ;; CASE B.2: brace-list-open ((or (consp special-brace-list) @@ -13856,7 +14402,7 @@ comment at the start of cc-engine.el for more info." literal char-before-ip before-ws-ip char-after-ip macro-start in-macro-expr c-syntactic-context placeholder step-type tmpsymbol keyword injava-inher special-brace-list tmp-pos - tmp-pos2 containing-< + tmp-pos2 containing-< tmp constraint-detail ;; The following record some positions for the containing ;; declaration block if we're directly within one: ;; `containing-decl-open' is the position of the open @@ -14186,7 +14732,10 @@ comment at the start of cc-engine.el for more info." 'lambda-intro-cont))) (goto-char (cdr placeholder)) (back-to-indentation) - (c-add-stmt-syntax tmpsymbol nil t + (c-add-stmt-syntax tmpsymbol + (and (eq tmpsymbol 'class-open) + (list (point))) + t (c-most-enclosing-brace state-cache (point)) paren-state) (unless (eq (point) (cdr placeholder)) @@ -14229,9 +14778,10 @@ comment at the start of cc-engine.el for more info." (goto-char indent-point) (skip-chars-forward " \t") (and (eq (char-after) ?{) - (c-looking-at-decl-block t) + (setq tmp-pos (c-looking-at-decl-block t)) (setq placeholder (point)))) - (c-add-syntax 'class-open placeholder)) + (c-add-syntax 'class-open placeholder + (c-point 'boi tmp-pos))) ;; CASE 5A.3: brace list open ((save-excursion @@ -14271,6 +14821,33 @@ comment at the start of cc-engine.el for more info." containing-decl-start containing-decl-kwd)) + ;; CASE 5A.7: "defun" open in a requires expression. + ((save-excursion + (goto-char indent-point) + (c-backward-syntactic-ws lim) + (and (or (not (eq (char-before) ?\))) + (c-go-list-backward nil lim)) + (progn (c-backward-syntactic-ws lim) + (zerop (c-backward-token-2 nil nil lim))) + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_)) + (setq placeholder (point)))) + (goto-char placeholder) + (back-to-indentation) + (c-add-syntax 'defun-open (point))) + + ;; CASE 5A.6: "defun" open in concept. + ;; ((save-excursion + ;; (goto-char indent-point) + ;; (skip-chars-forward " \t") + ;; (and (eq (char-after) ?{) + ;; (eq (c-beginning-of-statement-1 lim) 'same) + ;; (setq placeholder + ;; (cdr (c-looking-at-concept indent-point))))) + ;; (goto-char placeholder) + ;; (back-to-indentation) + ;; (c-add-syntax 'defun-open (point))) + ;; CASE 5A.5: ordinary defun open (t (save-excursion @@ -14441,10 +15018,35 @@ comment at the start of cc-engine.el for more info." nil nil containing-sexp paren-state)) + ;; CASE 5F: Close of a non-class declaration level block. + ((and (eq char-after-ip ?}) + (c-keyword-member containing-decl-kwd + 'c-other-block-decl-kwds)) + ;; This is inconsistent: Should use `containing-decl-open' + ;; here if it's at boi, like in case 5J. + (goto-char containing-decl-start) + (c-add-stmt-syntax + (if (string-equal (symbol-name containing-decl-kwd) "extern") + ;; Special case for compatibility with the + ;; extern-lang syntactic symbols. + 'extern-lang-close + (intern (concat (symbol-name containing-decl-kwd) + "-close"))) + nil t + (c-most-enclosing-brace paren-state (point)) + paren-state)) + + ;; CASE 5T: Continuation of a concept clause. + ((save-excursion + (and (eq (c-beginning-of-statement-1 nil t) 'same) + (setq tmp (c-looking-at-concept indent-point)))) + (c-add-syntax 'constraint-cont (car tmp))) + ;; CASE 5D: this could be a top-level initialization, a ;; member init list continuation, or a template argument ;; list continuation. ((save-excursion + (setq constraint-detail (c-in-requires-or-at-end-of-clause)) ;; Note: We use the fact that lim is always after any ;; preceding brace sexp. (if c-recognize-<>-arglists @@ -14474,8 +15076,9 @@ comment at the start of cc-engine.el for more info." ;; clause - we assume only C++ needs it. (c-syntactic-skip-backward "^;,=" lim t)) (setq placeholder (point)) - (and (memq (char-before) '(?, ?= ?<)) - (not (c-crosses-statement-barrier-p (point) indent-point)))) + (or constraint-detail + (and (memq (char-before) '(?, ?= ?<)) + (not (c-crosses-statement-barrier-p (point) indent-point))))) (cond ;; CASE 5D.6: Something like C++11's "using foo = <type-exp>" @@ -14493,8 +15096,7 @@ comment at the start of cc-engine.el for more info." (c-on-identifier)) (setq placeholder preserve-point))))) (c-add-syntax - 'statement-cont placeholder) - ) + 'statement-cont placeholder)) ;; CASE 5D.3: perhaps a template list continuation? ((and (c-major-mode-is 'c++-mode) @@ -14544,21 +15146,10 @@ comment at the start of cc-engine.el for more info." ;; CASE 5D.7: Continuation of a "concept foo =" line in C++20 (or ;; similar). - ((and c-equals-nontype-decl-key - (save-excursion - (prog1 - (and (zerop (c-backward-token-2 1 nil lim)) - (looking-at c-operator-re) - (equal (match-string 0) "=") - (zerop (c-backward-token-2 1 nil lim)) - (looking-at c-symbol-start) - (not (looking-at c-keywords-regexp)) - (zerop (c-backward-token-2 1 nil lim)) - (looking-at c-equals-nontype-decl-key) - (eq (c-beginning-of-statement-1 lim) 'same)) - (setq placeholder (point))))) - (goto-char placeholder) - (c-add-stmt-syntax 'topmost-intro-cont nil nil containing-sexp + ((and constraint-detail + (not (eq (cdr constraint-detail) 'expression))) + (goto-char (car constraint-detail)) + (c-add-stmt-syntax 'constraint-cont nil nil containing-sexp paren-state)) ;; CASE 5D.5: Continuation of the "expression part" of a @@ -14583,33 +15174,19 @@ comment at the start of cc-engine.el for more info." nil nil containing-sexp paren-state)) )) - ;; CASE 5F: Close of a non-class declaration level block. - ((and (eq char-after-ip ?}) - (c-keyword-member containing-decl-kwd - 'c-other-block-decl-kwds)) - ;; This is inconsistent: Should use `containing-decl-open' - ;; here if it's at boi, like in case 5J. - (goto-char containing-decl-start) - (c-add-stmt-syntax - (if (string-equal (symbol-name containing-decl-kwd) "extern") - ;; Special case for compatibility with the - ;; extern-lang syntactic symbols. - 'extern-lang-close - (intern (concat (symbol-name containing-decl-kwd) - "-close"))) - nil t - (c-most-enclosing-brace paren-state (point)) - paren-state)) - ;; CASE 5G: we are looking at the brace which closes the ;; enclosing nested class decl ((and containing-sexp (eq char-after-ip ?}) (eq containing-decl-open containing-sexp)) + (save-excursion + (goto-char containing-decl-open) + (setq tmp-pos (c-looking-at-decl-block t))) (c-add-class-syntax 'class-close containing-decl-open containing-decl-start - containing-decl-kwd)) + containing-decl-kwd + (c-point 'boi tmp-pos))) ;; CASE 5H: we could be looking at subsequent knr-argdecls ((and c-recognize-knr-p @@ -14813,7 +15390,59 @@ 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.) + ;; CASE 20: A C++ requires sub-clause. + ((and (setq tmp (c-in-requires-or-at-end-of-clause indent-point)) + (not (eq (cdr tmp) 'expression)) + (setq placeholder (car tmp))) + (c-add-syntax + (if (eq char-after-ip ?{) + 'substatement-open + 'substatement) + (c-point 'boi placeholder))) + + ;; ((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 @@ -15154,6 +15783,20 @@ comment at the start of cc-engine.el for more info." (c-add-syntax 'defun-close (point)) (c-add-syntax 'inline-close (point)))) + ;; CASE 16G: Do we have the closing brace of a "requires" clause + ;; of a C++20 "concept"? + ((save-excursion + (c-backward-syntactic-ws lim) + (and (or (not (eq (char-before) ?\))) + (c-go-list-backward nil lim)) + (progn (c-backward-syntactic-ws lim) + (zerop (c-backward-token-2 nil nil lim))) + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_)))) + (goto-char containing-sexp) + (back-to-indentation) + (c-add-stmt-syntax 'defun-close nil t lim paren-state)) + ;; CASE 16F: Can be a defun-close of a function declared ;; in a statement block, e.g. in Pike or when using gcc ;; extensions, but watch out for macros followed by @@ -15304,6 +15947,21 @@ comment at the start of cc-engine.el for more info." (if (eq char-after-ip ?{) (c-add-syntax 'block-open))) + ;; CASE 17J: first "statement" inside a C++20 requires + ;; "function". + ((save-excursion + (goto-char containing-sexp) + (c-backward-syntactic-ws lim) + (and (or (not (eq (char-before) ?\))) + (c-go-list-backward nil lim)) + (progn (c-backward-syntactic-ws lim) + (zerop (c-backward-token-2 nil nil lim))) + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_)))) + (goto-char containing-sexp) + (back-to-indentation) + (c-add-syntax 'defun-block-intro (point))) + ;; CASE 17F: first statement in an inline, or first ;; statement in a top-level defun. we can tell this is it ;; if there are no enclosing braces that haven't been diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index d4079bdd6dd..6419d6cf05a 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -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)))) @@ -387,7 +387,7 @@ (parse-sexp-lookup-properties (cc-eval-when-compile (boundp 'parse-sexp-lookup-properties)))) - ,(c-make-font-lock-search-form regexp highlights)) + ,(c-make-font-lock-search-form regexp highlights t)) nil))) (defun c-make-font-lock-BO-decl-search-function (regexp &rest highlights) @@ -1112,7 +1112,7 @@ casts and declarations are fontified. Used on level 2 and higher." ;; 'c-decl-type-start (according to TYPES). Stop at LIMIT. ;; ;; If TYPES is t, fontify all identifiers as types; if it is a number, a - ;; buffer position, additionally set the `c-deftype' text property on the + ;; buffer position, additionally set the `c-typedef' text property on the ;; keyword at that position; if it is nil fontify as either variables or ;; functions, otherwise TYPES is a face to use. If NOT-TOP is non-nil, we ;; are not at the top-level ("top-level" includes being directly inside a @@ -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) @@ -1378,7 +1388,8 @@ casts and declarations are fontified. Used on level 2 and higher." (memq type '(c-decl-arg-start c-decl-type-start)))))))) ((and (zerop (c-backward-token-2)) - (looking-at c-fun-name-substitute-key))))))))) + (looking-at c-fun-name-substitute-key) + (not (eq (char-after (match-end 0)) ?_)))))))))) ;; Cache the result of this test for next time around. (c-put-char-property (1- match-pos) 'c-type 'c-decl-arg-start) (cons 'decl nil)) @@ -1616,13 +1627,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 +1697,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 +1727,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. ;; @@ -1854,6 +1890,38 @@ casts and declarations are fontified. Used on level 2 and higher." (c-font-lock-declarators limit t in-typedef (not (c-bs-at-toplevel-p (point))))))))))) +(defun c-font-lock-ids-with-dollar (limit) + ;; Maybe fontify identifiers with a dollar using `font-lock-warning-face'. + ;; This is done only for languages which tolerate a $ in ids, and only when + ;; the flag variable `c-warn-ids-with-dollar' is set to non-nil. This + ;; function only works after functions such as `c-font-lock-declarations' + ;; have already been run. + ;; + ;; This function will be called from font-lock for a region bounded by POINT + ;; and LIMIT, as though it were to identify a keyword for + ;; font-lock-keyword-face. It always returns NIL to inhibit this and + ;; prevent a repeat invocation. See elisp/lispref page "Search-based + ;; Fontification". + (when c-warn-ids-with-dollar + (let (id-start) + (while (and (< (point) limit) + (skip-chars-forward "^$" limit) + (< (point) limit) + (eq (char-after) ?$)) + (if (and (memq (c-get-char-property (point) 'face) + '(font-lock-variable-name-face + font-lock-function-name-face + font-lock-type-face)) + (setq id-start (c-on-identifier))) + (progn + (goto-char id-start) + (looking-at c-identifier-key) + (c-put-font-lock-face (match-beginning 0) (match-end 0) + 'font-lock-warning-face) + (goto-char (match-end 0))) + (forward-char))) + nil))) + (defun c-font-lock-ml-strings (limit) ;; Fontify multi-line strings. ;; @@ -2254,7 +2322,12 @@ on level 2 only and so aren't combined with `c-complex-decl-matchers'." ;; Fontify generic colon labels in languages that support them. ,@(when (c-lang-const c-recognize-colon-labels) - '(c-font-lock-labels)))) + '(c-font-lock-labels)) + + ;; Maybe fontify identifiers containing a dollar sign with + ;; `font-lock-warning-face'. + ,@(when (c-lang-const c-dollar-in-ids) + `(c-font-lock-ids-with-dollar)))) (c-lang-defconst c-complex-decl-matchers "Complex font lock matchers for types and declarations. Used on level @@ -2330,7 +2403,11 @@ on level 2 only and so aren't combined with `c-complex-decl-matchers'." ;; (see Elisp page "Search-based Fontification"). '(("\\<new\\>" (c-font-lock-c++-new)))) - )) + + ;; Maybe fontify identifiers containing a dollar sign with + ;; `font-lock-warning-face'. + ,@(when (c-lang-const c-dollar-in-ids) + `(c-font-lock-ids-with-dollar)))) (defun c-font-lock-labels (limit) ;; Fontify all statement labels from the point to LIMIT. Assumes @@ -2623,7 +2700,9 @@ need for `c-font-lock-extra-types'.") ;; prevent a repeat invocation. See elisp/lispref page "Search-based ;; fontification". (let (pos) - (while (c-syntactic-re-search-forward c-using-key limit 'end) + (while + (and (< (point) limit) + (c-syntactic-re-search-forward c-using-key limit 'end)) (while ; Do one declarator of a comma separated list, each time around. (progn (c-forward-syntactic-ws) @@ -2643,9 +2722,7 @@ need for `c-font-lock-extra-types'.") 'same) (looking-at c-colon-type-list-re))) ;; Inherited protected member: leave unfontified - ) - (t (goto-char pos) - (c-font-lock-declarators limit nil c-label-face-name nil))) + )) (eq (char-after) ?,))) (forward-char))) ; over the comma. nil)) diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 9bbcd065b7f..ba0d1d0fc49 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -455,19 +455,29 @@ so that all identifiers are recognized as words.") c++ '(c-extend-region-for-CPP c-depropertize-CPP c-before-change-check-ml-strings + c-unmark-<>-around-region c-before-change-check-<>-operators c-before-after-change-check-c++-modules c-truncate-bs-cache c-before-change-check-unbalanced-strings c-parse-quotes-before-change c-before-change-fix-comment-escapes) - (c objc) '(c-extend-region-for-CPP - c-depropertize-CPP - c-truncate-bs-cache - c-before-change-check-unbalanced-strings - c-parse-quotes-before-change - c-before-change-fix-comment-escapes) + c '(c-extend-region-for-CPP + c-depropertize-CPP + c-truncate-bs-cache + c-before-change-check-unbalanced-strings + c-parse-quotes-before-change + c-before-change-fix-comment-escapes) + objc '(c-extend-region-for-CPP + c-depropertize-CPP + c-truncate-bs-cache + c-before-change-check-unbalanced-strings + c-unmark-<>-around-region + c-before-change-check-<>-operators + c-parse-quotes-before-change + c-before-change-fix-comment-escapes) java '(c-parse-quotes-before-change + c-unmark-<>-around-region c-before-change-check-unbalanced-strings c-before-change-check-<>-operators) pike '(c-before-change-check-ml-strings @@ -502,20 +512,31 @@ parameters \(point-min) and \(point-max).") c-after-change-escape-NL-in-string c-after-change-mark-abnormal-strings c-change-expand-fl-region) - (c objc) '(c-depropertize-new-text - c-after-change-fix-comment-escapes - c-after-change-escape-NL-in-string - c-parse-quotes-after-change - c-after-change-mark-abnormal-strings - c-extend-font-lock-region-for-macros - c-neutralize-syntax-in-CPP - c-change-expand-fl-region) + c '(c-depropertize-new-text + c-after-change-fix-comment-escapes + c-after-change-escape-NL-in-string + c-parse-quotes-after-change + c-after-change-mark-abnormal-strings + c-extend-font-lock-region-for-macros + c-neutralize-syntax-in-CPP + c-change-expand-fl-region) + objc '(c-depropertize-new-text + c-after-change-fix-comment-escapes + c-after-change-escape-NL-in-string + c-parse-quotes-after-change + c-after-change-mark-abnormal-strings + c-unmark-<>-around-region + c-extend-font-lock-region-for-macros + c-neutralize-syntax-in-CPP + c-restore-<>-properties + c-change-expand-fl-region) c++ '(c-depropertize-new-text c-after-change-fix-comment-escapes c-after-change-escape-NL-in-string c-after-change-unmark-ml-strings c-parse-quotes-after-change c-after-change-mark-abnormal-strings + c-unmark-<>-around-region c-extend-font-lock-region-for-macros c-before-after-change-check-c++-modules c-neutralize-syntax-in-CPP @@ -524,6 +545,7 @@ parameters \(point-min) and \(point-max).") java '(c-depropertize-new-text c-after-change-escape-NL-in-string c-parse-quotes-after-change + c-unmark-<>-around-region c-after-change-mark-abnormal-strings c-restore-<>-properties c-change-expand-fl-region) @@ -586,7 +608,8 @@ Such a function takes one optional parameter, a buffer position (defaults to point), and returns nil or t. This variable contains nil for languages which don't have EOL terminated statements. " t nil - (c c++ objc) 'c-at-macro-vsemi-p + (c objc) 'c-at-macro-vsemi-p + c++ 'c-c++-vsemi-p awk 'c-awk-at-vsemi-p) (c-lang-defvar c-at-vsemi-p-fn (c-lang-const c-at-vsemi-p-fn)) @@ -738,11 +761,11 @@ When non-nil, this variable should end in \"\\\\\\==\". Note that such a backward search will match a minimal string, so a \"context character\" is probably needed at the start of the regexp. The value for csharp-mode would be something like -\"\\\\(:?\\\\`\\\\|[^\\\"]\\\\)\\\"*\\\\\\==\"." +\"\\\\(?:\\\\`\\\\|[^\\\"]\\\\)\\\"*\\\\\\==\"." t nil - pike "\\(:?\\`\\|[^\\\"]\\)\\(:?\\\\.\\)*\\=" + pike "\\(?:\\`\\|[^\\\"]\\)\\(?:\\\\.\\)*\\=" ;;pike ;; 2 - ;; "\\(:?\\`\\|[^\"]\\)\"*\\=" + ;; "\\(?:\\`\\|[^\"]\\)\"*\\=" ) (c-lang-defvar c-ml-string-back-closer-re (c-lang-const c-ml-string-back-closer-re)) @@ -794,7 +817,7 @@ there be copies of the opener contained in the multi-line string." (c-lang-defconst c-cpp-or-ml-match-offset ;; The offset to be added onto match numbers for a multi-line string in - ;; matches for `c-cpp-or-ml-string-opener-re'. + ;; matches for `c-ml-string-cpp-or-opener-re'. t (if (c-lang-const c-anchored-cpp-prefix) (+ 2 (regexp-opt-depth (c-lang-const c-anchored-cpp-prefix))) 2)) @@ -829,8 +852,9 @@ which `c-backward-sexp' needs to be called twice to move backwards over." keyword. It's unspecified how far it matches. Does not contain a \\| operator at the top level." t (concat "[" c-alpha "_]") + (c c++) (concat "[" c-alpha "_$]") java (concat "[" c-alpha "_@]") - objc (concat "[" c-alpha "_@]") + objc (concat "[" c-alpha "_@$]") pike (concat "[" c-alpha "_`]")) (c-lang-defvar c-symbol-start (c-lang-const c-symbol-start)) @@ -843,6 +867,10 @@ This is of the form that fits inside [ ] in a regexp." objc (concat c-alnum "_$@")) (c-lang-defvar c-symbol-chars (c-lang-const c-symbol-chars)) +(c-lang-defconst c-dollar-in-ids + "Non-nil when a dollar (can be) a non-standard constituent of an identifier." + t (string-match (c-lang-const c-symbol-start) "$")) + (c-lang-defconst c-symbol-char-key "Regexp matching a sequence of at least one identifier character." t (concat "[" (c-lang-const c-symbol-chars) "]+")) @@ -854,9 +882,9 @@ to match if `c-symbol-start' matches on the same position." t (concat (c-lang-const c-symbol-start) "[" (c-lang-const c-symbol-chars) "]\\{,1000\\}") pike (concat - ;; Use the value from C here since the operator backquote is + ;; Use the value from AWK here since the operator backquote is ;; covered by the other alternative. - (c-lang-const c-symbol-key c) + (c-lang-const c-symbol-key awk) "\\|" (c-make-keywords-re nil (c-lang-const c-overloadable-operators)))) @@ -1043,14 +1071,6 @@ Currently (2022-09) just C++ Mode uses this." ;; matched. t nil) -(c-lang-defconst c-string-escaped-newlines - "Set if the language support backslash escaped newlines inside string -literals." - t nil - (c c++ objc pike) t) -(c-lang-defvar c-string-escaped-newlines - (c-lang-const c-string-escaped-newlines)) - (c-lang-defconst c-multiline-string-start-char "Set if the language supports multiline string literals without escaped newlines. If t, all string literals are multiline. If a character, @@ -1067,6 +1087,18 @@ further directions." (c-lang-defvar c-multiline-string-start-char (c-lang-const c-multiline-string-start-char)) +(c-lang-defconst c-escaped-newline-takes-precedence + "Set if the language resolves escaped newlines first. +This makes a difference in a string like \"...\\\\\n\". When +this variable is nil, the first backslash escapes the second, +leaving an unterminated string. When it's non-nil, the string is +continued onto the next line, and the first backslash escapes +whatever begins that next line." + t nil + (c c++ objc pike) t) +(c-lang-defvar c-escaped-newline-takes-precedence + (c-lang-const c-escaped-newline-takes-precedence)) + (c-lang-defconst c-string-innards-re-alist ;; An alist of regexps matching the innards of a string, the key being the ;; string's delimiter. @@ -1077,9 +1109,12 @@ further directions." t (mapcar (lambda (delim) (cons delim - (concat "\\(\\\\\\(.\\|\n\\)\\|[^\\\n\r" - (string delim) - "]\\)*"))) + (concat + (if (c-lang-const c-escaped-newline-takes-precedence) + "\\(\\\\\\(\\\\?\n\\|.\\)\\|[^\\\n\r" + "\\(\\\\\\(\n\\|.\\)\\|[^\\\n\r") + (string delim) + "]\\)*"))) (and (or (null (c-lang-const c-multiline-string-start-char)) (c-characterp (c-lang-const c-multiline-string-start-char))) @@ -2635,9 +2670,12 @@ clause. An arglist may or may not follow such a keyword." c++ '("requires")) (c-lang-defconst c-fun-name-substitute-key - ;; An adorned regular expression which matches any member of + ;; An unadorned regular expression which matches any member of ;; `c-fun-name-substitute-kwds'. - t (c-make-keywords-re t (c-lang-const c-fun-name-substitute-kwds))) + t (c-make-keywords-re 'appendable (c-lang-const c-fun-name-substitute-kwds))) +;; We use 'appendable, so that we get "\\>" on the regexp, but without a further +;; character, which would mess up backward regexp search from just after the +;; keyword. If only XEmacs had \\_>. ;-( (c-lang-defvar c-fun-name-substitute-key (c-lang-const c-fun-name-substitute-key)) @@ -3086,6 +3124,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) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 5c1cc761ad6..64a679eacc7 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -255,6 +255,13 @@ control). See \"cc-mode.el\" for more info." ;; Will try initialization hooks again if they failed. (put 'c-initialize-cc-mode initprop c-initialization-ok)))) + ;; Set up text conversion, for Emacs >= 30.0 + ;; This is needed here because CC-mode's implementation of + ;; electricity does not rely on `post-self-insert-hook' (which is + ;; already handled adequately by `analyze-text-conversion'). + (when (boundp 'post-text-conversion-hook) + (add-hook 'post-text-conversion-hook #'c-post-text-conversion nil t)) + (unless new-style-init (c-init-language-vars-for 'c-mode))) @@ -1275,7 +1282,9 @@ Note that the style variables are always made local to the buffer." ;; VALUE (which should not be nil). ;; `(let ((-pos- ,pos) ;; (-value- ,value)) - (c-put-char-property pos 'syntax-table value) + (if (equal value '(15)) + (c-put-string-fence pos) + (c-put-char-property pos 'syntax-table value)) (c-put-char-property pos 'c-fl-syn-tab value) (cond ((null c-min-syn-tab-mkr) @@ -1367,7 +1376,15 @@ Note that the style variables are always made local to the buffer." (and ;(< (point) end) (not (nth 3 s)) (c-get-char-property (1- (point)) 'c-fl-syn-tab)) - (c-put-char-property pos 'syntax-table '(1))) + (c-put-char-property pos 'syntax-table '(1)) + ;; Remove syntax-table text properties from template + ;; delimiters. + (c-clear-char-property-with-value + (1+ pos) (c-point 'eol pos) + 'syntax-table c-<-as-paren-syntax) + (c-clear-char-property-with-value + (1+ pos) (c-point 'eol pos) + 'syntax-table c->-as-paren-syntax)) (setq pos (point))) (setq pos (1+ pos))))))))) @@ -1384,6 +1401,9 @@ Note that the style variables are always made local to the buffer." (setq pos (c-min-property-position pos c-max-syn-tab-mkr 'c-fl-syn-tab)) (< pos c-max-syn-tab-mkr)) + (when (and (equal (c-get-char-property pos 'syntax-table) '(1)) + (equal (c-get-char-property pos 'c-fl-syn-tab) '(15))) + (c-clear-char-properties (1+ pos) (c-point 'eol pos) 'syntax-table)) (c-put-char-property pos 'syntax-table (c-get-char-property pos 'c-fl-syn-tab)) (setq pos (1+ pos)))))) @@ -2444,8 +2464,6 @@ with // and /*, not more generic line and block comments." (setq pseudo (c-cheap-inside-bracelist-p (c-parse-state))))))) (goto-char pseudo)) t) - (or (> (point) bod-lim) - (eq bod-lim (point-min))) ;; Move forward to the start of the next declaration. (progn (c-forward-syntactic-ws) ;; Have we got stuck in a comment at EOB? @@ -2720,18 +2738,18 @@ This function is called from `c-common-init', once per mode initialization." ;; Emacs < 22 and XEmacs (defmacro c-advise-fl-for-region (function) (declare (debug t)) - `(defadvice ,function (before get-awk-region activate) - ;; Make sure that any string/regexp is completely font-locked. - (when c-buffer-is-cc-mode - (save-excursion - (ad-set-arg 1 c-new-END) ; end - (ad-set-arg 0 c-new-BEG))))) ; beg - -(unless (boundp 'font-lock-extend-after-change-region-function) - (c-advise-fl-for-region font-lock-after-change-function) - (c-advise-fl-for-region jit-lock-after-change) - (c-advise-fl-for-region lazy-lock-defer-rest-after-change) - (c-advise-fl-for-region lazy-lock-defer-line-after-change)) + (unless (boundp 'font-lock-extend-after-change-region-function) + `(defadvice ,function (before get-awk-region activate) + ;; Make sure that any string/regexp is completely font-locked. + (when c-buffer-is-cc-mode + (save-excursion + (ad-set-arg 1 c-new-END) ; end + (ad-set-arg 0 c-new-BEG)))))) ; beg + +(c-advise-fl-for-region font-lock-after-change-function) +(c-advise-fl-for-region jit-lock-after-change) +(c-advise-fl-for-region lazy-lock-defer-rest-after-change) +(c-advise-fl-for-region lazy-lock-defer-line-after-change) ;; Connect up to `electric-indent-mode' (Emacs 24.4 and later). (defun c-electric-indent-mode-hook () @@ -2861,7 +2879,7 @@ Key bindings: "\\|" id "::" "\\|" id ws-maybe "=\\)" "\\|" "\\(?:inline" ws "\\)?namespace" - "\\(:?" ws "\\(?:" id "::\\)*" id "\\)?" ws-maybe "{" + "\\(?:" ws "\\(?:" id "::\\)*" id "\\)?" ws-maybe "{" "\\|" "class" ws id "\\(?:" ws "final" "\\)?" ws-maybe "[:{;\n]" "\\|" "struct" ws id "\\(?:" ws "final" ws-maybe "[:{\n]" diff --git a/lisp/progmodes/cc-styles.el b/lisp/progmodes/cc-styles.el index b79853252ac..ff6371d9368 100644 --- a/lisp/progmodes/cc-styles.el +++ b/lisp/progmodes/cc-styles.el @@ -658,8 +658,9 @@ any reason to call this function directly." (let ((func (if this-buf-only-p 'make-local-variable 'make-variable-buffer-local)) - (varsyms (cons 'c-indentation-style (copy-alist c-style-variables)))) - (delq 'c-special-indent-hook varsyms) + (varsyms (cons 'c-indentation-style + (delq 'c-special-indent-hook + (copy-alist c-style-variables))))) (mapc func varsyms) ;; Hooks must be handled specially (if this-buf-only-p diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el index 88c389b4e5d..3845c2d55f0 100644 --- a/lisp/progmodes/cc-vars.el +++ b/lisp/progmodes/cc-vars.el @@ -280,6 +280,14 @@ anchoring position to indent the line in that case." :type 'boolean :group 'c) +(defcustom c-warn-ids-with-dollar nil + "Fontify identifiers with a dollar character in font-lock-warn-face. +This has effect only for languages in which `c-dollar-in-ids' is +non-nil, e.g. C, C++, Objective C. It covers languages where +\"$\" is permitted in ids \"informally\", but only by some compilers." + :type 'boolean + :group 'c) + (defcustom-c-stylevar c-basic-offset 4 "Amount of basic offset used by + and - symbols in `c-offsets-alist'. Also used as the indentation step when `c-syntactic-indentation' is @@ -1094,6 +1102,8 @@ can always override the use of `c-default-style' by making calls to ;; Anchor pos: Bol at the last line of previous construct. (topmost-intro-cont . c-lineup-topmost-intro-cont) ;;Anchor pos: Bol at the topmost annotation line + (constraint-cont . +) + ;; Anchor pos: Boi of the starting requires/concept line (annotation-top-cont . 0) ;;Anchor pos: Bol at the topmost annotation line (annotation-var-cont . +) @@ -1217,7 +1227,8 @@ can always override the use of `c-default-style' by making calls to (incomposition . +) ;; Anchor pos: At the extern/namespace/etc block open brace if ;; it's at boi, otherwise boi at the keyword. - (template-args-cont . (c-lineup-template-args +)) + (template-args-cont . (c-lineup-template-args + c-lineup-template-args-indented-from-margin)) ;; Anchor pos: Boi at the decl start. This might be changed; ;; the logical position is clearly the opening '<'. (inlambda . 0) @@ -1326,6 +1337,9 @@ Here is the current list of valid syntactic element symbols: knr-argdecl -- Subsequent lines in a K&R C argument declaration. topmost-intro -- The first line in a topmost construct definition. topmost-intro-cont -- Topmost definition continuation lines. + constraint-cont -- Continuation line of a C++ requires clause (not + to be confused with a \"requires expression\") or + concept. annotation-top-cont -- Topmost definition continuation line where only annotations are on previous lines. annotation-var-cont -- A continuation of a C (or like) statement where
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor