]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/cc-engine.el
Handle "noise" macros and compiler directives.
[gnu-emacs] / lisp / progmodes / cc-engine.el
index 6382b14521141cd7808e3f6a63842b8649b8982c..66b5369bbba8cea755c53a0445744291f9ff4c2f 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
@@ -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 -
@@ -1544,7 +1543,7 @@ comment at the start of cc-engine.el for more info."
 ;;    two newlines with horizontal whitespace between them.
 ;;
 ;;    The reason to include the first following char is to cope with
-;;    "rung positions" that doesn't have any ordinary whitespace.  If
+;;    "rung positions" that don't have any ordinary whitespace.  If
 ;;    `c-is-sws' is put on a token character it does not have
 ;;    `c-in-sws' set simultaneously.  That's the only case when that
 ;;    can occur, and the reason for not extending the `c-in-sws'
@@ -1715,7 +1714,9 @@ comment at the start of cc-engine.el for more info."
     ;; if it's anything that can't start syntactic ws, so we can bail out
     ;; early in the majority of cases when there just are a few ws chars.
     (skip-chars-forward " \t\n\r\f\v")
-    (when (looking-at c-syntactic-ws-start)
+    (when (or (looking-at c-syntactic-ws-start)
+             (and c-opt-cpp-prefix
+                  (looking-at c-noise-macro-name-re)))
 
       (setq rung-end-pos (min (1+ (point)) (point-max)))
       (if (setq rung-is-marked (text-property-any rung-pos rung-end-pos
@@ -1734,6 +1735,10 @@ comment at the start of cc-engine.el for more info."
       (with-silent-modifications
       (while
          (progn
+           ;; In the following while form, we move over a "ladder" and
+           ;; following simple WS each time round the loop, appending the WS
+           ;; onto the ladder, joining adjacent ladders, and terminating when
+           ;; there is no more WS or we reach EOB.
            (while
                (when (and rung-is-marked
                           (get-text-property (point) 'c-in-sws))
@@ -1777,6 +1782,7 @@ comment at the start of cc-engine.el for more info."
                            (setq rung-pos (point)
                                  last-put-in-sws-pos rung-pos)))
 
+           ;; Now move over any comments (x)or a CPP construct.
            (setq simple-ws-end (point))
            (c-forward-comments)
 
@@ -1802,6 +1808,13 @@ comment at the start of cc-engine.el for more info."
              (forward-line 1)
              (setq safe-start t)
              ;; Don't cache at eob in case the buffer is narrowed.
+             (not (eobp)))
+
+            ((and c-opt-cpp-prefix
+                  (looking-at c-noise-macro-name-re))
+             ;; Skip over a noise macro.
+             (goto-char (match-end 1))
+             (setq safe-start t)
              (not (eobp)))))
 
        ;; We've searched over a piece of non-white syntactic ws.  See if this
@@ -1908,8 +1921,11 @@ comment at the start of cc-engine.el for more info."
     (when (and (not (bobp))
               (save-excursion
                 (backward-char)
-                (looking-at c-syntactic-ws-end)))
-
+                (or (looking-at c-syntactic-ws-end)
+                    (and c-opt-cpp-prefix
+                         (looking-at c-symbol-char-key)
+                         (progn (c-beginning-of-current-token)
+                                (looking-at c-noise-macro-name-re))))))
       ;; Try to find a rung position in the simple ws preceding point, so that
       ;; we can get a cache hit even if the last bit of the simple ws has
       ;; changed recently.
@@ -1928,6 +1944,9 @@ comment at the start of cc-engine.el for more info."
       (with-silent-modifications
       (while
          (progn
+           ;; Each time round the next while form, we move back over a ladder
+           ;; and append any simple WS preceding it, if possible joining with
+           ;; the previous ladder.
            (while
                (when (and rung-is-marked
                           (not (bobp))
@@ -2036,6 +2055,15 @@ comment at the start of cc-engine.el for more info."
              ;; narrowed out, and we can't risk marking the simple ws
              ;; at the end of it.
              (goto-char next-rung-pos)
+             t)
+
+            ((and c-opt-cpp-prefix
+                  (save-excursion
+                    (and (< (skip-syntax-backward "w_") 0)
+                         (progn (setq next-rung-pos (point))
+                                (looking-at c-noise-macro-name-re)))))
+             ;; Skipped over a noise macro
+             (goto-char next-rung-pos)
              t)))
 
        ;; We've searched over a piece of non-white syntactic ws.  See if this
@@ -2524,6 +2552,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 +2626,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 +3270,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 +3293,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 +3306,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 +3364,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 +3384,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)
@@ -5538,8 +5606,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 +5625,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 +5701,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.
 
@@ -5743,8 +5836,10 @@ comment at the start of cc-engine.el for more info."
                               `(c-forward-type)
                             `(c-forward-name)))
                nil
-             (and (looking-at c-keywords-regexp)
-                  (c-forward-keyword-clause 1))))
+             (cond ((looking-at c-keywords-regexp)
+                    (c-forward-keyword-clause 1))
+                   ((looking-at c-noise-macro-with-parens-name-re)
+                    (c-forward-noise-clause)))))
      (when (memq res '(t known found prefix))
        ,(when (eq type 'ref)
          `(when c-record-type-identifiers
@@ -5766,6 +5861,17 @@ comment at the start of cc-engine.el for more info."
                 (c-forward-syntactic-ws)
                 (c-forward-keyword-prefixed-id ,type)))))
 
+(defun c-forward-noise-clause ()
+  ;; Point is at a c-noise-macro-with-parens-names macro identifier.  Go
+  ;; forward over this name, any parenthesis expression which follows it, and
+  ;; any syntactic WS, ending up at the next token.  If there is an unbalanced
+  ;; paren expression, leave point at it.  Always Return t.
+  (c-forward-token-2)
+  (if (and (eq (char-after) ?\()
+          (c-go-list-forward))
+      (c-forward-syntactic-ws))
+  t)
+
 (defun c-forward-keyword-clause (match)
   ;; Submatch MATCH in the current match data is assumed to surround a
   ;; token.  If it's a keyword, move over it and any immediately
@@ -5925,7 +6031,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
@@ -5992,7 +6098,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 +6109,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 +6131,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 +6157,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 +6175,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) ?&)
@@ -6386,6 +6502,13 @@ comment at the start of cc-engine.el for more info."
                                     ; "typedef".
       (goto-char (match-end 1))
       (c-forward-syntactic-ws)
+
+      (while (cond
+             ((looking-at c-decl-hangon-key)
+              (c-forward-keyword-clause 1))
+             ((looking-at c-noise-macro-with-parens-name-re)
+              (c-forward-noise-clause))))
+
       (setq pos (point))
 
       (setq name-res (c-forward-name))
@@ -6577,16 +6700,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 +6756,65 @@ 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) ?:)
+                        (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) ?:)
+                          (c-just-after-func-arglist-p)))))
 
+           (and at-top-level level-plausible)))
     (or res (goto-char here))
     res))
 
@@ -6716,6 +6861,129 @@ 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
+                 (cond
+                  ((looking-at c-decl-hangon-key)
+                   (c-forward-keyword-clause 1))
+                  ((looking-at c-noise-macro-with-parens-name-re)
+                   (c-forward-noise-clause))
+                  ((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)
+                   t)))
+
+          ;; 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
+             (while (cond
+                     ((looking-at c-decl-hangon-key)
+                      (c-forward-keyword-clause 1))
+                     ((looking-at c-noise-macro-with-parens-name-re)
+                      (c-forward-noise-clause))))
+             (<= (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
@@ -6873,19 +7141,24 @@ comment at the start of cc-engine.el for more info."
     ;; macros like __INLINE__, so we recognize both types and known
     ;; specifiers after them too.
     (while
-       (let* ((start (point)) kwd-sym kwd-clause-end found-type)
+       (let* ((start (point)) kwd-sym kwd-clause-end found-type noise-start)
 
+         (cond
          ;; Look for a specifier keyword clause.
-         (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]+")))
+          ((or (looking-at c-prefix-spec-kwds-re)
+               (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)))
+                 (setq at-typedef t)))
            (setq kwd-sym (c-keyword-sym (match-string 1)))
            (save-excursion
              (c-forward-keyword-clause 1)
              (setq kwd-clause-end (point))))
+          ((looking-at c-noise-macro-with-parens-name-re)
+           (setq noise-start (point))
+           (c-forward-noise-clause)
+           (setq kwd-clause-end (point))))
 
          (when (setq found-type (c-forward-type t)) ; brace-block-too
            ;; Found a known or possible type or a prefix of a known type.
@@ -6923,16 +7196,17 @@ comment at the start of cc-engine.el for more info."
                  backup-at-type-decl nil
                  backup-maybe-typeless nil))
 
-         (if kwd-sym
+         (if (or kwd-sym noise-start)
              (progn
                ;; Handle known specifier keywords and
                ;; `c-decl-hangon-kwds' which can occur after known
                ;; types.
 
-               (if (c-keyword-member kwd-sym 'c-decl-hangon-kwds)
-                   ;; It's a hang-on keyword that can occur anywhere.
+               (if (or (c-keyword-member kwd-sym 'c-decl-hangon-kwds)
+                       noise-start)
+                   ;; It's a hang-on keyword or noise clause that can occur
+                   ;; anywhere.
                    (progn
-                     (setq at-decl-or-cast t)
                      (if at-type
                          ;; Move the identifier start position if
                          ;; we've passed a type.
@@ -6984,8 +7258,11 @@ comment at the start of cc-engine.el for more info."
       ;; If a known type was found, we still need to skip over any
       ;; hangon keyword clauses after it.  Otherwise it has already
       ;; been done in the loop above.
-      (while (looking-at c-decl-hangon-key)
-       (c-forward-keyword-clause 1))
+      (while
+         (cond ((looking-at c-decl-hangon-key)
+                (c-forward-keyword-clause 1))
+               ((looking-at c-noise-macro-with-parens-name-re)
+                (c-forward-noise-clause))))
       (setq id-start (point)))
 
      ((eq at-type 'prefix)
@@ -7071,7 +7348,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) ?\()
@@ -8009,6 +8286,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 +8348,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 +8364,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 +8388,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 +8439,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))
 
@@ -8705,6 +9029,11 @@ comment at the start of cc-engine.el for more info."
           t)
          ((looking-at c-after-brace-list-key) t)
          ((looking-at c-brace-list-key) nil)
+         ((eq (char-after) ?\()
+          (and (eq (c-backward-token-2) 0)
+               (or (looking-at c-decl-hangon-key)
+                   (looking-at c-noise-macro-with-parens-name-re))))
+
          ((and c-recognize-<>-arglists
                (eq (char-after) ?<)
                (looking-at "\\s("))
@@ -9024,6 +9353,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 +9905,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 +10159,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 +10187,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
@@ -9948,9 +10294,11 @@ comment at the start of cc-engine.el for more info."
           ;; CASE 5A.3: brace list open
           ((save-excursion
              (c-beginning-of-decl-1 lim)
-             (while (looking-at c-specifier-key)
-               (goto-char (match-end 1))
-               (c-forward-syntactic-ws indent-point))
+             (while (cond
+                     ((looking-at c-specifier-key)
+                      (c-forward-keyword-clause 1))
+                     ((looking-at c-noise-macro-with-parens-name-re)
+                      (c-forward-noise-clause))))
              (setq placeholder (c-point 'boi))
              (or (consp special-brace-list)
                  (and (or (save-excursion
@@ -10002,9 +10350,11 @@ comment at the start of cc-engine.el for more info."
           (t
            (save-excursion
              (c-beginning-of-decl-1 lim)
-             (while (looking-at c-specifier-key)
-               (goto-char (match-end 1))
-               (c-forward-syntactic-ws indent-point))
+             (while (cond
+                     ((looking-at c-specifier-key)
+                      (c-forward-keyword-clause 1))
+                     ((looking-at c-noise-macro-with-parens-name-re)
+                      (c-forward-noise-clause))))
              (c-add-syntax 'defun-open (c-point 'boi))
              ;; Bogus to use bol here, but it's the legacy.  (Resolved,
              ;; 2007-11-09)
@@ -10014,7 +10364,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
@@ -10634,9 +10985,11 @@ comment at the start of cc-engine.el for more info."
            (c-beginning-of-statement-1
             (c-safe-position (1- containing-sexp) paren-state))
            (c-forward-token-2 0)
-           (while (looking-at c-specifier-key)
-             (goto-char (match-end 1))
-             (c-forward-syntactic-ws))
+           (while (cond
+                   ((looking-at c-specifier-key)
+                    (c-forward-keyword-clause 1))
+                   ((looking-at c-noise-macro-with-parens-name-re)
+                    (c-forward-noise-clause))))
            (c-add-syntax 'brace-list-open (c-point 'boi))))
 
         ;; CASE 9B: brace-list-close brace