]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/cc-engine.el
Amend a cache so that typing into C++ raw strings has no undue delay.
[gnu-emacs] / lisp / progmodes / cc-engine.el
index f9eae213ca8508e89f2d2473ee67b5ba4226d658..4bc4056081b0cc60fff271a4146df33eee095edf 100644 (file)
@@ -83,8 +83,9 @@
 ;;
 ;; 'syntax-table
 ;;   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.
+;;   mark the "<" and ">" of angle bracket parens with paren syntax, to
+;;   "hide" obtrusive characters in preprocessor lines, and to mark C++
+;;   raw strings to enable their fontification.
 ;;
 ;;   This property is used on single characters and is therefore
 ;;   always treated as front and rear nonsticky (or start and end open
 ;; The starting position from where we determined `c-macro-cache'.
 (defvar c-macro-cache-syntactic nil)
 (make-variable-buffer-local 'c-macro-cache-syntactic)
-;; non-nil iff `c-macro-cache' has both elements set AND the cdr is at a
-;; syntactic end of macro, not merely an apparent one.
+;; Either nil, or the syntactic end of the macro currently represented by
+;; `c-macro-cache'.
+(defvar c-macro-cache-no-comment nil)
+(make-variable-buffer-local 'c-macro-cache-no-comment)
+;; Either nil, or the last character of the macro currently represented by
+;; `c-macro-cache' which isn't in a comment. */
 
 (defun c-invalidate-macro-cache (beg end)
   ;; Called from a before-change function.  If the change region is before or
    ((< beg (car c-macro-cache))
     (setq c-macro-cache nil
          c-macro-cache-start-pos nil
-         c-macro-cache-syntactic nil))
+         c-macro-cache-syntactic nil
+         c-macro-cache-no-comment nil))
    ((and (cdr c-macro-cache)
         (< beg (cdr c-macro-cache)))
     (setcdr c-macro-cache nil)
     (setq c-macro-cache-start-pos beg
-         c-macro-cache-syntactic nil))))
+         c-macro-cache-syntactic nil
+         c-macro-cache-no-comment nil))))
 
 (defun c-macro-is-genuine-p ()
   ;; Check that the ostensible CPP construct at point is a real one.  In
@@ -288,7 +295,8 @@ comment at the start of cc-engine.el for more info."
                   t))
        (setq c-macro-cache nil
              c-macro-cache-start-pos nil
-             c-macro-cache-syntactic nil)
+             c-macro-cache-syntactic nil
+             c-macro-cache-no-comment nil)
 
        (save-restriction
          (if lim (narrow-to-region lim (point-max)))
@@ -297,7 +305,7 @@ comment at the start of cc-engine.el for more info."
            (forward-line -1))
          (back-to-indentation)
          (if (and (<= (point) here)
-                  (looking-at c-opt-cpp-start)
+                  (save-match-data (looking-at c-opt-cpp-start))
                   (c-macro-is-genuine-p))
              (progn
                (setq c-macro-cache (cons (point) nil)
@@ -323,7 +331,8 @@ comment at the start of cc-engine.el for more info."
                  (>= (point) (car c-macro-cache)))
        (setq c-macro-cache nil
             c-macro-cache-start-pos nil
-            c-macro-cache-syntactic nil))
+            c-macro-cache-syntactic nil
+            c-macro-cache-no-comment nil))
      (while (progn
              (end-of-line)
              (when (and (eq (char-before) ?\\)
@@ -347,14 +356,38 @@ comment at the start of cc-engine.el for more info."
   (let* ((here (point))
         (there (progn (c-end-of-macro) (point)))
         s)
-    (unless c-macro-cache-syntactic
+    (if c-macro-cache-syntactic
+       (goto-char c-macro-cache-syntactic)
       (setq 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)))
-      (setq c-macro-cache-syntactic (car c-macro-cache)))
+      (setq c-macro-cache-syntactic (point)))
+    (point)))
+
+(defun c-no-comment-end-of-macro ()
+  ;; Go to the end of a CPP directive, or a pos just before which isn't in a
+  ;; comment.  For this purpose, open strings are ignored.
+  ;;
+  ;; 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)
+    (if c-macro-cache-no-comment
+       (goto-char c-macro-cache-no-comment)
+      (setq s (parse-partial-sexp here there))
+      (while (and (nth 3 s)     ; in a string
+                 (> there here))       ; No infinite loops, please.
+       (setq here (1+ (nth 8 s)))
+       (setq s (parse-partial-sexp here there)))
+      (when (nth 4 s)
+       (goto-char (1- (nth 8 s))))
+      (setq c-macro-cache-no-comment (point)))
     (point)))
 
 (defun c-forward-over-cpp-define-id ()
@@ -385,6 +418,25 @@ comment at the start of cc-engine.el for more info."
 \f
 ;;; Basic utility functions.
 
+(defun c-delq-from-dotted-list (elt dlist)
+  ;; If ELT is a member of the (possibly dotted) list DLIST, remove all
+  ;; occurrences of it (except for any in the last cdr of DLIST).
+  ;;
+  ;; Call this as (setq DLIST (c-delq-from-dotted-list ELT DLIST)), as
+  ;; sometimes the original structure is changed, sometimes it's not.
+  ;;
+  ;; This function is needed in Emacs < 24.5, and possibly XEmacs, because
+  ;; `delq' throws an error in these versions when given a dotted list.
+  (let ((tail dlist) prev)
+    (while (consp tail)
+      (if (eq (car tail) elt)
+         (if prev
+             (setcdr prev (cdr tail))
+           (setq dlist (cdr dlist)))
+       (setq prev tail))
+      (setq tail (cdr tail)))
+    dlist))
+
 (defun c-syntactic-content (from to paren-level)
   ;; Return the given region as a string where all syntactic
   ;; whitespace is removed or, where necessary, replaced with a single
@@ -1248,7 +1300,7 @@ comment at the start of cc-engine.el for more info."
            c-stmt-delim-chars))
         (non-skip-list
          (append (substring skip-chars 1) nil)) ; e.g. (?# ?\; ?{ ?} ?? ?:)
-        lit-range vsemi-pos)
+        lit-range lit-start vsemi-pos)
     (save-restriction
       (widen)
       (save-excursion
@@ -1263,8 +1315,8 @@ comment at the start of cc-engine.el for more info."
             ((and (bolp)
                   (save-excursion
                     (progn
-                      (if (setq lit-range (c-literal-limits from)) ; Have we landed in a string/comment?
-                          (goto-char (car lit-range)))
+                      (if (setq lit-start (c-literal-start from)) ; Have we landed in a string/comment?
+                          (goto-char lit-start))
                       (c-backward-syntactic-ws) ; ? put a limit here, maybe?
                       (setq vsemi-pos (point))
                       (c-at-vsemi-p))))
@@ -2227,22 +2279,118 @@ comment at the start of cc-engine.el for more info."
 
 (defvar c-state-semi-nonlit-pos-cache nil)
 (make-variable-buffer-local 'c-state-semi-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-semi-nonlit-pos-cache-limit' are valid.
+;; A list of elements which are either buffer positions (when such positions
+;; are not in literals) or lists of the form (POS TYPE START), where POS is
+;; a buffer position inside a literal, TYPE is the type of the literal
+;; ('string, 'c, or 'c++) and START is the start of the literal.
 
 (defvar c-state-semi-nonlit-pos-cache-limit 1)
 (make-variable-buffer-local 'c-state-semi-nonlit-pos-cache-limit)
-;; An upper limit on valid entries in `c-state-semi-nonlit-pos-cache'.  This is
-;; reduced by buffer changes, and increased by invocations of
-;; `c-state-literal-at'.  FIXME!!!
+;; An upper limit on valid entries in `c-state-semi-nonlit-pos-cache'.  This
+;; is reduced by buffer changes, and increased by invocations of
+;; `c-parse-ps-state-below'.
+
+(defun c-state-semi-pp-to-literal (here &optional not-in-delimiter)
+  ;; Do a parse-partial-sexp from a position in the buffer before HERE which
+  ;; isn't in a literal, and return information about HERE, either:
+  ;; (STATE TYPE BEG)          if HERE is in a literal; or
+  ;; (STATE)                   otherwise,
+  ;; where STATE is the parsing state at HERE, TYPE is the type of the literal
+  ;; enclosing HERE, (one of 'string, 'c, 'c++) and BEG is the starting
+  ;; position of that literal (including the delimiter).
+  ;;
+  ;; Unless NOT-IN-DELIMITER is non-nil, when TO is inside a two-character
+  ;; comment opener, this is recognized as being in a comment literal.
+  ;;
+  ;; Only elements 3 (in a string), 4 (in a comment), 5 (following a quote), 7
+  ;; (comment type), and 8 (start of comment/string), and possibly 10 (in
+  ;; newer Emacsen only, the syntax of a position after a potential first char
+  ;; of a two char construct) of STATE are valid.
+  (save-excursion
+    (save-match-data
+      (let* ((base-and-state (c-parse-ps-state-below here))
+            (base (car base-and-state))
+            (s (cdr base-and-state))
+            (s (parse-partial-sexp base here nil nil s))
+            ty)
+       (cond
+        ((or (nth 3 s) (nth 4 s))      ; in a string or comment
+         (setq ty (cond
+                   ((nth 3 s) 'string)
+                   ((nth 7 s) 'c++)
+                   (t 'c)))
+         (list s ty (nth 8 s)))
+        
+        ((and (not not-in-delimiter)   ; inside a comment starter
+              (not (bobp))
+              (progn (backward-char)
+                     (and (not (and (memq 'category-properties c-emacs-features)
+                                    (looking-at "\\s!")))
+                          (looking-at c-comment-start-regexp))))
+         (setq ty (if (looking-at c-block-comment-start-regexp) 'c 'c++))
+         (list s ty (point)))
+        
+        (t (list s)))))))
+
+(defun c-state-full-pp-to-literal (here &optional not-in-delimiter)
+  ;; This function will supersede c-state-pp-to-literal.
+  ;; 
+  ;; Do a parse-partial-sexp from a position in the buffer before HERE which
+  ;; isn't in a literal, and return information about HERE, either:
+  ;; (STATE TYPE (BEG . END))   if HERE is in a literal; or
+  ;; (STATE)                    otherwise,
+  ;; where STATE is the parsing state at HERE, TYPE is the type of the literal
+  ;; enclosing HERE, (one of 'string, 'c, 'c++) and (BEG . END) is the
+  ;; boundaries of that literal (including the delimiters).
+  ;;
+  ;; Unless NOT-IN-DELIMITER is non-nil, when TO is inside a two-character
+  ;; comment opener, this is recognized as being in a comment literal.
+  ;;
+  ;; Only elements 3 (in a string), 4 (in a comment), 5 (following a quote), 7
+  ;; (comment type), and 8 (start of comment/string), and possibly 10 (in
+  ;; newer Emacsen only, the syntax of a position after a potential first char
+  ;; of a two char construct) of STATE are valid.
+  (save-excursion
+    (save-match-data
+      (let* ((base-and-state (c-parse-ps-state-below here))
+            (base (car base-and-state))
+            (s (cdr base-and-state))
+            (s (parse-partial-sexp base here nil nil s))
+            ty start)
+       (cond
+        ((or (nth 3 s) (nth 4 s))      ; in a string or comment
+         (setq ty (cond
+                   ((nth 3 s) 'string)
+                   ((nth 7 s) 'c++)
+                   (t 'c)))
+         (setq start (nth 8 s))
+         (parse-partial-sexp here (point-max)
+                             nil                             ; TARGETDEPTH
+                             nil                             ; STOPBEFORE
+                             s                               ; OLDSTATE
+                             'syntax-table) ; stop at end of literal
+         (list s ty (cons start (point))))
+
+        ((and (not not-in-delimiter)   ; inside a comment starter
+              (not (bobp))
+              (progn (backward-char)
+                     (and (not (and (memq 'category-properties c-emacs-features)
+                                    (looking-at "\\s!")))
+                          (looking-at c-comment-start-regexp))))
+         (setq ty (if (looking-at c-block-comment-start-regexp) 'c 'c++)
+               start (point))
+         (forward-comment 1)
+         (list s ty (cons start (point))))
+
+        (t (list s)))))))
 
 (defsubst c-state-pp-to-literal (from to &optional not-in-delimiter)
   ;; Do a parse-partial-sexp from FROM to TO, returning either
   ;;     (STATE TYPE (BEG . END))     if TO is in a literal; or
   ;;     (STATE)                      otherwise,
   ;; where STATE is the parsing state at TO, TYPE is the type of the literal
-  ;; (one of 'c, 'c++, 'string) and (BEG . END) is the boundaries of the literal.
+  ;; (one of 'c, 'c++, 'string) and (BEG . END) is the boundaries of the literal,
+  ;; including the delimiters.
   ;;
   ;; Unless NOT-IN-DELIMITER is non-nil, when TO is inside a two-character
   ;; comment opener, this is recognized as being in a comment literal.
@@ -2251,32 +2399,130 @@ comment at the start of cc-engine.el for more info."
   ;; 7 (comment type) and 8 (start of comment/string) (and possibly 9) of
   ;; STATE are valid.
   (save-excursion
-    (let ((s (parse-partial-sexp from to))
-         ty co-st)
-      (cond
-       ((or (nth 3 s) (nth 4 s))       ; in a string or comment
-       (setq ty (cond
-                 ((nth 3 s) 'string)
-                 ((nth 7 s) 'c++)
-                 (t 'c)))
-       (parse-partial-sexp (point) (point-max)
-                           nil            ; TARGETDEPTH
-                           nil            ; STOPBEFORE
-                           s              ; OLDSTATE
-                           'syntax-table) ; stop at end of literal
-       `(,s ,ty (,(nth 8 s) . ,(point))))
-
-       ((and (not not-in-delimiter)    ; inside a comment starter
-            (not (bobp))
-            (progn (backward-char)
-                   (and (not (looking-at "\\s!"))
-                        (looking-at c-comment-start-regexp))))
-       (setq ty (if (looking-at c-block-comment-start-regexp) 'c 'c++)
-             co-st (point))
-       (forward-comment 1)
-       `(,s ,ty (,co-st . ,(point))))
-
-       (t `(,s))))))
+    (save-match-data
+      (let ((s (parse-partial-sexp from to))
+           ty co-st)
+       (cond
+        ((or (nth 3 s) (nth 4 s))      ; in a string or comment
+         (setq ty (cond
+                   ((nth 3 s) 'string)
+                   ((nth 7 s) 'c++)
+                   (t 'c)))
+         (parse-partial-sexp (point) (point-max)
+                             nil          ; TARGETDEPTH
+                             nil          ; STOPBEFORE
+                             s            ; OLDSTATE
+                             'syntax-table) ; stop at end of literal
+         `(,s ,ty (,(nth 8 s) . ,(point))))
+
+        ((and (not not-in-delimiter)   ; inside a comment starter
+              (not (bobp))
+              (progn (backward-char)
+                     (and (not (looking-at "\\s!"))
+                          (looking-at c-comment-start-regexp))))
+         (setq ty (if (looking-at c-block-comment-start-regexp) 'c 'c++)
+               co-st (point))
+         (forward-comment 1)
+         `(,s ,ty (,co-st . ,(point))))
+
+        (t `(,s)))))))
+
+(defun c-cache-to-parse-ps-state (elt)
+  ;; Create a list suitable to use as the old-state parameter to
+  ;; `parse-partial-sexp', out of ELT.  ELT is either just a number, a buffer
+  ;; position, or it is a list (POS TYPE STARTING-POS).  Here POS is the
+  ;; buffer position the other elements are pertinent for, TYPE is either 'c
+  ;; or 'c++ (for a comment) or a character (for a string delimiter) or t
+  ;; (meaning a string fence opened the string), STARTING-POS is the starting
+  ;; position of the comment or string.
+  (if (consp elt)
+      (let ((depth 0) (containing nil) (last nil)
+           in-string in-comment (after-quote nil)
+           (min-depth 0) com-style com-str-start (intermediate nil)
+           (between-syntax nil)
+           (type (cadr elt)))
+       (setq com-str-start (car (cddr elt)))
+       (cond
+        ((or (numberp type) (eq type t)) ; A string
+         (setq in-string type))
+        ((memq type '(c c++))          ; A comment
+         (setq in-comment t
+               com-style (if (eq type 'c++) 1 nil)))
+        (t (c-benign-error "Invalid type %s in c-cache-to-parse-ps-state"
+                           elt)))
+       (list depth containing last
+             in-string in-comment after-quote
+             min-depth com-style com-str-start
+             intermediate nil))
+    (copy-tree '(0 nil nil nil nil nil 0 nil nil nil nil))))
+
+(defun c-parse-ps-state-to-cache (state)
+  ;; Convert STATE, a `parse-partial-sexp' state valid at POINT, to an element
+  ;; for the `c-state-semi-nonlit-pos-cache' cache.  This is either POINT
+  ;; (when point is not in a literal) or a list (POINT TYPE STARTING-POS),
+  ;; where TYPE is the type of the literal, either 'string, 'c, or 'c++, and
+  ;; STARTING-POS is the starting position of the comment or string.
+  (cond
+   ((nth 3 state)                      ; A string
+    (list (point) (nth 3 state) (nth 8 state)))
+   ((nth 4 state)                      ; A comment
+    (list (point)
+         (if (eq (nth 7 state) 1) 'c++ 'c)
+         (nth 8 state)))
+   (t                                  ; Neither string nor comment.
+    (point))))
+
+(defsubst c-ps-state-cache-pos (elt)
+  ;; Get the buffer position from ELT, an element from the cache
+  ;; `c-state-semi-nonlit-pos-cache'.
+  (if (atom elt)
+      elt
+    (car elt)))
+
+(defun c-parse-ps-state-below (here)
+  ;; Given a buffer position HERE, Return a cons (CACHE-POS . STATE), where
+  ;; CACHE-POS is a position not very far before HERE for which the
+  ;; parse-partial-sexp STATE is valid.  Note that the only valid elements of
+  ;; STATE are those concerning comments and strings; STATE is the state of a
+  ;; null `parse-partial-sexp' scan when CACHE-POS is not in a comment or
+  ;; string.
+  (save-restriction
+    (widen)
+    (save-excursion
+      (let ((c c-state-semi-nonlit-pos-cache)
+           elt state pos npos high-elt)
+       ;; Trim the cache to take account of buffer changes.
+       (while (and c (> (c-ps-state-cache-pos (c-ps-state-cache-pos (car c)))
+                        c-state-semi-nonlit-pos-cache-limit))
+         (setq c (cdr c)))
+       (setq c-state-semi-nonlit-pos-cache c)
+
+       (while (and c (> (c-ps-state-cache-pos (car c)) here))
+         (setq high-elt (car c))
+         (setq c (cdr c)))
+       (setq pos (or (and c (c-ps-state-cache-pos (car c)))
+                     (point-min)))
+
+       (if high-elt
+           (setq state (c-cache-to-parse-ps-state (car c)))
+         (setq elt (if c (car c) (point-min)))
+         (setq state
+               (if c
+                   (c-cache-to-parse-ps-state (car c))
+                 (copy-tree '(0 nil nil nil nil nil 0 nil nil nil nil))))
+         (while
+             ;; Add an element to `c-state-semi-nonlit-pos-cache' each iteration.
+             (<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
+           (setq state (parse-partial-sexp pos npos nil nil state))
+           (setq elt (c-parse-ps-state-to-cache state))
+           (setq c-state-semi-nonlit-pos-cache
+                 (cons elt c-state-semi-nonlit-pos-cache))
+           (setq pos npos)))
+
+       (if (> pos c-state-semi-nonlit-pos-cache-limit)
+           (setq c-state-semi-nonlit-pos-cache-limit pos))
+
+       (cons pos state)))))
 
 (defun c-state-safe-place (here)
   ;; Return a buffer position before HERE which is "safe", i.e. outside any
@@ -2343,45 +2589,6 @@ comment at the start of cc-engine.el for more info."
            (setq c-state-nonlit-pos-cache-limit pos))
        pos))))
 
-(defun c-state-semi-safe-place (here)
-  ;; Return a buffer position before HERE which is "safe", i.e. outside any
-  ;; string or comment.  It may be in a macro.
-  (save-restriction
-    (widen)
-    (save-excursion
-      (let ((c c-state-semi-nonlit-pos-cache)
-           pos npos high-pos lit macro-beg macro-end)
-       ;; Trim the cache to take account of buffer changes.
-       (while (and c (> (car c) c-state-semi-nonlit-pos-cache-limit))
-         (setq c (cdr c)))
-       (setq c-state-semi-nonlit-pos-cache c)
-
-       (while (and c (> (car c) here))
-         (setq high-pos (car c))
-         (setq c (cdr c)))
-       (setq pos (or (car c) (point-min)))
-
-       (unless high-pos
-         (while
-             ;; Add an element to `c-state-semi-nonlit-pos-cache' each iteration.
-             (and
-              (<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
-
-              ;; Test for being in a literal.  If so, go to after it.
-              (progn
-                (setq lit (car (cddr (c-state-pp-to-literal pos npos))))
-                (or (null lit)
-                    (prog1 (<= (cdr lit) here)
-                      (setq npos (cdr lit))))))
-
-           (setq pos npos)
-           (setq c-state-semi-nonlit-pos-cache
-                 (cons pos c-state-semi-nonlit-pos-cache))))
-
-       (if (> pos c-state-semi-nonlit-pos-cache-limit)
-           (setq c-state-semi-nonlit-pos-cache-limit pos))
-       pos))))
-
 (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
@@ -2699,7 +2906,11 @@ comment at the start of cc-engine.el for more info."
        (setq ptr (cdr ptr)))
 
       (when (consp ptr)
-       (if (eq (cdr ptr) c-state-cache)
+       (if (or (eq (cdr ptr) c-state-cache)
+               (and (consp (cadr ptr))
+                    (> (cdr (cadr ptr)) (point-min)))) ; Our new point-min is
+                                                       ; inside a recorded
+                                                       ; brace pair.
            (setq c-state-cache nil
                  c-state-cache-good-pos c-state-min-scan-pos)
          (setcdr ptr nil)
@@ -3440,7 +3651,7 @@ comment at the start of cc-engine.el for more info."
                (< 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-state-old-cpp-end
            (c-invalidate-state-cache-1 here))
         (c-with-cpps-commented-out
          (c-invalidate-state-cache-1 here))))
@@ -3501,6 +3712,9 @@ comment at the start of cc-engine.el for more info."
 (make-variable-buffer-local 'c-parse-state-state)
 (defun c-record-parse-state-state ()
   (setq c-parse-state-point (point))
+  (when (markerp (cdr (assq 'c-state-old-cpp-beg c-parse-state-state)))
+    (move-marker (cdr (assq 'c-state-old-cpp-beg c-parse-state-state)) nil)
+    (move-marker (cdr (assq 'c-state-old-cpp-end c-parse-state-state)) nil))
   (setq c-parse-state-state
        (mapcar
         (lambda (arg)
@@ -3524,7 +3738,7 @@ comment at the start of cc-engine.el for more info."
           c-state-old-cpp-end
           c-parse-state-point))))
 (defun c-replay-parse-state-state ()
-  (message
+  (message "%s"
    (concat "(setq "
     (mapconcat
      (lambda (arg)
@@ -3547,7 +3761,7 @@ comment at the start of cc-engine.el for more info."
     conses-not-ok))
 
 (defun c-debug-parse-state ()
-  (let ((here (point)) (res1 (c-real-parse-state)) res2)
+  (let ((here (point)) (min-point (point-min)) (res1 (c-real-parse-state)) res2)
     (let ((c-state-cache nil)
          (c-state-cache-good-pos 1)
          (c-state-nonlit-pos-cache nil)
@@ -3574,8 +3788,8 @@ comment at the start of cc-engine.el for more info."
       ;;                          "using cache: %s, from scratch: %s")
       ;;                  here res1 res2)))
       (message (concat "c-parse-state inconsistency at %s: "
-                      "using cache: %s, from scratch: %s")
-              here res1 res2)
+                      "using cache: %s, from scratch: %s.  POINT-MIN: %s")
+              here res1 res2 min-point)
       (message "Old state:")
       (c-replay-parse-state-state))
 
@@ -4572,8 +4786,7 @@ Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
   (save-restriction
     (widen)
-    (let* ((safe-place (c-state-semi-safe-place (point)))
-          (lit (c-state-pp-to-literal safe-place (point))))
+    (let ((lit (c-state-semi-pp-to-literal (point))))
       (or (cadr lit)
          (and detect-cpp
               (save-excursion (c-beginning-of-macro))
@@ -4595,14 +4808,19 @@ Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
 
   (save-excursion
-    (let* ((pos (point))
-          (lim (or lim (c-state-semi-safe-place pos)))
-          (pp-to-lit (save-restriction
-                       (widen)
-                       (c-state-pp-to-literal lim pos not-in-delimiter)))
-          (state (car pp-to-lit))
-          (lit-limits (car (cddr pp-to-lit))))
-
+    (let*
+       ((pos (point))
+        (lit-limits
+         (if lim
+             (let ((s (parse-partial-sexp lim (point))))
+               (when (or (nth 3 s) (nth 4 s))
+                 (cons (nth 8 s)
+                       (progn (parse-partial-sexp (point) (point-max)
+                                                  nil 'syntax-table
+                                                  s)
+                              (point)))))
+           (let ((pp-to-lit (c-state-full-pp-to-literal pos not-in-delimiter)))
+             (car (cddr pp-to-lit))))))
       (cond
        (lit-limits)
 
@@ -4641,6 +4859,16 @@ comment at the start of cc-engine.el for more info."
            (if beg (cons beg end))))))
        ))))
 
+(defun c-literal-start (&optional safe-pos)
+  "Return the start of the string or comment surrounding point, or nil if
+point isn't in one.  SAFE-POS, if non-nil, is a position before point which is
+a known \"safe position\", i.e. outside of any string or comment."
+  (if safe-pos
+      (let ((s (parse-partial-sexp safe-pos (point))))
+       (and (or (nth 3 s) (nth 4 s))
+            (nth 8 s)))
+    (car (cddr (c-state-semi-pp-to-literal (point))))))
+
 ;; In case external callers use this; it did have a docstring.
 (defalias 'c-literal-limits-fast 'c-literal-limits)
 
@@ -4705,13 +4933,10 @@ comment at the start of cc-engine.el for more info."
 
 (defsubst c-determine-limit-get-base (start try-size)
   ;; Get a "safe place" approximately TRY-SIZE characters before START.
-  ;; This doesn't preserve point.
+  ;; This defsubst doesn't preserve point.
   (let* ((pos (max (- start try-size) (point-min)))
-        (base (c-state-semi-safe-place pos))
-        (s (parse-partial-sexp base pos)))
-    (if (or (nth 4 s) (nth 3 s))       ; comment or string
-       (nth 8 s)
-      (point))))
+        (s (c-state-semi-pp-to-literal pos)))
+    (or (car (cddr s)) pos)))
 
 (defun c-determine-limit (how-far-back &optional start try-size)
   ;; Return a buffer position HOW-FAR-BACK non-literal characters from START
@@ -5091,8 +5316,9 @@ comment at the start of cc-engine.el for more info."
           ;; arrived at something that looks like a start or else
           ;; resort to `c-literal-limits'.
           (unless (looking-at c-literal-start-regexp)
-            (let ((range (c-literal-limits)))
-              (if range (goto-char (car range)))))
+            (let ((lit-start (c-literal-start)))
+              (if lit-start (goto-char lit-start)))
+            )
 
           (setq start-in-literal (point))) ; end of `and' arm.
 
@@ -5603,6 +5829,9 @@ comment at the start of cc-engine.el for more info."
 ;; Set by c-common-init in cc-mode.el.
 (defvar c-new-BEG)
 (defvar c-new-END)
+;; Set by c-after-change in cc-mode.el.
+(defvar c-old-BEG)
+(defvar c-old-END)
 
 (defun c-before-change-check-<>-operators (beg end)
   ;; Unmark certain pairs of "< .... >" which are currently marked as
@@ -5626,12 +5855,12 @@ comment at the start of cc-engine.el for more info."
   ;; 2010-01-29.
   (save-excursion
     (c-save-buffer-state
-       ((beg-lit-limits (progn (goto-char beg) (c-literal-limits)))
+       ((beg-lit-start (progn (goto-char beg) (c-literal-start)))
         (end-lit-limits (progn (goto-char end) (c-literal-limits)))
         new-beg new-end beg-limit end-limit)
       ;; Locate the earliest < after the barrier before the changed region,
       ;; which isn't already marked as a paren.
-      (goto-char  (if beg-lit-limits (car beg-lit-limits) beg))
+      (goto-char (or beg-lit-start beg))
       (setq beg-limit (c-determine-limit 512))
 
       ;; Remove the syntax-table/category properties from each pertinent <...>
@@ -5723,6 +5952,332 @@ comment at the start of cc-engine.el for more info."
                                       'c-decl-arg-start)))))))
       (or (c-forward-<>-arglist nil)
          (forward-char)))))
+
+\f
+;; Functions to handle C++ raw strings.
+;;
+;; A valid C++ raw string looks like
+;;     R"<id>(<contents>)<id>"
+;; , where <id> is an identifier from 0 to 16 characters long, not containing
+;; spaces, control characters, double quote or left/right paren.  <contents>
+;; can include anything which isn't the terminating )<id>", including new
+;; lines, "s, parentheses, etc.
+;;
+;; CC Mode handles C++ raw strings by the use of `syntax-table' text
+;; properties as follows:
+;;
+;; (i) On a validly terminated raw string, no `syntax-table' text properties
+;;   are applied to the opening and closing delimiters, but any " in the
+;;   contents is given the property value "punctuation" (`(1)') to prevent it
+;;   interacting with the "s in the delimiters.
+;;
+;;   The font locking routine `c-font-lock-c++-raw-strings' (in cc-fonts.el)
+;;   recognizes valid raw strings, and fontifies the delimiters (apart from
+;;   the parentheses) with the default face and the parentheses and the
+;;   <contents> with font-lock-string-face.
+;;
+;; (ii) A valid, but unterminated, raw string opening delimiter gets the
+;;   "punctuation" value (`(1)') of the `syntax-table' text property, and the
+;;   open parenthesis gets the "string fence" value (`(15)').
+;;
+;;   `c-font-lock-c++-raw-strings' puts c-font-lock-warning-face on the entire
+;;   unmatched opening delimiter (from the R up to the open paren), and allows
+;;   the rest of the buffer to get font-lock-string-face, caused by the
+;;   unmatched "string fence" `syntax-table' text property value.
+;;
+;; (iii) Inside a macro, a valid raw string is handled as in (i).  An
+;;   unmatched opening delimiter is handled slightly differently.  In addition
+;;   to the "punctuation" and "string fence" properties on the delimiter,
+;;   another "string fence" `syntax-table' property is applied to the last
+;;   possible character of the macro before the terminating linefeed (if there
+;;   is such a character after the "(").  This "last possible" character is
+;;   never a backslash escaping the end of line.  If the character preceding
+;;   this "last possible" character is itself a backslash, this preceding
+;;   character gets a "punctuation" `syntax-table' value.  If the "(" is
+;;   already at the end of the macro, it gets the "punctuation" value, and no
+;;   "string fence"s are used.
+;;
+;;   The effect on the fontification of either of these tactics is that rest of
+;;   the macro (if any) after the "(" gets font-lock-string-face, but the rest
+;;   of the file is fontified normally.
+
+
+(defun c-raw-string-pos ()
+  ;; Get POINT's relationship to any containing raw string.
+  ;; If point isn't in a raw string, return nil.
+  ;; Otherwise, return the following list:
+  ;;
+  ;;   (POS B\" B\( E\) E\")
+  ;;
+  ;; , where POS is the symbol `open-delim' if point is in the opening
+  ;; delimiter, the symbol `close-delim' if it's in the closing delimiter, and
+  ;; nil if it's in the string body.  B\", B\(, E\), E\" are the positions of
+  ;; the opening and closing quotes and parentheses of a correctly terminated
+  ;; raw string.  (N.B.: E\) and E\" are NOT on the "outside" of these
+  ;; characters.)  If the raw string is not terminated, E\) and E\" are set to
+  ;; nil.
+  ;;
+  ;; Note: this routine is dependant upon the correct syntax-table text
+  ;; properties being set.
+  (let ((state (c-state-semi-pp-to-literal (point)))
+       open-quote-pos open-paren-pos close-paren-pos close-quote-pos id)
+    (save-excursion
+      (when
+         (and
+          (cond
+           ((null (cadr state))
+            (or (eq (char-after) ?\")
+                (search-backward "\"" (max (- (point) 17) (point-min)) t)))
+           ((and (eq (cadr state) 'string)
+                 (goto-char (nth 2 state))
+                 (or (eq (char-after) ?\")
+                     (search-backward "\"" (max (- (point) 17) (point-min)) t))
+                 (not (bobp)))))
+          (eq (char-before) ?R)
+          (looking-at "\"\\([^ ()\\\n\r\t]\\{,16\\}\\)("))
+       (setq open-quote-pos (point)
+             open-paren-pos (match-end 1)
+             id (match-string-no-properties 1))
+       (goto-char (1+ open-paren-pos))
+       (when (and (not (c-get-char-property open-paren-pos 'syntax-table))
+                  (search-forward (concat ")" id "\"") nil t))
+         (setq close-paren-pos (match-beginning 0)
+               close-quote-pos (1- (point))))))
+    (and open-quote-pos
+        (list
+         (cond
+          ((<= (point) open-paren-pos)
+           'open-delim)
+          ((and close-paren-pos
+                (> (point) close-paren-pos))
+           'close-delim)
+          (t nil))
+         open-quote-pos open-paren-pos close-paren-pos close-quote-pos))))
+
+(defun c-depropertize-raw-string (id open-quote open-paren bound)
+  ;; Point is immediately after a raw string opening delimiter.  Remove any
+  ;; `syntax-table' text properties associated with the delimiter (if it's
+  ;; unmatched) or the raw string.
+  ;;
+  ;; ID, a string, is the delimiter's identifier.  OPEN-QUOTE and OPEN-PAREN
+  ;; are the buffer positions of the delimiter's components.  BOUND is the
+  ;; bound for searching for a matching closing delimiter; it is usually nil,
+  ;; but if we're inside a macro, it's the end of the macro.
+  ;;
+  ;; Point is moved to after the (terminated) raw string, or left after the
+  ;; unmatched opening delimiter, as the case may be.  The return value is of
+  ;; no significance.
+  (let ((open-paren-prop (c-get-char-property open-paren 'syntax-table)))
+    (cond
+     ((null open-paren-prop)
+      ;; A terminated raw string
+      (if (search-forward (concat ")" id "\"") nil t)
+         (c-clear-char-property-with-value
+          (1+ open-paren) (match-beginning 0) 'syntax-table '(1))))
+     ((or (and (equal open-paren-prop '(15)) (null bound))
+         (equal open-paren-prop '(1)))
+      ;; An unterminated raw string either not in a macro, or in a macro with
+      ;; the open parenthesis right up against the end of macro
+      (c-clear-char-property open-quote 'syntax-table)
+      (c-clear-char-property open-paren 'syntax-table))
+     (t
+      ;; An unterminated string in a macro, with at least one char after the
+      ;; open paren
+      (c-clear-char-property open-quote 'syntax-table)
+      (c-clear-char-property open-paren 'syntax-table)
+      (let ((after-string-fence-pos
+            (save-excursion
+              (goto-char (1+ open-paren))
+              (c-search-forward-char-property 'syntax-table '(15) bound))))
+       (when after-string-fence-pos
+         (c-clear-char-property (1- after-string-fence-pos) 'syntax-table)))
+      ))))
+
+(defun c-depropertize-raw-strings-in-region (start finish)
+  ;; Remove any `syntax-table' text properties associated with C++ raw strings
+  ;; contained in the region (START FINISH).  Point is undefined at entry and
+  ;; exit, and the return value has no significance.
+  (goto-char start)
+  (while (and (< (point) finish)
+             (re-search-forward
+              (concat "\\("                                 ; 1
+                      c-anchored-cpp-prefix                 ; 2
+                      "\\)\\|\\("                           ; 3
+                      "R\"\\([^ ()\\\n\r\t]\\{,16\\}\\)("   ; 4
+                      "\\)")
+              finish t))
+    (when (save-excursion
+           (goto-char (match-beginning 0)) (not (c-in-literal)))
+      (if (match-beginning 4)          ; the id
+         ;; We've found a raw string
+         (c-depropertize-raw-string
+          (match-string-no-properties 4) ; id
+          (1+ (match-beginning 3))       ; open quote
+          (match-end 4)                  ; open paren
+          nil)                           ; bound
+       ;; We've found a CPP construct.  Search for raw strings within it.
+       (goto-char (match-beginning 2)) ; the "#"
+       (c-end-of-macro)
+       (let ((eom (point)))
+         (goto-char (match-end 2))     ; after the "#".
+         (while (and (< (point) eom)
+                     (c-syntactic-re-search-forward
+                      "R\"\\([^ ()\\\n\r\t]\\{,16\\}\\)(" eom t))
+           (c-depropertize-raw-string
+            (match-string-no-properties 1) ; id
+            (1+ (match-beginning 0))       ; open quote
+            (match-end 1)                  ; open paren
+            eom)))))))                     ; bound.
+
+(defun c-before-change-check-raw-strings (beg end)
+  ;; This function clears `syntax-table' text properties from C++ raw strings
+  ;; in the region (c-new-BEG c-new-END).  BEG and END are the standard
+  ;; arguments supplied to any before-change function.
+  ;;
+  ;; Point is undefined on both entry and exit, and the return value has no
+  ;; significance.
+  ;;
+  ;; This function is called as a before-change function solely due to its
+  ;; membership of the C++ value of `c-get-state-before-change-functions'.
+  (c-save-buffer-state
+      ((beg-rs (progn (goto-char beg) (c-raw-string-pos)))
+       (beg-plus (if (null beg-rs)
+                    beg
+                  (max beg
+                       (1+ (or (nth 4 beg-rs) (nth 2 beg-rs))))))
+       (end-rs (progn (goto-char end) (c-raw-string-pos))) ; FIXME!!!
+                                       ; Optimize this so that we don't call
+                                       ; `c-raw-string-pos' twice when once
+                                       ; will do.  (2016-06-02).
+       (end-minus (if (null end-rs)
+                     end
+                   (min end (cadr end-rs))))
+       )
+    (when beg-rs
+      (setq c-new-BEG (min c-new-BEG (1- (cadr beg-rs)))))
+    (c-depropertize-raw-strings-in-region c-new-BEG beg-plus)
+
+    (when end-rs
+      (setq c-new-END (max c-new-END
+                          (1+ (or (nth 4 end-rs)
+                                  (nth 2 end-rs))))))
+    (c-depropertize-raw-strings-in-region end-minus c-new-END)))
+
+(defun c-propertize-raw-string-opener (id open-quote open-paren bound)
+  ;; Point is immediately after a raw string opening delimiter.  Apply any
+  ;; pertinent `syntax-table' text properties to the delimiter and also the
+  ;; raw string, should there be a valid matching closing delimiter.
+  ;;
+  ;; ID, a string, is the delimiter's identifier.  OPEN-QUOTE and OPEN-PAREN
+  ;; are the buffer positions of the delimiter's components.  BOUND is the
+  ;; bound for searching for a matching closing delimiter; it is usually nil,
+  ;; but if we're inside a macro, it's the end of the macro.
+  ;;
+  ;; Point is moved to after the (terminated) raw string, or left after the
+  ;; unmatched opening delimiter, as the case may be.  The return value is of
+  ;; no significance.
+  (if (search-forward (concat ")" id "\"") bound t)
+      (let ((end-string (match-beginning 0))
+           (after-quote (match-end 0)))
+       (goto-char open-paren)
+       (while (progn (skip-syntax-forward "^\"" end-string)
+                     (< (point) end-string))
+         (c-put-char-property (point) 'syntax-table '(1)) ; punctuation
+         (forward-char))
+       (goto-char after-quote))
+    (c-put-char-property open-quote 'syntax-table '(1))             ; punctuation
+    (c-put-char-property open-paren 'syntax-table '(15))     ; generic string
+    (when bound
+      ;; In a CPP construct, we try to apply a generic-string `syntax-table'
+      ;; text property to the last possible character in the string, so that
+      ;; only characters within the macro get "stringed out".
+      (goto-char bound)
+      (if (save-restriction
+           (narrow-to-region (1+ open-paren) (point-max))
+           (re-search-backward
+            (eval-when-compile
+              ;; This regular expression matches either an escape pair (which
+              ;; isn't an escaped NL) (submatch 5) or a non-escaped character
+              ;; (which isn't itself a backslash) (submatch 10).  The long
+              ;; preambles to these (respectively submatches 2-4 and 6-9)
+              ;; ensure that we have the correct parity for sequences of
+              ;; backslashes, etc..
+              (concat "\\("            ; 1
+                      "\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)*" ; 2-4
+                      "\\(\\\\.\\)"    ; 5
+                      "\\|"
+                      "\\(\\`\\|[^\\]\\|\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)+\\)" ; 6-9
+                      "\\([^\\]\\)"    ; 10
+                      "\\)"
+                      "\\(\\\\\n\\)*\\=")) ; 11
+             (1+ open-paren) t))
+         (if (match-beginning 10)
+             (c-put-char-property (match-beginning 10) 'syntax-table '(15))
+           (c-put-char-property (match-beginning 5) 'syntax-table '(1))
+           (c-put-char-property (1+ (match-beginning 5)) 'syntax-table '(15)))
+       (c-put-char-property open-paren 'syntax-table '(1)))
+      (goto-char bound))))
+
+(defun c-after-change-re-mark-raw-strings (beg end old-len)
+  ;; This function applies `syntax-table' text properties to C++ raw strings
+  ;; beginning in the region (c-new-BEG c-new-END).  BEG, END, and OLD-LEN are
+  ;; the standard arguments supplied to any after-change function.
+  ;;
+  ;; Point is undefined on both entry and exit, and the return value has no
+  ;; significance.
+  ;;
+  ;; This function is called as an after-change function solely due to its
+  ;; membership of the C++ value of `c-before-font-lock-functions'.
+  (c-save-buffer-state ()
+    ;; If the region (c-new-BEG c-new-END) has expanded, remove
+    ;; `syntax-table' text-properties from the new piece(s).
+    (when (< c-new-BEG c-old-BEG)
+      (let ((beg-rs (progn (goto-char c-old-BEG) (c-raw-string-pos))))
+       (c-depropertize-raw-strings-in-region
+        c-new-BEG
+        (if beg-rs
+            (1+ (or (nth 4 beg-rs) (nth 2 beg-rs)))
+          c-old-BEG))))
+    (when (> c-new-END c-old-END)
+      (let ((end-rs (progn (goto-char c-old-END) (c-raw-string-pos))))
+       (c-depropertize-raw-strings-in-region
+        (if end-rs
+            (cadr end-rs)
+          c-old-END)
+        c-new-END)))
+
+    (goto-char c-new-BEG)
+    (while (and (< (point) c-new-END)
+               (re-search-forward
+                (concat "\\("                                 ; 1
+                        c-anchored-cpp-prefix                 ; 2
+                        "\\)\\|\\("                           ; 3
+                        "R\"\\([^ ()\\\n\r\t]\\{,16\\}\\)("   ; 4
+                        "\\)")
+                c-new-END t))
+      (when (save-excursion
+             (goto-char (match-beginning 0)) (not (c-in-literal)))
+       (if (match-beginning 4)         ; the id
+           ;; We've found a raw string.
+           (c-propertize-raw-string-opener
+            (match-string-no-properties 4) ; id
+            (1+ (match-beginning 3))       ; open quote
+            (match-end 4)                  ; open paren
+            nil)                           ; bound
+         ;; We've found a CPP construct.  Search for raw strings within it.
+         (goto-char (match-beginning 2)) ; the "#"
+         (c-end-of-macro)
+         (let ((eom (point)))
+           (goto-char (match-end 2))   ; after the "#".
+           (while (and (< (point) eom)
+                       (c-syntactic-re-search-forward
+                        "R\"\\([^ ()\\\n\r\t]\\{,16\\}\\)(" eom t))
+             (c-propertize-raw-string-opener
+              (match-string-no-properties 1) ; id
+              (1+ (match-beginning 0))       ; open quote
+              (match-end 1)                  ; open paren
+              eom))))))))                    ; bound
+
 \f
 ;; Handling of small scale constructs like types and names.
 
@@ -5832,18 +6387,21 @@ comment at the start of cc-engine.el for more info."
   ;;
   ;; This macro might do hidden buffer changes.
   `(let (res)
+     (setq c-last-identifier-range nil)
      (while (if (setq res ,(if (eq type 'type)
                               `(c-forward-type)
                             `(c-forward-name)))
                nil
              (cond ((looking-at c-keywords-regexp)
                     (c-forward-keyword-clause 1))
-                   ((looking-at c-noise-macro-with-parens-name-re)
+                   ((and c-opt-cpp-prefix
+                         (looking-at c-noise-macro-with-parens-name-re))
                     (c-forward-noise-clause)))))
-     (when (memq res '(t known found prefix))
-       ,(when (eq type 'ref)
-         `(when c-record-type-identifiers
-            (c-record-ref-id c-last-identifier-range)))
+     (when (memq res '(t known found prefix maybe))
+       (when c-record-type-identifiers
+        ,(if (eq type 'type)
+             `(c-record-type-id c-last-identifier-range)
+           `(c-record-ref-id c-last-identifier-range)))
        t)))
 
 (defmacro c-forward-id-comma-list (type update-safe-pos)
@@ -6021,7 +6579,6 @@ comment at the start of cc-engine.el for more info."
                  ;; `nconc' doesn't mind that the tail of
                  ;; `c-record-found-types' is t.
                  (nconc c-record-found-types c-record-type-identifiers)))
-           (if (c-major-mode-is 'java-mode) (c-fontify-recorded-types-and-refs))
          t)
 
       (goto-char start)
@@ -6067,28 +6624,31 @@ comment at the start of cc-engine.el for more info."
                (progn
                  (c-forward-syntactic-ws)
                  (when (or (and c-record-type-identifiers all-types)
-                           (c-major-mode-is 'java-mode))
-                   ;; All encountered identifiers are types, so set the
-                   ;; promote flag and parse the type.
-                   (progn
-                     (c-forward-syntactic-ws)
-                     (if (looking-at "\\?")
-                         (forward-char)
-                       (when (looking-at c-identifier-start)
+                           (not (equal c-inside-<>-type-key "\\(\\<\\>\\)")))
+                   (c-forward-syntactic-ws)
+                   (cond
+                    ((eq (char-after) ??)
+                     (forward-char))
+                    ((and (looking-at c-identifier-start)
+                          (not (looking-at c-keywords-regexp)))
+                     (if (or (and all-types c-record-type-identifiers)
+                             (c-major-mode-is 'java-mode))
+                         ;; All encountered identifiers are types, so set the
+                         ;; promote flag and parse the type.
                          (let ((c-promote-possible-types t)
                                (c-record-found-types t))
-                           (c-forward-type))))
+                           (c-forward-type))
+                       (c-forward-token-2))))
 
-                     (c-forward-syntactic-ws)
+                   (c-forward-syntactic-ws)
 
-                     (when (or (looking-at "extends")
-                               (looking-at "super"))
-                       (forward-word-strictly)
-                       (c-forward-syntactic-ws)
-                       (let ((c-promote-possible-types t)
-                             (c-record-found-types t))
-                         (c-forward-type)
-                         (c-forward-syntactic-ws)))))
+                   (when (looking-at c-inside-<>-type-key)
+                     (goto-char (match-end 1))
+                     (c-forward-syntactic-ws)
+                     (let ((c-promote-possible-types t)
+                           (c-record-found-types t))
+                       (c-forward-type))
+                     (c-forward-syntactic-ws)))
 
                  (setq pos (point))    ; e.g. first token inside the '<'
 
@@ -6409,14 +6969,14 @@ comment at the start of cc-engine.el for more info."
              ((and c-recognize-<>-arglists
                    (eq (char-after) ?<))
               ;; Maybe an angle bracket arglist.
-              (when (let ((c-record-type-identifiers t)
-                          (c-record-found-types t))
+              (when (let (c-last-identifier-range)
                       (c-forward-<>-arglist nil))
 
-                (c-add-type start (1+ pos))
                 (c-forward-syntactic-ws)
-                (setq pos (point)
-                      c-last-identifier-range nil)
+                (unless (eq (char-after) ?\()
+                  (setq c-last-identifier-range nil)
+                  (c-add-type start (1+ pos)))
+                (setq pos (point))
 
                 (if (and c-opt-identifier-concat-key
                          (looking-at c-opt-identifier-concat-key))
@@ -6430,7 +6990,8 @@ comment at the start of cc-engine.el for more info."
                       (c-forward-syntactic-ws)
                       t)
 
-                  (when (and c-record-type-identifiers id-start)
+                  (when (and c-record-type-identifiers id-start
+                             (not (eq (char-after) ?\()))
                     (c-record-type-id (cons id-start id-end)))
                   (setq res 'template)
                   nil)))
@@ -6506,7 +7067,8 @@ comment at the start of cc-engine.el for more info."
       (while (cond
              ((looking-at c-decl-hangon-key)
               (c-forward-keyword-clause 1))
-             ((looking-at c-noise-macro-with-parens-name-re)
+             ((and c-opt-cpp-prefix
+                   (looking-at c-noise-macro-with-parens-name-re))
               (c-forward-noise-clause))))
 
       (setq pos (point))
@@ -6611,9 +7173,18 @@ comment at the start of cc-engine.el for more info."
                           ;; It's an identifier that might be a type.
                           'maybe))))
            ((eq name-res 'template)
-            ;; A template is a type.
+            ;; A template is sometimes a type.
             (goto-char id-end)
-            (setq res t))
+            (c-forward-syntactic-ws)
+            (setq res
+                  (if (eq (char-after) ?\()
+                      (if (c-check-type id-start id-end)
+                          ;; It's an identifier that has been used as
+                          ;; a type somewhere else.
+                          'found
+                        ;; It's an identifier that might be a type.
+                        'maybe)
+                    t)))
            (t
             ;; Otherwise it's an operator identifier, which is not a type.
             (goto-char start)
@@ -6726,6 +7297,31 @@ comment at the start of cc-engine.el for more info."
      (prog1 (car ,ps)
        (setq ,ps (cdr ,ps)))))
 
+(defun c-back-over-compound-identifier ()
+  ;; Point is putatively just after a "compound identifier", i.e. something
+  ;; looking (in C++) like this "FQN::of::base::Class".  Move to the start of
+  ;; this construct and return t.  If the parsing fails, return nil, leaving
+  ;; point unchanged.
+  (let ((here (point))
+       end
+       )
+    (if (not (c-simple-skip-symbol-backward))
+       nil
+      (while
+         (progn
+           (setq end (point))
+           (c-backward-syntactic-ws)
+           (c-backward-token-2)
+           (and
+            c-opt-identifier-concat-key
+            (looking-at c-opt-identifier-concat-key)
+            (progn
+              (c-backward-syntactic-ws)
+              (c-simple-skip-symbol-backward))))
+       (setq end (point)))
+      (goto-char end)
+      t)))
+
 (defun c-back-over-member-initializer-braces ()
   ;; Point is just after a closing brace/parenthesis.  Try to parse this as a
   ;; C++ member initializer list, going back to just after the introducing ":"
@@ -6736,7 +7332,7 @@ comment at the start of cc-engine.el for more info."
          (when (not (c-go-list-backward))
            (throw 'done nil))
          (c-backward-syntactic-ws)
-         (when (not (c-simple-skip-symbol-backward))
+         (when (not (c-back-over-compound-identifier))
            (throw 'done nil))
          (c-backward-syntactic-ws)
 
@@ -6748,7 +7344,7 @@ comment at the start of cc-engine.el for more info."
            (when (not (c-go-list-backward))
              (throw 'done nil))
            (c-backward-syntactic-ws)
-           (when (not (c-simple-skip-symbol-backward))
+           (when (not (c-back-over-compound-identifier))
              (throw 'done nil))
            (c-backward-syntactic-ws))
 
@@ -6772,7 +7368,7 @@ comment at the start of cc-engine.el for more info."
      (when (not (c-go-list-backward))
        (throw 'done nil))
      (c-backward-syntactic-ws)
-     (when (not (c-simple-skip-symbol-backward))
+     (when (not (c-back-over-compound-identifier))
        (throw 'level nil))
      (c-backward-syntactic-ws)))
 
@@ -6794,7 +7390,7 @@ comment at the start of cc-engine.el for more info."
                      (when (not (c-go-list-backward))
                        (throw 'done nil))
                      (c-backward-syntactic-ws))
-                   (when (c-simple-skip-symbol-backward)
+                   (when (c-back-over-compound-identifier)
                      (c-backward-syntactic-ws))
                    (c-back-over-list-of-member-inits)
                    (and (eq (char-before) ?:)
@@ -6810,7 +7406,7 @@ comment at the start of cc-engine.el for more info."
                    (catch 'level
                      (goto-char pos)
                      (c-backward-syntactic-ws)
-                     (when (not (c-simple-skip-symbol-backward))
+                     (when (not (c-back-over-compound-identifier))
                        (throw 'level nil))
                      (c-backward-syntactic-ws)
                      (c-back-over-list-of-member-inits)
@@ -6911,7 +7507,8 @@ comment at the start of cc-engine.el for more info."
                  (cond
                   ((looking-at c-decl-hangon-key)
                    (c-forward-keyword-clause 1))
-                  ((looking-at c-noise-macro-with-parens-name-re)
+                  ((and c-opt-cpp-prefix
+                        (looking-at c-noise-macro-with-parens-name-re))
                    (c-forward-noise-clause))
                   ((and (looking-at c-type-decl-prefix-key)
                         (if (and (c-major-mode-is 'c++-mode)
@@ -6966,7 +7563,8 @@ comment at the start of cc-engine.el for more info."
              (while (cond
                      ((looking-at c-decl-hangon-key)
                       (c-forward-keyword-clause 1))
-                     ((looking-at c-noise-macro-with-parens-name-re)
+                     ((and c-opt-cpp-prefix
+                           (looking-at c-noise-macro-with-parens-name-re))
                       (c-forward-noise-clause))))
              (<= (point) limit))
 
@@ -6999,9 +7597,9 @@ comment at the start of cc-engine.el for more info."
   ;; If a declaration is parsed:
   ;;
   ;;   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.  (See
-  ;;   below for the cdr.)
+  ;;   declarator, if there is one.  The return value is a list of 4 elements,
+  ;;   where the first is the position of the first token in the declarator.
+  ;;   (See below for the other three.)
   ;;   Some examples:
   ;;
   ;;    void foo (int a, char *b) stuff ...
@@ -7032,7 +7630,7 @@ comment at the start of cc-engine.el for more info."
   ;;
   ;;
   ;;
-  ;;   The cdr of the return value is non-nil when a
+  ;;   The second element of the return value is non-nil when a
   ;;   `c-typedef-decl-kwds' specifier is found in the declaration.
   ;;   Specifically it is a dotted pair (A . B) where B is t when a
   ;;   `c-typedef-kwds' ("typedef") is present, and A is t when some
@@ -7040,6 +7638,10 @@ comment at the start of cc-engine.el for more info."
   ;;   specifier is present.  I.e., (some of) the declared
   ;;   identifier(s) are types.
   ;;
+  ;;   The third element of the return value is non-nil when the declaration
+  ;;   parsed might be an expression.  The fourth element is the position of
+  ;;   the start of the type identifier.
+  ;;
   ;; If a cast is parsed:
   ;;
   ;;   The point is left at the first token after the closing paren of
@@ -7132,12 +7734,27 @@ comment at the start of cc-engine.el for more info."
        cast-end
        ;; Have we got a new-style C++11 "auto"?
        new-style-auto
+       ;; Set when the symbol before `preceding-token-end' is known to
+       ;; terminate the previous construct, or when we're at point-min.
+       at-decl-start
        ;; Save `c-record-type-identifiers' and
        ;; `c-record-ref-identifiers' since ranges are recorded
        ;; speculatively and should be thrown away if it turns out
        ;; that it isn't a declaration or cast.
        (save-rec-type-ids c-record-type-identifiers)
-       (save-rec-ref-ids c-record-ref-identifiers))
+       (save-rec-ref-ids c-record-ref-identifiers)
+       ;; Set when we parse a declaration which might also be an expression,
+       ;; such as "a *b".  See CASE 16 and CASE 17.
+       maybe-expression)
+
+    (save-excursion
+      (goto-char preceding-token-end)
+      (setq at-decl-start
+           (or (bobp)
+               (let ((tok-end (point)))
+                 (c-backward-token-2)
+                 (member (buffer-substring-no-properties (point) tok-end)
+                         c-pre-start-tokens)))))
 
     (while (c-forward-annotation)
       (c-forward-syntactic-ws))
@@ -7161,7 +7778,8 @@ comment at the start of cc-engine.el for more info."
            (save-excursion
              (c-forward-keyword-clause 1)
              (setq kwd-clause-end (point))))
-          ((looking-at c-noise-macro-with-parens-name-re)
+          ((and c-opt-cpp-prefix
+                (looking-at c-noise-macro-with-parens-name-re))
            (setq noise-start (point))
            (c-forward-noise-clause)
            (setq kwd-clause-end (point))))
@@ -7267,7 +7885,8 @@ comment at the start of cc-engine.el for more info."
       (while
          (cond ((looking-at c-decl-hangon-key)
                 (c-forward-keyword-clause 1))
-               ((looking-at c-noise-macro-with-parens-name-re)
+               ((and c-opt-cpp-prefix
+                     (looking-at c-noise-macro-with-parens-name-re))
                 (c-forward-noise-clause))))
       (setq id-start (point)))
 
@@ -7399,36 +8018,42 @@ comment at the start of cc-engine.el for more info."
               (setq got-identifier (c-forward-name))
               (setq name-start pos)))
 
-      ;; Skip over type decl suffix operators.
-      (while (if (looking-at c-type-decl-suffix-key)
+      ;; Skip over type decl suffix operators and trailing noise macros.
+      (while
+         (cond
+          ((and c-opt-cpp-prefix
+                (looking-at c-noise-macro-with-parens-name-re))
+           (c-forward-noise-clause))
+
+          ((looking-at c-type-decl-suffix-key)
+           (if (eq (char-after) ?\))
+               (when (> paren-depth 0)
+                 (setq paren-depth (1- paren-depth))
+                 (forward-char)
+                 t)
+             (when (if (save-match-data (looking-at "\\s("))
+                       (c-safe (c-forward-sexp 1) t)
+                     (goto-char (match-end 1))
+                     t)
+               (when (and (not got-suffix-after-parens)
+                          (= paren-depth 0))
+                 (setq got-suffix-after-parens (match-beginning 0)))
+               (setq got-suffix t))))
 
-                (if (eq (char-after) ?\))
-                    (when (> paren-depth 0)
-                      (setq paren-depth (1- paren-depth))
-                      (forward-char)
-                      t)
-                  (when (if (save-match-data (looking-at "\\s("))
-                            (c-safe (c-forward-sexp 1) t)
-                          (goto-char (match-end 1))
-                          t)
-                    (when (and (not got-suffix-after-parens)
-                               (= paren-depth 0))
-                      (setq got-suffix-after-parens (match-beginning 0)))
-                    (setq got-suffix t)))
-
-              ;; No suffix matched.  We might have matched the
-              ;; identifier as a type and the open paren of a
-              ;; function arglist as a type decl prefix.  In that
-              ;; case we should "backtrack": Reinterpret the last
-              ;; type as the identifier, move out of the arglist and
-              ;; continue searching for suffix operators.
-              ;;
-              ;; Do this even if there's no preceding type, to cope
-              ;; with old style function declarations in K&R C,
-              ;; (con|de)structors in C++ and `c-typeless-decl-kwds'
-              ;; style declarations.  That isn't applicable in an
-              ;; arglist context, though.
-              (when (and (= paren-depth 1)
+          (t
+           ;; No suffix matched.  We might have matched the
+           ;; identifier as a type and the open paren of a
+           ;; function arglist as a type decl prefix.  In that
+           ;; case we should "backtrack": Reinterpret the last
+           ;; type as the identifier, move out of the arglist and
+           ;; continue searching for suffix operators.
+           ;;
+           ;; Do this even if there's no preceding type, to cope
+           ;; with old style function declarations in K&R C,
+           ;; (con|de)structors in C++ and `c-typeless-decl-kwds'
+           ;; style declarations.  That isn't applicable in an
+           ;; arglist context, though.
+           (when (and (= paren-depth 1)
                          (not got-prefix-before-parens)
                          (not (eq at-type t))
                          (or backup-at-type
@@ -7440,7 +8065,7 @@ comment at the start of cc-engine.el for more info."
                          (eq (char-before pos) ?\)))
                 (c-fdoc-shift-type-backward)
                 (goto-char pos)
-                t))
+                t)))
 
        (c-forward-syntactic-ws))
 
@@ -7506,16 +8131,32 @@ comment at the start of cc-engine.el for more info."
                              maybe-typeless
                              backup-maybe-typeless
                              (eq at-decl-or-cast t)
+                             ;; Check whether we have "bar (gnu);" where we
+                             ;; are directly inside a class (etc.) called "bar".
                              (save-excursion
-                               (goto-char name-start)
-                               (not (memq (c-forward-type) '(nil maybe))))))
+                               (and
+                                (progn
+                                  (goto-char name-start)
+                                  (not (memq (c-forward-type) '(nil maybe))))
+                                (progn
+                                 (goto-char id-start)
+                                 (c-directly-in-class-called-p
+                                  (buffer-substring
+                                   type-start
+                                   (progn
+                                     (goto-char type-start)
+                                     (c-forward-type)
+                                     (c-backward-syntactic-ws)
+                                     (point)))))))))
                 ;; Got a declaration of the form "foo bar (gnu);" or "bar
                 ;; (gnu);" where we've recognized "bar" as the type and "gnu"
-                ;; as the declarator.  In this case it's however more likely
-                ;; that "bar" is the declarator and "gnu" a function argument
-                ;; or initializer (if `c-recognize-paren-inits' is set),
-                ;; since the parens around "gnu" would be superfluous if it's
-                ;; a declarator.  Shift the type one step backward.
+                ;; as the declarator, and in the latter case, checked that
+                ;; "bar (gnu)" appears directly inside the class "bar".  In
+                ;; this case it's however more likely that "bar" is the
+                ;; declarator and "gnu" a function argument or initializer
+                ;; (if `c-recognize-paren-inits' is set), since the parens
+                ;; around "gnu" would be superfluous if it's a declarator.
+                ;; Shift the type one step backward.
                 (c-fdoc-shift-type-backward)))
 
           ;; Found no identifier.
@@ -7749,12 +8390,16 @@ comment at the start of cc-engine.el for more info."
                          at-type
                          (or at-decl-end (looking-at "=[^=]"))
                          (not context)
-                         (not got-suffix))
-                ;; Got something like "foo * bar;".  Since we're not inside an
-                ;; arglist it would be a meaningless expression because the
-                ;; result isn't used.  We therefore choose to recognize it as
-                ;; a declaration.  Do not allow a suffix since it could then
-                ;; be a function call.
+                         (or (not got-suffix)
+                             at-decl-start))
+                ;; Got something like "foo * bar;".  Since we're not inside
+                ;; an arglist it would be a meaningless expression because
+                ;; the result isn't used.  We therefore choose to recognize
+                ;; it as a declaration.  We only allow a suffix (which makes
+                ;; the construct look like a function call) when
+                ;; `at-decl-start' provides additional evidence that we do
+                ;; have a declaration.
+                (setq maybe-expression t)
                 (throw 'at-decl-or-cast t))
 
               ;; CASE 17
@@ -7766,6 +8411,7 @@ comment at the start of cc-engine.el for more info."
                 ;; be an odd expression or it could be a declaration.  Treat
                 ;; it as a declaration if "a" has been used as a type
                 ;; somewhere else (if it's a known type we won't get here).
+                (setq maybe-expression t)
                 (throw 'at-decl-or-cast t)))
 
           ;; CASE 18
@@ -7889,9 +8535,11 @@ comment at the start of cc-engine.el for more info."
            (goto-char type-start)
            (c-forward-type))))
 
-      (cons id-start
+      (list id-start
            (and (or at-type-decl at-typedef)
-                (cons at-type-decl at-typedef))))
+                (cons at-type-decl at-typedef))
+           maybe-expression
+           type-start))
 
      (t
       ;; False alarm.  Restore the recorded ranges.
@@ -8825,6 +9473,22 @@ comment at the start of cc-engine.el for more info."
                  (c-syntactic-skip-backward c-block-prefix-charset limit t)
                  (eq (char-before) ?>))))))
 
+    ;; Skip back over noise clauses.
+    (while (and
+           c-opt-cpp-prefix
+           (eq (char-before) ?\))
+           (let ((after-paren (point)))
+             (if (and (c-go-list-backward)
+                      (progn (c-backward-syntactic-ws)
+                             (c-simple-skip-symbol-backward))
+                      (or (looking-at c-paren-nontype-key)
+                          (looking-at c-noise-macro-with-parens-name-re)))
+                 (progn
+                   (c-syntactic-skip-backward c-block-prefix-charset limit t)
+                   t)
+               (goto-char after-paren)
+               nil))))
+
     ;; Note: Can't get bogus hits inside template arglists below since they
     ;; have gotten paren syntax above.
     (when (and
@@ -8931,6 +9595,26 @@ comment at the start of cc-engine.el for more info."
 
       kwd-start)))
 
+(defun c-directly-in-class-called-p (name)
+  ;; Check whether point is directly inside a brace block which is the brace
+  ;; block of a class, struct, or union which is called NAME, a string.
+  (let* ((paren-state (c-parse-state))
+        (brace-pos (c-pull-open-brace paren-state))
+       )
+    (when (eq (char-after brace-pos) ?{)
+      (goto-char brace-pos)
+      (save-excursion
+                                       ; *c-looking-at-decl-block
+                                       ; containing-sexp goto-start &optional
+                                       ; limit)
+       (when (and (c-looking-at-decl-block
+                   (c-pull-open-brace paren-state)
+                   nil)
+                  (looking-at c-class-key))
+         (goto-char (match-end 1))
+         (c-forward-syntactic-ws)
+         (looking-at name))))))
+
 (defun c-search-uplist-for-classkey (paren-state)
   ;; Check if the closest containing paren sexp is a declaration
   ;; block, returning a 2 element vector in that case.  Aref 0
@@ -8981,11 +9665,11 @@ comment at the start of cc-engine.el for more info."
                      (not (looking-at "=")))))
       b-pos)))
 
-(defun c-backward-colon-prefixed-type ()
-  ;; We're at the token after what might be a type prefixed with a colon.  Try
-  ;; moving backward over this type and the colon.  On success, return t and
-  ;; leave point before colon; on failure, leave point unchanged.  Will clobber
-  ;; match data.
+(defun c-backward-typed-enum-colon ()
+  ;; We're at a "{" which might be the opening brace of a enum which is
+  ;; strongly typed (by a ":" followed by a type).  If this is the case, leave
+  ;; point before the colon and return t.  Otherwise leave point unchanged and return nil.
+  ;; Match data will be clobbered.
   (let ((here (point))
        (colon-pos nil))
     (save-excursion
@@ -8994,7 +9678,10 @@ comment at the start of cc-engine.el for more info."
               (or (not (looking-at "\\s)"))
                   (c-go-up-list-backward))
               (cond
-               ((eql (char-after) ?:)
+               ((and (eql (char-after) ?:)
+                     (save-excursion
+                       (c-backward-syntactic-ws)
+                       (c-on-identifier)))
                 (setq colon-pos (point))
                 (forward-char)
                 (c-forward-syntactic-ws)
@@ -9018,7 +9705,7 @@ comment at the start of cc-engine.el for more info."
   (let ((here (point))
        up-sexp-pos before-identifier)
     (when c-recognize-post-brace-list-type-p
-      (c-backward-colon-prefixed-type))
+      (c-backward-typed-enum-colon))
     (while
        (and
         (eq (c-backward-token-2) 0)
@@ -9038,7 +9725,8 @@ comment at the start of cc-engine.el for more info."
          ((eq (char-after) ?\()
           (and (eq (c-backward-token-2) 0)
                (or (looking-at c-decl-hangon-key)
-                   (looking-at c-noise-macro-with-parens-name-re))))
+                   (and c-opt-cpp-prefix
+                        (looking-at c-noise-macro-with-parens-name-re)))))
 
          ((and c-recognize-<>-arglists
                (eq (char-after) ?<)
@@ -10027,8 +10715,8 @@ comment at the start of cc-engine.el for more info."
             ;; versions, which results in that we get nil from
             ;; `c-literal-limits' even when `c-in-literal' claims
             ;; we're inside a comment.
-            (setq placeholder (c-literal-limits lim)))
-       (c-add-syntax literal (car placeholder)))
+            (setq placeholder (c-literal-start lim)))
+       (c-add-syntax literal placeholder))
 
        ;; CASE 3: in a cpp preprocessor macro continuation.
        ((and (save-excursion
@@ -10303,7 +10991,8 @@ comment at the start of cc-engine.el for more info."
              (while (cond
                      ((looking-at c-specifier-key)
                       (c-forward-keyword-clause 1))
-                     ((looking-at c-noise-macro-with-parens-name-re)
+                     ((and c-opt-cpp-prefix
+                           (looking-at c-noise-macro-with-parens-name-re))
                       (c-forward-noise-clause))))
              (setq placeholder (c-point 'boi))
              (or (consp special-brace-list)
@@ -10359,7 +11048,8 @@ comment at the start of cc-engine.el for more info."
              (while (cond
                      ((looking-at c-specifier-key)
                       (c-forward-keyword-clause 1))
-                     ((looking-at c-noise-macro-with-parens-name-re)
+                     ((and c-opt-cpp-prefix
+                           (looking-at c-noise-macro-with-parens-name-re))
                       (c-forward-noise-clause))))
              (c-add-syntax 'defun-open (c-point 'boi))
              ;; Bogus to use bol here, but it's the legacy.  (Resolved,
@@ -10994,7 +11684,8 @@ comment at the start of cc-engine.el for more info."
            (while (cond
                    ((looking-at c-specifier-key)
                     (c-forward-keyword-clause 1))
-                   ((looking-at c-noise-macro-with-parens-name-re)
+                   ((and c-opt-cpp-prefix
+                         (looking-at c-noise-macro-with-parens-name-re))
                     (c-forward-noise-clause))))
            (c-add-syntax 'brace-list-open (c-point 'boi))))