]> 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 617c94aae08599c8a488632bfd684bf3376d5b4f..aac7e631087ca6cd63e368ffcb124f11b55b9e73 100644 (file)
@@ -3241,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
@@ -3265,7 +3265,7 @@ comment at the start of cc-engine.el for more info."
     ;; below `here'.  To maintain its consistency, we may need to insert a new
     ;; brace pair.
     (let ((here-bol (c-point 'bol here))
-         too-high-pa             ; recorded {/(/[ next above here, or nil.
+         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'.
@@ -3277,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)))))
@@ -3472,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)
@@ -4259,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)))
@@ -4308,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))
+  (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)
 
-              (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))))))
 
-                (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)))))
+          (> (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
@@ -5577,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
@@ -5595,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
@@ -5668,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.
 
@@ -6016,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))
@@ -6031,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
@@ -6039,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.
@@ -6109,6 +6142,11 @@ comment at the start of cc-engine.el for more info."
                      )))
                  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) ?&)
                                (not (eq (char-after) ?&)))
@@ -6616,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),
@@ -6708,6 +6752,9 @@ comment at the start of cc-engine.el for more info."
                      (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
@@ -6722,6 +6769,9 @@ comment at the start of cc-engine.el for more info."
                      (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)))
@@ -6771,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
@@ -6934,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)
@@ -7126,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) ?\()
@@ -8126,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
@@ -8142,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
@@ -8162,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.
@@ -8209,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))
 
@@ -9081,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
@@ -9882,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)
@@ -9898,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