From 578d9aaf82b386c1a0316dde491d297e18e10636 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Sun, 21 Aug 2016 16:00:15 +0000 Subject: [PATCH] Adapt CC Mode for C++11 uniform initialization. For fontification, introduce a new "context", 'non-decl, to be used for brace lists; also a new value for the property 'c-type, called 'c-not-decl. * lisp/progmodes/cc-engine.el (c-back-over-compound-identifier): Check that an ostensible symbol we're going to move over isn't a keyword. (c-forward-decl-or-cast-1): CASE 1: Where we have two consecutive identifiers (hence a declaration), and an unmatched open paren, perform c-fdoc-shift-type-backwards to recognize the partial construct correctly. Whilst checking a type decl expression, check for and handle C++11's "copy initialization", where we have (). Recognize (... (where the paren is unclosed) as a declaration. (c-looking-at-or-maybe-in-bracelist): New function, extracted from c-inside-bracelist-p. Recognize as bracelists "{"s which are preceded by valid tokens other than "=". Recognize a bracelist when preceded by a template declaration. (c-inside-bracelist-p): Call c-looking-at-or-maybe-in-bracelist in place of much inline code. (c-looking-at-inexpr-block): Amend so that it won't wrongly recognise an initialization starting "({" as an in-expression block, by checking for semicolons, as opposed to commas, separating elements inside it. (c-guess-continued-construct): (CASE B-2): Recognize a brace-list-open by calling c-looking-at-or-maybe-in-bracelist rather than checking for a preceding "=". (CASE B-5): New code to recognize new construct "return { ...}". (c-guess-basic-syntax): (CASE 5A.3): Additionally recognize a "{" preceded by "return", or "{" preceded by as a bracelist. * lisp/progmodes/cc-fonts.el (c-font-lock-declarations): Recognize brace lists, giving them `context' 'non-decl. Pass over elements of one by regexp search for "," rather than calling c-forward-decl-or-cast-1. * lisp/progmodes/cc-langs.el (c-return-kwds, c-return-key): New lang constants/variables to recognize "return". (c-pre-id-bracelist-key): New lang constant/variable to recognize tokens which, when preceding an identifier followed by a brace, signify the brace as a bracelist. * lisp/progmodes/cc-mode.el (c-fl-decl-start): When searching outwards for the start of a "local" declaration, move out from an enclosing brace when that is the start of a brace list. --- lisp/progmodes/cc-engine.el | 364 ++++++++++++++++++++++++------------ lisp/progmodes/cc-fonts.el | 267 ++++++++++++++------------ lisp/progmodes/cc-langs.el | 17 ++ lisp/progmodes/cc-mode.el | 15 +- 4 files changed, 415 insertions(+), 248 deletions(-) diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 8e8e4e490b7..ccdc1b15a68 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -130,6 +130,10 @@ ;; 'c-decl-type-start is used when the declarators are types, ;; 'c-decl-id-start otherwise. ;; +;; 'c-not-decl +;; Put on the brace which introduces a brace list and on the commas +;; which separate the element within it. +;; ;; 'c-awk-NL-prop ;; Used in AWK mode to mark the various kinds of newlines. See ;; cc-awk.el. @@ -7354,10 +7358,10 @@ comment at the start of cc-engine.el for more info." ;; this construct and return t. If the parsing fails, return nil, leaving ;; point unchanged. (let ((here (point)) - end - ) - (if (not (c-simple-skip-symbol-backward)) + end) + (if (not (c-on-identifier)) nil + (c-simple-skip-symbol-backward) (while (progn (setq end (point)) @@ -7712,6 +7716,8 @@ comment at the start of cc-engine.el for more info." ;; 'arglist Some other type of arglist. ;; nil Some other context or unknown context. Includes ;; within the parens of an if, for, ... construct. + ;; 'not-decl This value is never supplied to this function. It + ;; would mean we're definitely not in a declaration. ;; ;; LAST-CAST-END is the first token after the closing paren of a ;; preceding cast, or nil if none is known. If @@ -8019,7 +8025,10 @@ comment at the start of cc-engine.el for more info." ;; arglist paren that gets entered. c-parse-and-markup-<>-arglists ;; Start of the identifier for which `got-identifier' was set. - name-start) + name-start + ;; Position after (innermost) open parenthesis encountered in the + ;; prefix operators. + after-paren-pos) (goto-char id-start) @@ -8030,7 +8039,8 @@ comment at the start of cc-engine.el for more info." (when (eq (char-after) ?\() (progn (setq paren-depth (1+ paren-depth)) - (forward-char))) + (forward-char) + (setq after-paren-pos (point)))) (while (and (looking-at c-type-decl-prefix-key) (if (and (c-major-mode-is 'c++-mode) (match-beginning 3)) @@ -8053,7 +8063,8 @@ comment at the start of cc-engine.el for more info." (if (eq (char-after) ?\() (progn (setq paren-depth (1+ paren-depth)) - (forward-char)) + (forward-char) + (setq after-paren-pos (point))) (unless got-prefix-before-parens (setq got-prefix-before-parens (= paren-depth 0))) (setq got-prefix t) @@ -8062,7 +8073,7 @@ comment at the start of cc-engine.el for more info." (setq got-parens (> paren-depth 0)) - ;; Skip over an identifier. + ;; Try to skip over an identifier. (or got-identifier (and (looking-at c-identifier-start) (setq pos (point)) @@ -8111,7 +8122,15 @@ comment at the start of cc-engine.el for more info." maybe-typeless backup-maybe-typeless (when c-recognize-typeless-decls - (not context))) + (and (not context) + ;; Deal with C++11's "copy-initialization" + ;; where we have (), by + ;; contraasting with a typeless + ;; (, ...). + (save-excursion + (goto-char after-paren-pos) + (c-forward-syntactic-ws) + (c-forward-type))))) (setq pos (c-up-list-forward (point))) (eq (char-before pos) ?\))) (c-fdoc-shift-type-backward) @@ -8149,11 +8168,15 @@ comment at the start of cc-engine.el for more info." ;; Encountered something inside parens that isn't matched by ;; the `c-type-decl-*' regexps, so it's not a type decl ;; expression. Try to skip out to the same paren depth to - ;; not confuse the cast check below. - (c-safe (goto-char (scan-lists (point) 1 paren-depth))) + ;; not confuse the cast check below. If we don't manage this and + ;; `at-decl-or-cast' is 'ids we might have an expression like + ;; "foo bar ({ ..." which is a valid C++11 initialization. + (if (and (not (c-safe (goto-char (scan-lists (point) 1 paren-depth)))) + (eq at-decl-or-cast 'ids)) + (c-fdoc-shift-type-backward)) ;; If we've found a specifier keyword then it's a ;; declaration regardless. - (throw 'at-decl-or-cast (eq at-decl-or-cast t))) + (throw 'at-decl-or-cast (memq at-decl-or-cast '(t ids)))) (setq at-decl-end (looking-at (cond ((eq context '<>) "[,>]") @@ -9788,6 +9811,169 @@ comment at the start of cc-engine.el for more info." (or (looking-at c-brace-list-key) (progn (goto-char here) nil)))) +(defun c-looking-at-or-maybe-in-bracelist (containing-sexp &optional lim) + ;; Point is at an open brace. If this starts a brace list, return the + ;; buffer position of the start of the construct which introduces the list. + ;; Otherwise, if point might be inside an enclosing brace list, return t. + ;; If point is definitely neither at nor in a brace list, return nil. + ;; + ;; CONTAINING-SEXP is the position of the brace/paren/braacket enclosing + ;; POINT, or nil if there is no such position. LIM is a backward search + ;; limit. + ;; + ;; Here, "brace list" does not include the body of an enum. + (save-excursion + (let ((start (point)) + (class-key + ;; Pike can have class definitions anywhere, so we must + ;; check for the class key here. + (and (c-major-mode-is 'pike-mode) + c-decl-block-key)) + (braceassignp 'dontknow) + bufpos macro-start res after-type-id-pos) + + (setq res (c-backward-token-2 1 t lim)) + ;; Checks to do only on the first sexp before the brace. + ;; Have we a C++ initialisation, without an "="? + (if (and (c-major-mode-is 'c++-mode) + (cond + ((and (not (eq res 0)) + (c-go-up-list-backward nil lim) ; FIXME!!! Check ; `lim' 2016-07-12. + (eq (char-after) ?\()) + (setq braceassignp 'c++-noassign)) + ((looking-at c-pre-id-bracelist-key)) + ((looking-at c-return-key)) + ((and (looking-at c-symbol-start) + (not (looking-at c-keywords-regexp))) + (setq after-type-id-pos (point))) + (t nil)) + (save-excursion + (cond + ((not (eq res 0)) + (and (c-go-up-list-backward nil lim) ; FIXME!!! Check `lim' 2016-07-12. + (eq (char-after) ?\())) + ((looking-at c-pre-id-bracelist-key)) + ((looking-at c-return-key)) + (t (setq after-type-id-pos (point)) + nil)))) + (setq braceassignp 'c++-noassign)) + + (when (and c-opt-inexpr-brace-list-key + (eq (char-after) ?\[)) + ;; In Java, an initialization brace list may follow + ;; directly after "new Foo[]", so check for a "new" + ;; earlier. + (while (eq braceassignp 'dontknow) + (setq braceassignp + (cond ((/= (c-backward-token-2 1 t lim) 0) nil) + ((looking-at c-opt-inexpr-brace-list-key) t) + ((looking-at "\\sw\\|\\s_\\|[.[]") + ;; Carry on looking if this is an + ;; identifier (may contain "." in Java) + ;; or another "[]" sexp. + 'dontknow) + (t nil))))) + + ;; Checks to do on all sexps before the brace, up to the + ;; beginning of the statement. + (while (eq braceassignp 'dontknow) + (cond ((eq (char-after) ?\;) + (setq braceassignp nil)) + ((and class-key + (looking-at class-key)) + (setq braceassignp nil)) + ((eq (char-after) ?=) + ;; We've seen a =, but must check earlier tokens so + ;; that it isn't something that should be ignored. + (setq braceassignp 'maybe) + (while (and (eq braceassignp 'maybe) + (zerop (c-backward-token-2 1 t lim))) + (setq braceassignp + (cond + ;; Check for operator = + ((and c-opt-op-identifier-prefix + (looking-at c-opt-op-identifier-prefix)) + nil) + ;; Check for `= in Pike. + ((and (c-major-mode-is 'pike-mode) + (or (eq (char-after) ?`) + ;; Special case for Pikes + ;; `[]=, since '[' is not in + ;; the punctuation class. + (and (eq (char-after) ?\[) + (eq (char-before) ?`)))) + nil) + ((looking-at "\\s.") 'maybe) + ;; make sure we're not in a C++ template + ;; argument assignment + ((and + (c-major-mode-is 'c++-mode) + (save-excursion + (let ((here (point)) + (pos< (progn + (skip-chars-backward "^<>") + (point)))) + (and (eq (char-before) ?<) + (not (c-crosses-statement-barrier-p + pos< here)) + (not (c-in-literal)) + )))) + nil) + (t t)))))) + (if (and (eq braceassignp 'dontknow) + (/= (c-backward-token-2 1 t lim) 0)) + (setq braceassignp nil))) + + (cond + (braceassignp + ;; We've hit the beginning of the aggregate list. + (c-beginning-of-statement-1 containing-sexp) + (point)) + ((and after-type-id-pos + (save-excursion + (when (eq (char-after) ?\;) + (c-forward-token-2 1 t)) + (setq bufpos (point)) + (when (looking-at c-opt-<>-sexp-key) + (c-forward-token-2) + (when (and (eq (char-after) ?<) + (c-get-char-property (point) 'syntax-table)) + (c-go-list-forward nil after-type-id-pos) + (c-forward-syntactic-ws))) + (and + (or (not (looking-at c-class-key)) + (save-excursion + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (not (eq (point) after-type-id-pos)))) + (progn + (setq res + (c-forward-decl-or-cast-1 + (save-excursion (c-backward-syntactic-ws) (point)) + nil nil)) + (and (consp res) + (eq (car res) after-type-id-pos)))))) + bufpos) + ((eq (char-after) ?\;) + ;; Brace lists can't contain a semicolon, so we're done. + ;; (setq containing-sexp nil) + nil) + ((and (setq macro-start (point)) + (c-forward-to-cpp-define-body) + (eq (point) start)) + ;; We've a macro whose expansion starts with the '{'. + ;; Heuristically, if we have a ';' in it we've not got a + ;; brace list, otherwise we have. + (let ((macro-end (progn (c-end-of-macro) (point)))) + (goto-char start) + (forward-char) + (if (and (c-syntactic-re-search-forward "[;,]" macro-end t t) + (eq (char-before) ?\;)) + nil + macro-start))) + (t t)) ;; The caller can go up one level. + ))) + (defun c-inside-bracelist-p (containing-sexp paren-state) ;; return the buffer position of the beginning of the brace list ;; statement if we're inside a brace list, otherwise return nil. @@ -9807,13 +9993,9 @@ comment at the start of cc-engine.el for more info." (c-backward-over-enum-header)) ;; this will pick up array/aggregate init lists, even if they are nested. (save-excursion - (let ((class-key - ;; Pike can have class definitions anywhere, so we must - ;; check for the class key here. - (and (c-major-mode-is 'pike-mode) - c-decl-block-key)) - bufpos braceassignp lim next-containing macro-start) - (while (and (not bufpos) + (let ((bufpos t) + lim next-containing) + (while (and (eq bufpos t) containing-sexp) (when paren-state (if (consp (car paren-state)) @@ -9823,113 +10005,22 @@ comment at the start of cc-engine.el for more info." (when paren-state (setq next-containing (car paren-state) paren-state (cdr paren-state)))) + (goto-char containing-sexp) (if (c-looking-at-inexpr-block next-containing next-containing) ;; We're in an in-expression block of some kind. Do not ;; check nesting. We deliberately set the limit to the ;; containing sexp, so that c-looking-at-inexpr-block ;; doesn't check for an identifier before it. - (setq containing-sexp nil) - ;; see if the open brace is preceded by = or [...] in - ;; this statement, but watch out for operator= - (setq braceassignp 'dontknow) - (c-backward-token-2 1 t lim) - ;; Checks to do only on the first sexp before the brace. - (when (and c-opt-inexpr-brace-list-key - (eq (char-after) ?\[)) - ;; In Java, an initialization brace list may follow - ;; directly after "new Foo[]", so check for a "new" - ;; earlier. - (while (eq braceassignp 'dontknow) - (setq braceassignp - (cond ((/= (c-backward-token-2 1 t lim) 0) nil) - ((looking-at c-opt-inexpr-brace-list-key) t) - ((looking-at "\\sw\\|\\s_\\|[.[]") - ;; Carry on looking if this is an - ;; identifier (may contain "." in Java) - ;; or another "[]" sexp. - 'dontknow) - (t nil))))) - ;; Checks to do on all sexps before the brace, up to the - ;; beginning of the statement. - (while (eq braceassignp 'dontknow) - (cond ((eq (char-after) ?\;) - (setq braceassignp nil)) - ((and class-key - (looking-at class-key)) - (setq braceassignp nil)) - ((eq (char-after) ?=) - ;; We've seen a =, but must check earlier tokens so - ;; that it isn't something that should be ignored. - (setq braceassignp 'maybe) - (while (and (eq braceassignp 'maybe) - (zerop (c-backward-token-2 1 t lim))) - (setq braceassignp - (cond - ;; Check for operator = - ((and c-opt-op-identifier-prefix - (looking-at c-opt-op-identifier-prefix)) - nil) - ;; Check for `= in Pike. - ((and (c-major-mode-is 'pike-mode) - (or (eq (char-after) ?`) - ;; Special case for Pikes - ;; `[]=, since '[' is not in - ;; the punctuation class. - (and (eq (char-after) ?\[) - (eq (char-before) ?`)))) - nil) - ((looking-at "\\s.") 'maybe) - ;; make sure we're not in a C++ template - ;; argument assignment - ((and - (c-major-mode-is 'c++-mode) - (save-excursion - (let ((here (point)) - (pos< (progn - (skip-chars-backward "^<>") - (point)))) - (and (eq (char-before) ?<) - (not (c-crosses-statement-barrier-p - pos< here)) - (not (c-in-literal)) - )))) - nil) - (t t)))))) - (if (and (eq braceassignp 'dontknow) - (/= (c-backward-token-2 1 t lim) 0)) - (setq braceassignp nil))) - (cond - (braceassignp - ;; We've hit the beginning of the aggregate list. - (c-beginning-of-statement-1 - (c-most-enclosing-brace paren-state)) - (setq bufpos (point))) - ((eq (char-after) ?\;) - ;; Brace lists can't contain a semicolon, so we're done. - (setq containing-sexp nil)) - ((and (setq macro-start (point)) - (c-forward-to-cpp-define-body) - (eq (point) containing-sexp)) - ;; We've a macro whose expansion starts with the '{'. - ;; Heuristically, if we have a ';' in it we've not got a - ;; brace list, otherwise we have. - (let ((macro-end (progn (c-end-of-macro) (point)))) - (goto-char containing-sexp) - (forward-char) - (if (and (c-syntactic-re-search-forward "[;,]" macro-end t t) - (eq (char-before) ?\;)) - (setq bufpos nil - containing-sexp nil) - (setq bufpos macro-start)))) - (t - ;; Go up one level + (setq bufpos nil) + (when (or (not (eq (char-after) ?{)) + (eq (setq bufpos (c-looking-at-or-maybe-in-bracelist + next-containing lim)) + t)) (setq containing-sexp next-containing lim nil - next-containing nil))))) - - bufpos)) - )) + next-containing nil)))) + (and (numberp bufpos) bufpos))))) (defun c-looking-at-special-brace-list (&optional lim) ;; If we're looking at the start of a pike-style list, i.e., `({ })', @@ -10156,7 +10247,19 @@ comment at the start of cc-engine.el for more info." (and (> (point) (or lim (point-min))) (c-on-identifier))) (and c-special-brace-lists - (c-looking-at-special-brace-list))) + (c-looking-at-special-brace-list)) + (and (c-major-mode-is 'c++-mode) + (save-excursion + (goto-char block-follows) + (if (c-go-list-forward) + (progn + (backward-char) + (c-syntactic-skip-backward + "^;," block-follows t) + (not (eq (char-before) ?\;))) + (or (not (c-syntactic-re-search-forward + "[;,]" nil t t)) + (not (eq (char-before) ?\;))))))) nil (cons 'inexpr-statement (point))))) @@ -10565,10 +10668,10 @@ comment at the start of cc-engine.el for more info." ;; CASE B.2: brace-list-open ((or (consp special-brace-list) - (save-excursion - (goto-char beg-of-same-or-containing-stmt) - (c-syntactic-re-search-forward "=\\([^=]\\|$\\)" - indent-point t t t))) + (numberp + (c-looking-at-or-maybe-in-bracelist + containing-sexp beg-of-same-or-containing-stmt)) + ) ;; The most semantically accurate symbol here is ;; brace-list-open, but we normally report it simply as a ;; statement-cont. The reason is that one normally adjusts @@ -10601,6 +10704,14 @@ comment at the start of cc-engine.el for more info." (c-add-stmt-syntax 'defun-open nil t containing-sexp paren-state)) + ;; CASE B.5: We have a C++11 "return \n { ..... }" Note that we're + ;; not at the "{", currently. + ((progn (goto-char indent-point) + (backward-sexp) + (looking-at c-return-key)) + (c-add-stmt-syntax 'statement-cont nil t + containing-sexp paren-state)) + ;; CASE B.4: Continued statement with block open. The most ;; accurate analysis is perhaps `statement-cont' together with ;; `block-open' but we play DWIM and use `substatement-open' @@ -11120,7 +11231,14 @@ comment at the start of cc-engine.el for more info." (looking-at c-opt-inexpr-brace-list-key) (setq tmpsymbol 'topmost-intro-cont))) (looking-at "=\\([^=]\\|$\\)")) - (looking-at c-brace-list-key)) + (looking-at c-brace-list-key) + (looking-at c-return-key) + (save-excursion + (and (c-forward-type) + (looking-at c-identifier-start) + (not (looking-at c-keywords-regexp)) + (c-forward-token-2) + (eq (point) (c-point 'boi indent-point))))) (save-excursion (while (and (< (point) indent-point) (zerop (c-forward-token-2 1 t)) diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index ae18d0a9436..60b8b6db3cc 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -1166,7 +1166,8 @@ casts and declarations are fontified. Used on level 2 and higher." ;; `parse-sexp-lookup-properties' (when it exists). (parse-sexp-lookup-properties (cc-eval-when-compile - (boundp 'parse-sexp-lookup-properties)))) + (boundp 'parse-sexp-lookup-properties)) + )) ;; Below we fontify a whole declaration even when it crosses the limit, ;; to avoid gaps when jit/lazy-lock fontifies the file a block at a @@ -1204,7 +1205,8 @@ casts and declarations are fontified. Used on level 2 and higher." (setq start-pos (point)) (when ;; The result of the form below is true when we don't recognize a - ;; declaration or cast. + ;; declaration or cast, and we don't recognise a "non-decl", + ;; typically a brace list. (if (or (and (eq (get-text-property (point) 'face) 'font-lock-keyword-face) (looking-at c-not-decl-init-keywords)) @@ -1220,7 +1222,7 @@ casts and declarations are fontified. Used on level 2 and higher." ;; (e.g. "for ("). (let ((type (and (> match-pos (point-min)) (c-get-char-property (1- match-pos) 'c-type)))) - (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?<))) + (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?< ?{))) (setq context nil c-restricted-<>-arglists nil)) ;; A control flow expression or a decltype @@ -1242,6 +1244,10 @@ casts and declarations are fontified. Used on level 2 and higher." ((eq type 'c-decl-arg-start) (setq context 'decl c-restricted-<>-arglists nil)) + ;; We're inside (probably) a brace list. + ((eq type 'c-not-decl) + (setq context 'not-decl + c-restricted-<>-arglists nil)) ;; Inside a C++11 lambda function arglist. ((and (c-major-mode-is 'c++-mode) (eq (char-before match-pos) ?\() @@ -1255,7 +1261,20 @@ casts and declarations are fontified. Used on level 2 and higher." c-restricted-<>-arglists nil) (c-put-char-property (1- match-pos) 'c-type 'c-decl-arg-start)) - + ;; We're inside an brace list. + ((and (eq (char-before match-pos) ?{) + (save-excursion + (goto-char (1- match-pos)) + (numberp + (c-looking-at-or-maybe-in-bracelist nil)))) + (setq context 'not-decl + c-restricted-<>-arglists nil) + (c-put-char-property (1- match-pos) 'c-type + 'c-not-decl)) + ;; We're inside an "ordinary" open brace. + ((eq (char-before match-pos) ?{) + (setq context nil + c-restricted-<>-arglists nil)) ;; Inside an angle bracket arglist. ((or (eq type 'c-<>-arg-sep) (eq (char-before match-pos) ?<)) @@ -1301,123 +1320,131 @@ casts and declarations are fontified. Used on level 2 and higher." (c-forward-syntactic-ws)) ;; Now analyze the construct. - (setq decl-or-cast (c-forward-decl-or-cast-1 - match-pos context last-cast-end)) - - ;; Ensure that c-<>-arg-sep c-type properties are in place on the - ;; commas separating the arguments inside template/generic <..>s. - (when (and (eq (char-before match-pos) ?<) - (> match-pos max-<>-end)) - (save-excursion - (goto-char match-pos) - (c-backward-token-2) - (if (and - (eq (char-after) ?<) - (let ((c-restricted-<>-arglists - (save-excursion - (c-backward-token-2) - (and - (not (looking-at c-opt-<>-sexp-key)) - (progn (c-backward-syntactic-ws) - (memq (char-before) '(?\( ?,))) - (not (eq (c-get-char-property (1- (point)) - 'c-type) - 'c-decl-arg-start)))))) - (c-forward-<>-arglist nil))) - (setq max-<>-end (point))))) - - (cond - ((eq decl-or-cast 'cast) - ;; Save the position after the previous cast so we can feed - ;; it to `c-forward-decl-or-cast-1' in the next round. That - ;; helps it discover cast chains like "(a) (b) c". - (setq last-cast-end (point)) - (c-fontify-recorded-types-and-refs) - nil) + (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) + (setq decl-or-cast + (c-forward-decl-or-cast-1 + match-pos context last-cast-end)) + + ;; Ensure that c-<>-arg-sep c-type properties are in place on the + ;; commas separating the arguments inside template/generic <..>s. + (when (and (eq (char-before match-pos) ?<) + (> match-pos max-<>-end)) + (save-excursion + (goto-char match-pos) + (c-backward-token-2) + (if (and + (eq (char-after) ?<) + (let ((c-restricted-<>-arglists + (save-excursion + (c-backward-token-2) + (and + (not (looking-at c-opt-<>-sexp-key)) + (progn (c-backward-syntactic-ws) + (memq (char-before) '(?\( ?,))) + (not (eq (c-get-char-property (1- (point)) + 'c-type) + 'c-decl-arg-start)))))) + (c-forward-<>-arglist nil))) + (setq max-<>-end (point))))) + + (cond + ((eq decl-or-cast 'cast) + ;; Save the position after the previous cast so we can feed + ;; it to `c-forward-decl-or-cast-1' in the next round. That + ;; helps it discover cast chains like "(a) (b) c". + (setq last-cast-end (point)) + (c-fontify-recorded-types-and-refs) + nil) + + (decl-or-cast + ;; We've found a declaration. + + ;; Set `max-type-decl-end' or `max-type-decl-end-before-token' + ;; under the assumption that we're after the first type decl + ;; expression in the declaration now. That's not really true; + ;; we could also be after a parenthesized initializer + ;; expression in C++, but this is only used as a last resort + ;; to slant ambiguous expression/declarations, and overall + ;; it's worth the risk to occasionally fontify an expression + ;; as a declaration in an initializer expression compared to + ;; getting ambiguous things in normal function prototypes + ;; fontified as expressions. + (if inside-macro + (when (> (point) max-type-decl-end-before-token) + (setq max-type-decl-end-before-token (point))) + (when (> (point) max-type-decl-end) + (setq max-type-decl-end (point)))) + + ;; Do we have an expression as the second or third clause of + ;; a "for" paren expression? + (if (save-excursion + (and + (car (cddr decl-or-cast)) ; maybe-expression flag. + (goto-char start-pos) + (c-go-up-list-backward) + (eq (char-after) ?\() + (progn (c-backward-syntactic-ws) + (c-simple-skip-symbol-backward)) + (looking-at c-paren-stmt-key) + (progn (goto-char match-pos) + (while (and (eq (char-before) ?\)) + (c-go-list-backward)) + (c-backward-syntactic-ws)) + (eq (char-before) ?\;)))) + ;; We've got an expression in "for" parens. Remove the + ;; "type" that would spuriously get fontified. + (let ((elt (and (consp c-record-type-identifiers) + (assq (cadr (cddr decl-or-cast)) + c-record-type-identifiers)))) + (when elt + (setq c-record-type-identifiers + (c-delq-from-dotted-list + elt c-record-type-identifiers))) + t) + ;; Back up to the type to fontify the declarator(s). + (goto-char (car decl-or-cast)) + + (let ((decl-list + (if context + ;; Should normally not fontify a list of + ;; declarators inside an arglist, but the first + ;; argument in the ';' separated list of a "for" + ;; statement is an exception. + (when (eq (char-before match-pos) ?\() + (save-excursion + (goto-char (1- match-pos)) + (c-backward-syntactic-ws) + (and (c-simple-skip-symbol-backward) + (looking-at c-paren-stmt-key)))) + t))) + + ;; Fix the `c-decl-id-start' or `c-decl-type-start' property + ;; before the first declarator if it's a list. + ;; `c-font-lock-declarators' handles the rest. + (when decl-list + (save-excursion + (c-backward-syntactic-ws) + (unless (bobp) + (c-put-char-property (1- (point)) 'c-type + (if (cadr decl-or-cast) + 'c-decl-type-start + 'c-decl-id-start))))) + + (c-font-lock-declarators + (min limit (point-max)) decl-list (cadr decl-or-cast))) + + ;; A declaration has been successfully identified, so do all the + ;; fontification of types and refs that've been recorded. + (c-fontify-recorded-types-and-refs) + nil)) - (decl-or-cast - ;; We've found a declaration. - - ;; Set `max-type-decl-end' or `max-type-decl-end-before-token' - ;; under the assumption that we're after the first type decl - ;; expression in the declaration now. That's not really true; - ;; we could also be after a parenthesized initializer - ;; expression in C++, but this is only used as a last resort - ;; to slant ambiguous expression/declarations, and overall - ;; it's worth the risk to occasionally fontify an expression - ;; as a declaration in an initializer expression compared to - ;; getting ambiguous things in normal function prototypes - ;; fontified as expressions. - (if inside-macro - (when (> (point) max-type-decl-end-before-token) - (setq max-type-decl-end-before-token (point))) - (when (> (point) max-type-decl-end) - (setq max-type-decl-end (point)))) - - ;; Do we have an expression as the second or third clause of - ;; a "for" paren expression? - (if (save-excursion - (and - (car (cddr decl-or-cast)) ; maybe-expression flag. - (goto-char start-pos) - (c-go-up-list-backward) - (eq (char-after) ?\() - (progn (c-backward-syntactic-ws) - (c-simple-skip-symbol-backward)) - (looking-at c-paren-stmt-key) - (progn (goto-char match-pos) - (while (and (eq (char-before) ?\)) - (c-go-list-backward)) - (c-backward-syntactic-ws)) - (eq (char-before) ?\;)))) - ;; We've got an expression in "for" parens. Remove the - ;; "type" that would spuriously get fontified. - (let ((elt (and (consp c-record-type-identifiers) - (assq (cadr (cddr decl-or-cast)) - c-record-type-identifiers)))) - (when elt - (setq c-record-type-identifiers - (c-delq-from-dotted-list - elt c-record-type-identifiers))) - t) - ;; Back up to the type to fontify the declarator(s). - (goto-char (car decl-or-cast)) - - (let ((decl-list - (if context - ;; Should normally not fontify a list of - ;; declarators inside an arglist, but the first - ;; argument in the ';' separated list of a "for" - ;; statement is an exception. - (when (eq (char-before match-pos) ?\() - (save-excursion - (goto-char (1- match-pos)) - (c-backward-syntactic-ws) - (and (c-simple-skip-symbol-backward) - (looking-at c-paren-stmt-key)))) - t))) - - ;; Fix the `c-decl-id-start' or `c-decl-type-start' property - ;; before the first declarator if it's a list. - ;; `c-font-lock-declarators' handles the rest. - (when decl-list - (save-excursion - (c-backward-syntactic-ws) - (unless (bobp) - (c-put-char-property (1- (point)) 'c-type - (if (cadr decl-or-cast) - 'c-decl-type-start - 'c-decl-id-start))))) - - (c-font-lock-declarators - (min limit (point-max)) decl-list (cadr decl-or-cast))) - - ;; A declaration has been successfully identified, so do all the - ;; fontification of types and refs that've been recorded. - (c-fontify-recorded-types-and-refs) - nil)) - - (t t))) + (t t)))) ;; It was a false alarm. Check if we're in a label (or other ;; construct with `:' except bitfield) instead. diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 1d9b8d3f0a4..e1ccc7924ab 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -1772,6 +1772,16 @@ the appropriate place for that." "array" "float" "function" "int" "mapping" "mixed" "multiset" "object" "program" "string" "this_program" "void")) +(c-lang-defconst c-return-kwds + "Keywords which return a value to the calling function." + t '("return") + idl nil) + +(c-lang-defconst c-return-key + ;; Adorned regexp matching `c-return-kwds'. + t (c-make-keywords-re t (c-lang-const c-return-kwds))) +(c-lang-defvar c-return-key (c-lang-const c-return-key)) + (c-lang-defconst c-primitive-type-key ;; An adorned regexp that matches `c-primitive-type-kwds'. t (c-make-keywords-re t (c-lang-const c-primitive-type-kwds))) @@ -3150,6 +3160,13 @@ list." c t) (c-lang-defvar c-recognize-knr-p (c-lang-const c-recognize-knr-p)) +(c-lang-defconst c-pre-id-bracelist-key + "A regexp matching tokens which, preceding an identifier, signify a bracelist. +" + t "\\<\\>" + c++ "new\\([^[:alnum:]_$]\\|$\\)\\|&&?\\(\\S.\\|$\\)") +(c-lang-defvar c-pre-id-bracelist-key (c-lang-const c-pre-id-bracelist-key)) + (c-lang-defconst c-recognize-typeless-decls "Non-nil means function declarations without return type should be recognized. That can introduce an ambiguity with parenthesized macro diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 694a510677a..5b324d6d24c 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -1351,10 +1351,10 @@ Note that the style variables are always made local to the buffer." (defun c-fl-decl-start (pos) ;; If the beginning of the line containing POS is in the middle of a "local" - ;; declaration (i.e. one which does not start outside of braces enclosing - ;; POS, such as a struct), return the beginning of that declaration. - ;; Otherwise return nil. Note that declarations, in this sense, can be - ;; nested. + ;; declaration, return the beginning of that declaration. Otherwise return + ;; nil. Note that declarations, in this sense, can be nested. (A local + ;; declaration is one which does not start outside of struct braces (and + ;; similar) enclosing POS. Brace list braces here are not "similar". ;; ;; This function is called indirectly from font locking stuff - either from ;; c-after-change (to prepare for after-change font-locking) or from font @@ -1402,7 +1402,12 @@ Note that the style variables are always made local to the buffer." (and (eq (char-before) ?\<) (eq (c-get-char-property (1- (point)) 'syntax-table) - c-<-as-paren-syntax))))) + c-<-as-paren-syntax)) + (and (eq (char-before) ?{) + (save-excursion + (backward-char) + (numberp (c-looking-at-or-maybe-in-bracelist nil)))) + ))) (not (bobp))) (backward-char)) ; back over (, [, <. (when (and capture-opener (< capture-opener new-pos)) -- 2.39.2