]> git.eshelyaron.com Git - emacs.git/commitdiff
Correctly fontify C++ direct initializations with parens inside functions
authorAlan Mackenzie <acm@muc.de>
Sun, 11 Sep 2016 21:09:08 +0000 (21:09 +0000)
committerAlan Mackenzie <acm@muc.de>
Sun, 11 Sep 2016 21:09:08 +0000 (21:09 +0000)
Or, more clearly, when something looks like a function declaration and it's
inside a function, fontify it as a direct initialization.

For this purpose, introduce a "brace stack" for each buffer, where an entry on
the brace stack states how deeply nested a particular position is inside
braces inside a "top level", which includes classes and namespaces.

Also introduce a new "context", "top", with which c-font-lock-declarations
signals to c-forward-decl-or-cast-1 that point is at the top level.

* lisp/progmodes/cc-langs.el (c-get-state-before-change-functions): add
c-truncate-bs-cache.
(c-flat-decl-block-kwds, c-brace-stack-thing-key, c-brace-stack-no-semi-key)
(c-type-decl-operator-prefix-key): new language constants/variables.

* lisp/progmodes/cc-engine.el (c-bs-interval, c-bs-cache, c-bs-cache-limit)
(c-bs-prev-pos, c-bs-prev-stack): New mostly local variables for the brace
stack cache.
(c-init-bs-cache, c-truncate-bs-cache, c-truncate-bs-cache, c-brace-stack-at)
(c-bs-at-toplevel-p): New functions which manipulate the brace stack (cache).
(c-find-decl-prefix-search): Keep track of whether we're at top level.
(c-find-decl-spots): New local variable cfd-top-level which records what it
says.  On calling cfd-fun, pass cfd-top-level as an additional argument.
(c-forward-declarator): Add new element DECORATED to the result list.  Set it
to non-nil when a match for c-type-decl-operator-prefix-key is found.
(c-forward-decl-or-cast-1): Handle the newly introduced context "top".
Introduce "CASE 9.5", which recognizes direct initializations.

* lisp/progmodes/cc-fonts.el (c-font-lock-complex-decl-prepare)
(c-font-lock-enum-tail, c-font-lock-cut-off-declarators)
(c-font-lock-enclosing-decls, c-simple-decl-matchers, c-basic-matchers-after):
Add appropriate `not-top' argument to calls to c-font-lock-declarators.
(c-font-lock-declarators): Additional parameter `not-top'.  Use not-top to
participate in the decision whether to fontify an identifier as a function or
a variable.
(c-font-lock-declarations): The internal lambda function takes an additional
argument `toplev' from c-find-decl-spots, which it uses in determining the
"context" of a declaration.  Add appropriate `not-top' argument to calls to
c-font-lock-declarators.
(c-font-lock-objc-methods): Add extra parameter to internal lambda function,
like for c-font-lock-declarators.

* lisp/progmodes/cc-mode.el (c-basic-common-init): Initialize the brace stack
cache.

lisp/progmodes/cc-engine.el
lisp/progmodes/cc-fonts.el
lisp/progmodes/cc-langs.el
lisp/progmodes/cc-mode.el

index 259f8a03b37e94565f7f83c69f94be6658fa5886..a1574b23c5ac288f3c3744eebccfa2db42797de5 100644 (file)
@@ -5128,6 +5128,211 @@ comment at the start of cc-engine.el for more info."
        (c-debug-remove-face ,beg ,end 'c-debug-decl-spot-face)
        (c-debug-remove-face ,beg ,end 'c-debug-decl-sws-face))))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Machinery for determining when we're at top level (this including being
+;; directly inside a class or namespace, etc.)
+;;
+;; We maintain a stack of brace depths in structures like classes and
+;; namespaces.  The car of this structure, when non-nil, indicates that the
+;; associated position is within a template (etc.) structure, and the value is
+;; the position where the (outermost) template ends.  The other elements in
+;; the structure are stacked elements, one each for each enclosing "top level"
+;; structure.
+;;
+;; At the very outermost level, the value of the stack would be (nil 1), the
+;; "1" indicating an enclosure in a notional all-enclosing block.  After
+;; passing a keyword such as "namespace", the value would become (nil 0 1).
+;; At this point, passing a semicolon would cause the 0 to be dropped from the
+;; stack (at any other time, a semicolon is ignored).  Alternatively, on
+;; passing an opening brace, the stack would become (nil 1 1).  Each opening
+;; brace passed causes the cadr to be incremented, and passing closing braces
+;; causes it to be decremented until it reaches 1.  On passing a closing brace
+;; when the cadr of the stack is at 1, this causes it to be removed from the
+;; stack, the corresponding namespace (etc.) structure having been closed.
+;;
+;; There is a special stack value -1 which means the C++ colon operator
+;; introducing a list of inherited classes has just been parsed.  The value
+;; persists on the stack until the next open brace or semicolon.
+;;
+;; When the car of the stack is non-nil, i.e. when we're in a template (etc.)
+;; structure, braces are not counted.  The counting resumes only after passing
+;; the template's closing position, which is recorded in the car of the stack.
+;;
+;; The test for being at top level consists of the cadr being 0 or 1.
+;;
+;; The values of this stack throughout a buffer are cached in a simple linear
+;; cache, every 5000 characters.
+;;
+;; Note to maintainers: This cache mechanism is MUCH faster than recalculating
+;; the stack at every entry to `c-find-decl-spots' using `c-at-toplevel-p' or
+;; the like.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; The approximate interval at which we cache the value of the brace stack.
+(defconst c-bs-interval 5000)
+;; The list of cached values of the brace stack.  Each value in the list is a
+;; cons of the position it is valid for and the value of the stack as
+;; described above.
+(defvar c-bs-cache nil)
+(make-variable-buffer-local 'c-bs-cache)
+;; The position of the buffer at and below which entries in `c-bs-cache' are
+;; valid.
+(defvar c-bs-cache-limit 1)
+(make-variable-buffer-local 'c-bs-cache-limit)
+;; The previous buffer position for which the brace stack value was
+;; determined.
+(defvar c-bs-prev-pos most-positive-fixnum)
+(make-variable-buffer-local 'c-bs-prev-pos)
+;; The value of the brace stack at `c-bs-prev-pos'.
+(defvar c-bs-prev-stack nil)
+(make-variable-buffer-local 'c-bs-prev-stack)
+
+(defun c-init-bs-cache ()
+  ;; Initialize the cache in `c-bs-cache' and related variables.
+  (setq c-bs-cache nil
+       c-bs-cache-limit 1
+       c-bs-prev-pos most-positive-fixnum
+       c-bs-prev-stack nil))
+
+(defun c-truncate-bs-cache (pos &rest _ignore)
+  ;; Truncate the upper bound of the cache `c-bs-cache' to POS, if it is
+  ;; higher than that position.  This is called as either a before- or
+  ;; after-change-function.
+  (setq c-bs-cache-limit
+       (min c-bs-cache-limit pos)))
+
+(defun c-update-brace-stack (stack from to)
+  ;; Give a brace-stack which has the value STACK at position FROM, update it
+  ;; to it's value at position TO, where TO is after (or equal to) FROM.
+  ;; Return a cons of either TO (if it is outside a literal) and this new
+  ;; value, or of the next position after TO outside a literal and the new
+  ;; value.
+  (let (match kwd-sym (prev-match-pos 1)
+             (s (cdr stack))
+             (bound-<> (car stack))
+             )
+    (save-excursion
+      (cond
+       ((and bound-<> (<= to bound-<>))
+       (goto-char to))                 ; Nothing to do.
+       (bound-<>
+       (goto-char bound-<>)
+       (setq bound-<> nil))
+       (t (goto-char from)))
+      (while (and (< (point) to)
+                 (c-syntactic-re-search-forward
+                  (if (<= (car s) 0)
+                      c-brace-stack-thing-key
+                    c-brace-stack-no-semi-key)
+                  to 'after-literal)
+                 (> (point) prev-match-pos)) ; prevent infinite loop.
+       (setq prev-match-pos (point))
+       (setq match (match-string-no-properties 1)
+             kwd-sym (c-keyword-sym match))
+       (cond
+        ((and (equal match "{")
+              (progn (backward-char)
+                     (prog1 (looking-at "\\s(")
+                       (forward-char))))
+         (setq s (if s
+                     (cons (if (<= (car s) 0)
+                               1
+                             (1+ (car s)))
+                           (cdr s))
+                   (list 1))))
+        ((and (equal match "}")
+              (progn (backward-char)
+                     (prog1 (looking-at "\\s)")
+                       (forward-char))))
+         (setq s
+               (cond
+                ((and s (> (car s) 1))
+                 (cons (1- (car s)) (cdr s)))
+                ((and (cdr s) (eq (car s) 1))
+                 (cdr s))
+                (t s))))
+        ((and (equal match "<")
+              (progn (backward-char)
+                     (prog1 (looking-at "\\s(")
+                       (forward-char))))
+         (backward-char)
+         (if (c-forward-<>-arglist nil) ; Should always work.
+             (when (> (point) to)
+               (setq bound-<> (point)))
+           (forward-char)))
+        ((and (equal match ":")
+              s
+              (eq (car s) 0))
+         (setq s (cons -1 (cdr s))))
+        ((and (equal match ",")
+              (eq (car s) -1)))        ; at "," in "class foo : bar, ..."
+        ((member match '(";" "," ")"))
+         (when (and s (cdr s) (<= (car s) 0))
+           (setq s (cdr s))))
+        ((c-keyword-member kwd-sym 'c-flat-decl-block-kwds)
+         (push 0 s))))
+      (cons (point)
+           (cons bound-<> s)))))
+
+(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)
+           (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.
+       (while (and c
+                   (> (caar c) c-bs-cache-limit))
+         (setq c (cdr c)))
+       (setq c-bs-cache c)
+
+       (while (and c
+                   (> (caar c) here))
+         (setq high-elt (car c))
+         (setq c (cdr c)))
+       (setq pos (or (and c (caar c))
+                     (point-min)))
+
+       (setq elt (if c
+                     (car c)
+                   (cons (point-min)
+                         (cons nil (list 1)))))
+       (when (not high-elt)
+         (setq stack (cdr elt))
+         (while
+             ;; Add an element to `c-state-semi-nonlit-pos-cache' each iteration.
+             (<= (setq npos (+ pos c-bs-interval)) here)
+           (setq elt (c-update-brace-stack stack pos npos))
+           (setq npos (car elt))
+           (setq stack (cdr elt))
+           (unless (eq npos (point-max)) ; NPOS could be in a literal at EOB.
+             (setq c-bs-cache (cons elt c-bs-cache)))
+           (setq pos npos)))
+
+       (if (> pos c-bs-cache-limit)
+           (setq c-bs-cache-limit pos))
+
+       ;; Can we just use the previous value?
+       (if (and can-use-prev
+                (<= c-bs-prev-pos here)
+                (> c-bs-prev-pos (car elt)))
+           (setq pos c-bs-prev-pos
+                 stack c-bs-prev-stack)
+         (setq pos (car elt)
+               stack (cdr elt)))
+       (if (> here c-bs-cache-limit)
+           (setq c-bs-cache-limit here))
+       (setq elt (c-update-brace-stack stack pos here)
+             c-bs-prev-pos (car elt)
+             c-bs-prev-stack (cdr elt))))))
+
+(defun c-bs-at-toplevel-p (here)
+  ;; Is position HERE at the top level, as indicated by the brace stack?
+  (let ((stack (c-brace-stack-at here)))
+    (or (null stack)                   ; Probably unnecessary.
+       (<= (cadr stack) 1))))
+
 (defmacro c-find-decl-prefix-search ()
   ;; Macro used inside `c-find-decl-spots'.  It ought to be a defun,
   ;; but it contains lots of free variables that refer to things
@@ -5221,6 +5426,7 @@ comment at the start of cc-engine.el for more info."
               cfd-re-match nil)
        (setq cfd-match-pos cfd-prop-match
             cfd-prop-match nil))
+     (setq cfd-top-level (c-bs-at-toplevel-p cfd-match-pos))
 
      (goto-char cfd-match-pos)
 
@@ -5319,7 +5525,11 @@ comment at the start of cc-engine.el for more info."
        ;; comments.
        (cfd-token-pos 0)
        ;; The end position of the last entered macro.
-       (cfd-macro-end 0))
+       (cfd-macro-end 0)
+       ;; Whether the last position returned from `c-find-decl-prefix-search'
+       ;; is at the top-level (including directly in a class or namespace,
+       ;; etc.).
+       cfd-top-level)
 
     ;; Initialize by finding a syntactically relevant start position
     ;; before the point, and do the first `c-decl-prefix-or-start-re'
@@ -5627,7 +5837,7 @@ comment at the start of cc-engine.el for more info."
                   nil))))              ; end of when condition
 
        (c-debug-put-decl-spot-faces cfd-match-pos (point))
-       (if (funcall cfd-fun cfd-match-pos (/= cfd-macro-end 0))
+       (if (funcall cfd-fun cfd-match-pos (/= cfd-macro-end 0) cfd-top-level)
            (setq cfd-prop-match nil))
 
        (when (/= cfd-macro-end 0)
@@ -7552,10 +7762,12 @@ comment at the start of cc-engine.el for more info."
   ;; Assuming point is at the start of a declarator, move forward over it,
   ;; leaving point at the next token after it (e.g. a ) or a ; or a ,).
   ;;
-  ;; Return a list (ID-START ID-END BRACKETS-AFTER-ID GOT-INIT), where ID-START and
-  ;; ID-END are the bounds of the declarator's identifier, and
-  ;; BRACKETS-AFTER-ID is non-nil if a [...] pair is present after the id.
-  ;; GOT-INIT is non-nil when the declarator is followed by "=" or "(".
+  ;; Return a list (ID-START ID-END BRACKETS-AFTER-ID GOT-INIT DECORATED),
+  ;; where ID-START and ID-END are the bounds of the declarator's identifier,
+  ;; and BRACKETS-AFTER-ID is non-nil if a [...] pair is present after the id.
+  ;; GOT-INIT is non-nil when the declarator is followed by "=" or "(",
+  ;; DECORATED is non-nil when the identifier is embellished by an operator,
+  ;; like "*x", or "(*x)".
   ;;
   ;; If ACCEPT-ANON is non-nil, move forward over any "anonymous declarator",
   ;; i.e. something like the (*) in int (*), such as might be found in a
@@ -7574,7 +7786,7 @@ comment at the start of cc-engine.el for more info."
   ;; array/struct initialization) or "=" or terminating delimiter
   ;; (e.g. "," or ";" or "}").
   (let ((here (point))
-       id-start id-end brackets-after-id paren-depth)
+       id-start id-end brackets-after-id paren-depth decorated)
     (or limit (setq limit (point-max)))
     (if        (and
         (< (point) limit)
@@ -7614,6 +7826,8 @@ comment at the start of cc-engine.el for more info."
                                 (setq got-identifier t)
                                 nil))
                           t))
+                   (if (looking-at c-type-decl-operator-prefix-key)
+                       (setq decorated t))
                    (if (eq (char-after) ?\()
                        (progn
                          (setq paren-depth (1+ paren-depth))
@@ -7668,7 +7882,7 @@ comment at the start of cc-engine.el for more info."
             (setq brackets-after-id t))
           (backward-char)
           found))
-       (list id-start id-end brackets-after-id (match-beginning 1))
+       (list id-start id-end brackets-after-id (match-beginning 1) decorated)
 
       (goto-char here)
       nil)))
@@ -7744,6 +7958,9 @@ comment at the start of cc-engine.el for more info."
   ;;           inside a function declaration arglist).
   ;; '<>       In an angle bracket arglist.
   ;; 'arglist  Some other type of arglist.
+  ;; 'top      Some other context and point is at the top-level (either
+  ;;           outside any braces or directly inside a class or namespace,
+  ;;           etc.)
   ;; 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
@@ -8152,7 +8369,7 @@ comment at the start of cc-engine.el for more info."
                              maybe-typeless
                              backup-maybe-typeless
                              (when c-recognize-typeless-decls
-                               (and (not context)
+                               (and (memq context '(nil top))
                                     ;; Deal with C++11's "copy-initialization"
                                     ;; where we have <type>(<constant>), by
                                     ;; contrasting with a typeless
@@ -8215,7 +8432,7 @@ comment at the start of cc-engine.el for more info."
 
         (setq at-decl-end
               (looking-at (cond ((eq context '<>) "[,>]")
-                                (context "[,)]")
+                                ((not (memq context '(nil top))) "[,\)]")
                                 (t "[,;]"))))
 
         ;; Now we've collected info about various characteristics of
@@ -8344,7 +8561,7 @@ comment at the start of cc-engine.el for more info."
 
           (if (and got-parens
                    (not got-prefix)
-                   (not context)
+                   (memq context '(nil top))
                    (not (eq at-type t))
                    (or backup-at-type
                        maybe-typeless
@@ -8394,6 +8611,18 @@ comment at the start of cc-engine.el for more info."
               ;; instantiation expression).
               (throw 'at-decl-or-cast nil))))
 
+        ;; CASE 9.5
+        (when (and (not context)       ; i.e. not at top level.
+                   (c-major-mode-is 'c++-mode)
+                   (eq at-decl-or-cast 'ids)
+                   after-paren-pos)
+          ;; We've got something like "foo bar (...)" in C++ which isn't at
+          ;; the top level.  This is probably a uniform initialization of bar
+          ;; to the contents of the parens.  In this case the declarator ends
+          ;; at the open paren.
+          (goto-char (1- after-paren-pos))
+          (throw 'at-decl-or-cast t))
+
         ;; CASE 10
         (when at-decl-or-cast
           ;; By now we've located the type in the declaration that we know
@@ -8402,7 +8631,7 @@ comment at the start of cc-engine.el for more info."
 
         ;; CASE 11
         (when (and got-identifier
-                   (not context)
+                   (memq context '(nil top))
                    (looking-at c-after-suffixed-type-decl-key)
                    (if (and got-parens
                             (not got-prefix)
@@ -8498,7 +8727,7 @@ comment at the start of cc-engine.el for more info."
               (when (and got-prefix-before-parens
                          at-type
                          (or at-decl-end (looking-at "=[^=]"))
-                         (not context)
+                         (memq context '(nil top))
                          (or (not got-suffix)
                              at-decl-start))
                 ;; Got something like "foo * bar;".  Since we're not inside
@@ -8524,7 +8753,7 @@ comment at the start of cc-engine.el for more info."
                 (throw 'at-decl-or-cast t)))
 
           ;; CASE 18
-          (when (and context
+          (when (and (not (memq context '(nil top)))
                      (or got-prefix
                          (and (eq context 'decl)
                               (not c-recognize-paren-inits)
index 735108ff7dc94aa11b614169eb680b4468dadf54..26a002ac8a14cec0e820c70b292675720480c0df 100644 (file)
@@ -899,7 +899,8 @@ casts and declarations are fontified.  Used on level 2 and higher."
                  (c-get-char-property (1- (point)) 'c-type)))))
     (when (memq prop '(c-decl-id-start c-decl-type-start))
       (c-forward-syntactic-ws limit)
-      (c-font-lock-declarators limit t (eq prop 'c-decl-type-start))))
+      (c-font-lock-declarators limit t (eq prop 'c-decl-type-start)
+                              (c-bs-at-toplevel-p (point)))))
 
   (setq c-font-lock-context ;; (c-guess-font-lock-context)
        (save-excursion
@@ -991,7 +992,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
          (goto-char pos)))))
   nil)
 
-(defun c-font-lock-declarators (limit list types)
+(defun c-font-lock-declarators (limit list types not-top)
   ;; Assuming the point is at the start of a declarator in a declaration,
   ;; fontify the identifier it declares.  (If TYPES is set, it does this via
   ;; the macro `c-fontify-types-and-refs'.)
@@ -1001,7 +1002,9 @@ casts and declarations are fontified.  Used on level 2 and higher."
   ;; additionally, mark the commas with c-type property 'c-decl-id-start or
   ;; 'c-decl-type-start (according to TYPES).  Stop at LIMIT.
   ;;
-  ;; If TYPES is non-nil, fontify all identifiers as types.
+  ;; If TYPES is non-nil, fontify all identifiers as types.  If NOT-TOP is
+  ;; non-nil, we are not at the top-level ("top-level" includes being directly
+  ;; inside a class or namespace, etc.).
   ;;
   ;; Nil is always returned.  The function leaves point at the delimiter after
   ;; the last declarator it processes.
@@ -1025,6 +1028,14 @@ casts and declarations are fontified.  Used on level 2 and higher."
       (setq next-pos (point)
            id-start (car decl-res)
            id-face (if (and (eq (char-after) ?\()
+                            (or (not (c-major-mode-is 'c++-mode))
+                                (not not-top)
+                                (car (cddr (cddr decl-res))) ; Id is in
+                                                             ; parens, etc.
+                                (save-excursion
+                                  (forward-char)
+                                  (c-forward-syntactic-ws)
+                                  (looking-at "[*&]")))
                             (not (car (cddr decl-res))) ; brackets-after-id
                             (or (not (c-major-mode-is 'c++-mode))
                                 (save-excursion
@@ -1199,7 +1210,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
        c-decl-start-re
        (eval c-maybe-decl-faces)
 
-       (lambda (match-pos inside-macro)
+       (lambda (match-pos inside-macro &optional toplev)
         ;; Note to maintainers: don't use `limit' inside this lambda form;
         ;; c-find-decl-spots sometimes narrows to less than `limit'.
         (setq start-pos (point))
@@ -1223,7 +1234,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
            (let ((type (and (> match-pos (point-min))
                             (c-get-char-property (1- match-pos) 'c-type))))
              (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?< ?{)))
-                    (setq context nil
+                    (setq context (and toplev 'top)
                           c-restricted-<>-arglists nil))
                    ;; A control flow expression or a decltype
                    ((and (eq (char-before match-pos) ?\()
@@ -1273,7 +1284,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
                                          'c-not-decl))
                    ;; We're inside an "ordinary" open brace.
                    ((eq (char-before match-pos) ?{)
-                    (setq context nil
+                    (setq context (and toplev 'top)
                           c-restricted-<>-arglists nil))
                    ;; Inside an angle bracket arglist.
                    ((or (eq type 'c-<>-arg-sep)
@@ -1411,7 +1422,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
                  (goto-char (car decl-or-cast))
 
                  (let ((decl-list
-                        (if context
+                        (if (not (memq context '(nil top)))
                             ;; Should normally not fontify a list of
                             ;; declarators inside an arglist, but the first
                             ;; argument in the ';' separated list of a "for"
@@ -1437,7 +1448,8 @@ casts and declarations are fontified.  Used on level 2 and higher."
                                                 'c-decl-id-start)))))
 
                    (c-font-lock-declarators
-                    (min limit (point-max)) decl-list (cadr decl-or-cast)))
+                    (min limit (point-max)) decl-list
+                    (cadr decl-or-cast) (not toplev)))
 
                  ;; A declaration has been successfully identified, so do all the
                  ;; fontification of types and refs that've been recorded.
@@ -1498,7 +1510,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
       (c-put-char-property (1- (point)) 'c-type 'c-decl-id-start)
 
       (c-forward-syntactic-ws)
-      (c-font-lock-declarators limit t nil)))
+      (c-font-lock-declarators limit t nil t)))
   nil)
 
 (defun c-font-lock-cut-off-declarators (limit)
@@ -1512,6 +1524,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
   ;; fontification".
   (let ((decl-search-lim (c-determine-limit 1000))
        paren-state bod-res is-typedef encl-pos
+       (here (point))
        c-recognize-knr-p)              ; Strictly speaking, bogus, but it
                                        ; speeds up lisp.h tremendously.
     (save-excursion
@@ -1539,7 +1552,8 @@ casts and declarations are fontified.  Used on level 2 and higher."
                  (c-forward-syntactic-ws))
                ;; At a real declaration?
                (if (memq (c-forward-type t) '(t known found decltype))
-                   (c-font-lock-declarators limit t is-typedef)))))))
+                   (c-font-lock-declarators
+                    limit t is-typedef (not (c-bs-at-toplevel-p here)))))))))
     nil))
 
 (defun c-font-lock-enclosing-decls (limit)
@@ -1573,7 +1587,8 @@ casts and declarations are fontified.  Used on level 2 and higher."
            (goto-char ps-elt)
            (when (c-safe (c-forward-sexp))
              (c-forward-syntactic-ws)
-             (c-font-lock-declarators limit t in-typedef))))))))
+             (c-font-lock-declarators limit t in-typedef
+                                      (not (c-bs-at-toplevel-p (point)))))))))))
 
 (defun c-font-lock-raw-strings (limit)
   ;; Fontify C++ raw strings.
@@ -1741,7 +1756,7 @@ on level 2 only and so aren't combined with `c-complex-decl-matchers'."
       (eval . (list ,(c-make-font-lock-search-function
                      'c-known-type-key
                      '(1 'font-lock-type-face t)
-                     '((c-font-lock-declarators limit t nil)
+                     '((c-font-lock-declarators limit t nil nil)
                        (save-match-data
                          (goto-char (match-end 1))
                          (c-forward-syntactic-ws))
@@ -1763,7 +1778,7 @@ on level 2 only and so aren't combined with `c-complex-decl-matchers'."
                                 "\\)"))
                 `(,type-match
                   'font-lock-type-face t)
-                `((c-font-lock-declarators limit t nil)
+                `((c-font-lock-declarators limit t nil nil)
                   (save-match-data
                     (goto-char (match-end ,type-match))
                     (c-forward-syntactic-ws))
@@ -1775,7 +1790,7 @@ on level 2 only and so aren't combined with `c-complex-decl-matchers'."
               (concat "\\<\\("
                       (regexp-opt (c-lang-const c-typeless-decl-kwds))
                       "\\)\\>")
-              '((c-font-lock-declarators limit t nil)
+              '((c-font-lock-declarators limit t nil nil)
                 (save-match-data
                   (goto-char (match-end 1))
                   (c-forward-syntactic-ws))
@@ -2014,7 +2029,7 @@ higher."
                ;; before the '{' of the enum list, to avoid searching too far.
                "[^][{};/#=]*"
                "{")
-              '((c-font-lock-declarators limit t nil)
+              '((c-font-lock-declarators limit t nil t)
                 (save-match-data
                   (goto-char (match-end 0))
                   (c-put-char-property (1- (point)) 'c-type
@@ -2413,7 +2428,7 @@ need for `c++-font-lock-extra-types'.")
      limit
      "[-+]"
      nil
-     (lambda (match-pos inside-macro)
+     (lambda (match-pos inside-macro &optional top-level)
        (forward-char)
        (c-font-lock-objc-method))))
   nil)
index ae6e6a3071f4fb927cc257d4831bf144e7923bed..3c328489ec1af1b7073ad887f4ef4fd9425400f5 100644 (file)
@@ -479,10 +479,12 @@ so that all identifiers are recognized as words.")
        c-before-change-check-<>-operators
        c-depropertize-CPP
        c-before-after-change-digit-quote
-       c-invalidate-macro-cache)
+       c-invalidate-macro-cache
+       c-truncate-bs-cache)
   (c objc) '(c-extend-region-for-CPP
             c-depropertize-CPP
-            c-invalidate-macro-cache)
+            c-invalidate-macro-cache
+            c-truncate-bs-cache)
   ;; java 'c-before-change-check-<>-operators
   awk 'c-awk-record-region-clear-NL)
 (c-lang-defvar c-get-state-before-change-functions
@@ -2588,6 +2590,41 @@ Note that Java specific rules are currently applied to tell this from
 (c-lang-defvar c-opt-inexpr-brace-list-key
   (c-lang-const c-opt-inexpr-brace-list-key))
 
+(c-lang-defconst c-flat-decl-block-kwds
+  ;; Keywords that can introduce another declaration level, i.e. where a
+  ;; following "{" isn't a function block or brace list.  Note that, for
+  ;; historical reasons, `c-decl-block-key' is NOT constructed from this lang
+  ;; const.
+  t (c--delete-duplicates
+     (append (c-lang-const c-class-decl-kwds)
+            (c-lang-const c-other-block-decl-kwds)
+            (c-lang-const c-inexpr-class-kwds))
+     :test 'string-equal))
+
+(c-lang-defconst c-brace-stack-thing-key
+  ;; Regexp matching any keyword or operator relevant to the brace stack (see
+  ;; `c-update-brace-stack' in cc-engine.el).
+  t (c-make-keywords-re 'appendable
+      (append
+       (c-lang-const c-flat-decl-block-kwds)
+       (if (c-lang-const c-recognize-<>-arglists)
+          '("{" "}" ";" "," ")" ":" "<")
+        '("{" "}" ";" "," ")" ":")))))
+(c-lang-defvar c-brace-stack-thing-key (c-lang-const c-brace-stack-thing-key))
+
+(c-lang-defconst c-brace-stack-no-semi-key
+  ;; Regexp matching any keyword or operator relevant to the brace stack when
+  ;; a semicolon is not relevant (see `c-update-brace-stack' in
+  ;; cc-engine.el).
+  t (c-make-keywords-re 'appendable
+      (append
+       (c-lang-const c-flat-decl-block-kwds)
+       (if (c-lang-const c-recognize-<>-arglists)
+          '("{" "}" "<")
+        '("{" "}")))))
+(c-lang-defvar c-brace-stack-no-semi-key
+  (c-lang-const c-brace-stack-no-semi-key))
+
 (c-lang-defconst c-decl-block-key
   ;; Regexp matching keywords in any construct that contain another
   ;; declaration level, i.e. that isn't followed by a function block
@@ -3031,6 +3068,28 @@ Identifier syntax is in effect when this is matched \(see
 (c-lang-defvar c-type-decl-prefix-key (c-lang-const c-type-decl-prefix-key)
   'dont-doc)
 
+(c-lang-defconst c-type-decl-operator-prefix-key
+  "Regexp matching any declarator operator which isn't a keyword
+that might precede the identifier in a declaration, e.g. the
+\"*\" in \"char *argv\".  The end of the first submatch is taken
+as the end of the operator.  Identifier syntax is in effect when
+this is matched \(see `c-identifier-syntax-table')."
+  t ;; Default to a regexp that never matches.
+    "\\<\\>"
+  ;; Check that there's no "=" afterwards to avoid matching tokens
+  ;; like "*=".
+  (c objc) (concat "\\(\\*\\)"
+                  "\\([^=]\\|$\\)")
+  c++  (concat "\\("
+              "\\.\\.\\."
+              "\\|"
+              "\\*"
+              "\\)"
+              "\\([^=]\\|$\\)")
+  pike "\\(\\*\\)\\([^=]\\|$\\)")
+(c-lang-defvar c-type-decl-operator-prefix-key
+  (c-lang-const c-type-decl-operator-prefix-key))
+
 (c-lang-defconst c-type-decl-suffix-key
   "Regexp matching the declarator operators that might follow after the
 identifier in a declaration, e.g. the \"[\" in \"char argv[]\".  This
index f2c62563c5f314313b89f545ea89feca72e833d1..5b0679ac5b2ea04c55273c946153033d0ccde80d 100644 (file)
@@ -557,6 +557,8 @@ that requires a literal mode spec at compile time."
 
   ;; Initialize the cache of brace pairs, and opening braces/brackets/parens.
   (c-state-cache-init)
+  ;; Initialize the "brace stack" cache.
+  (c-init-bs-cache)
 
   (when (or c-recognize-<>-arglists
            (c-major-mode-is 'awk-mode)