Change strategy for marking < and > as template delimiters: mark them
[bpt/emacs.git] / lisp / progmodes / cc-engine.el
index d1a27d5..3b7f6e4 100644 (file)
@@ -1,13 +1,14 @@
 ;;; cc-engine.el --- core syntax guessing engine for CC mode
 
 ;; Copyright (C) 1985, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;;   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+;;   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
 ;;   Free Software Foundation, Inc.
 
 ;; Authors:    2001- Alan Mackenzie
 ;;             1998- Martin Stjernholm
 ;;             1992-1999 Barry A. Warsaw
-;;             1987 Dave Detlefs and Stewart Clamen
+;;             1987 Dave Detlefs
+;;             1987 Stewart Clamen
 ;;             1985 Richard M. Stallman
 ;; Maintainer: bug-cc-mode@gnu.org
 ;; Created:    22-Apr-1997 (split from cc-mode.el)
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -27,9 +28,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with this program; see the file COPYING.  If not, write to
-;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 ;; Note: This doc is for internal use only.  Other packages should not
 ;; assume that these text properties are used as described here.
 ;;
+;; 'category
+;;   Used for "indirection".  With its help, some other property can
+;;   be cheaply and easily switched on or off everywhere it occurs.
+;;
 ;; 'syntax-table
-;;   Used to modify the syntax of some characters.  Currently used to
-;;   mark the "<" and ">" of angle bracket parens with paren syntax.
+;;   Used to modify the syntax of some characters.  It is used to
+;;   mark the "<" and ">" of angle bracket parens with paren syntax, and
+;;   to "hide" obtrusive characters in preprocessor lines.
 ;;
 ;;   This property is used on single characters and is therefore
 ;;   always treated as front and rear nonsticky (or start and end open
@@ -256,6 +260,27 @@ comment at the start of cc-engine.el for more info."
             (forward-char)
             t))))
 
+(defun c-syntactic-end-of-macro ()
+  ;; Go to the end of a CPP directive, or a "safe" pos just before.
+  ;;
+  ;; This is normally the end of the next non-escaped line.  A "safe"
+  ;; position is one not within a string or comment.  (The EOL on a line
+  ;; comment is NOT "safe").
+  ;;
+  ;; This function must only be called from the beginning of a CPP construct.
+  ;;
+  ;; Note that this function might do hidden buffer changes.  See the comment
+  ;; at the start of cc-engine.el for more info.
+  (let* ((here (point))
+        (there (progn (c-end-of-macro) (point)))
+        (s (parse-partial-sexp here there)))
+    (while (and (or (nth 3 s)   ; in a string
+                   (nth 4 s))   ; in a comment (maybe at end of line comment)
+               (> there here))  ; No infinite loops, please.
+      (setq there (1- (nth 8 s)))
+      (setq s (parse-partial-sexp here there)))
+    (point)))
+
 (defun c-forward-over-cpp-define-id ()
   ;; Assuming point is at the "#" that introduces a preprocessor
   ;; directive, it's moved forward to the end of the identifier which is
@@ -422,7 +447,7 @@ comment at the start of cc-engine.el for more info."
   (c-put-char-property pos 'c-type value))
 
 (defun c-clear-c-type-property (from to value)
-  ;; Remove all occurences of the c-type property that has the given
+  ;; Remove all occurrences of the c-type property that has the given
   ;; value in the region between FROM and TO.  VALUE is assumed to not
   ;; be nil.
   ;;
@@ -530,6 +555,10 @@ the previous one if already at the beginning of one.  Only
 statements/declarations on the same level are considered, i.e. don't
 move into or out of sexps (not even normal expression parentheses).
 
+If point is already at the earliest statement within braces or parens,
+this function doesn't move back into any whitespace preceding it; it
+returns 'same in this case.
+
 Stop at statement continuation tokens like \"else\", \"catch\",
 \"finally\" and the \"while\" in \"do ... while\" if the start point
 is within the continuation.  If starting at such a token, move to the
@@ -549,12 +578,16 @@ of the content in the macro, i.e. the expression of an \"#if\" or the
 start of the definition in a \"#define\".  Also stop at start of
 macros before leaving them.
 
-Return 'label if stopped at a label, 'same if stopped at the beginning
-of the current statement, 'up if stepped to a containing statement,
-'previous if stepped to a preceding statement, 'beginning if stepped
-from a statement continuation clause to its start clause, or 'macro if
-stepped to a macro start.  Note that 'same and not 'label is returned
-if stopped at the same label without crossing the colon character.
+Return:
+'label          if stopped at a label or \"case...:\" or \"default:\";
+'same           if stopped at the beginning of the current statement;
+'up             if stepped to a containing statement;
+'previous       if stepped to a preceding statement;
+'beginning      if stepped from a statement continuation clause to
+                its start clause; or
+'macro          if stepped to a macro start.
+Note that 'same and not 'label is returned if stopped at the same
+label without crossing the colon character.
 
 LIM may be given to limit the search.  If the search hits the limit,
 point will be left at the closest following token, or at the start
@@ -572,7 +605,7 @@ comment at the start of cc-engine.el for more info."
   ;; The bulk of this function is a pushdown automaton that looks at statement
   ;; boundaries and the tokens (such as "while") in c-opt-block-stmt-key.  Its
   ;; purpose is to keep track of nested statements, ensuring that such
-  ;; statments are skipped over in their entirety (somewhat akin to what C-M-p
+  ;; statements are skipped over in their entirety (somewhat akin to what C-M-p
   ;; does with nested braces/brackets/parentheses).
   ;;
   ;; Note: The position of a boundary is the following token.
@@ -604,7 +637,7 @@ comment at the start of cc-engine.el for more info."
   ;;         (e.g. if).
   ;;
   ;;
-  ;; The following diagram briefly outlines the PDA.  
+  ;; The following diagram briefly outlines the PDA.
   ;;
   ;; Common state:
   ;;   "else": Push state, goto state `else'.
@@ -657,7 +690,7 @@ comment at the start of cc-engine.el for more info."
        (c-stmt-delim-chars (if comma-delim
                                c-stmt-delim-chars-with-comma
                              c-stmt-delim-chars))
-       c-in-literal-cache c-maybe-labelp saved
+       c-in-literal-cache c-maybe-labelp after-case:-pos saved
        ;; Current position.
        pos
        ;; Position of last stmt boundary character (e.g. ;).
@@ -971,7 +1004,7 @@ comment at the start of cc-engine.el for more info."
                            ;; Like a C "continue".  Analyze the next sexp.
                            (throw 'loop t)))
 
-                       sexp-loop-continue-pos) ; End of "go back a sexp" loop.
+                       sexp-loop-continue-pos) ; End of "go back a sexp" loop condition.
                    (goto-char sexp-loop-continue-pos)
                    (setq sexp-loop-end-pos sexp-loop-continue-pos
                          sexp-loop-continue-pos nil))))
@@ -989,19 +1022,16 @@ comment at the start of cc-engine.el for more info."
                  ;; `c-crosses-statement-barrier-p' has found a colon, so we
                  ;; might be in a label now.  Have we got a real label
                  ;; (including a case label) or something like C++'s "public:"?
-                 (if (or (not (looking-at c-nonlabel-token-key)) ; proper label
-                         (save-excursion ; e.g. "case 'a':" ?
-                           (and (c-safe (c-backward-sexp) t)
-                                (looking-at "\\<case\\>")))) ; FIXME!!! this is
-                                       ; wrong for AWK.  2006/1/14.
-                     (progn
-                       (if after-labels-pos ; Have we already encountered a label?
-                           (if (not last-label-pos)
-                               (setq last-label-pos (or tok start)))
-                         (setq after-labels-pos (or tok start)))
-                       (setq c-maybe-labelp t
-                             label-good-pos nil))
-                   (setq c-maybe-labelp nil))) ; bogus "label"
+                 ;; A case label might use an expression rather than a token.
+                 (setq after-case:-pos (or tok start))
+                 (if (looking-at c-nonlabel-token-key) ; e.g. "while" or "'a'"
+                     (setq c-maybe-labelp nil)
+                   (if after-labels-pos ; Have we already encountered a label?
+                       (if (not last-label-pos)
+                           (setq last-label-pos (or tok start)))
+                     (setq after-labels-pos (or tok start)))
+                   (setq c-maybe-labelp t
+                         label-good-pos nil))) ; bogus "label"
 
                (when (and (not label-good-pos) ; i.e. no invalid "label"'s yet
                                                ; been found.
@@ -1056,8 +1086,17 @@ comment at the start of cc-engine.el for more info."
                ;; Might have jumped over several labels.  Go to the last one.
                (setq pos last-label-pos)))))
 
-      ;; Skip over the unary operators that can start the statement.
+      ;; Have we got "case <expression>:"?
       (goto-char pos)
+      (when (and after-case:-pos
+                (not (eq ret 'beginning))
+                (looking-at c-case-kwds-regexp))
+       (if (< after-case:-pos start)
+           (setq pos after-case:-pos))
+       (if (eq ret 'same)
+           (setq ret 'label)))
+
+      ;; Skip over the unary operators that can start the statement.
       (while (progn
               (c-backward-syntactic-ws)
               ;; protect AWK post-inc/decrement operators, etc.
@@ -1079,7 +1118,7 @@ single `?' is found, then `c-maybe-labelp' is cleared.
 
 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 recognises it.
+the line.  If this virtual semicolon is _at_ from, the function recognizes it.
 
 Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
@@ -1916,7 +1955,7 @@ comment at the start of cc-engine.el for more info."
 (defun c-partial-ws-p (beg end)
   ;; Is the region (beg end) WS, and is there WS (or BOB/EOB) next to the
   ;; region?  This is a "heuristic" function.  .....
-  ;; 
+  ;;
   ;; The motivation for the second bit is to check whether removing this
   ;; region would coalesce two symbols.
   ;;
@@ -1933,10 +1972,18 @@ comment at the start of cc-engine.el for more info."
 \f
 ;; A system for finding noteworthy parens before the point.
 
+(defconst c-state-cache-too-far 5000)
+;; A maximum comfortable scanning distance, e.g. between
+;; `c-state-cache-good-pos' and "HERE" (where we call c-parse-state).  When
+;; this distance is exceeded, we take "emergency meausures", e.g. by clearing
+;; the cache and starting again from point-min or a beginning of defun.  This
+;; value can be tuned for efficiency or set to a lower value for testing.
+
 (defvar c-state-cache nil)
 (make-variable-buffer-local 'c-state-cache)
 ;; The state cache used by `c-parse-state' to cut down the amount of
-;; searching.  It's the result from some earlier `c-parse-state' call.
+;; searching.  It's the result from some earlier `c-parse-state' call.  See
+;; `c-parse-state''s doc string for details of its structure.
 ;;
 ;; The use of the cached info is more effective if the next
 ;; `c-parse-state' call is on a line close by the one the cached state
@@ -1945,18 +1992,12 @@ comment at the start of cc-engine.el for more info."
 ;; most effective if `c-parse-state' is used on each line while moving
 ;; forward.
 
-(defvar c-state-cache-start 1)
-(make-variable-buffer-local 'c-state-cache-start)
-;; This is (point-min) when `c-state-cache' was calculated, since a
-;; change of narrowing is likely to affect the parens that are visible
-;; before the point.
-
 (defvar c-state-cache-good-pos 1)
 (make-variable-buffer-local 'c-state-cache-good-pos)
-;; This is a position where `c-state-cache' is known to be correct.
-;; It's a position inside one of the recorded unclosed parens or the
-;; top level, but not further nested inside any literal or subparen
-;; that is closed before the last recorded position.
+;; This is a position where `c-state-cache' is known to be correct, or
+;; nil (see below).  It's a position inside one of the recorded unclosed
+;; parens or the top level, but not further nested inside any literal or
+;; subparen that is closed before the last recorded position.
 ;;
 ;; The exact position is chosen to try to be close to yet earlier than
 ;; the position where `c-state-cache' will be called next.  Right now
@@ -1964,313 +2005,1055 @@ comment at the start of cc-engine.el for more info."
 ;; closing paren (of any type) before the line on which
 ;; `c-parse-state' was called.  That is chosen primarily to work well
 ;; with refontification of the current line.
+;;
+;; 2009-07-28: When `c-state-point-min' and the last position where
+;; `c-parse-state' or for which `c-invalidate-state-cache' was called, are
+;; both in the same literal, there is no such "good position", and
+;; c-state-cache-good-pos is then nil.  This is the ONLY circumstance in which
+;; it can be nil.  In this case, `c-state-point-min-literal' will be non-nil.
+;;
+;; 2009-06-12: In a brace desert, c-state-cache-good-pos may also be in
+;; the middle of the desert, as long as it is not within a brace pair
+;; recorded in `c-state-cache' or a paren/bracket pair.
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; We maintain a simple cache of positions which aren't in a literal, so as to
+;; speed up testing for non-literality.
+(defconst c-state-nonlit-pos-interval 10000)
+;; The approximate interval between entries in `c-state-nonlit-pos-cache'.
+
+(defvar c-state-nonlit-pos-cache nil)
+(make-variable-buffer-local 'c-state-nonlit-pos-cache)
+;; A list of buffer positions which are known not to be in a literal.  This is
+;; ordered with higher positions at the front of the list.  Only those which
+;; are less than `c-state-nonlit-pos-cache-limit' are valid.
+
+(defvar c-state-nonlit-pos-cache-limit 1)
+(make-variable-buffer-local 'c-state-nonlit-pos-cache-limit)
+;; An upper limit on valid entries in `c-state-nonlit-pos-cache'.  This is
+;; reduced by buffer changes, and increased by invocations of
+;; `c-state-literal-at'.
+
+(defsubst c-state-pp-to-literal (from to)
+  ;; Do a parse-partial-sexp from FROM to TO, returning the bounds of any
+  ;; literal at TO as a cons, otherwise NIL.
+  ;; FROM must not be in a literal, and the buffer should already be wide
+  ;; enough.
+  (save-excursion
+    (let ((s (parse-partial-sexp from to)))
+      (when (or (nth 3 s) (nth 4 s))   ; in a string or comment
+       (parse-partial-sexp (point) (point-max)
+                           nil                  ; TARGETDEPTH
+                           nil                  ; STOPBEFORE
+                           s                    ; OLDSTATE
+                           'syntax-table)       ; stop at end of literal
+       (cons (nth 8 s) (point))))))
+
+(defun c-state-literal-at (here)
+  ;; If position HERE is inside a literal, return (START . END), the
+  ;; boundaries of the literal (which may be outside the accessible bit of the
+  ;; buffer).  Otherwise, return nil.
+  ;;
+  ;; This function is almost the same as `c-literal-limits'.  It differs in
+  ;; that it is a lower level function, and that it rigourously follows the
+  ;; syntax from BOB, whereas `c-literal-limits' uses a "local" safe position.
+  (save-restriction
+    (widen)
+    (save-excursion
+      (let ((c c-state-nonlit-pos-cache)
+           pos npos lit)
+       ;; Trim the cache to take account of buffer changes.
+       (while (and c (> (car c) c-state-nonlit-pos-cache-limit))
+         (setq c (cdr c)))
+       (setq c-state-nonlit-pos-cache c)
+
+       (while (and c (> (car c) here))
+         (setq c (cdr c)))
+       (setq pos (or (car c) (point-min)))
+
+       (while (<= (setq npos (+ pos c-state-nonlit-pos-interval))
+                  here)
+         (setq lit (c-state-pp-to-literal pos npos))
+         (setq pos (or (cdr lit) npos)) ; end of literal containing npos.
+         (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
+
+       (if (> pos c-state-nonlit-pos-cache-limit)
+           (setq c-state-nonlit-pos-cache-limit pos))
+       (if (< pos here)
+           (setq lit (c-state-pp-to-literal pos here)))
+       lit))))
+
+(defsubst c-state-lit-beg (pos)
+  ;; Return the start of the literal containing POS, or POS itself.
+  (or (car (c-state-literal-at pos))
+      pos))
+
+(defsubst c-state-cache-non-literal-place (pos state)
+  ;; Return a position outside of a string/comment at or before POS.
+  ;; STATE is the parse-partial-sexp state at POS.
+  (if (or (nth 3 state)                        ; in a string?
+         (nth 4 state))                ; in a comment?
+      (nth 8 state)
+    pos))
 
-(defsubst c-invalidate-state-cache (pos)
-  ;; Invalidate all info on `c-state-cache' that applies to the buffer
-  ;; at POS or higher.  This is much like `c-whack-state-after', but
-  ;; it never changes a paren 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.
-  (while (and (or c-state-cache
-                 (when (< pos c-state-cache-good-pos)
-                   (setq c-state-cache-good-pos 1)
-                   nil))
-             (let ((elem (car c-state-cache)))
-               (if (consp elem)
-                   (or (< pos (cdr elem))
-                       (when (< pos c-state-cache-good-pos)
-                         (setq c-state-cache-good-pos (cdr elem))
-                         nil))
-                 (or (<= pos elem)
-                     (when (< pos c-state-cache-good-pos)
-                       (setq c-state-cache-good-pos (1+ elem))
-                       nil)))))
-    (setq c-state-cache (cdr c-state-cache))))
-
-(defun c-get-fallback-start-pos (here)
-  ;; Return the start position for building `c-state-cache' from
-  ;; scratch.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Stuff to do with point-min, and coping with any literal there.
+(defvar c-state-point-min 1)
+(make-variable-buffer-local 'c-state-point-min)
+;; This is (point-min) when `c-state-cache' was last calculated.  A change of
+;; narrowing is likely to affect the parens that are visible before the point.
+
+(defvar c-state-point-min-lit-type nil)
+(make-variable-buffer-local 'c-state-point-min-lit-type)
+(defvar c-state-point-min-lit-start nil)
+(make-variable-buffer-local 'c-state-point-min-lit-start)
+;; These two variables define the literal, if any, containing point-min.
+;; Their values are, respectively, 'string, c, or c++, and the start of the
+;; literal.  If there's no literal there, they're both nil.
+
+(defvar c-state-min-scan-pos 1)
+(make-variable-buffer-local 'c-state-min-scan-pos)
+;; This is the earliest buffer-pos from which scanning can be done.  It is
+;; either the end of the literal containing point-min, or point-min itself.
+;; It becomes nil if the buffer is changed earlier than this point.
+(defun c-state-get-min-scan-pos ()
+  ;; Return the lowest valid scanning pos.  This will be the end of the
+  ;; literal enclosing point-min, or point-min itself.
+  (or c-state-min-scan-pos
+      (save-restriction
+       (save-excursion
+         (widen)
+         (goto-char c-state-point-min-lit-start)
+         (if (eq c-state-point-min-lit-type 'string)
+             (forward-sexp)
+           (forward-comment 1))
+         (setq c-state-min-scan-pos (point))))))
+
+(defun c-state-mark-point-min-literal ()
+  ;; Determine the properties of any literal containing POINT-MIN, setting the
+  ;; variables `c-state-point-min-lit-type', `c-state-point-min-lit-start',
+  ;; and `c-state-min-scan-pos' accordingly.  The return value is meaningless.
+  (let ((p-min (point-min))
+       lit)
+    (save-restriction
+      (widen)
+      (setq lit (c-state-literal-at p-min))
+      (if lit
+         (setq c-state-point-min-lit-type
+               (save-excursion
+                 (goto-char (car lit))
+                 (cond
+                  ((looking-at c-block-comment-start-regexp) 'c)
+                  ((looking-at c-line-comment-starter) 'c++)
+                  (t 'string)))
+               c-state-point-min-lit-start (car lit)
+               c-state-min-scan-pos (cdr lit))
+       (setq c-state-point-min-lit-type nil
+             c-state-point-min-lit-start nil
+             c-state-min-scan-pos p-min)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; A variable which signals a brace dessert - helpful for reducing the number
+;; of fruitless backward scans.
+(defvar c-state-brace-pair-desert nil)
+(make-variable-buffer-local 'c-state-brace-pair-desert)
+;; Used only in `c-append-lower-brace-pair-to-state-cache'.  It is set when an
+;; that defun has searched backwards for a brace pair and not found one.  Its
+;; value is either nil or a cons (PA . FROM), where PA is the position of the
+;; enclosing opening paren/brace/bracket which bounds the backwards search (or
+;; nil when at top level) and FROM is where the backward search started.  It
+;; is reset to nil in `c-invalidate-state-cache'.
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Lowish level functions/macros which work directly on `c-state-cache', or a
+;; list of like structure.
+(defmacro c-state-cache-top-lparen (&optional cache)
+  ;; Return the address of the top left brace/bracket/paren recorded in CACHE
+  ;; (default `c-state-cache') (or nil).
+  (let ((cash (or cache 'c-state-cache)))
+    `(if (consp (car ,cash))
+        (caar ,cash)
+       (car ,cash))))
+
+(defmacro c-state-cache-top-paren (&optional cache)
+  ;; Return the address of the latest brace/bracket/paren (whether left or
+  ;; right) recorded in CACHE (default `c-state-cache') or nil.
+  (let ((cash (or cache 'c-state-cache)))
+    `(if (consp (car ,cash))
+        (cdar ,cash)
+       (car ,cash))))
+
+(defmacro c-state-cache-after-top-paren (&optional cache)
+  ;; Return the position just after the latest brace/bracket/paren (whether
+  ;; left or right) recorded in CACHE (default `c-state-cache') or nil.
+  (let ((cash (or cache 'c-state-cache)))
+    `(if (consp (car ,cash))
+        (cdar ,cash)
+       (and (car ,cash)
+           (1+ (car ,cash))))))
+
+(defun c-get-cache-scan-pos (here)
+  ;; From the state-cache, determine the buffer position from which we might
+  ;; scan forward to HERE to update this cache.  This position will be just
+  ;; after a paren/brace/bracket recorded in the cache, if possible, otherwise
+  ;; return the earliest position in the accessible region which isn't within
+  ;; a literal.  If the visible portion of the buffer is entirely within a
+  ;; literal, return NIL.
+  (let ((c c-state-cache) elt)
+    ;(while (>= (or (c-state-cache-top-lparen c) 1) here)
+    (while (and c
+               (>= (c-state-cache-top-lparen c) here))
+      (setq c (cdr c)))
+
+    (setq elt (car c))
+    (cond
+     ((consp elt)
+      (if (> (cdr elt) here)
+         (1+ (car elt))
+       (cdr elt)))
+     (elt (1+ elt))
+     ((<= (c-state-get-min-scan-pos) here)
+      (c-state-get-min-scan-pos))
+     (t nil))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Variables which keep track of preprocessor constructs.
+(defvar c-state-old-cpp-beg nil)
+(make-variable-buffer-local 'c-state-old-cpp-beg)
+(defvar c-state-old-cpp-end nil)
+(make-variable-buffer-local 'c-state-old-cpp-end)
+;; These are the limits of the macro containing point at the previous call of
+;; `c-parse-state', or nil.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Defuns which analyse 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)
+       (c-beginning-of-defun-1)        ; Pure elisp BOD.
        (if (eq (char-after) ?\{)
            (setq cnt (1- cnt)))))
     (point)))
 
-(defun c-parse-state ()
-  ;; Find and record all noteworthy parens between some good point
-  ;; earlier in the file and point.  That good point is at least the
-  ;; beginning of the top-level construct we are in, or the beginning
-  ;; of the preceding top-level construct if we aren't in one.
-  ;;
-  ;; The returned value is a list of the noteworthy parens with the
-  ;; last one first.  If an element in the list is an integer, it's
-  ;; the position of an open paren which has not been closed before
-  ;; the point.  If an element is a cons, it gives the position of a
-  ;; closed brace paren pair; the car is the start paren position and
-  ;; the cdr is the position following the closing paren.  Only the
-  ;; last closed brace paren pair before each open paren and before
-  ;; the point is recorded, and thus the state never contains two cons
-  ;; elements in succession.
+(defun c-state-balance-parens-backwards (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, like this:
+  ;;
+  ;;      ......................................
+  ;;      |                                    |
+  ;;      (    [ ( ...........  )      ( )  ]  )
+  ;;      ^                 ^                       ^
+  ;;      |                 |                       |
+  ;;   return             HERE                     TOP
+  ;;
+  ;; If there aren't enough opening paren/brace/brackets, return the position
+  ;; of the outermost one found, or HERE it there are none.  If there are no
+  ;; closeing p/b/bs between HERE and TOP, return HERE.  HERE and TOP must not
+  ;; be inside literals.  Only the accessible portion of the buffer will be
+  ;; scanned.
+
+  ;; PART 1: scan from `here' up to `top', accumulating ")"s which enclose
+  ;; `here'.  Go round the next loop each time we pass over such a ")".  These
+  ;; probably match "("s before `here'.
+  (let (pos pa ren+1 lonely-rens)
+    (save-excursion
+      (save-restriction
+       (narrow-to-region (point-min) top) ; This can move point, sometimes.
+       (setq pos here)
+       (c-safe
+         (while
+             (setq ren+1 (scan-lists pos 1 1)) ; might signal
+           (setq lonely-rens (cons ren+1 lonely-rens)
+                 pos ren+1)))))
+
+      ;; PART 2: Scan back before `here' searching for the "("s
+      ;; matching/mismatching the ")"s found above. We only need to direct the
+      ;; caller to scan when we've encountered unmatched right parens.
+      (when lonely-rens
+       (setq pos here)
+       (c-safe
+         (while
+             (and lonely-rens          ; actual values aren't used.
+                  (setq pa (scan-lists pos -1 1)))
+           (setq pos pa)
+           (setq lonely-rens (cdr lonely-rens)))) ;)
+       )
+      pos))
+
+(defun c-parse-state-get-strategy (here good-pos)
+  ;; Determine the scanning strategy for adjusting `c-parse-state', attempting
+  ;; to minimise the amount of scanning.  HERE is the pertinent position in
+  ;; the buffer, GOOD-POS is a position where `c-state-cache' (possibly with
+  ;; its head trimmed) is known to be good, or nil if there is no such
+  ;; position.
+  ;;
+  ;; The return value is a list, one of the following:
+  ;;
+  ;; o - ('forward CACHE-POS START-POINT) - scan forward from START-POINT,
+  ;;                                        which is not less than CACHE-POS.
+  ;; o - ('backward CACHE-POS nil) - scan backwards (from HERE).
+  ;; o - ('BOD nil START-POINT) - scan forwards from START-POINT, which is at the
+  ;;   top level.
+  ;; o - ('IN-LIT nil nil) - point is inside the literal containing point-min.
+  ;; , where CACHE-POS is the highest position recorded in `c-state-cache' at
+  ;; or below HERE.
+  (let ((cache-pos (c-get-cache-scan-pos here))        ; highest position below HERE in cache (or 1)
+       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
+           start-point nil
+           cache-pos nil
+           how-far 0))
+     ((<= good-pos here)
+      (setq strategy 'forward
+           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
+           how-far (- good-pos here)))
+     (t
+      (setq strategy 'forward
+             how-far (- here cache-pos)
+             start-point cache-pos)))
+
+    ;; Might we be better off starting from the top level, two defuns back,
+    ;; instead?
+    (when (> 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
+     (and (memq strategy '(forward backward)) cache-pos)
+     (and (memq strategy '(forward BOD)) start-point))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Routines which change `c-state-cache' and associated values.
+(defun c-renarrow-state-cache ()
+  ;; The region (more precisely, point-min) has changed since we
+  ;; calculated `c-state-cache'.  Amend `c-state-cache' accordingly.
+  (if (< (point-min) c-state-point-min)
+      ;; If point-min has MOVED BACKWARDS then we drop the state completely.
+      ;; It would be possible to do a better job here and recalculate the top
+      ;; only.
+      (progn
+       (c-state-mark-point-min-literal)
+       (setq c-state-cache nil
+             c-state-cache-good-pos c-state-min-scan-pos
+             c-state-brace-pair-desert nil))
+
+    ;; point-min has MOVED FORWARD.
+
+    ;; Is the new point-min inside a (different) literal?
+    (unless (and c-state-point-min-lit-start ; at prev. point-min
+                (< (point-min) (c-state-get-min-scan-pos)))
+      (c-state-mark-point-min-literal))
+
+    ;; Cut off a bit of the tail from `c-state-cache'.
+    (let ((ptr (cons nil c-state-cache))
+         pa)
+      (while (and (setq pa (c-state-cache-top-lparen (cdr ptr)))
+                 (>= pa (point-min)))
+       (setq ptr (cdr ptr)))
+
+      (when (consp ptr)
+       (if (eq (cdr ptr) c-state-cache)
+           (setq c-state-cache nil
+                 c-state-cache-good-pos c-state-min-scan-pos)
+         (setcdr ptr nil)
+         (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen))))
+       )))
+
+  (setq c-state-point-min (point-min)))
+
+(defun c-append-lower-brace-pair-to-state-cache (from &optional upper-lim)
+  ;; If there is a brace pair preceding FROM in the buffer (not necessarily
+  ;; immediately preceding), push a cons onto `c-state-cache' to represent it.
+  ;; FROM must not be inside a literal.  If UPPER-LIM is non-nil, we append
+  ;; the highest brace pair whose "}" is below UPPER-LIM.
+  ;;
+  ;; Return non-nil when this has been done.
+  ;;
+  ;; This routine should be fast.  Since it can get called a LOT, we maintain
+  ;; `c-state-brace-pair-desert', a small cache of "failures", such that we
+  ;; reduce the time wasted in repeated fruitless searches in brace deserts.
+  (save-excursion
+    (save-restriction
+      (let ((bra from) ce              ; Positions of "{" and "}".
+           new-cons
+           (cache-pos (c-state-cache-top-lparen)) ; might be nil.
+           (macro-start-or-from
+            (progn (goto-char from)
+                   (c-beginning-of-macro)
+                   (point))))
+       (or upper-lim (setq upper-lim from))
+
+       ;; If we're essentially repeating a fruitless search, just give up.
+       (unless (and c-state-brace-pair-desert
+                    (eq cache-pos (car c-state-brace-pair-desert))
+                    (<= from (cdr c-state-brace-pair-desert)))
+         ;; Only search what we absolutely need to:
+         (if (and c-state-brace-pair-desert
+                  (> from (cdr c-state-brace-pair-desert)))
+             (narrow-to-region (cdr c-state-brace-pair-desert) (point-max)))
+
+         ;; In the next pair of nested loops, the inner one moves back past a
+         ;; pair of (mis-)matching parens or brackets; the outer one moves
+         ;; back over a sequence of unmatched close brace/paren/bracket each
+         ;; time round.
+         (while
+             (progn
+               (c-safe
+                 (while
+                     (and (setq ce (scan-lists bra -1 -1)) ; back past )/]/}; might signal
+                          (setq bra (scan-lists ce -1 1)) ; back past (/[/{; might signal
+                          (or (> ce upper-lim)
+                              (not (eq (char-after bra) ?\{))
+                              (and (goto-char bra)
+                                   (c-beginning-of-macro)
+                                   (< (point) macro-start-or-from))))))
+               (and ce (< ce bra)))
+           (setq bra ce))      ; If we just backed over an unbalanced closing
+                                       ; brace, ignore it.
+
+         (if (and ce (< bra ce) (eq (char-after bra) ?\{))
+             ;; We've found the desired brace-pair.
+             (progn
+               (setq new-cons (cons bra (1+ ce)))
+               (cond
+                ((consp (car c-state-cache))
+                 (setcar c-state-cache new-cons))
+                ((and (numberp (car c-state-cache)) ; probably never happens
+                      (< ce (car c-state-cache)))
+                 (setcdr c-state-cache
+                         (cons new-cons (cdr c-state-cache))))
+                (t (setq c-state-cache (cons new-cons c-state-cache)))))
+
+           ;; We haven't found a brace pair.  Record this.
+           (setq c-state-brace-pair-desert (cons cache-pos from))))))))
+
+(defsubst c-state-push-any-brace-pair (bra+1 macro-start-or-here)
+  ;; If BRA+1 is nil, do nothing.  Otherwise, BRA+1 is the buffer position
+  ;; following a {, and that brace has a (mis-)matching } (or ]), and we
+  ;; "push" "a" brace pair onto `c-state-cache'.
+  ;;
+  ;; Here "push" means overwrite the top element if it's itself a brace-pair,
+  ;; otherwise push it normally.
+  ;;
+  ;; The brace pair we push is normally the one surrounding BRA+1, but if the
+  ;; latter is inside a macro, not being a macro containing
+  ;; MACRO-START-OR-HERE, we scan backwards through the buffer for a non-macro
+  ;; base pair.  This latter case is assumed to be rare.
+  ;;
+  ;; Note: POINT is not preserved in this routine.
+  (if bra+1
+      (if (or (> bra+1 macro-start-or-here)
+             (progn (goto-char bra+1)
+                    (not (c-beginning-of-macro))))
+         (setq c-state-cache
+               (cons (cons (1- bra+1)
+                           (scan-lists bra+1 1 1))
+                     (if (consp (car c-state-cache))
+                         (cdr c-state-cache)
+                       c-state-cache)))
+       ;; N.B.  This defsubst codes one method for the simple, normal case,
+       ;; and a more sophisticated, slower way for the general case.  Don't
+       ;; eliminate this defsubst - it's a speed optimisation.
+       (c-append-lower-brace-pair-to-state-cache (1- bra+1)))))
+
+(defun c-append-to-state-cache (from)
+  ;; Scan the buffer from FROM to (point-max), adding elements into
+  ;; `c-state-cache' for braces etc.  Return a candidate for
+  ;; `c-state-cache-good-pos'.
+  ;;
+  ;; FROM must be after the latest brace/paren/bracket in `c-state-cache', if
+  ;; any.  Typically, it is immediately after it.  It must not be inside a
+  ;; literal.
+  (let ((here-bol (c-point 'bol (point-max)))
+       (macro-start-or-here
+        (save-excursion (goto-char (point-max))
+                        (if (c-beginning-of-macro)
+                            (point)
+                          (point-max))))
+       pa+1                  ; pos just after an opening PAren (or brace).
+       (ren+1 from)          ; usually a pos just after an closing paREN etc.
+                             ; Is actually the pos. to scan for a (/{/[ from,
+                             ; which sometimes is after a silly )/}/].
+       paren+1               ; Pos after some opening or closing paren.
+       paren+1s              ; A list of `paren+1's; used to determine a
+                             ; good-pos.
+       bra+1 ce+1            ; just after L/R bra-ces.
+       bra+1s                ; list of OLD values of bra+1.
+       mstart)               ; start of a macro.
+
+    (save-excursion
+      ;; Each time round the following loop, we enter a succesively deeper
+      ;; level of brace/paren nesting.  (Except sometimes we "continue at
+      ;; the existing level".)  `pa+1' is a pos inside an opening
+      ;; brace/paren/bracket, usually just after it.
+      (while
+         (progn
+           ;; Each time round the next loop moves forward over an opening then
+           ;; a closing brace/bracket/paren.  This loop is white hot, so it
+           ;; plays ugly tricks to go fast.  DON'T PUT ANYTHING INTO THIS
+           ;; LOOP WHICH ISN'T ABSOLUTELY NECESSARY!!!  It terminates when a
+           ;; call of `scan-lists' signals an error, which happens when there
+           ;; are no more b/b/p's to scan.
+           (c-safe
+             (while t
+               (setq pa+1 (scan-lists ren+1 1 -1) ; Into (/{/[; might signal
+                     paren+1s (cons pa+1 paren+1s))
+               (setq ren+1 (scan-lists pa+1 1 1)) ; Out of )/}/]; might signal
+               (if (and (eq (char-before pa+1) ?{)) ; Check for a macro later.
+                   (setq bra+1 pa+1))
+               (setcar paren+1s ren+1)))
+
+           (if (and pa+1 (> pa+1 ren+1))
+               ;; We've just entered a deeper nesting level.
+               (progn
+                 ;; Insert the brace pair (if present) and the single open
+                 ;; paren/brace/bracket into `c-state-cache' It cannot be
+                 ;; inside a macro, except one around point, because of what
+                 ;; `c-neutralize-syntax-in-CPP' has done.
+                 (c-state-push-any-brace-pair bra+1 macro-start-or-here)
+                 ;; Insert the opening brace/bracket/paren position.
+                 (setq c-state-cache (cons (1- pa+1) c-state-cache))
+                 ;; Clear admin stuff for the next more nested part of the scan.
+                 (setq ren+1 pa+1  pa+1 nil  bra+1 nil  bra+1s nil)
+                 t)                    ; Carry on the loop
+
+             ;; All open p/b/b's at this nesting level, if any, have probably
+             ;; been closed by matching/mismatching ones.  We're probably
+             ;; finished - we just need to check for having found an
+             ;; unmatched )/}/], which we ignore.  Such a )/}/] can't be in a
+             ;; macro, due the action of `c-neutralize-syntax-in-CPP'.
+             (c-safe (setq ren+1 (scan-lists ren+1 1 1)))))) ; acts as loop control.
+
+      ;; Record the final, innermost, brace-pair if there is one.
+      (c-state-push-any-brace-pair bra+1 macro-start-or-here)
+
+      ;; Determine a good pos
+      (while (and (setq paren+1 (car paren+1s))
+                 (> (if (> paren+1 macro-start-or-here)
+                        paren+1
+                      (goto-char paren+1)
+                      (setq mstart (and (c-beginning-of-macro)
+                                        (point)))
+                      (or mstart paren+1))
+                    here-bol))
+       (setq paren+1s (cdr paren+1s)))
+      (cond
+       ((and paren+1 mstart)
+       (min paren+1 mstart))
+       (paren+1)
+       (t from)))))
+
+(defun c-remove-stale-state-cache (good-pos pps-point)
+  ;; Remove stale entries from the `c-cache-state', i.e. those which will
+  ;; not be in it when it is amended for position (point-max).
+  ;; Additionally, the "outermost" open-brace entry before (point-max)
+  ;; will be converted to a cons if the matching close-brace is scanned.
+  ;;
+  ;; GOOD-POS is a "maximal" "safe position" - there must be no open
+  ;; parens/braces/brackets between GOOD-POS and (point-max).
+  ;;
+  ;; As a second thing, calculate the result of parse-partial-sexp at
+  ;; PPS-POINT, w.r.t. GOOD-POS.  The motivation here is that
+  ;; `c-state-cache-good-pos' may become PPS-POINT, but the caller may need to
+  ;; adjust it to get outside a string/comment.  (Sorry about this!  The code
+  ;; needs to be FAST).
+  ;;
+  ;; Return a list (GOOD-POS SCAN-BACK-POS PPS-STATE), where
+  ;; o - GOOD-POS is a position where the new value `c-state-cache' is known
+  ;;   to be good (we aim for this to be as high as possible);
+  ;; o - SCAN-BACK-POS, if not nil, indicates there may be a brace pair
+  ;;   preceding POS which needs to be recorded in `c-state-cache'.  It is a
+  ;;   position to scan backwards from.
+  ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
+  (save-restriction
+    (narrow-to-region 1 (point-max))
+    (save-excursion
+      (let* ((in-macro-start   ; point-max or beginning of macro containing it
+             (save-excursion
+               (goto-char (point-max))
+               (and (c-beginning-of-macro)
+                    (point))))
+            (good-pos-actual-macro-start ; Start of macro containing good-pos
+                                       ; or nil
+             (and (< good-pos (point-max))
+                  (save-excursion
+                    (goto-char good-pos)
+                    (and (c-beginning-of-macro)
+                         (point)))))
+            (good-pos-actual-macro-end ; End of this macro, (maybe
+                                       ; (point-max)), or nil.
+             (and good-pos-actual-macro-start
+                  (save-excursion
+                    (goto-char good-pos-actual-macro-start)
+                    (c-end-of-macro)
+                    (point))))
+            pps-state                  ; Will be 9 or 10 elements long.
+            pos
+            upper-lim     ; ,beyond which `c-state-cache' entries are removed
+            scan-back-pos
+            pair-beg pps-point-state target-depth)
+
+       ;; Remove entries beyond (point-max).  Also remove any entries inside
+       ;; a macro, unless (point-max) is in the same macro.
+       (setq upper-lim
+             (if (or (null c-state-old-cpp-beg)
+                     (and (> (point-max) c-state-old-cpp-beg)
+                          (< (point-max) c-state-old-cpp-end)))
+                 (point-max)
+               (min (point-max) c-state-old-cpp-beg)))
+       (while (and c-state-cache (> (c-state-cache-top-lparen) upper-lim))
+         (setq c-state-cache (cdr c-state-cache)))
+       ;; If `upper-lim' is inside the last recorded brace pair, remove its
+       ;; RBrace and indicate we'll need to search backwards for a previous
+       ;; brace pair.
+       (when (and c-state-cache
+                  (consp (car c-state-cache))
+                  (> (cdar c-state-cache) upper-lim))
+         (setcar c-state-cache (caar c-state-cache))
+         (setq scan-back-pos (car c-state-cache)))
+
+       ;; The next loop jumps forward out of a nested level of parens each
+       ;; time round; the corresponding elements in `c-state-cache' are
+       ;; removed.  `pos' is just after the brace-pair or the open paren at
+       ;; (car c-state-cache).  There can be no open parens/braces/brackets
+       ;; between `good-pos'/`good-pos-actual-macro-start' and (point-max),
+       ;; due to the interface spec to this function.
+       (setq pos (if good-pos-actual-macro-end
+                     (1+ good-pos-actual-macro-end) ; get outside the macro as
+                                       ; marked by a `category' text property.
+                   good-pos))
+       (goto-char pos)
+       (while (and c-state-cache
+                   (< (point) (point-max)))
+         (cond
+          ((null pps-state)            ; first time through
+           (setq target-depth -1))
+          ((eq (car pps-state) target-depth) ; found closing ),},]
+           (setq target-depth (1- (car pps-state))))
+          ;; Do nothing when we've merely reached pps-point.
+          )
+
+         ;; Scan!
+         (setq pps-state
+               (parse-partial-sexp
+                (point) (if (< (point) pps-point) pps-point (point-max))
+                target-depth
+                nil pps-state))
+
+         (if (= (point) pps-point)
+             (setq pps-point-state pps-state))
+
+         (when (eq (car pps-state) target-depth)
+           (setq pos (point))       ; POS is now just after an R-paren/brace.
+           (cond
+            ((and (consp (car c-state-cache))
+                  (eq (point) (cdar c-state-cache)))
+               ;; We've just moved out of the paren pair containing the brace-pair
+               ;; at (car c-state-cache).  `pair-beg' is where the open paren is,
+               ;; and is potentially where the open brace of a cons in
+               ;; c-state-cache will be.
+             (setq pair-beg (car-safe (cdr c-state-cache))
+                   c-state-cache (cdr-safe (cdr c-state-cache)))) ; remove {}pair + containing Lparen.
+            ((numberp (car c-state-cache))
+             (setq pair-beg (car c-state-cache)
+                   c-state-cache (cdr c-state-cache))) ; remove this
+                                       ; containing Lparen
+            ((numberp (cadr c-state-cache))
+             (setq pair-beg (cadr c-state-cache)
+                   c-state-cache (cddr c-state-cache))) ; Remove a paren pair
+                                       ; together with enclosed brace pair.
+            ;; (t nil)                 ; Ignore an unmated Rparen.
+            )))
+
+       (if (< (point) pps-point)
+           (setq pps-state (parse-partial-sexp (point) pps-point
+                                               nil nil ; TARGETDEPTH, STOPBEFORE
+                                               pps-state)))
+
+       ;; If the last paren pair we moved out of was actually a brace pair,
+       ;; insert it into `c-state-cache'.
+       (when (and pair-beg (eq (char-after pair-beg) ?{))
+         (if (consp (car-safe c-state-cache))
+             (setq c-state-cache (cdr c-state-cache)))
+         (setq c-state-cache (cons (cons pair-beg pos)
+                                   c-state-cache)))
+
+       (list pos scan-back-pos pps-state)))))
+
+(defun c-remove-stale-state-cache-backwards (here cache-pos)
+  ;; Strip stale elements of `c-state-cache' by moving backwards through the
+  ;; buffer, and inform the caller of the scenario detected.
+  ;;
+  ;; HERE is the position we're setting `c-state-cache' for.
+  ;; CACHE-POS is just after the latest recorded position in `c-state-cache'
+  ;;   before HERE, or a position at or near point-min which isn't in a
+  ;;   literal.
+  ;;
+  ;; This function must only be called only when (> `c-state-cache-good-pos'
+  ;; HERE).  Usually the gap between CACHE-POS and HERE is large.  It is thus
+  ;; optimised to eliminate (or minimise) scanning between these two
+  ;; positions.
+  ;;
+  ;; Return a three element list (GOOD-POS SCAN-BACK-POS FWD-FLAG), where:
+  ;; o - GOOD-POS is a "good position", where `c-state-cache' is valid, or
+  ;;   could become so after missing elements are inserted into
+  ;;   `c-state-cache'.  This is JUST AFTER an opening or closing
+  ;;   brace/paren/bracket which is already in `c-state-cache' or just before
+  ;;   one otherwise.  exceptionally (when there's no such b/p/b handy) the BOL
+  ;;   before `here''s line, or the start of the literal containing it.
+  ;; o - SCAN-BACK-POS, if non-nil, indicates there may be a brace pair
+  ;;   preceding POS which isn't recorded in `c-state-cache'.  It is a position
+  ;;   to scan backwards from.
+  ;; o - FWD-FLAG, if non-nil, indicates there may be parens/braces between
+  ;;   POS and HERE which aren't recorded in `c-state-cache'.
+  ;;
+  ;; The comments in this defun use "paren" to mean parenthesis or square
+  ;; bracket (as contrasted with a brace), and "(" and ")" likewise.
+  ;;
+  ;;    .   {..} (..) (..)  ( .. {   }  ) (...)    ( ....          .  ..)
+  ;;    |                   |       |   |     |                    |
+  ;;    CP                  E      here D     C                   good
+  (let ((pos c-state-cache-good-pos)
+       pa ren         ; positions of "(" and ")"
+       dropped-cons ; whether the last element dropped from `c-state-cache'
+                    ; was a cons (representing a brace-pair)
+       good-pos                        ; see above.
+       lit         ; (START . END) of a literal containing some point.
+       here-lit-start here-lit-end     ; bounds of literal containing `here'
+                                       ; or `here' itself.
+       (here-bol (c-point 'bol here))
+       (too-far-back (max (- here c-state-cache-too-far) 1)))
+
+    ;; Remove completely irrelevant entries from `c-state-cache'.
+    (while (and c-state-cache
+               (>= (setq pa (c-state-cache-top-lparen)) here))
+      (setq dropped-cons (consp (car c-state-cache)))
+      (setq c-state-cache (cdr c-state-cache))
+      (setq pos pa))
+    ;; At this stage, (> pos here);
+    ;; (< (c-state-cache-top-lparen) here)  (or is nil).
+
+    ;; CASE 1: The top of the cache is a brace pair which now encloses `here'.
+    ;; As good-pos, return the address. of the "{".
+    (if (and (consp (car c-state-cache))
+            (> (cdar c-state-cache) here))
+       ;; Since we've no knowledge of what's inside these braces, we have no
+       ;; alternative but to direct the caller to scan the buffer from the
+       ;; opening brace.
+       (progn
+         (setq pos (caar c-state-cache))
+         (setcar c-state-cache pos)
+         (list (1+ pos) pos t)) ; return value.  We've just converted a brace
+                                ; pair entry into a { entry, so the caller
+                                ; needs to search for a brace pair before the
+                                ; {.
+
+      ;; ;; `here' might be inside a literal.  Check for this.
+      (setq lit (c-state-literal-at here)
+           here-lit-start (or (car lit) here)
+           here-lit-end (or (cdr lit) here))
+
+      ;; `here' might be nested inside any depth of parens (or brackets but
+      ;; not braces).  Scan backwards to find the outermost such opening
+      ;; paren, if there is one.  This will be the scan position to return.
+      (save-restriction
+       (narrow-to-region cache-pos (point-max))
+       (setq pos (c-state-balance-parens-backwards here-lit-end pos)))
+
+      (if (< pos here-lit-start)
+         ;; CASE 2: Address of outermost ( or [ which now encloses `here',
+         ;; but didn't enclose the (previous) `c-state-cache-good-pos'.  If
+         ;; there is a brace pair preceding this, it will already be in
+         ;; `c-state-cache', unless there was a brace pair after it,
+         ;; i.e. there'll only be one to scan for if we've just deleted one.
+         (list pos (and dropped-cons pos) t) ; Return value.
+
+       ;; `here' isn't enclosed in a (previously unrecorded) bracket/paren.
+       ;; Further forward scanning isn't needed, but we still need to find a
+       ;; GOOD-POS.  Step out of all enclosing "("s on HERE's line.
+       (save-restriction
+         (narrow-to-region here-bol (point-max))
+         (setq pos here-lit-start)
+         (c-safe (while (setq pa (scan-lists pos -1 1))
+                   (setq pos pa))))    ; might signal
+       (if (setq ren (c-safe-scan-lists pos -1 -1 too-far-back))
+           ;; CASE 3: After a }/)/] before `here''s BOL.
+           (list (1+ ren) (and dropped-cons pos) nil) ; Return value
+
+         ;; CASE 4; Best of a bad job: BOL before `here-bol', or beginning of
+         ;; literal containing it.
+         (setq good-pos (c-state-lit-beg (c-point 'bopl here-bol)))
+         (list good-pos (and dropped-cons good-pos) nil))))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Externally visible routines.
+
+(defun c-state-cache-init ()
+  (setq c-state-cache nil
+       c-state-cache-good-pos 1
+       c-state-nonlit-pos-cache nil
+       c-state-nonlit-pos-cache-limit 1
+       c-state-brace-pair-desert nil
+       c-state-point-min 1
+       c-state-point-min-lit-type nil
+       c-state-point-min-lit-start nil
+       c-state-min-scan-pos 1
+       c-state-old-cpp-beg nil
+       c-state-old-cpp-end nil)
+  (c-state-mark-point-min-literal))
+
+(defun c-invalidate-state-cache-1 (here)
+  ;; Invalidate all info on `c-state-cache' that applies to the buffer at HERE
+  ;; or higher and set `c-state-cache-good-pos' accordingly.  The cache is
+  ;; left in a consistent state.
+  ;;
+  ;; This is much like `c-whack-state-after', but it never changes a paren
+  ;; 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.
+
+  ;; The cache of non-literals:
+  (if (< here c-state-nonlit-pos-cache-limit)
+      (setq c-state-nonlit-pos-cache-limit here))
+
+  ;; `c-state-cache':
+  ;; Case 1: if `here' is in a literal containing point-min, everything
+  ;; becomes (or is already) nil.
+  (if (or (null c-state-cache-good-pos)
+         (< here (c-state-get-min-scan-pos)))
+      (setq c-state-cache nil
+           c-state-cache-good-pos nil
+           c-state-min-scan-pos nil)
+
+;;; 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 ((here-bol (c-point 'bol here))
+         too-high-pa             ; recorded {/(/[ next above 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'.
+      (while (and c-state-cache
+                 (>= (setq pa (c-state-cache-top-paren)) here))
+       (setq dropped-cons (consp (car c-state-cache))
+             too-high-pa (c-state-cache-top-lparen)
+             c-state-cache (cdr c-state-cache)))
+
+      ;; 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)))
+         (c-append-lower-brace-pair-to-state-cache too-high-pa here-bol))
+      (setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
+                                      (c-state-get-min-scan-pos)))))
+
+  ;; The brace-pair desert marker:
+  (when (car c-state-brace-pair-desert)
+    (if (< here (car c-state-brace-pair-desert))
+       (setq c-state-brace-pair-desert nil)
+      (if (< here (cdr c-state-brace-pair-desert))
+         (setcdr c-state-brace-pair-desert here)))))
+
+(defun c-parse-state-1 ()
+  ;; Find and record all noteworthy parens between some good point earlier in
+  ;; the file and point.  That good point is at least the beginning of the
+  ;; top-level construct we are in, or the beginning of the preceding
+  ;; top-level construct if we aren't in one.
+  ;;
+  ;; The returned value is a list of the noteworthy parens with the last one
+  ;; first.  If an element in the list is an integer, it's the position of an
+  ;; open paren (of any type) which has not been closed before the point.  If
+  ;; an element is a cons, it gives the position of a closed BRACE paren
+  ;; pair[*]; the car is the start brace position and the cdr is the position
+  ;; following the closing brace.  Only the last closed brace paren pair
+  ;; before each open paren and before the point is recorded, and thus the
+  ;; state never contains two cons elements in succession.  When a close brace
+  ;; has no matching open brace (e.g., the matching brace is outside the
+  ;; visible region), it is not represented in the returned value.
+  ;;
+  ;; [*] N.B. The close "brace" might be a mismatching close bracket or paren.
+  ;; This defun explicitly treats mismatching parens/braces/brackets as
+  ;; matching.  It is the open brace which makes it a "brace" pair.
+  ;;
+  ;; If POINT is within a macro, open parens and brace pairs within
+  ;; THIS macro MIGHT be recorded.  This depends on whether their
+  ;; syntactic properties have been suppressed by
+  ;; `c-neutralize-syntax-in-CPP'.  This might need fixing (2008-12-11).
   ;;
   ;; Currently no characters which are given paren syntax with the
   ;; syntax-table property are recorded, i.e. angle bracket arglist
   ;; parens are never present here.  Note that this might change.
   ;;
   ;; BUG: This function doesn't cope entirely well with unbalanced
-  ;; parens in macros.  E.g. in the following case the brace before
-  ;; the macro isn't balanced with the one after it:
+  ;; parens in macros.  (2008-12-11: this has probably been resolved
+  ;; by the function `c-neutralize-syntax-in-CPP'.)  E.g. in the
+  ;; following case the brace before the macro isn't balanced with the
+  ;; one after it:
   ;;
   ;;     {
   ;;     #define X {
   ;;     }
   ;;
+  ;; Note to maintainers: this function DOES get called with point
+  ;; within comments and strings, so don't assume it doesn't!
+  ;;
   ;; This function might do hidden buffer changes.
+  (let* ((here (point))
+        (here-bopl (c-point 'bopl))
+        strategy            ; 'forward, 'backward etc..
+        ;; Candidate positions to start scanning from:
+        cache-pos           ; highest position below HERE already existing in
+                            ; cache (or 1).
+        good-pos
+        start-point
+        bopl-state
+        res
+        scan-backward-pos scan-forward-p) ; used for 'backward.
+    ;; If POINT-MIN has changed, adjust the cache
+    (unless (= (point-min) c-state-point-min)
+      (c-renarrow-state-cache))
+
+    ;; Strategy?
+    (setq res (c-parse-state-get-strategy here c-state-cache-good-pos)
+         strategy (car res)
+         cache-pos (cadr res)
+         start-point (nth 2 res))
+
+    (when (eq strategy 'BOD)
+      (setq c-state-cache nil
+           c-state-cache-good-pos start-point))
+
+    ;; SCAN!
+    (save-restriction
+      (cond
+       ((memq strategy '(forward BOD))
+       (narrow-to-region (point-min) here)
+       (setq res (c-remove-stale-state-cache start-point here-bopl))
+       (setq cache-pos (car res)
+             scan-backward-pos (cadr res)
+             bopl-state (car (cddr res))) ; will be nil if (< here-bopl
+                                       ; start-point)
+       (if scan-backward-pos
+           (c-append-lower-brace-pair-to-state-cache scan-backward-pos))
+       (setq good-pos
+             (c-append-to-state-cache cache-pos))
+       (setq c-state-cache-good-pos
+             (if (and bopl-state
+                      (< good-pos (- here c-state-cache-too-far)))
+                 (c-state-cache-non-literal-place here-bopl bopl-state)
+               good-pos)))
+
+       ((eq strategy 'backward)
+       (setq res (c-remove-stale-state-cache-backwards here cache-pos)
+             good-pos (car res)
+             scan-backward-pos (cadr res)
+             scan-forward-p (car (cddr res)))
+       (if scan-backward-pos
+           (c-append-lower-brace-pair-to-state-cache
+            scan-backward-pos))
+       (setq c-state-cache-good-pos
+             (if scan-forward-p
+                 (progn (narrow-to-region (point-min) here)
+                        (c-append-to-state-cache good-pos))
+
+               (c-get-cache-scan-pos good-pos))))
+
+       (t ; (eq strategy 'IN-LIT)
+       (setq c-state-cache nil
+             c-state-cache-good-pos nil)))))
+
+  c-state-cache)
+
+(defun c-invalidate-state-cache (here)
+  ;; This is a wrapper over `c-invalidate-state-cache-1'.
+  ;;
+  ;; It suppresses the syntactic effect of the < and > (template) brackets and
+  ;; of all parens in preprocessor constructs, except for any such construct
+  ;; containing point.  We can then call `c-invalidate-state-cache-1' without
+  ;; worrying further about macros and template delimiters.
+  (c-with-<->-as-parens-suppressed
+   (if (and c-state-old-cpp-beg
+           (< c-state-old-cpp-beg here))
+       (c-with-all-but-one-cpps-commented-out
+       c-state-old-cpp-beg
+       (min c-state-old-cpp-end here)
+       (c-invalidate-state-cache-1 here))
+     (c-with-cpps-commented-out
+      (c-invalidate-state-cache-1 here)))))
 
-  (save-restriction
-    (let* ((here (point))
-          (here-bol (c-point 'bol))
-          (c-macro-start (c-query-macro-start))
-          (in-macro-start (or c-macro-start (point)))
-          old-state last-pos brace-pair-open brace-pair-close
-          pos save-pos)
-      (c-invalidate-state-cache here)
-
-      ;; If the minimum position has changed due to narrowing then we
-      ;; have to fix the tail of `c-state-cache' accordingly.
-      (unless (= c-state-cache-start (point-min))
-       (if (> (point-min) c-state-cache-start)
-           ;; If point-min has moved forward then we just need to cut
-           ;; off a bit of the tail.
-           (let ((ptr (cons nil c-state-cache)) elem)
-             (while (and (setq elem (car-safe (cdr ptr)))
-                         (>= (if (consp elem) (car elem) elem)
-                             (point-min)))
-               (setq ptr (cdr ptr)))
-             (when (consp ptr)
-               (if (eq (cdr ptr) c-state-cache)
-                   (setq c-state-cache nil
-                         c-state-cache-good-pos 1)
-                 (setcdr ptr nil))))
-         ;; If point-min has moved backward then we drop the state
-         ;; completely.  It's possible to do a better job here and
-         ;; recalculate the top only.
-         (setq c-state-cache nil
-               c-state-cache-good-pos 1))
-       (setq c-state-cache-start (point-min)))
-
-      ;; Get the latest position we know are directly inside the
-      ;; closest containing paren of the cached state.
-      (setq last-pos (and c-state-cache
-                         (if (consp (car c-state-cache))
-                             (cdr (car c-state-cache))
-                           (1+ (car c-state-cache)))))
-      (if (or (not last-pos)
-             (< last-pos c-state-cache-good-pos))
-         (setq last-pos c-state-cache-good-pos)
-       ;; Take the opportunity to move the cached good position
-       ;; further down.
-       (if (< last-pos here-bol)
-           (setq c-state-cache-good-pos last-pos)))
+(defun c-parse-state ()
+  ;; This is a wrapper over `c-parse-state-1'.  See that function for a
+  ;; description of the functionality and return value.
+  ;;
+  ;; It suppresses the syntactic effect of the < and > (template) brackets and
+  ;; of all parens in preprocessor constructs, except for any such construct
+  ;; containing point.  We can then call `c-parse-state-1' without worrying
+  ;; further about macros and template delimiters.
+  (let (here-cpp-beg here-cpp-end)
+    (save-excursion
+      (when (c-beginning-of-macro)
+       (setq here-cpp-beg (point))
+       (unless
+           (> (setq here-cpp-end (c-syntactic-end-of-macro))
+              here-cpp-beg)
+         (setq here-cpp-beg nil  here-cpp-end nil))))
+    ;; FIXME!!! Put in a `condition-case' here to protect the integrity of the
+    ;; subsystem.
+    (prog1
+       (c-with-<->-as-parens-suppressed
+        (if (and here-cpp-beg (> here-cpp-end here-cpp-beg))
+            (c-with-all-but-one-cpps-commented-out
+             here-cpp-beg here-cpp-end
+             (c-parse-state-1))
+          (c-with-cpps-commented-out
+           (c-parse-state-1))))
+      (setq c-state-old-cpp-beg (and here-cpp-beg (copy-marker here-cpp-beg t))
+           c-state-old-cpp-end (and here-cpp-end (copy-marker here-cpp-end t)))
+      )))
 
-      ;; Check if `last-pos' is in a macro.  If it is, and we're not
-      ;; in the same macro, we must discard everything on
-      ;; `c-state-cache' that is inside the macro before using it.
-      (save-excursion
-       (goto-char last-pos)
-       (when (and (c-beginning-of-macro)
-                  (/= (point) in-macro-start))
-         (c-invalidate-state-cache (point))
-         ;; Set `last-pos' again just like above except that there's
-         ;; no use looking at `c-state-cache-good-pos' here.
-         (setq last-pos (if c-state-cache
-                            (if (consp (car c-state-cache))
-                                (cdr (car c-state-cache))
-                              (1+ (car c-state-cache)))
-                          1))))
-
-      ;; If we've moved very far from the last cached position then
-      ;; it's probably better to redo it from scratch, otherwise we
-      ;; might spend a lot of time searching from `last-pos' down to
-      ;; here.
-      (when (< last-pos (- here 20000))
-       ;; First get the fallback start position.  If it turns out
-       ;; that it's so far back that the cached state is closer then
-       ;; we'll keep it afterall.
-       (setq pos (c-get-fallback-start-pos here))
-       (if (<= pos last-pos)
-           (setq pos nil)
-         (setq last-pos nil
-               c-state-cache nil
-               c-state-cache-good-pos 1)))
-
-      ;; Find the start position for the forward search.  (Can't
-      ;; search in the backward direction since the point might be in
-      ;; some kind of literal.)
-
-      (unless pos
-       (setq old-state c-state-cache)
-
-       ;; There's a cached state with a containing paren.  Pop off
-       ;; the stale containing sexps from it by going forward out of
-       ;; parens as far as possible.
-       (narrow-to-region (point-min) here)
-       (let (placeholder pair-beg)
-         (while (and c-state-cache
-                     (setq placeholder
-                           (c-up-list-forward last-pos)))
-           (setq last-pos placeholder)
-           (if (consp (car c-state-cache))
-               (setq pair-beg (car-safe (cdr c-state-cache))
-                     c-state-cache (cdr-safe (cdr c-state-cache)))
-             (setq pair-beg (car c-state-cache)
-                   c-state-cache (cdr c-state-cache))))
-
-         (when (and pair-beg (eq (char-after pair-beg) ?{))
-           ;; The last paren pair we moved out from was a brace
-           ;; pair.  Modify the state to record this as a closed
-           ;; pair now.
-           (if (consp (car-safe c-state-cache))
-               (setq c-state-cache (cdr c-state-cache)))
-           (setq c-state-cache (cons (cons pair-beg last-pos)
-                                     c-state-cache))))
-
-       ;; Check if the preceding balanced paren is within a
-       ;; macro; it should be ignored if we're outside the
-       ;; macro.  There's no need to check any further upwards;
-       ;; if the macro contains an unbalanced opening paren then
-       ;; we're smoked anyway.
-       (when (and (<= (point) in-macro-start)
-                  (consp (car c-state-cache)))
-         (save-excursion
-           (goto-char (car (car c-state-cache)))
-           (when (c-beginning-of-macro)
-             (setq here (point)
-                   c-state-cache (cdr c-state-cache)))))
-
-       (unless (eq c-state-cache old-state)
-         ;; Have to adjust the cached good position if state has been
-         ;; popped off.
-         (setq c-state-cache-good-pos
-               (if c-state-cache
-                   (if (consp (car c-state-cache))
-                       (cdr (car c-state-cache))
-                     (1+ (car c-state-cache)))
-                 1)
-               old-state c-state-cache))
-
-       (when c-state-cache
-         (setq pos last-pos)))
-
-      ;; Get the fallback start position.
-      (unless pos
-       (setq pos (c-get-fallback-start-pos here)
-             c-state-cache nil
-             c-state-cache-good-pos 1))
-
-      (narrow-to-region (point-min) here)
-
-      (while pos
-       (setq save-pos pos
-             brace-pair-open nil)
-
-       ;; Find the balanced brace pairs.  This loop is hot, so it
-       ;; does ugly tricks to go faster.
-       (c-safe
-         (let (set-good-pos set-brace-pair)
-           (while t
-             (setq last-pos nil
-                   last-pos (scan-lists pos 1 -1)) ; Might signal.
-             (setq pos (scan-lists last-pos 1 1) ; Might signal.
-                   set-good-pos (< pos here-bol)
-                   set-brace-pair (eq (char-before last-pos) ?{))
-
-             ;; Update the cached good position and record the brace
-             ;; pair, whichever is applicable for the paren we've
-             ;; just jumped over.  But first check that it isn't
-             ;; inside a macro and the point isn't inside the same
-             ;; one.
-             (when (and (or set-good-pos set-brace-pair)
-                        (or (>= pos in-macro-start)
-                            (save-excursion
-                              (goto-char pos)
-                              (not (c-beginning-of-macro)))))
-               (if set-good-pos
-                   (setq c-state-cache-good-pos pos))
-               (if set-brace-pair
-                   (setq brace-pair-open last-pos
-                         brace-pair-close pos))))))
-
-       ;; Record the last brace pair.
-       (when brace-pair-open
-         (let ((head (car-safe c-state-cache)))
-           (if (consp head)
-               (progn
-                 (setcar head (1- brace-pair-open))
-                 (setcdr head brace-pair-close))
-             (setq c-state-cache (cons (cons (1- brace-pair-open)
-                                             brace-pair-close)
-                                       c-state-cache)))))
-
-       (if last-pos
-           ;; Prepare to loop, but record the open paren only if it's
-           ;; outside a macro or within the same macro as point, and
-           ;; if it is a legitimate open paren and not some character
-           ;; that got an open paren syntax-table property.
-           (progn
-             (setq pos last-pos)
-             (when (and (or (>= last-pos in-macro-start)
-                            (save-excursion
-                              (goto-char last-pos)
-                              (not (c-beginning-of-macro))))
-                        ;; Check for known types of parens that we
-                        ;; want to record.  The syntax table is not to
-                        ;; be trusted here since the caller might be
-                        ;; using e.g. `c++-template-syntax-table'.
-                        (memq (char-before last-pos) '(?{ ?\( ?\[)))
-               (if (< last-pos here-bol)
-                   (setq c-state-cache-good-pos last-pos))
-               (setq c-state-cache (cons (1- last-pos) c-state-cache))))
-
-         (if (setq last-pos (c-up-list-forward pos))
-             ;; Found a close paren without a corresponding opening
-             ;; one.  Maybe we didn't go back far enough, so try to
-             ;; scan backward for the start paren and then start over.
-             (progn
-               (setq pos (c-up-list-backward pos)
-                     c-state-cache nil
-                     c-state-cache-good-pos c-state-cache-start)
-               (when (or (not pos)
-                         ;; Emacs (up to at least 21.2) can get confused by
-                         ;; open parens in column zero inside comments: The
-                         ;; sexp functions can then misbehave and bring us
-                         ;; back to the same point again.  Check this so that
-                         ;; we don't get an infinite loop.
-                         (>= pos save-pos))
-                 (setq pos last-pos
-                       c-parsing-error
-                       (format "Unbalanced close paren at line %d"
-                               (1+ (count-lines (point-min)
-                                                (c-point 'bol last-pos)))))))
-           (setq pos nil))))
-
-      ;;(message "c-parse-state: %S end: %S" c-state-cache c-state-cache-good-pos)
-      c-state-cache)))
-
-;; Debug tool to catch cache inconsistencies.
+;; Debug tool to catch cache inconsistencies.  This is called from
+;; 000tests.el.
 (defvar c-debug-parse-state nil)
 (unless (fboundp 'c-real-parse-state)
   (fset 'c-real-parse-state (symbol-function 'c-parse-state)))
 (cc-bytecomp-defun c-real-parse-state)
 (defun c-debug-parse-state ()
-  (let ((res1 (c-real-parse-state)) res2)
+  (let ((here (point)) (res1 (c-real-parse-state)) res2)
     (let ((c-state-cache nil)
-         (c-state-cache-start 1)
-         (c-state-cache-good-pos 1))
+         (c-state-cache-good-pos 1)
+         (c-state-nonlit-pos-cache nil)
+         (c-state-nonlit-pos-cache-limit 1)
+         (c-state-brace-pair-desert nil)
+         (c-state-point-min 1)
+         (c-state-point-min-lit-type nil)
+         (c-state-point-min-lit-start nil)
+         (c-state-min-scan-pos 1)
+         (c-state-old-cpp-beg nil)
+         (c-state-old-cpp-end nil))
       (setq res2 (c-real-parse-state)))
     (unless (equal res1 res2)
       ;; The cache can actually go further back due to the ad-hoc way
@@ -2282,10 +3065,11 @@ comment at the start of cc-engine.el for more info."
        (while (not (or (bobp) (eq (char-after) ?{)))
          (c-beginning-of-defun-1))
        (unless (equal (c-whack-state-before (point) res1) res2)
-         (message (concat "c-parse-state inconsistency: "
+         (message (concat "c-parse-state inconsistency at %s: "
                           "using cache: %s, from scratch: %s")
-                  res1 res2))))
+                  here res1 res2))))
     res1))
+
 (defun c-toggle-parse-state-debug (&optional arg)
   (interactive "P")
   (setq c-debug-parse-state (c-calculate-state arg c-debug-parse-state))
@@ -2296,6 +3080,7 @@ comment at the start of cc-engine.el for more info."
 (when c-debug-parse-state
   (c-toggle-parse-state-debug 1))
 
+\f
 (defun c-whack-state-before (bufpos paren-state)
   ;; Whack off any state information from PAREN-STATE which lies
   ;; before BUFPOS.  Not destructive on PAREN-STATE.
@@ -2510,7 +3295,7 @@ comment at the start of cc-engine.el for more info."
   ;; Move to the beginning of the current token.  Do not move if not
   ;; in the middle of one.  BACK-LIMIT may be used to bound the
   ;; backward search; if given it's assumed to be at the boundary
-  ;; between two tokens.  Return non-nil if the point is move, nil
+  ;; between two tokens.  Return non-nil if the point is moved, nil
   ;; otherwise.
   ;;
   ;; This function might do hidden buffer changes.
@@ -2961,6 +3746,59 @@ comment at the start of cc-engine.el for more info."
        (goto-char bound))
       nil)))
 
+(defvar safe-pos-list)           ; bound in c-syntactic-skip-backward
+
+(defsubst c-ssb-lit-begin ()
+  ;; Return the start of the literal point is in, or nil.
+  ;; We read and write the variables `safe-pos', `safe-pos-list', `state'
+  ;; bound in the caller.
+
+  ;; Use `parse-partial-sexp' from a safe position down to the point to check
+  ;; if it's outside comments and strings.
+  (save-excursion
+    (let ((pos (point)) safe-pos state pps-end-pos)
+      ;; Pick a safe position as close to the point as possible.
+      ;;
+      ;; FIXME: Consult `syntax-ppss' here if our cache doesn't give a good
+      ;; position.
+
+      (while (and safe-pos-list
+                 (> (car safe-pos-list) (point)))
+       (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)))
+                               0)
+                           (point-min))
+             safe-pos-list (list safe-pos)))
+
+      ;; Cache positions along the way to use if we have to back up more.  We
+      ;; cache every closing paren on the same level.  If the paren cache is
+      ;; relevant in this region then we're typically already on the same
+      ;; level as the target position.  Note that we might cache positions
+      ;; after opening parens in case safe-pos is in a nested list.  That's
+      ;; both uncommon and harmless.
+      (while (progn
+              (setq state (parse-partial-sexp
+                           safe-pos pos 0))
+              (< (point) pos))
+       (setq safe-pos (point)
+             safe-pos-list (cons safe-pos safe-pos-list)))
+
+      ;; If the state contains the start of the containing sexp we cache that
+      ;; position too, so that parse-partial-sexp in the next run has a bigger
+      ;; chance of starting at the same level as the target position and thus
+      ;; will get more good safe positions into the list.
+      (if (elt state 1)
+         (setq safe-pos (1+ (elt state 1))
+               safe-pos-list (cons safe-pos safe-pos-list)))
+
+      (if (or (elt state 3) (elt state 4))
+         ;; Inside string or comment.  Continue search at the
+         ;; beginning of it.
+         (elt state 8)))))
+
 (defun c-syntactic-skip-backward (skip-chars &optional limit paren-level)
   "Like `skip-chars-backward' but only look at syntactically relevant chars,
 i.e. don't stop at positions inside syntactic whitespace or string
@@ -2979,140 +3817,100 @@ 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
+       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.
+       ;; each position.  Used in `c-ssb-lit-begin'
        safe-pos-list
-       ;; The position at the beginning of `safe-pos-list'.
-       safe-pos
        ;; 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
-            (while (and
-                    (< (skip-chars-backward skip-chars limit) 0)
-
-                    ;; Use `parse-partial-sexp' from a safe position down to
-                    ;; the point to check if it's outside comments and
-                    ;; strings.
-                    (let ((pos (point)) state-2 pps-end-pos)
-                      ;; Pick a safe position as close to the point as
-                      ;; possible.
-                      ;;
-                      ;; FIXME: Consult `syntax-ppss' here if our
-                      ;; cache doesn't give a good position.
-                      (while (and safe-pos-list
-                                  (> (car safe-pos-list) (point)))
-                        (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)))
-                                                0)
-                                            (point-min))
-                              safe-pos-list (list safe-pos)))
-
-                      ;; Cache positions along the way to use if we have to
-                      ;; back up more.  We cache every closing paren on the
-                      ;; same level.  If the paren cache is relevant in this
-                      ;; region then we're typically already on the same
-                      ;; level as the target position.  Note that we might
-                      ;; cache positions after opening parens in case
-                      ;; safe-pos is in a nested list.  That's both uncommon
-                      ;; and harmless.
-                      (while (progn
-                               (setq state (parse-partial-sexp
-                                            safe-pos pos 0))
-                               (< (point) pos))
-                        (setq safe-pos (point)
-                              safe-pos-list (cons safe-pos safe-pos-list)))
-
-                      (cond
-                       ((or (elt state 3) (elt state 4))
-                        ;; Inside string or comment.  Continue search at the
-                        ;; beginning of it.
-                        (goto-char (elt state 8))
-                        t)
-
-                       ((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
+    (while
+       (progn
+         ;; The next loop "tries" to find the end point each time round,
+         ;; loops when it hasn't succeeded.
+         (while
+             (and
+              (< (skip-chars-backward skip-chars limit) 0)
+
+              (let ((pos (point)) state-2 pps-end-pos)
+
+                (cond
+                 ;; Don't stop inside a literal
+                 ((setq lit-beg (c-ssb-lit-begin))
+                  (goto-char lit-beg)
+                  t)
+
+                 ((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 (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)))))
-
-              ;; If the state contains the start of the containing sexp we
-              ;; cache that position too, so that parse-partial-sexp in the
-              ;; next run has a bigger chance of starting at the same level
-              ;; as the target position and thus will get more good safe
-              ;; positions into the list.
-              (if (elt state 1)
-                  (setq safe-pos (1+ (elt state 1))
-                        safe-pos-list (cons safe-pos safe-pos-list))))
-
-            (> (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)))))
+                                  (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.
@@ -3291,7 +4089,7 @@ comment at the start of cc-engine.el for more info."
 ;; The workaround for this is for the AWK Mode initialisation to switch the
 ;; defalias for c-in-literal to c-slow-in-literal.  This will slow down other
 ;; cc-modes in Xemacs whenever an awk-buffer has been initialised.
-;; 
+;;
 ;; (Alan Mackenzie, 2003/4/30).
 
 (defun c-fast-in-literal (&optional lim detect-cpp)
@@ -3320,7 +4118,7 @@ literal next to point is returned.  \"Next to\" means there's only
 spaces and tabs between point and the literal.  The search for such a
 literal is done first in forward direction.  If NOT-IN-DELIMITER is
 non-nil, the case when point is inside a starting delimiter won't be
-recognized.  This only has effect for comments, which have starting
+recognized.  This only has effect for comments which have starting
 delimiters with more than one character.
 
 Note that this function might do hidden buffer changes.  See the
@@ -3406,7 +4204,7 @@ comment at the start of cc-engine.el for more info."
        (if (and (consp range) (progn
                                 (goto-char (car range))
                                 (looking-at c-line-comment-starter)))
-           (let ((col (current-column)) 
+           (let ((col (current-column))
                  (beg (point))
                  (bopl (c-point 'bopl))
                  (end (cdr range)))
@@ -3430,9 +4228,10 @@ comment at the start of cc-engine.el for more info."
 
 (defun c-literal-type (range)
   "Convenience function that given the result of `c-literal-limits',
-returns nil or the type of literal that the range surrounds.  It's
-much faster than using `c-in-literal' and is intended to be used when
-you need both the type of a literal and its limits.
+returns nil or the type of literal that the range surrounds, one
+of the symbols 'c, 'c++ or 'string.  It's much faster than using
+`c-in-literal' and is intended to be used when you need both the
+type of a literal and its limits.
 
 Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
@@ -3582,14 +4381,23 @@ comment at the start of cc-engine.el for more info."
 
 (defun c-find-decl-spots (cfd-limit cfd-decl-re cfd-face-checklist cfd-fun)
   ;; Call CFD-FUN for each possible spot for a declaration, cast or
-  ;; label from the point to CFD-LIMIT.  Such a spot is:
+  ;; label from the point to CFD-LIMIT.
+  ;;
+  ;; CFD-FUN is called with point at the start of the spot.  It's
+  ;; passed two arguments: The first is the end position of the token
+  ;; preceding the spot, or 0 for the implicit match at bob.  The
+  ;; second is a flag that is t when the match is inside a macro.  If
+  ;; CFD-FUN adds `c-decl-end' properties somewhere below the current
+  ;; spot, it should return non-nil to ensure that the next search
+  ;; will find them.
   ;;
+  ;; Such a spot is:
   ;; o  The first token after bob.
   ;; o  The first token after the end of submatch 1 in
   ;;    `c-decl-prefix-or-start-re' when that submatch matches.
   ;; o  The start of each `c-decl-prefix-or-start-re' match when
   ;;    submatch 1 doesn't match.
-  ;; o  The first token after the end of each occurence of the
+  ;; o  The first token after the end of each occurrence of the
   ;;    `c-type' text property with the value `c-decl-end', provided
   ;;    `c-type-decl-end-used' is set.
   ;;
@@ -3603,14 +4411,6 @@ comment at the start of cc-engine.el for more info."
   ;; outside it.  It's to avoid this work that the CFD-DECL-RE and
   ;; CFD-FACE-CHECKLIST checks exist.
   ;;
-  ;; CFD-FUN is called with point at the start of the spot.  It's
-  ;; passed two arguments: The first is the end position of the token
-  ;; preceding the spot, or 0 for the implicit match at bob.  The
-  ;; second is a flag that is t when the match is inside a macro.  If
-  ;; CFD-FUN adds `c-decl-end' properties somewhere below the current
-  ;; spot, it should return non-nil to ensure that the next search
-  ;; will find them.
-  ;;
   ;; The spots are visited approximately in order from top to bottom.
   ;; It's however the positions where `c-decl-prefix-or-start-re'
   ;; matches and where `c-decl-end' properties are found that are in
@@ -4035,6 +4835,9 @@ comment at the start of cc-engine.el for more info."
              c-found-types)
     (sort type-list 'string-lessp)))
 
+;; Shut up the byte compiler.
+(defvar c-maybe-stale-found-type)
+
 (defun c-trim-found-types (beg end old-len)
   ;; An after change function which, in conjunction with the info in
   ;; c-maybe-stale-found-type (set in c-before-change), removes a type
@@ -4042,7 +4845,7 @@ comment at the start of cc-engine.el for more info."
   ;; example, this happens to "foo" when "foo \n bar();" becomes
   ;; "foo(); \n bar();".  Such stale types, if not removed, foul up
   ;; the fontification.
-  ;; 
+  ;;
   ;; Have we, perhaps, added non-ws characters to the front/back of a found
   ;; type?
   (when (> end beg)
@@ -4061,7 +4864,7 @@ comment at the start of cc-engine.el for more info."
                        (c-beginning-of-current-token)))
            (c-unfind-type (buffer-substring-no-properties
                            (point) beg))))))
-           
+
   (if c-maybe-stale-found-type ; e.g. (c-decl-id-start "foo" 97 107 " (* ooka) " "o")
       (cond
        ;; Changing the amount of (already existing) whitespace - don't do anything.
@@ -4077,7 +4880,168 @@ comment at the start of cc-engine.el for more info."
        )))
 
 \f
-;; Handling of small scale constructs like types and names.
+;; Setting and removing syntax properties on < and > in languages (C++
+;; and Java) where they can be template/generic delimiters as well as
+;; their normal meaning of "less/greater than".
+
+;; Normally, < and > have syntax 'punctuation'.  When they are found to
+;; be delimiters, they are marked as such with the category properties
+;; c-<-as-paren-syntax, c->-as-paren-syntax respectively.
+
+;; STRATEGY:
+;;
+;; It is impossible to determine with certainty whether a <..> pair in
+;; C++ is two comparison operators or is template delimiters, unless
+;; one duplicates a lot of a C++ compiler.  For example, the following
+;; code fragment:
+;;
+;;     foo (a < b, c > d) ;
+;;
+;; could be a function call with two integer parameters (each a
+;; relational expression), or it could be a constructor for class foo
+;; taking one parameter d of templated type "a < b, c >".  They are
+;; somewhat easier to distinguish in Java.
+;;
+;; The strategy now (2010-01) adopted is to mark and unmark < and
+;; > IN MATCHING PAIRS ONLY.  [Previously, they were marked
+;; individually when their context so indicated.  This gave rise to
+;; intractible problems when one of a matching pair was deleted, or
+;; pulled into a literal.]
+;;
+;; At each buffer change, the syntax-table properties are removed in a
+;; before-change function and reapplied, when needed, in an
+;; after-change function.  It is far more important that the
+;; properties get removed when they they are spurious than that they
+;; be present when wanted.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun c-clear-<-pair-props (&optional pos)
+  ;; POS (default point) is at a < character.  If it is marked with
+  ;; open paren syntax-table text property, remove the property,
+  ;; together with the close paren property on the matching > (if
+  ;; any).
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c-<-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-list-forward))
+      (when (equal (c-get-char-property (1- (point)) 'syntax-table)
+                  c->-as-paren-syntax) ; should always be true.
+       (c-clear-char-property (1- (point)) 'syntax-table))
+      (c-clear-char-property pos 'syntax-table))))
+
+(defun c-clear->-pair-props (&optional pos)
+  ;; POS (default point) is at a > character.  If it is marked with
+  ;; close paren syntax-table property, remove the property, together
+  ;; with the open paren property on the matching < (if any).
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c->-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-up-list-backward))
+      (when (equal (c-get-char-property (point) 'syntax-table)
+                       c-<-as-paren-syntax) ; should always be true.
+       (c-clear-char-property (point) 'syntax-table))
+      (c-clear-char-property pos 'syntax-table))))
+
+(defun c-clear-<>-pair-props (&optional pos)
+  ;; POS (default point) is at a < or > character.  If it has an
+  ;; open/close paren syntax-table property, remove this property both
+  ;; from the current character and its partner (which will also be
+  ;; thusly marked).
+  (cond
+   ((eq (char-after) ?\<)
+    (c-clear-<-pair-props pos))
+   ((eq (char-after) ?\>)
+    (c-clear->-pair-props pos))
+   (t (c-benign-error
+       "c-clear-<>-pair-props called from wrong position"))))
+
+(defun c-clear-<-pair-props-if-match-after (lim &optional pos)
+  ;; POS (default point) is at a < character.  If it is both marked
+  ;; with open/close paren syntax-table property, and has a matching >
+  ;; (also marked) which is after LIM, remove the property both from
+  ;; the current > and its partner.
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c-<-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-list-forward))
+      (when (and (>= (point) lim)
+                (equal (c-get-char-property (1- (point)) 'syntax-table)
+                       c->-as-paren-syntax)) ; should always be true.
+       (c-unmark-<->-as-paren (1- (point)))
+       (c-unmark-<->-as-paren pos)))))
+
+(defun c-clear->-pair-props-if-match-before (lim &optional pos)
+  ;; POS (default point) is at a > character.  If it is both marked
+  ;; with open/close paren syntax-table property, and has a matching <
+  ;; (also marked) which is before LIM, remove the property both from
+  ;; the current < and its partner.
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c->-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-up-list-backward))
+      (when (and (<= (point) lim)
+                (equal (c-get-char-property (point) 'syntax-table)
+                       c-<-as-paren-syntax)) ; should always be true.
+       (c-unmark-<->-as-paren (point))
+       (c-unmark-<->-as-paren pos)))))
+
+(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).
+  ;;
+  ;; These pairs are those which are in the current "statement" (i.e.,
+  ;; the region between the {, }, or ; before BEG and the one after
+  ;; END), and which enclose any part of the interval (BEG END).
+  ;;
+  ;; Note that in C++ (?and Java), template/generic parens cannot
+  ;; enclose a brace or semicolon, so we use these as bounds on the
+  ;; region we must work on.
+  ;;
+  ;; This function is called from before-change-functions (via
+  ;; c-get-state-before-change-functions).  Thus the buffer is widened,
+  ;; and point is undefined, both at entry and exit.
+  ;;
+  ;; 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))))
+      ;; Locate the barrier before the changed region
+      (goto-char  (if beg-lit-limits (car beg-lit-limits) beg))
+      (c-syntactic-skip-backward "^;{}" (max (- beg 2048) (point-min)))
+
+      ;; Remove the syntax-table properties from each pertinent <...> pair.
+      ;; Firsly, the ones with the < before beg and > after beg.
+      (while (c-search-forward-char-property 'category 'c-<-as-paren-syntax beg)
+       (c-clear-<-pair-props-if-match-after beg (1- (point))))
+
+      ;; Locate the barrier after END.
+      (goto-char (if end-lit-limits (cdr end-lit-limits) end))
+      (c-syntactic-re-search-forward "[;{}]"
+                                    (min (+ end 2048) (point-max)) 'end)
+
+      ;; Remove syntax-table properties from the remaining pertinent <...>
+      ;; pairs, those with a > after end and < before end.
+      (while (c-search-backward-char-property 'category 'c->-as-paren-syntax end)
+       (c-clear->-pair-props-if-match-before end)))))
+
+
 
 (defun c-after-change-check-<>-operators (beg end)
   ;; This is called from `after-change-functions' when
@@ -4099,7 +5063,7 @@ comment at the start of cc-engine.el for more info."
                 (< beg (setq beg (match-end 0))))
        (while (progn (skip-chars-forward "^<>" beg)
                      (< (point) beg))
-         (c-clear-char-property (point) 'syntax-table)
+         (c-clear-<>-pair-props)
          (forward-char))))
 
     (when (< beg end)
@@ -4114,9 +5078,13 @@ comment at the start of cc-engine.el for more info."
                   (< end (setq end (match-end 0))))
          (while (progn (skip-chars-forward "^<>" end)
                        (< (point) end))
-           (c-clear-char-property (point) 'syntax-table)
+           (c-clear-<>-pair-props)
            (forward-char)))))))
 
+
+\f
+;; Handling of small scale constructs like types and names.
+
 ;; Dynamically bound variable that instructs `c-forward-type' to also
 ;; treat possible types (i.e. those that it normally returns 'maybe or
 ;; 'found for) as actual types (and always return 'found for them).
@@ -4363,7 +5331,7 @@ comment at the start of cc-engine.el for more info."
 
 (defun c-forward-<>-arglist (all-types)
   ;; The point is assumed to be at a "<".  Try to treat it as the open
-  ;; paren of an angle bracket arglist and move forward to the the
+  ;; paren of an angle bracket arglist and move forward to the
   ;; corresponding ">".  If successful, the point is left after the
   ;; ">" and t is returned, otherwise the point isn't moved and nil is
   ;; returned.  If ALL-TYPES is t then all encountered arguments in
@@ -5091,7 +6059,8 @@ comment at the start of cc-engine.el for more info."
   ;;
   ;;   The point is left at the first token after the first complete
   ;;   declarator, if there is one.  The return value is a cons where
-  ;;   the car is the position of the first token in the declarator.
+  ;;   the car is the position of the first token in the declarator.  (See
+  ;;   below for the cdr.)
   ;;   Some examples:
   ;;
   ;;    void foo (int a, char *b) stuff ...
@@ -5115,9 +6084,9 @@ comment at the start of cc-engine.el for more info."
   ;;     Foo::Foo (int b) : Base (b) {}
   ;; car ^                ^ point
   ;;
-  ;;   The cdr of the return value is non-nil if a
-  ;;   `c-typedef-decl-kwds' specifier is found in the declaration,
-  ;;   i.e. the declared identifier(s) are types.
+  ;;   The cdr of the return value is non-nil iff a `c-typedef-decl-kwds'
+  ;;   specifier (e.g. class, struct, enum, typedef) is found in the
+  ;;   declaration, i.e. the declared identifier(s) are types.
   ;;
   ;; If a cast is parsed:
   ;;
@@ -5132,11 +6101,12 @@ comment at the start of cc-engine.el for more info."
   ;; the first token in (the visible part of) the buffer.
   ;;
   ;; CONTEXT is a symbol that describes the context at the point:
-  ;; 'decl     In a comma-separatded declaration context (typically
+  ;; 'decl     In a comma-separated declaration context (typically
   ;;           inside a function declaration arglist).
   ;; '<>       In an angle bracket arglist.
   ;; 'arglist  Some other type of arglist.
-  ;; nil       Some other context or unknown context.
+  ;; nil       Some other context or unknown context.  Includes
+  ;;           within the parens of an if, for, ... construct.
   ;;
   ;; LAST-CAST-END is the first token after the closing paren of a
   ;; preceding cast, or nil if none is known.  If
@@ -5484,6 +6454,7 @@ comment at the start of cc-engine.el for more info."
        at-decl-or-cast
        (catch 'at-decl-or-cast
 
+        ;; CASE 1
        (when (> paren-depth 0)
          ;; Encountered something inside parens that isn't matched by
          ;; the `c-type-decl-*' regexps, so it's not a type decl
@@ -5507,6 +6478,7 @@ comment at the start of cc-engine.el for more info."
        (if got-identifier
            (progn
 
+             ;; CASE 2
              (when (and (or at-type maybe-typeless)
                         (not (or got-prefix got-parens)))
                ;; Got another identifier directly after the type, so it's a
@@ -5533,6 +6505,7 @@ comment at the start of cc-engine.el for more info."
          (if backup-at-type
              (progn
 
+               ;; CASE 3
                (when (= (point) start)
                  ;; Got a plain list of identifiers.  If a colon follows it's
                  ;; a valid label.  Otherwise the last one probably is the
@@ -5545,6 +6518,7 @@ comment at the start of cc-engine.el for more info."
                    (setq backup-if-not-cast t)
                    (throw 'at-decl-or-cast t)))
 
+               ;; CASE 4
                (when (and got-suffix
                           (not got-prefix)
                           (not got-parens))
@@ -5555,6 +6529,7 @@ comment at the start of cc-engine.el for more info."
                  (setq backup-if-not-cast t)
                  (throw 'at-decl-or-cast t)))
 
+           ;; CASE 5
            (when (eq at-type t)
              ;; If the type is known we know that there can't be any
              ;; identifier somewhere else, and it's only in declarations in
@@ -5564,6 +6539,7 @@ comment at the start of cc-engine.el for more info."
 
            (when (= (point) start)
              ;; Only got a single identifier (parsed as a type so far).
+             ;; CASE 6
              (if (and
                   ;; Check that the identifier isn't at the start of an
                   ;; expression.
@@ -5584,6 +6560,7 @@ comment at the start of cc-engine.el for more info."
                     ;; constants in C++.
                     (memq at-type '(known found)))))
                  (throw 'at-decl-or-cast t)
+               ;; CASE 7
                ;; Can't be a valid declaration or cast, but if we've found a
                ;; specifier it can't be anything else either, so treat it as
                ;; an invalid/unfinished declaration or cast.
@@ -5617,7 +6594,7 @@ comment at the start of cc-engine.el for more info."
              (c-fdoc-shift-type-backward)
 
            ;; Still no identifier.
-
+           ;; CASE 8
            (when (and got-prefix (or got-parens got-suffix))
              ;; Require `got-prefix' together with either `got-parens' or
              ;; `got-suffix' to recognize it as an abstract declarator:
@@ -5630,6 +6607,7 @@ comment at the start of cc-engine.el for more info."
              ;; the point when the fontification was invoked.
              (throw 'at-decl-or-cast t))
 
+           ;; CASE 9
            (when (and at-type
                       (not got-prefix)
                       (not got-parens)
@@ -5640,11 +6618,13 @@ comment at the start of cc-engine.el for more info."
              ;; instantiation expression).
              (throw 'at-decl-or-cast nil))))
 
+       ;; CASE 10
        (when at-decl-or-cast
          ;; By now we've located the type in the declaration that we know
          ;; we're in.
          (throw 'at-decl-or-cast t))
 
+       ;; CASE 11
        (when (and got-identifier
                   (not context)
                   (looking-at c-after-suffixed-type-decl-key)
@@ -5663,6 +6643,7 @@ comment at the start of cc-engine.el for more info."
          ;; A declaration according to `c-after-suffixed-type-decl-key'.
          (throw 'at-decl-or-cast t))
 
+       ;; CASE 12
        (when (and (or got-prefix (not got-parens))
                   (memq at-type '(t known)))
          ;; It's a declaration if a known type precedes it and it can't be a
@@ -5693,11 +6674,13 @@ comment at the start of cc-engine.el for more info."
        ;; Below are tests that only should be applied when we're certain to
        ;; not have parsed halfway through an expression.
 
+       ;; CASE 14
        (when (memq at-type '(t known))
          ;; The expression starts with a known type so treat it as a
          ;; declaration.
          (throw 'at-decl-or-cast t))
 
+       ;; CASE 15
        (when (and (c-major-mode-is 'c++-mode)
                   ;; In C++ we check if the identifier is a known type, since
                   ;; (con|de)structors use the class name as identifier.
@@ -5731,6 +6714,7 @@ comment at the start of cc-engine.el for more info."
 
        (if got-identifier
            (progn
+             ;; CASE 16
              (when (and got-prefix-before-parens
                         at-type
                         (or at-decl-end (looking-at "=[^=]"))
@@ -5743,6 +6727,7 @@ comment at the start of cc-engine.el for more info."
                ;; be a function call.
                (throw 'at-decl-or-cast t))
 
+             ;; CASE 17
              (when (and (or got-suffix-after-parens
                             (looking-at "=[^=]"))
                         (eq at-type 'found)
@@ -5753,6 +6738,7 @@ comment at the start of cc-engine.el for more info."
                ;; somewhere else (if it's a known type we won't get here).
                (throw 'at-decl-or-cast t)))
 
+         ;; CASE 18
          (when (and context
                     (or got-prefix
                         (and (eq context 'decl)
@@ -5924,9 +6910,10 @@ comment at the start of cc-engine.el for more info."
        label-end
        qt-symbol-idx
        macro-start                     ; if we're in one.
-       label-type)
+       label-type
+       kwd)
     (cond
-     ;; "case" or "default" (Doesn't apply to AWK). 
+     ;; "case" or "default" (Doesn't apply to AWK).
      ((looking-at c-label-kwds-regexp)
       (let ((kwd-end (match-end 1)))
        ;; Record only the keyword itself for fontification, since in
@@ -6045,7 +7032,7 @@ comment at the start of cc-engine.el for more info."
                         (c-forward-label nil pte start))))))))))
 
           ;; Point is still at the beginning of the possible label construct.
-          ;; 
+          ;;
           ;; Check that the next nonsymbol token is ":", or that we're in one
           ;; of QT's "slots" declarations.  Allow '(' for the sake of macro
           ;; arguments.  FIXME: Should build this regexp from the language
@@ -6071,18 +7058,19 @@ comment at the start of cc-engine.el for more info."
                     (and (c-major-mode-is 'c++-mode)
                          (string-match
                           "\\(p\\(r\\(ivate\\|otected\\)\\|ublic\\)\\|more\\)\\>"
-                          (buffer-substring start (point)))))  
+                          (buffer-substring start (point)))))
               (c-forward-syntactic-ws limit)
               (cond
                ((looking-at ":\\([^:]\\|\\'\\)") ; A single colon.
                 (forward-char)
                 (setq label-type
-                      (if (string= "signals" ; Special QT macro
-                                   (buffer-substring-no-properties start label-end))
+                      (if (or (string= "signals" ; Special QT macro
+                                       (setq kwd (buffer-substring-no-properties start label-end)))
+                              (string= "Q_SIGNALS" kwd))
                           'qt-1kwd-colon
                         'goto-target)))
                ((and qt-symbol-idx
-                     (search-forward-regexp "\\=slots\\>" limit t)
+                     (search-forward-regexp "\\=\\(slots\\|Q_SLOTS\\)\\>" limit t)
                      (progn (c-forward-syntactic-ws limit)
                             (looking-at ":\\([^:]\\|\\'\\)"))) ; A single colon
                 (forward-char)
@@ -6242,10 +7230,14 @@ comment at the start of cc-engine.el for more info."
         (looking-at c-opt-asm-stmt-key))))
 
 (defun c-at-toplevel-p ()
-  "Return a determination as to whether point is at the `top-level'.
-Being at the top-level means that point is either outside any
-enclosing block (such function definition), or only inside a class,
-namespace or other block that contains another declaration level.
+  "Return a determination as to whether point is \"at the top level\".
+Informally, \"at the top level\" is anywhere where you can write
+a function.
+
+More precisely, being at the top-level means that point is either
+outside any enclosing block (such as a function definition), or
+directly inside a class, namespace or other block that contains
+another declaration level.
 
 If point is not at the top-level (e.g. it is inside a method
 definition), then nil is returned.  Otherwise, if point is at a
@@ -6331,7 +7323,8 @@ comment at the start of cc-engine.el for more info."
       ;; the searchable range.
       (let* ((macro-start (c-query-macro-start))
             (lim (max (or lim (point-min)) (or macro-start (point-min))))
-            before-lparen after-rparen)
+            before-lparen after-rparen
+            (pp-count-out 20)) ; Max number of paren/brace constructs before we give up
        (narrow-to-region lim (c-point 'eol))
 
        ;; Search backwards for the defun's argument list.  We give up if we
@@ -6353,7 +7346,8 @@ comment at the start of cc-engine.el for more info."
        ;; {
 
        (catch 'knr
-         (while t ; go round one paren/bracket construct each time round.
+         (while (> pp-count-out 0) ; go back one paren/bracket pair each time.
+           (setq pp-count-out (1- pp-count-out))
            (c-syntactic-skip-backward "^)]}")
            (cond ((eq (char-before) ?\))
                   (setq after-rparen (point)))
@@ -7059,7 +8053,7 @@ comment at the start of cc-engine.el for more info."
   ;;
   ;; This function might do hidden buffer changes.
   (c-at-statement-start-p))
-(make-obsolete 'c-looking-at-bos 'c-at-statement-start-p)
+(make-obsolete 'c-looking-at-bos 'c-at-statement-start-p "22.1")
 
 (defun c-looking-at-inexpr-block (lim containing-sexp &optional check-at-end)
   ;; Return non-nil if we're looking at the beginning of a block
@@ -7235,7 +8229,7 @@ comment at the start of cc-engine.el for more info."
   ;; needed with further syntax elements of the types `substatement',
   ;; `inexpr-statement', `arglist-cont-nonempty', `statement-block-intro', and
   ;; `defun-block-intro'.
-  ;; 
+  ;;
   ;; Do the generic processing to anchor the given syntax symbol on
   ;; the preceding statement: Skip over any labels and containing
   ;; statements on the same line, and then search backward until we
@@ -7421,7 +8415,7 @@ comment at the start of cc-engine.el for more info."
                                 c-other-decl-block-key-in-symbols-alist))
                     (max (c-point 'boi paren-pos) (point))))
                   (t (c-add-syntax 'defun-block-intro nil))))
-                            
+
                 (c-add-syntax 'statement-block-intro nil)))
 
          (if (= paren-pos boi)
@@ -7613,6 +8607,7 @@ comment at the start of cc-engine.el for more info."
           literal char-before-ip before-ws-ip char-after-ip macro-start
           in-macro-expr c-syntactic-context placeholder c-in-literal-cache
           step-type tmpsymbol keyword injava-inher special-brace-list tmp-pos
+          containing-<
           ;; The following record some positions for the containing
           ;; declaration block if we're directly within one:
           ;; `containing-decl-open' is the position of the open
@@ -8029,12 +9024,15 @@ comment at the start of cc-engine.el for more info."
 
             ;; CASE 5A.5: ordinary defun open
             (t
-             (goto-char placeholder)
-             (if (or containing-decl-open macro-start)
-                 (c-add-syntax 'defun-open (c-point 'boi))
-               ;; Bogus to use bol here, but it's the legacy.
-               (c-add-syntax 'defun-open (c-point 'bol)))
-             )))
+             (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))
+               (c-add-syntax 'defun-open (c-point 'boi))
+               ;; Bogus to use bol here, but it's the legacy.  (Resolved,
+               ;; 2007-11-09)
+               ))))
 
           ;; CASE 5B: After a function header but before the body (or
           ;; the ending semicolon if there's no body).
@@ -8170,7 +9168,7 @@ comment at the start of cc-engine.el for more info."
           ;; member init list continuation, or a template argument
           ;; list continuation.
           ((save-excursion
-             ;; Note: We use the fact that lim always is after any
+             ;; Note: We use the fact that lim is always after any
              ;; preceding brace sexp.
              (if c-recognize-<>-arglists
                  (while (and
@@ -8224,7 +9222,7 @@ comment at the start of cc-engine.el for more info."
                  (back-to-indentation)))
              ;; FIXME: Should use c-add-stmt-syntax, but it's not yet
              ;; template aware.
-             (c-add-syntax 'template-args-cont (point)))
+             (c-add-syntax 'template-args-cont (point) placeholder))
 
             ;; CASE 5D.4: perhaps a multiple inheritance line?
             ((and (c-major-mode-is 'c++-mode)
@@ -8244,24 +9242,27 @@ comment at the start of cc-engine.el for more info."
              (c-add-syntax 'inher-cont (c-point 'boi)))
 
             ;; CASE 5D.5: Continuation of the "expression part" of a
-            ;; top level construct.
+            ;; top level construct.  Or, perhaps, an unrecognised construct.
             (t
-             (while (and (eq (car (c-beginning-of-decl-1 containing-sexp))
+             (while (and (setq placeholder (point))
+                         (eq (car (c-beginning-of-decl-1 containing-sexp))
                              'same)
                          (save-excursion
                            (c-backward-syntactic-ws)
-                           (eq (char-before) ?}))))
+                           (eq (char-before) ?}))
+                         (< (point) placeholder)))
              (c-add-stmt-syntax
-              (if (eq char-before-ip ?,)
+              (cond
+               ((eq (point) placeholder) 'statement) ; unrecognised construct
                   ;; A preceding comma at the top level means that a
                   ;; new variable declaration starts here.  Use
                   ;; topmost-intro-cont for it, for consistency with
                   ;; the first variable declaration.  C.f. case 5N.
-                  'topmost-intro-cont
-                'statement-cont)
+               ((eq char-before-ip ?,) 'topmost-intro-cont)
+               (t 'statement-cont))
               nil nil containing-sexp paren-state))
             ))
-          
+
           ;; CASE 5F: Close of a non-class declaration level block.
           ((and (eq char-after-ip ?})
                 (c-keyword-member containing-decl-kwd
@@ -8293,6 +9294,7 @@ comment at the start of cc-engine.el for more info."
 
           ;; CASE 5H: we could be looking at subsequent knr-argdecls
           ((and c-recognize-knr-p
+                (not containing-sexp)  ; can't be knr inside braces.
                 (not (eq char-before-ip ?}))
                 (save-excursion
                   (setq placeholder (cdr (c-beginning-of-decl-1 lim)))
@@ -8432,10 +9434,11 @@ comment at the start of cc-engine.el for more info."
           ;; arglist that begins on the previous line.
           ((and c-recognize-<>-arglists
                 (eq (char-before) ?<)
+                (setq placeholder (1- (point)))
                 (not (and c-overloadable-operators-regexp
                           (c-after-special-operator-id lim))))
            (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
-           (c-add-syntax 'template-args-cont (c-point 'boi)))
+           (c-add-syntax 'template-args-cont (c-point 'boi) placeholder))
 
           ;; CASE 5Q: we are at a statement within a macro.
           (macro-start
@@ -8457,14 +9460,38 @@ comment at the start of cc-engine.el for more info."
 
         ;; (CASE 6 has been removed.)
 
+        ;; CASE 19: line is an expression, not a statement, and is directly
+        ;; contained by a template delimiter.  Most likely, we are in a
+        ;; template arglist within a statement.  This case is based on CASE
+        ;; 7.  At some point in the future, we may wish to create more
+        ;; syntactic symbols such as `template-intro',
+        ;; `template-cont-nonempty', etc., and distinguish between them as we
+        ;; do for `arglist-intro' etc. (2009-12-07).
+        ((and c-recognize-<>-arglists
+              (setq containing-< (c-up-list-backward indent-point containing-sexp))
+              (eq (char-after containing-<) ?\<))
+         (setq placeholder (c-point 'boi containing-<))
+         (goto-char containing-sexp)   ; Most nested Lbrace/Lparen (but not
+                                       ; '<') before indent-point.
+         (if (>= (point) placeholder)
+             (progn
+               (forward-char)
+               (skip-chars-forward " \t"))
+           (goto-char placeholder))
+         (c-add-stmt-syntax 'template-args-cont (list containing-<) t
+                            (c-most-enclosing-brace c-state-cache (point))
+                            paren-state))
+                            
+
         ;; CASE 7: line is an expression, not a statement.  Most
         ;; likely we are either in a function prototype or a function
-        ;; call argument list
+        ;; call argument list, or a template argument list.
         ((not (or (and c-special-brace-lists
                        (save-excursion
                          (goto-char containing-sexp)
                          (c-looking-at-special-brace-list)))
-                  (eq (char-after containing-sexp) ?{)))
+                  (eq (char-after containing-sexp) ?{)
+                  (eq (char-after containing-sexp) ?<)))
          (cond
 
           ;; CASE 7A: we are looking at the arglist closing paren.
@@ -8561,7 +9588,7 @@ comment at the start of cc-engine.el for more info."
                   (c-forward-syntactic-ws)
                   (point))
                 (c-point 'bonl)))
-           (goto-char containing-sexp)
+           (goto-char containing-sexp) ; paren opening the arglist
            (setq placeholder (c-point 'boi))
            (if (and (c-safe (backward-up-list 1) t)
                     (>= (point) placeholder))
@@ -9206,5 +10233,5 @@ Cannot combine absolute offsets %S and %S in `add' method"
 \f
 (cc-provide 'cc-engine)
 
-;;; arch-tag: 149add18-4673-4da5-ac47-6805e4eae089
+;; arch-tag: 149add18-4673-4da5-ac47-6805e4eae089
 ;;; cc-engine.el ends here