merge emacs-23
[bpt/emacs.git] / lisp / progmodes / cc-engine.el
index d5a3103..9c04920 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, 2008
+;;   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:
 
@@ -423,7 +422,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.
   ;;
@@ -531,6 +530,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
@@ -550,12 +553,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
@@ -573,7 +580,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.
@@ -658,7 +665,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. ;).
@@ -972,7 +979,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))))
@@ -990,19 +997,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.
@@ -1057,8 +1061,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.
@@ -2511,7 +2524,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.
@@ -2962,6 +2975,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
@@ -2980,140 +3046,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.
@@ -3321,7 +3347,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
@@ -3431,9 +3457,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."
@@ -3583,14 +3610,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.
   ;;
@@ -3604,14 +3640,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
@@ -4367,7 +4395,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
@@ -5141,7 +5169,8 @@ comment at the start of cc-engine.el for more info."
   ;;           inside a function declaration arglist).
   ;; '<>       In an angle bracket arglist.
   ;; 'arglist  Some other type of arglist.
-  ;; 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
@@ -5489,6 +5518,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
@@ -5512,6 +5542,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
@@ -5538,6 +5569,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
@@ -5550,6 +5582,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))
@@ -5560,6 +5593,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
@@ -5569,6 +5603,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.
@@ -5589,6 +5624,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.
@@ -5622,7 +5658,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:
@@ -5635,6 +5671,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)
@@ -5645,11 +5682,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)
@@ -5668,6 +5707,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
@@ -5698,11 +5738,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.
@@ -5736,6 +5778,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 "=[^=]"))
@@ -5748,6 +5791,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)
@@ -5758,6 +5802,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)
@@ -5929,7 +5974,8 @@ 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).
      ((looking-at c-label-kwds-regexp)
@@ -6082,12 +6128,13 @@ comment at the start of cc-engine.el for more info."
                ((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)
@@ -6247,10 +6294,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
@@ -7066,7 +7117,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
@@ -7620,6 +7671,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
@@ -8180,7 +8232,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
@@ -8234,7 +8286,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)
@@ -8254,21 +8306,24 @@ 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))
             ))
 
@@ -8443,10 +8498,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
@@ -8468,14 +8524,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.
@@ -8572,7 +8652,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))