]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/cc-engine.el
Finish fixing a cacheing bug in CC Mode (see 2016-03-09)
[gnu-emacs] / lisp / progmodes / cc-engine.el
index 82f0d722d036f86e0a05f8810247154da655deb4..aac7e631087ca6cd63e368ffcb124f11b55b9e73 100644 (file)
@@ -1,6 +1,6 @@
 ;;; cc-engine.el --- core syntax guessing engine for CC mode -*- coding: utf-8 -*-
 
-;; Copyright (C) 1985, 1987, 1992-2015 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1987, 1992-2016 Free Software Foundation, Inc.
 
 ;; Authors:    2001- Alan Mackenzie
 ;;             1998- Martin Stjernholm
@@ -1060,7 +1060,7 @@ comment at the start of cc-engine.el for more info."
                          (save-excursion
                            (c-forward-sexp) (point)))
                         ;; Just gone back over some paren block?
-                        ((looking-at "\\s\(")
+                        ((looking-at "\\s(")
                          (save-excursion
                            (goto-char (1+ (c-down-list-backward
                                            before-sws-pos)))
@@ -1233,7 +1233,7 @@ The variable `c-maybe-labelp' is set to the position of the first `:' that
 might start a label (i.e. not part of `::' and not preceded by `?').  If a
 single `?' is found, then `c-maybe-labelp' is cleared.
 
-For AWK, a statement which is terminated by an EOL (not a \; or a }) is
+For AWK, a statement which is terminated by an EOL (not a ; or a }) is
 regarded as having a \"virtual semicolon\" immediately after the last token on
 the line.  If this virtual semicolon is _at_ from, the function recognizes it.
 
@@ -1449,13 +1449,12 @@ This function does not do any hidden buffer changes."
       ;; same line.
       (re-search-forward "\\=\\s *[\n\r]" start t)
 
-      (if (if (let (open-paren-in-column-0-is-defun-start) (forward-comment -1))
+      (if (if (forward-comment -1)
              (if (eolp)
                  ;; If forward-comment above succeeded and we're at eol
                  ;; then the newline we moved over above didn't end a
                  ;; line comment, so we give it another go.
-                 (let (open-paren-in-column-0-is-defun-start)
-                   (forward-comment -1))
+                 (forward-comment -1)
                t))
 
          ;; Emacs <= 20 and XEmacs move back over the closer of a
@@ -1482,7 +1481,7 @@ comment at the start of cc-engine.el for more info."
            ;; return t when moving backwards at bob.
            (not (bobp))
 
-           (if (let (open-paren-in-column-0-is-defun-start moved-comment)
+           (if (let (moved-comment)
                  (while
                      (and (not (setq moved-comment (forward-comment -1)))
                      ;; Cope specifically with ^M^J here -
@@ -2524,6 +2523,20 @@ comment at the start of cc-engine.el for more info."
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Defuns which analyze the buffer, yet don't change `c-state-cache'.
+(defun c-get-fallback-scan-pos (here)
+  ;; Return a start position for building `c-state-cache' from
+  ;; scratch.  This will be at the top level, 2 defuns back.
+  (save-excursion
+    ;; Go back 2 bods, but ignore any bogus positions returned by
+    ;; beginning-of-defun (i.e. open paren in column zero).
+    (goto-char here)
+    (let ((cnt 2))
+      (while (not (or (bobp) (zerop cnt)))
+       (c-beginning-of-defun-1)        ; Pure elisp BOD.
+       (if (eq (char-after) ?\{)
+           (setq cnt (1- cnt)))))
+    (point)))
+
 (defun c-state-balance-parens-backwards (here- here+ top)
   ;; Return the position of the opening paren/brace/bracket before HERE- which
   ;; matches the outermost close p/b/b between HERE+ and TOP.  Except when
@@ -2584,22 +2597,46 @@ comment at the start of cc-engine.el for more info."
   ;; o - ('backward nil) - scan backwards (from HERE).
   ;; o - ('back-and-forward START-POINT) - like 'forward, but when HERE is earlier
   ;;     than GOOD-POS.
+  ;; o - ('BOD START-POINT) - scan forwards from START-POINT, which is at the
+  ;;   top level.
   ;; o - ('IN-LIT nil) - point is inside the literal containing point-min.
   (let ((cache-pos (c-get-cache-scan-pos here))        ; highest position below HERE in cache (or 1)
-       strategy            ; 'forward, 'backward, or 'IN-LIT.
-       start-point)
+       BOD-pos             ; position of 2nd BOD before HERE.
+       strategy            ; 'forward, 'backward, 'BOD, or 'IN-LIT.
+       start-point
+       how-far)                        ; putative scanning distance.
     (setq good-pos (or good-pos (c-state-get-min-scan-pos)))
     (cond
      ((< here (c-state-get-min-scan-pos))
-      (setq strategy 'IN-LIT))
+      (setq strategy 'IN-LIT
+           start-point nil
+           cache-pos nil
+           how-far 0))
      ((<= good-pos here)
       (setq strategy 'forward
-           start-point (max good-pos cache-pos)))
+           start-point (max good-pos cache-pos)
+           how-far (- here start-point)))
      ((< (- good-pos here) (- here cache-pos)) ; FIXME!!! ; apply some sort of weighting.
-      (setq strategy 'backward))
+      (setq strategy 'backward
+           how-far (- good-pos here)))
      (t
       (setq strategy 'back-and-forward
-           start-point cache-pos)))
+           start-point cache-pos
+           how-far (- here start-point))))
+
+    ;; Might we be better off starting from the top level, two defuns back,
+    ;; instead?  This heuristic no longer works well in C++, where
+    ;; declarations inside namespace brace blocks are frequently placed at
+    ;; column zero.  (2015-11-10): Remove the condition on C++ Mode.
+    (when (and (or (not (memq 'col-0-paren c-emacs-features))
+                  open-paren-in-column-0-is-defun-start)
+              ;; (not (c-major-mode-is 'c++-mode))
+              (> how-far c-state-cache-too-far))
+      (setq BOD-pos (c-get-fallback-scan-pos here)) ; somewhat EXPENSIVE!!!
+      (if (< (- here BOD-pos) how-far)
+         (setq strategy 'BOD
+               start-point BOD-pos)))
+
     (list strategy start-point)))
 
 
@@ -3204,7 +3241,7 @@ comment at the start of cc-engine.el for more info."
   ;; pair element into an open paren element.  Doing that would mean that the
   ;; new open paren wouldn't have the required preceding paren pair element.
   ;;
-  ;; This function is called from c-after-change.
+  ;; This function is called from c-before-change.
 
   ;; The caches of non-literals:
   ;; Note that we use "<=" for the possibility of the second char of a two-char
@@ -3227,9 +3264,8 @@ comment at the start of cc-engine.el for more info."
     ;; Truncate `c-state-cache' and set `c-state-cache-good-pos' to a value
     ;; below `here'.  To maintain its consistency, we may need to insert a new
     ;; brace pair.
-    (let (open-paren-in-column-0-is-defun-start
-         (here-bol (c-point 'bol here))
-         too-high-pa             ; recorded {/(/[ next above here, or nil.
+    (let ((here-bol (c-point 'bol here))
+         too-high-pa  ; recorded {/(/[ next above or just below here, or nil.
          dropped-cons            ; was the last removed element a brace pair?
          pa)
       ;; The easy bit - knock over-the-top bits off `c-state-cache'.
@@ -3241,7 +3277,7 @@ comment at the start of cc-engine.el for more info."
 
       ;; Do we need to add in an earlier brace pair, having lopped one off?
       (if (and dropped-cons
-              (< too-high-pa (+ here c-state-cache-too-far)))
+              (<= too-high-pa here))
          (c-append-lower-brace-pair-to-state-cache too-high-pa here here-bol))
       (setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
                                       (c-state-get-min-scan-pos)))))
@@ -3299,7 +3335,6 @@ comment at the start of cc-engine.el for more info."
   ;; This function might do hidden buffer changes.
   (let* ((here (point))
         (here-bopl (c-point 'bopl))
-        open-paren-in-column-0-is-defun-start
         strategy            ; 'forward, 'backward etc..
         ;; Candidate positions to start scanning from:
         cache-pos           ; highest position below HERE already existing in
@@ -3320,9 +3355,13 @@ comment at the start of cc-engine.el for more info."
          strategy (car res)
          start-point (cadr res))
 
+    (when (eq strategy 'BOD)
+      (setq c-state-cache nil
+           c-state-cache-good-pos start-point))
+
     ;; SCAN!
     (cond
-     ((memq strategy '(forward back-and-forward))
+     ((memq strategy '(forward back-and-forward BOD))
       (setq res (c-remove-stale-state-cache start-point here here-bopl))
       (setq cache-pos (car res)
            scan-backward-pos (cadr res)
@@ -3433,6 +3472,9 @@ comment at the start of cc-engine.el for more info."
 (make-variable-buffer-local 'c-parse-state-state)
 (defun c-record-parse-state-state ()
   (setq c-parse-state-point (point))
+  (when (markerp (cdr (assq 'c-state-old-cpp-beg c-parse-state-state)))
+    (move-marker (cdr (assq 'c-state-old-cpp-beg c-parse-state-state)) nil)
+    (move-marker (cdr (assq 'c-state-old-cpp-end c-parse-state-state)) nil))
   (setq c-parse-state-state
        (mapcar
         (lambda (arg)
@@ -3792,8 +3834,8 @@ comment at the start of cc-engine.el for more info."
 
 (defconst c-jump-syntax-balanced
   (if (memq 'gen-string-delim c-emacs-features)
-      "\\w\\|\\s_\\|\\s\(\\|\\s\)\\|\\s\"\\|\\s|"
-    "\\w\\|\\s_\\|\\s\(\\|\\s\)\\|\\s\""))
+      "\\w\\|\\s_\\|\\s(\\|\\s)\\|\\s\"\\|\\s|"
+    "\\w\\|\\s_\\|\\s(\\|\\s)\\|\\s\""))
 
 (defconst c-jump-syntax-unbalanced
   (if (memq 'gen-string-delim c-emacs-features)
@@ -3960,7 +4002,7 @@ See `c-forward-token-2' for details."
 tokens like \"==\" as single tokens, i.e. all sequences of symbol
 characters are jumped over character by character.  This function is
 for compatibility only; it's only a wrapper over `c-forward-token-2'."
-  (let ((c-nonsymbol-token-regexp "\\s.\\|\\s\(\\|\\s\)"))
+  (let ((c-nonsymbol-token-regexp "\\s."))
     (c-forward-token-2 count balanced limit)))
 
 (defun c-backward-token-1 (&optional count balanced limit)
@@ -3968,7 +4010,7 @@ for compatibility only; it's only a wrapper over `c-forward-token-2'."
 tokens like \"==\" as single tokens, i.e. all sequences of symbol
 characters are jumped over character by character.  This function is
 for compatibility only; it's only a wrapper over `c-backward-token-2'."
-  (let ((c-nonsymbol-token-regexp "\\s.\\|\\s\(\\|\\s\)"))
+  (let ((c-nonsymbol-token-regexp "\\s."))
     (c-backward-token-2 count balanced limit)))
 
 \f
@@ -4220,8 +4262,7 @@ comment at the start of cc-engine.el for more info."
        (setq safe-pos-list (cdr safe-pos-list)))
       (unless (setq safe-pos (car-safe safe-pos-list))
        (setq safe-pos (max (or (c-safe-position
-                                (point) (or c-state-cache
-                                            (c-parse-state)))
+                                (point) (c-parse-state))
                                0)
                            (point-min))
              safe-pos-list (list safe-pos)))
@@ -4269,107 +4310,108 @@ Non-nil is returned if the point moved, nil otherwise.
 Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
 
-  (let ((start (point))
-       state-2
-       ;; A list of syntactically relevant positions in descending
-       ;; order.  It's used to avoid scanning repeatedly over
-       ;; potentially large regions with `parse-partial-sexp' to verify
-       ;; each position.  Used in `c-ssb-lit-begin'
-       safe-pos-list
-       ;; The result from `c-beginning-of-macro' at the start position or the
-       ;; start position itself if it isn't within a macro.  Evaluated on
-       ;; demand.
-       start-macro-beg
-       ;; The earliest position after the current one with the same paren
-       ;; level.  Used only when `paren-level' is set.
-       lit-beg
-       (paren-level-pos (point)))
-
-    (while
-       (progn
-         ;; The next loop "tries" to find the end point each time round,
-         ;; loops when it hasn't succeeded.
-         (while
-             (and
-              (let ((pos (point)))
-                (while (and
-                        (< (skip-chars-backward skip-chars limit) 0)
-                        ;; Don't stop inside a literal.
-                        (when (setq lit-beg (c-ssb-lit-begin))
-                          (goto-char lit-beg)
-                          t)))
-                (< (point) pos))
-
-              (let ((pos (point)) state-2 pps-end-pos)
+  (c-self-bind-state-cache
+   (let ((start (point))
+        state-2
+        ;; A list of syntactically relevant positions in descending
+        ;; order.  It's used to avoid scanning repeatedly over
+        ;; potentially large regions with `parse-partial-sexp' to verify
+        ;; each position.  Used in `c-ssb-lit-begin'
+        safe-pos-list
+        ;; The result from `c-beginning-of-macro' at the start position or the
+        ;; start position itself if it isn't within a macro.  Evaluated on
+        ;; demand.
+        start-macro-beg
+        ;; The earliest position after the current one with the same paren
+        ;; level.  Used only when `paren-level' is set.
+        lit-beg
+        (paren-level-pos (point)))
+
+     (while
+        (progn
+          ;; The next loop "tries" to find the end point each time round,
+          ;; loops when it hasn't succeeded.
+          (while
+              (and
+               (let ((pos (point)))
+                 (while (and
+                         (< (skip-chars-backward skip-chars limit) 0)
+                         ;; Don't stop inside a literal.
+                         (when (setq lit-beg (c-ssb-lit-begin))
+                           (goto-char lit-beg)
+                           t)))
+                 (< (point) pos))
+
+               (let ((pos (point)) state-2 pps-end-pos)
 
-                (cond
-                 ((and paren-level
-                       (save-excursion
-                         (setq state-2 (parse-partial-sexp
-                                        pos paren-level-pos -1)
-                               pps-end-pos (point))
-                         (/= (car state-2) 0)))
-                  ;; Not at the right level.
-
-                  (if (and (< (car state-2) 0)
-                           ;; We stop above if we go out of a paren.
-                           ;; Now check whether it precedes or is
-                           ;; nested in the starting sexp.
-                           (save-excursion
-                             (setq state-2
-                                   (parse-partial-sexp
-                                    pps-end-pos paren-level-pos
-                                    nil nil state-2))
-                             (< (car state-2) 0)))
-
-                      ;; We've stopped short of the starting position
-                      ;; so the hit was inside a nested list.  Go up
-                      ;; until we are at the right level.
-                      (condition-case nil
-                          (progn
-                            (goto-char (scan-lists pos -1
-                                                   (- (car state-2))))
-                            (setq paren-level-pos (point))
-                            (if (and limit (>= limit paren-level-pos))
-                                (progn
-                                  (goto-char limit)
-                                  nil)
-                              t))
-                        (error
-                         (goto-char (or limit (point-min)))
-                         nil))
-
-                    ;; The hit was outside the list at the start
-                    ;; position.  Go to the start of the list and exit.
-                    (goto-char (1+ (elt state-2 1)))
-                    nil))
-
-                 ((c-beginning-of-macro limit)
-                  ;; Inside a macro.
-                  (if (< (point)
-                         (or start-macro-beg
-                             (setq start-macro-beg
-                                   (save-excursion
-                                     (goto-char start)
-                                     (c-beginning-of-macro limit)
-                                     (point)))))
-                      t
-
-                    ;; It's inside the same macro we started in so it's
-                    ;; a relevant match.
-                    (goto-char pos)
-                    nil))))))
-
-         (> (point)
-            (progn
-              ;; Skip syntactic ws afterwards so that we don't stop at the
-              ;; end of a comment if `skip-chars' is something like "^/".
-              (c-backward-syntactic-ws)
-              (point)))))
+                 (cond
+                  ((and paren-level
+                        (save-excursion
+                          (setq state-2 (parse-partial-sexp
+                                         pos paren-level-pos -1)
+                                pps-end-pos (point))
+                          (/= (car state-2) 0)))
+                   ;; Not at the right level.
+
+                   (if (and (< (car state-2) 0)
+                            ;; We stop above if we go out of a paren.
+                            ;; Now check whether it precedes or is
+                            ;; nested in the starting sexp.
+                            (save-excursion
+                              (setq state-2
+                                    (parse-partial-sexp
+                                     pps-end-pos paren-level-pos
+                                     nil nil state-2))
+                              (< (car state-2) 0)))
+
+                       ;; We've stopped short of the starting position
+                       ;; so the hit was inside a nested list.  Go up
+                       ;; until we are at the right level.
+                       (condition-case nil
+                           (progn
+                             (goto-char (scan-lists pos -1
+                                                    (- (car state-2))))
+                             (setq paren-level-pos (point))
+                             (if (and limit (>= limit paren-level-pos))
+                                 (progn
+                                   (goto-char limit)
+                                   nil)
+                               t))
+                         (error
+                          (goto-char (or limit (point-min)))
+                          nil))
+
+                     ;; The hit was outside the list at the start
+                     ;; position.  Go to the start of the list and exit.
+                     (goto-char (1+ (elt state-2 1)))
+                     nil))
+
+                  ((c-beginning-of-macro limit)
+                   ;; Inside a macro.
+                   (if (< (point)
+                          (or start-macro-beg
+                              (setq start-macro-beg
+                                    (save-excursion
+                                      (goto-char start)
+                                      (c-beginning-of-macro limit)
+                                      (point)))))
+                       t
+
+                     ;; It's inside the same macro we started in so it's
+                     ;; a relevant match.
+                     (goto-char pos)
+                     nil))))))
+
+          (> (point)
+             (progn
+               ;; Skip syntactic ws afterwards so that we don't stop at the
+               ;; end of a comment if `skip-chars' is something like "^/".
+               (c-backward-syntactic-ws)
+               (point)))))
 
-    ;; We might want to extend this with more useful return values in
-    ;; the future.
-    (/= (point) start)))
+     ;; We might want to extend this with more useful return values in
+     ;; the future.
+     (/= (point) start))))
 
 ;; The following is an alternative implementation of
 ;; `c-syntactic-skip-backward' that uses backward movement to keep
@@ -5538,8 +5580,9 @@ comment at the start of cc-engine.el for more info."
 
 (defun c-before-change-check-<>-operators (beg end)
   ;; Unmark certain pairs of "< .... >" which are currently marked as
-  ;; template/generic delimiters.  (This marking is via syntax-table
-  ;; text properties).
+  ;; 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
@@ -5556,40 +5599,43 @@ comment at the start of cc-engine.el for more info."
   ;; FIXME!!!  This routine ignores the possibility of macros entirely.
   ;; 2010-01-29.
   (save-excursion
-    (let ((beg-lit-limits (progn (goto-char beg) (c-literal-limits)))
-         (end-lit-limits (progn (goto-char end) (c-literal-limits)))
-         new-beg new-end need-new-beg need-new-end)
-      ;; Locate the barrier before the changed region
+    (c-save-buffer-state
+       ((beg-lit-limits (progn (goto-char beg) (c-literal-limits)))
+        (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  (if beg-lit-limits (car beg-lit-limits) beg))
-      (c-syntactic-skip-backward "^;{}" (c-determine-limit 512))
-      (setq new-beg (point))
+      (setq beg-limit (c-determine-limit 512))
 
       ;; Remove the syntax-table/category properties from each pertinent <...>
-      ;; pair.  Firsly, the ones with the < before beg and > after beg.
-      (while
-         (c-search-forward-char-property 'syntax-table c-<-as-paren-syntax beg)
-       (if (c-clear-<-pair-props-if-match-after beg (1- (point)))
-           (setq need-new-beg t)))
+      ;; 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)))
+      (c-forward-syntactic-ws)
+      (setq new-beg (point))
 
-      ;; Locate the barrier after END.
+      ;; ...Then the ones with < before end and > after end.
       (goto-char (if end-lit-limits (cdr end-lit-limits) end))
-      (c-syntactic-re-search-forward "[;{}]" (c-determine-+ve-limit 512) '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)))))
+      (c-backward-syntactic-ws)
       (setq new-end (point))
 
-      ;; Remove syntax-table properties from the remaining pertinent <...>
-      ;; pairs, those with a > after end and < before end.
-      (while (c-search-backward-char-property 'syntax-table c->-as-paren-syntax end)
-       (if (c-clear->-pair-props-if-match-before end)
-           (setq need-new-end t)))
-
       ;; Extend the fontification region, if needed.
-      (when need-new-beg
-       (goto-char new-beg)
-       (c-forward-syntactic-ws)
-       (and (< (point) c-new-BEG) (setq c-new-BEG (point))))
-
-      (when need-new-end
-       (and (> new-end c-new-END) (setq c-new-END new-end))))))
+      (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-after-change-check-<>-operators (beg end)
   ;; This is called from `after-change-functions' when
@@ -5629,7 +5675,28 @@ comment at the start of cc-engine.el for more info."
            (c-clear-<>-pair-props)
            (forward-char)))))))
 
-
+(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)
+    (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)
+         (forward-char)))))
 \f
 ;; Handling of small scale constructs like types and names.
 
@@ -5925,7 +5992,7 @@ comment at the start of cc-engine.el for more info."
   ;; Recursive part of `c-forward-<>-arglist'.
   ;;
   ;; This function might do hidden buffer changes.
-  (let ((start (point)) res pos tmp
+  (let ((start (point)) res pos
        ;; Cover this so that any recorded found type ranges are
        ;; automatically lost if it turns out to not be an angle
        ;; bracket arglist.  It's propagated through the return value
@@ -5977,7 +6044,7 @@ comment at the start of cc-engine.el for more info."
 
                      (when (or (looking-at "extends")
                                (looking-at "super"))
-                       (forward-word)
+                       (forward-word-strictly)
                        (c-forward-syntactic-ws)
                        (let ((c-promote-possible-types t)
                              (c-record-found-types t))
@@ -5992,7 +6059,10 @@ comment at the start of cc-engine.el for more info."
                   ;; Stop on ',', '|', '&', '+' and '-' to catch
                   ;; common binary operators that could be between
                   ;; two comparison expressions "a<b" and "c>d".
-                  "[<;{},|+&-]\\|[>)]"
+                  ;; 2016-02-11: C++11 templates can now contain arithmetic
+                  ;; expressions, so template detection in C++ is now less
+                  ;; robust than it was.
+                  c-<>-notable-chars-re
                   nil t t))
 
                (cond
@@ -6000,7 +6070,9 @@ comment at the start of cc-engine.el for more info."
                  ;; Either an operator starting with '>' or the end of
                  ;; the angle bracket arglist.
 
-                 (if (looking-at c->-op-without->-cont-regexp)
+                 (if (save-excursion
+                       (c-backward-token-2)
+                       (looking-at c-multichar->-op-not->>-regexp))
                      (progn
                        (goto-char (match-end 0))
                        t)              ; Continue the loop.
@@ -6020,15 +6092,13 @@ comment at the start of cc-engine.el for more info."
                  ;; Either an operator starting with '<' or a nested arglist.
                  (setq pos (point))
                  (let (id-start id-end subres keyword-match)
-                  (cond
+                   (cond
                     ;; The '<' begins a multi-char operator.
                     ((looking-at c-<-op-cont-regexp)
-                     (setq tmp (match-end 0))
                      (goto-char (match-end 0)))
                     ;; We're at a nested <.....>
                     ((progn
-                       (setq tmp pos)
-                       (backward-char) ; to the '<'
+                       (backward-char) ; to the '<'
                        (and
                         (save-excursion
                           ;; There's always an identifier before an angle
@@ -6048,7 +6118,9 @@ comment at the start of cc-engine.el for more info."
                                  (and keyword-match
                                       (c-keyword-member
                                        (c-keyword-sym (match-string 1))
-                                       'c-<>-type-kwds)))))))
+                                       'c-<>-type-kwds))))))
+                       (or subres (goto-char pos))
+                       subres)
                      ;; It was an angle bracket arglist.
                      (setq c-record-found-types subres)
 
@@ -6064,11 +6136,16 @@ comment at the start of cc-engine.el for more info."
                            (c-record-ref-id (cons id-start id-end))
                         (c-record-type-id (cons id-start id-end)))))
 
-                   ;; At a "less than" operator.
-                   (t
-                    (forward-char)
-                    )))
-                t)                    ; carry on looping.
+                    ;; At a "less than" operator.
+                    (t
+                     ;; (forward-char) ; NO!  We've already gone over the <.
+                     )))
+                 t)                    ; carry on looping.
+
+                ((and
+                  (eq (char-before) ?\()
+                  (c-go-up-list-forward)
+                  (eq (char-before) ?\))))
 
                 ((and (not c-restricted-<>-arglists)
                       (or (and (eq (char-before) ?&)
@@ -6577,16 +6654,22 @@ comment at the start of cc-engine.el for more info."
     res))
 
 (defun c-forward-annotation ()
-  ;; Used for Java code only at the moment.  Assumes point is on the
-  ;; @, moves forward an annotation.  returns nil if there is no
-  ;; annotation at point.
-  (and (looking-at "@")
-       (progn (forward-char) t)
-       (c-forward-type)
-       (progn (c-forward-syntactic-ws) t)
-       (if (looking-at "(")
-          (c-go-list-forward)
-        t)))
+  ;; Used for Java code only at the moment.  Assumes point is on the @, moves
+  ;; forward an annotation and returns t.  Leaves point unmoved and returns
+  ;; nil if there is no annotation at point.
+  (let ((pos (point)))
+    (or
+     (and (looking-at "@")
+         (not (looking-at c-keywords-regexp))
+         (progn (forward-char) t)
+         (looking-at c-symbol-key)
+         (progn (goto-char (match-end 0))
+                (c-forward-syntactic-ws)
+                t)
+         (if (looking-at "(")
+             (c-go-list-forward)
+           t))
+     (progn (goto-char pos) nil))))
 
 (defmacro c-pull-open-brace (ps)
   ;; Pull the next open brace from PS (which has the form of paren-state),
@@ -6627,49 +6710,71 @@ comment at the start of cc-engine.el for more info."
     (or res (goto-char here))
     res))
 
+(defmacro c-back-over-list-of-member-inits ()
+  ;; Go back over a list of elements, each looking like:
+  ;; <symbol> (<expression>) ,
+  ;; or <symbol> {<expression>} ,
+  ;; when we are putatively immediately after a comma.  Stop when we don't see
+  ;; a comma.  If either of <symbol> or bracketed <expression> is missing,
+  ;; throw nil to 'level.  If the terminating } or ) is unmatched, throw nil
+  ;; to 'done.  This is not a general purpose macro!
+  `(while (eq (char-before) ?,)
+     (backward-char)
+     (c-backward-syntactic-ws)
+     (when (not (memq (char-before) '(?\) ?})))
+       (throw 'level nil))
+     (when (not (c-go-list-backward))
+       (throw 'done nil))
+     (c-backward-syntactic-ws)
+     (when (not (c-simple-skip-symbol-backward))
+       (throw 'level nil))
+     (c-backward-syntactic-ws)))
+
 (defun c-back-over-member-initializers ()
   ;; Test whether we are in a C++ member initializer list, and if so, go back
   ;; to the introducing ":", returning the position of the opening paren of
   ;; the function's arglist.  Otherwise return nil, leaving point unchanged.
   (let ((here (point))
        (paren-state (c-parse-state))
-       res)
-
+       pos level-plausible at-top-level res)
+    ;; Assume tentatively that we're at the top level.  Try to go back to the
+    ;; colon we seek.
     (setq res
          (catch 'done
-           (if (not (c-at-toplevel-p))
-               (progn
-                 (while (not (c-at-toplevel-p))
-                   (goto-char (c-pull-open-brace paren-state)))
-                 (c-backward-syntactic-ws)
-                 (when (not (c-simple-skip-symbol-backward))
-                   (throw 'done nil))
-                 (c-backward-syntactic-ws))
-             (c-backward-syntactic-ws)
-             (when (memq (char-before) '(?\) ?}))
-               (when (not (c-go-list-backward))
-                 (throw 'done nil))
-               (c-backward-syntactic-ws))
-             (when (c-simple-skip-symbol-backward)
-               (c-backward-syntactic-ws)))
-
-           (while (eq (char-before) ?,)
-             (backward-char)
-             (c-backward-syntactic-ws)
-
-             (when (not (memq (char-before) '(?\) ?})))
-               (throw 'done nil))
-             (when (not (c-go-list-backward))
-               (throw 'done nil))
-             (c-backward-syntactic-ws)
-             (when (not (c-simple-skip-symbol-backward))
-               (throw 'done nil))
-             (c-backward-syntactic-ws))
-
-           (and
-            (eq (char-before) ?:)
-            (c-just-after-func-arglist-p))))
+           (setq level-plausible
+                 (catch 'level
+                   (c-backward-syntactic-ws)
+                   (when (memq (char-before) '(?\) ?}))
+                     (when (not (c-go-list-backward))
+                       (throw 'done nil))
+                     (c-backward-syntactic-ws))
+                   (when (c-simple-skip-symbol-backward)
+                     (c-backward-syntactic-ws))
+                   (c-back-over-list-of-member-inits)
+                   (and (eq (char-before) ?:)
+                        (save-excursion
+                          (c-backward-token-2)
+                          (not (looking-at c-:$-multichar-token-regexp)))
+                        (c-just-after-func-arglist-p))))
+
+           (while (and (not (and level-plausible
+                                 (setq at-top-level (c-at-toplevel-p))))
+                       (setq pos (c-pull-open-brace paren-state))) ; might be a paren.
+             (setq level-plausible
+                   (catch 'level
+                     (goto-char pos)
+                     (c-backward-syntactic-ws)
+                     (when (not (c-simple-skip-symbol-backward))
+                       (throw 'level nil))
+                     (c-backward-syntactic-ws)
+                     (c-back-over-list-of-member-inits)
+                     (and (eq (char-before) ?:)
+                          (save-excursion
+                            (c-backward-token-2)
+                            (not (looking-at c-:$-multichar-token-regexp)))
+                          (c-just-after-func-arglist-p)))))
 
+           (and at-top-level level-plausible)))
     (or res (goto-char here))
     res))
 
@@ -6716,6 +6821,119 @@ comment at the start of cc-engine.el for more info."
        ;; This identifier is bound only in the inner let.
        '(setq start id-start))))
 
+(defun c-forward-declarator (&optional limit accept-anon)
+  ;; 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 "(".
+  ;;
+  ;; 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
+  ;; declaration.  In such a case ID-START and ID-END in the return value are
+  ;; both set to nil.  A "null" "anonymous declarator" gives a non-nil result.
+  ;;
+  ;; If no declarator is found, leave point unmoved and return nil.  LIMIT is
+  ;; an optional limit for forward searching.
+  ;;
+  ;; Note that the global variable `c-last-identifier-range' is written to, so
+  ;; the caller should bind it if necessary.
+
+  ;; Inside the following "condition form", we move forward over the
+  ;; declarator's identifier up as far as any opening bracket (for array
+  ;; size) or paren (for parameters of function-type) or brace (for
+  ;; array/struct initialization) or "=" or terminating delimiter
+  ;; (e.g. "," or ";" or "}").
+  (let ((here (point))
+       id-start id-end brackets-after-id paren-depth)
+    (or limit (setq limit (point-max)))
+    (if        (and
+        (< (point) limit)
+
+        ;; The following form moves forward over the declarator's
+        ;; identifier (and what precedes it), returning t.  If there
+        ;; wasn't one, it returns nil.
+        (let (got-identifier)
+          (setq paren-depth 0)
+          ;; Skip over type decl prefix operators, one for each iteration
+          ;; of the while.  These are, e.g. "*" in "int *foo" or "(" and
+          ;; "*" in "int (*foo) (void)" (Note similar code in
+          ;; `c-forward-decl-or-cast-1'.)
+          (while (and (looking-at c-type-decl-prefix-key)
+                      (if (and (c-major-mode-is 'c++-mode)
+                               (match-beginning 3))
+                          ;; If the third submatch matches in C++ then
+                          ;; we're looking at an identifier that's a
+                          ;; prefix only if it specifies a member pointer.
+                          (progn
+                            (setq id-start (point))
+                            (c-forward-name)
+                            (if (looking-at "\\(::\\)")
+                                ;; We only check for a trailing "::" and
+                                ;; let the "*" that should follow be
+                                ;; matched in the next round.
+                                t
+                              ;; It turned out to be the real identifier,
+                              ;; so flag that and stop.
+                              (setq got-identifier t)
+                              nil))
+                        t))
+            (if (eq (char-after) ?\()
+                (progn
+                  (setq paren-depth (1+ paren-depth))
+                  (forward-char))
+              (goto-char (match-end 1)))
+            (c-forward-syntactic-ws))
+
+          ;; If we haven't passed the identifier already, do it now.
+          (unless got-identifier
+            (setq id-start (point)))
+          (cond
+           ((or got-identifier
+                (c-forward-name))
+            (save-excursion
+              (c-backward-syntactic-ws)
+              (setq id-end (point))))
+           (accept-anon
+            (setq id-start nil id-end nil)
+            t)
+           (t (/= (point) here))))
+
+        ;; Skip out of the parens surrounding the identifier.  If closing
+        ;; parens are missing, this form returns nil.
+        (or (= paren-depth 0)
+            (c-safe (goto-char (scan-lists (point) 1 paren-depth))))
+
+        (<= (point) limit)
+
+        ;; Skip over any trailing bit, such as "__attribute__".
+        (progn
+          (when (looking-at c-decl-hangon-key)
+            (c-forward-keyword-clause 1))
+          (<= (point) limit))
+
+        ;; Search syntactically to the end of the declarator (";",
+        ;; ",", a closing paren, eob etc) or to the beginning of an
+        ;; initializer or function prototype ("=" or "\\s\(").
+        ;; Note that square brackets are now not also treated as
+        ;; initializers, since this broke when there were also
+        ;; initializing brace lists.
+        (let (found)
+          (while
+              (and (setq found (c-syntactic-re-search-forward
+                                "[;,]\\|\\s)\\|\\'\\|\\(=\\|\\s(\\)" limit t t))
+                   (eq (char-before) ?\[)
+                   (c-go-up-list-forward))
+            (setq brackets-after-id t))
+          (backward-char)
+          found))
+       (list id-start id-end brackets-after-id (match-beginning 1))
+
+      (goto-char here)
+      nil)))
+
 (defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end)
   ;; Move forward over a declaration or a cast if at the start of one.
   ;; The point is assumed to be at the start of some token.  Nil is
@@ -6879,9 +7097,8 @@ comment at the start of cc-engine.el for more info."
          (when (or (looking-at c-prefix-spec-kwds-re) ;FIXME!!! includes auto
                    (and (c-major-mode-is 'java-mode)
                         (looking-at "@[A-Za-z0-9]+")))
-           (save-match-data
-             (if (looking-at c-typedef-key)
-               (setq at-typedef t)))
+           (if (save-match-data (looking-at c-typedef-key))
+               (setq at-typedef t))
            (setq kwd-sym (c-keyword-sym (match-string 1)))
            (save-excursion
              (c-forward-keyword-clause 1)
@@ -7071,7 +7288,7 @@ comment at the start of cc-engine.el for more info."
       (goto-char id-start)
 
       ;; Skip over type decl prefix operators.  (Note similar code in
-      ;; `c-font-lock-declarators'.)
+      ;; `c-forward-declarator'.)
       (if (and c-recognize-typeless-decls
               (equal c-type-decl-prefix-key "\\<\\>"))
          (when (eq (char-after) ?\()
@@ -7124,7 +7341,7 @@ comment at the start of cc-engine.el for more info."
                       (setq paren-depth (1- paren-depth))
                       (forward-char)
                       t)
-                  (when (if (save-match-data (looking-at "\\s\("))
+                  (when (if (save-match-data (looking-at "\\s("))
                             (c-safe (c-forward-sexp 1) t)
                           (goto-char (match-end 1))
                           t)
@@ -7198,7 +7415,7 @@ comment at the start of cc-engine.el for more info."
 
         (setq at-decl-end
               (looking-at (cond ((eq context '<>) "[,>]")
-                                (context "[,\)]")
+                                (context "[,)]")
                                 (t "[,;]"))))
 
         ;; Now we've collected info about various characteristics of
@@ -7522,7 +7739,7 @@ comment at the start of cc-engine.el for more info."
         ;; The closing paren should follow.
         (progn
           (c-forward-syntactic-ws)
-          (looking-at "\\s\)"))
+          (looking-at "\\s)"))
 
         ;; There should be a primary expression after it.
         (let (pos)
@@ -7919,7 +8136,7 @@ comment at the start of cc-engine.el for more info."
 
          (catch 'break
            ;; Look for ": superclass-name" or "( category-name )".
-           (when (looking-at "[:\(]")
+           (when (looking-at "[:(]")
              (setq start-char (char-after))
              (forward-char)
              (c-forward-syntactic-ws)
@@ -8009,6 +8226,8 @@ brace.
 
 Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
+  ;; Note to maintainers: this function consumes a great mass of CPU cycles.
+  ;; Its use should thus be minimized as far as possible.
   (let ((paren-state (c-parse-state)))
     (or (not (c-most-enclosing-brace paren-state))
        (c-search-uplist-for-classkey paren-state))))
@@ -8069,14 +8288,14 @@ comment at the start of cc-engine.el for more info."
   ;; Return the position of the first argument declaration if point is
   ;; inside a K&R style argument declaration list, nil otherwise.
   ;; `c-recognize-knr-p' is not checked.  If LIM is non-nil, it's a
-  ;; position that bounds the backward search for the argument list.
+  ;; position that bounds the backward search for the argument list.  This
+  ;; function doesn't move point.
   ;;
   ;; Point must be within a possible K&R region, e.g. just before a top-level
   ;; "{".  It must be outside of parens and brackets.  The test can return
   ;; false positives otherwise.
   ;;
   ;; This function might do hidden buffer changes.
-
   (save-excursion
     (save-restriction
       ;; If we're in a macro, our search range is restricted to it.  Narrow to
@@ -8085,8 +8304,12 @@ comment at the start of cc-engine.el for more info."
             (macro-end (save-excursion (and macro-start (c-end-of-macro) (point))))
             (low-lim (max (or lim (point-min))   (or macro-start (point-min))))
             before-lparen after-rparen
-            (pp-count-out 20)) ; Max number of paren/brace constructs before
-                               ; we give up
+            (here (point))
+            (pp-count-out 20)  ; Max number of paren/brace constructs before
+                               ; we give up.
+            ids              ; List of identifiers in the parenthesized list.
+            id-start after-prec-token decl-or-cast decl-res
+            c-last-identifier-range identifier-ok)
        (narrow-to-region low-lim (or macro-end (point-max)))
 
        ;; Search backwards for the defun's argument list.  We give up if we
@@ -8105,8 +8328,12 @@ comment at the start of cc-engine.el for more info."
        ;; int foo (bar, baz, yuk)
        ;;     int bar [] ;
        ;;     int (*baz) (my_type) ;
-       ;;     int (*) (void) (*yuk) (void) ;
+       ;;     int (*(* yuk) (void)) (void) ;
        ;; {
+       ;;
+       ;; Additionally, for a knr list to be recognized:
+       ;; o - The identifier of each declarator up to and including the
+       ;;   one "near" point must be contained in the arg list.
 
        (catch 'knr
          (while (> pp-count-out 0) ; go back one paren/bracket pair each time.
@@ -8152,21 +8379,58 @@ comment at the start of cc-engine.el for more info."
                       (goto-char before-lparen)
                       (c-forward-token-2) ; to first token inside parens
                       (and
-                       (c-on-identifier)
-                       (c-forward-token-2)
+                       (setq id-start (c-on-identifier)) ; Must be at least one.
                        (catch 'id-list
-                         (while (eq (char-after) ?\,)
+                         (while
+                             (progn
+                               (forward-char)
+                               (c-end-of-current-token)
+                               (push (buffer-substring-no-properties id-start
+                                                                     (point))
+                                     ids)
+                               (c-forward-syntactic-ws)
+                               (eq (char-after) ?\,))
                            (c-forward-token-2)
-                           (unless (c-on-identifier) (throw 'id-list nil))
-                           (c-forward-token-2))
-                         (eq (char-after) ?\))))))
+                           (unless (setq id-start (c-on-identifier))
+                             (throw 'id-list nil)))
+                         (eq (char-after) ?\)))))
 
+                    ;; Are all the identifiers in the k&r list up to the
+                    ;; current one also in the argument list?
+                    (progn
+                      (forward-char)   ; over the )
+                      (setq after-prec-token after-rparen)
+                      (c-forward-syntactic-ws)
+                      (while (and
+                              (or (consp (setq decl-or-cast
+                                               (c-forward-decl-or-cast-1
+                                                after-prec-token
+                                                nil ; Or 'arglist ???
+                                                nil)))
+                                  (progn
+                                    (goto-char after-prec-token)
+                                    (c-forward-syntactic-ws)
+                                    (setq identifier-ok (eq (char-after) ?{))
+                                    nil))
+                              (eq (char-after) ?\;)
+                              (setq after-prec-token (1+ (point)))
+                              (goto-char (car decl-or-cast))
+                              (setq decl-res (c-forward-declarator))
+                              (setq identifier-ok
+                                    (member (buffer-substring-no-properties
+                                       (car decl-res) (cadr decl-res))
+                                      ids))
+                              (progn
+                                (goto-char after-prec-token)
+                                (prog1 (< (point) here)
+                                  (c-forward-syntactic-ws))))
+                        (setq identifier-ok nil))
+                      identifier-ok))
                    ;; ...Yes.  We've identified the function's argument list.
                    (throw 'knr
                           (progn (goto-char after-rparen)
                                  (c-forward-syntactic-ws)
                                  (point)))
-
                  ;; ...No.  The current parens aren't the function's arg list.
                  (goto-char before-lparen))
 
@@ -8434,7 +8698,7 @@ comment at the start of cc-engine.el for more info."
                            ;; Check for `c-opt-block-decls-with-vars-key'
                            ;; before the first paren.
                            (c-syntactic-re-search-forward
-                            (concat "[;=\(\[{]\\|\\("
+                            (concat "[;=([{]\\|\\("
                                     c-opt-block-decls-with-vars-key
                                     "\\)")
                             lim t t t)
@@ -8442,7 +8706,7 @@ comment at the start of cc-engine.el for more info."
                            (not (eq (char-before) ?_))
                            ;; Check that the first following paren is
                            ;; the block.
-                           (c-syntactic-re-search-forward "[;=\(\[{]"
+                           (c-syntactic-re-search-forward "[;=([{]"
                                                           lim t t t)
                            (eq (char-before) ?{)))))))
            ;; The declaration doesn't have any of the
@@ -8961,7 +9225,7 @@ comment at the start of cc-engine.el for more info."
                         (> (point) closest-lim))
                  (not (bobp))
                  (progn (backward-char)
-                        (looking-at "[\]\).]\\|\\w\\|\\s_"))
+                        (looking-at "[]).]\\|\\w\\|\\s_"))
                  (c-safe (forward-char)
                          (goto-char (scan-sexps (point) -1))))
 
@@ -9024,6 +9288,11 @@ comment at the start of cc-engine.el for more info."
            (goto-char containing-sexp)
            (if (or (save-excursion
                      (c-backward-syntactic-ws lim)
+                     (while (and (eq (char-before) ?>)
+                                 (c-get-char-property (1- (point))
+                                                      'syntax-table)
+                                 (c-go-list-backward nil lim))
+                       (c-backward-syntactic-ws lim))
                      (and (> (point) (or lim (point-min)))
                           (c-on-identifier)))
                    (and c-special-brace-lists
@@ -9571,7 +9840,6 @@ comment at the start of cc-engine.el for more info."
     (c-save-buffer-state
        ((indent-point (point))
         (case-fold-search nil)
-        open-paren-in-column-0-is-defun-start
         ;; A whole ugly bunch of various temporary variables.  Have
         ;; to declare them here since it's not possible to declare
         ;; a variable with only the scope of a cond test and the
@@ -9826,7 +10094,19 @@ comment at the start of cc-engine.el for more info."
                                       paren-state)))
 
        ;; CASE 14: A case or default label
-       ((looking-at c-label-kwds-regexp)
+       ((save-excursion
+         (and (looking-at c-label-kwds-regexp)
+              (or (c-major-mode-is 'idl-mode)
+                  (and
+                   containing-sexp
+                   (goto-char containing-sexp)
+                   (eq (char-after) ?{)
+                   (progn (c-backward-syntactic-ws) t)
+                   (eq (char-before) ?\))
+                   (c-go-list-backward)
+                   (progn (c-backward-syntactic-ws) t)
+                   (c-simple-skip-symbol-backward)
+                   (looking-at c-block-stmt-2-key)))))
        (if containing-sexp
            (progn
              (goto-char containing-sexp)
@@ -9842,6 +10122,7 @@ comment at the start of cc-engine.el for more info."
        ((save-excursion
          (back-to-indentation)
          (and (not (looking-at c-syntactic-ws-start))
+              (not (looking-at c-label-kwds-regexp))
               (c-forward-label)))
        (cond (containing-decl-open
               (setq placeholder (c-add-class-syntax 'inclass
@@ -10014,7 +10295,8 @@ comment at the start of cc-engine.el for more info."
         ;; Note there is no limit on the backward search here, since member
         ;; init lists can, in practice, be very large.
         ((save-excursion
-           (when (setq placeholder (c-back-over-member-initializers))
+           (when (and (c-major-mode-is 'c++-mode)
+                      (setq placeholder (c-back-over-member-initializers)))
              (setq tmp-pos (point))))
          (if (= (c-point 'bosws) (1+ tmp-pos))
                (progn