From 578d9aaf82b386c1a0316dde491d297e18e10636 Mon Sep 17 00:00:00 2001
From: Alan Mackenzie <acm@muc.de>
Date: Sun, 21 Aug 2016 16:00:15 +0000
Subject: [PATCH] Adapt CC Mode for C++11 uniform initialization.

For fontification, introduce a new "context", 'non-decl, to be used for
brace
lists; also a new value for the property 'c-type, called 'c-not-decl.

* lisp/progmodes/cc-engine.el (c-back-over-compound-identifier): Check that
an ostensible symbol we're going to move over isn't a keyword.
(c-forward-decl-or-cast-1): CASE 1: Where we have two consecutive identifiers
(hence a declaration), and an unmatched open paren, perform
c-fdoc-shift-type-backwards to recognize the partial construct correctly.
Whilst checking a type decl expression, check for and handle C++11's "copy
initialization", where we have <type>(<constant>).  Recognize
<id><id>(... (where the paren is unclosed) as a declaration.
(c-looking-at-or-maybe-in-bracelist): New function, extracted from
c-inside-bracelist-p.  Recognize as bracelists "{"s which are preceded by
valid tokens other than "=".  Recognize a bracelist when preceded by a
template declaration.
(c-inside-bracelist-p): Call c-looking-at-or-maybe-in-bracelist in place of
much inline code.
(c-looking-at-inexpr-block): Amend so that it won't wrongly recognise an
initialization starting "({" as an in-expression block, by checking for
semicolons, as opposed to commas, separating elements inside it.
(c-guess-continued-construct): (CASE B-2): Recognize a brace-list-open by
calling c-looking-at-or-maybe-in-bracelist rather than checking for a
preceding "=".  (CASE B-5): New code to recognize new construct "return {
...}".
(c-guess-basic-syntax): (CASE 5A.3): Additionally recognize a "{" preceded by
"return", or "{" preceded by <type><identifier> as a bracelist.

* lisp/progmodes/cc-fonts.el (c-font-lock-declarations): Recognize brace
lists, giving them `context' 'non-decl.  Pass over elements of one by regexp
search for "," rather than calling c-forward-decl-or-cast-1.

* lisp/progmodes/cc-langs.el (c-return-kwds, c-return-key): New lang
constants/variables to recognize "return".
(c-pre-id-bracelist-key): New lang constant/variable to recognize tokens
which, when preceding an identifier followed by a brace, signify the brace as
a bracelist.

* lisp/progmodes/cc-mode.el (c-fl-decl-start): When searching outwards for
the start of a "local" declaration, move out from an enclosing brace when
that is the start of a brace list.
---
 lisp/progmodes/cc-engine.el | 364 ++++++++++++++++++++++++------------
 lisp/progmodes/cc-fonts.el  | 267 ++++++++++++++------------
 lisp/progmodes/cc-langs.el  |  17 ++
 lisp/progmodes/cc-mode.el   |  15 +-
 4 files changed, 415 insertions(+), 248 deletions(-)

diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 8e8e4e490b7..ccdc1b15a68 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -130,6 +130,10 @@
 ;;  	 'c-decl-type-start is used when the declarators are types,
 ;;  	 'c-decl-id-start otherwise.
 ;;
+;;     'c-not-decl
+;;       Put on the brace which introduces a brace list and on the commas
+;;       which separate the element within it.
+;;
 ;; 'c-awk-NL-prop
 ;;   Used in AWK mode to mark the various kinds of newlines.  See
 ;;   cc-awk.el.
@@ -7354,10 +7358,10 @@ comment at the start of cc-engine.el for more info."
   ;; 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))
+	end)
+    (if (not (c-on-identifier))
 	nil
+      (c-simple-skip-symbol-backward)
       (while
 	  (progn
 	    (setq end (point))
@@ -7712,6 +7716,8 @@ comment at the start of cc-engine.el for more info."
   ;; 'arglist  Some other type of arglist.
   ;; nil       Some other context or unknown context.  Includes
   ;;           within the parens of an if, for, ... construct.
+  ;; 'not-decl This value is never supplied to this function.  It
+  ;;           would mean we're definitely not in a declaration.
   ;;
   ;; LAST-CAST-END is the first token after the closing paren of a
   ;; preceding cast, or nil if none is known.  If
@@ -8019,7 +8025,10 @@ comment at the start of cc-engine.el for more info."
 	  ;; arglist paren that gets entered.
 	  c-parse-and-markup-<>-arglists
 	  ;; Start of the identifier for which `got-identifier' was set.
-	  name-start)
+	  name-start
+	  ;; Position after (innermost) open parenthesis encountered in the
+	  ;; prefix operators.
+	  after-paren-pos)
 
       (goto-char id-start)
 
@@ -8030,7 +8039,8 @@ comment at the start of cc-engine.el for more info."
 	  (when (eq (char-after) ?\()
 	    (progn
 	      (setq paren-depth (1+ paren-depth))
-	      (forward-char)))
+	      (forward-char)
+	      (setq after-paren-pos (point))))
 	(while (and (looking-at c-type-decl-prefix-key)
 		    (if (and (c-major-mode-is 'c++-mode)
 			     (match-beginning 3))
@@ -8053,7 +8063,8 @@ comment at the start of cc-engine.el for more info."
 	  (if (eq (char-after) ?\()
 	      (progn
 		(setq paren-depth (1+ paren-depth))
-		(forward-char))
+		(forward-char)
+		(setq after-paren-pos (point)))
 	    (unless got-prefix-before-parens
 	      (setq got-prefix-before-parens (= paren-depth 0)))
 	    (setq got-prefix t)
@@ -8062,7 +8073,7 @@ comment at the start of cc-engine.el for more info."
 
       (setq got-parens (> paren-depth 0))
 
-      ;; Skip over an identifier.
+      ;; Try to skip over an identifier.
       (or got-identifier
 	  (and (looking-at c-identifier-start)
 	       (setq pos (point))
@@ -8111,7 +8122,15 @@ comment at the start of cc-engine.el for more info."
 			      maybe-typeless
 			      backup-maybe-typeless
 			      (when c-recognize-typeless-decls
-				(not context)))
+				(and (not context)
+				     ;; Deal with C++11's "copy-initialization"
+				     ;; where we have <type>(<constant>), by
+				     ;; contraasting with a typeless
+				     ;; <name>(<type><parameter>, ...).
+				     (save-excursion
+				       (goto-char after-paren-pos)
+				       (c-forward-syntactic-ws)
+				       (c-forward-type)))))
 			  (setq pos (c-up-list-forward (point)))
 			  (eq (char-before pos) ?\)))
 		 (c-fdoc-shift-type-backward)
@@ -8149,11 +8168,15 @@ comment at the start of cc-engine.el for more info."
 	   ;; Encountered something inside parens that isn't matched by
 	   ;; the `c-type-decl-*' regexps, so it's not a type decl
 	   ;; expression.  Try to skip out to the same paren depth to
-	   ;; not confuse the cast check below.
-	   (c-safe (goto-char (scan-lists (point) 1 paren-depth)))
+	   ;; not confuse the cast check below.  If we don't manage this and
+	   ;; `at-decl-or-cast' is 'ids we might have an expression like
+	   ;; "foo bar ({ ..." which is a valid C++11 initialization.
+	   (if (and (not (c-safe (goto-char (scan-lists (point) 1 paren-depth))))
+		    (eq at-decl-or-cast 'ids))
+	       (c-fdoc-shift-type-backward))
 	   ;; If we've found a specifier keyword then it's a
 	   ;; declaration regardless.
-	   (throw 'at-decl-or-cast (eq at-decl-or-cast t)))
+	   (throw 'at-decl-or-cast (memq at-decl-or-cast '(t ids))))
 
 	 (setq at-decl-end
 	       (looking-at (cond ((eq context '<>) "[,>]")
@@ -9788,6 +9811,169 @@ comment at the start of cc-engine.el for more info."
     (or (looking-at c-brace-list-key)
 	(progn (goto-char here) nil))))
 
+(defun c-looking-at-or-maybe-in-bracelist (containing-sexp &optional lim)
+  ;; Point is at an open brace.  If this starts a brace list, return the
+  ;; buffer position of the start of the construct which introduces the list.
+  ;; Otherwise, if point might be inside an enclosing brace list, return t.
+  ;; If point is definitely neither at nor in a brace list, return nil.
+  ;;
+  ;; CONTAINING-SEXP is the position of the brace/paren/braacket enclosing
+  ;; POINT, or nil if there is no such position.  LIM is a backward search
+  ;; limit.
+  ;;
+  ;; Here, "brace list" does not include the body of an enum.
+  (save-excursion
+    (let ((start (point))
+	  (class-key
+	   ;; Pike can have class definitions anywhere, so we must
+	   ;; check for the class key here.
+	   (and (c-major-mode-is 'pike-mode)
+		c-decl-block-key))
+	  (braceassignp 'dontknow)
+	  bufpos macro-start res after-type-id-pos)
+
+      (setq res (c-backward-token-2 1 t lim))
+      ;; Checks to do only on the first sexp before the brace.
+      ;; Have we a C++ initialisation, without an "="?
+      (if (and (c-major-mode-is 'c++-mode)
+	       (cond
+		((and (not (eq res 0))
+		      (c-go-up-list-backward nil lim) ; FIXME!!! Check ; `lim' 2016-07-12.
+		      (eq (char-after) ?\())
+		 (setq braceassignp 'c++-noassign))
+		((looking-at c-pre-id-bracelist-key))
+		((looking-at c-return-key))
+		((and (looking-at c-symbol-start)
+		      (not (looking-at c-keywords-regexp)))
+		 (setq after-type-id-pos (point)))
+		(t nil))
+	       (save-excursion
+		 (cond
+		  ((not (eq res 0))
+		   (and (c-go-up-list-backward nil lim) ; FIXME!!! Check `lim' 2016-07-12.
+			(eq (char-after) ?\()))
+		  ((looking-at c-pre-id-bracelist-key))
+		  ((looking-at c-return-key))
+		  (t (setq after-type-id-pos (point))
+		     nil))))
+	  (setq braceassignp 'c++-noassign))
+
+      (when (and c-opt-inexpr-brace-list-key
+		 (eq (char-after) ?\[))
+	;; In Java, an initialization brace list may follow
+	;; directly after "new Foo[]", so check for a "new"
+	;; earlier.
+	(while (eq braceassignp 'dontknow)
+	  (setq braceassignp
+		(cond ((/= (c-backward-token-2 1 t lim) 0) nil)
+		      ((looking-at c-opt-inexpr-brace-list-key) t)
+		      ((looking-at "\\sw\\|\\s_\\|[.[]")
+		       ;; Carry on looking if this is an
+		       ;; identifier (may contain "." in Java)
+		       ;; or another "[]" sexp.
+		       'dontknow)
+		      (t nil)))))
+
+      ;; Checks to do on all sexps before the brace, up to the
+      ;; beginning of the statement.
+      (while (eq braceassignp 'dontknow)
+	(cond ((eq (char-after) ?\;)
+	       (setq braceassignp nil))
+	      ((and class-key
+		    (looking-at class-key))
+	       (setq braceassignp nil))
+	      ((eq (char-after) ?=)
+	       ;; We've seen a =, but must check earlier tokens so
+	       ;; that it isn't something that should be ignored.
+	       (setq braceassignp 'maybe)
+	       (while (and (eq braceassignp 'maybe)
+			   (zerop (c-backward-token-2 1 t lim)))
+		 (setq braceassignp
+		       (cond
+			;; Check for operator =
+			((and c-opt-op-identifier-prefix
+			      (looking-at c-opt-op-identifier-prefix))
+			 nil)
+			;; Check for `<opchar>= in Pike.
+			((and (c-major-mode-is 'pike-mode)
+			      (or (eq (char-after) ?`)
+				  ;; Special case for Pikes
+				  ;; `[]=, since '[' is not in
+				  ;; the punctuation class.
+				  (and (eq (char-after) ?\[)
+				       (eq (char-before) ?`))))
+			 nil)
+			((looking-at "\\s.") 'maybe)
+			;; make sure we're not in a C++ template
+			;; argument assignment
+			((and
+			  (c-major-mode-is 'c++-mode)
+			  (save-excursion
+			    (let ((here (point))
+				  (pos< (progn
+					  (skip-chars-backward "^<>")
+					  (point))))
+			      (and (eq (char-before) ?<)
+				   (not (c-crosses-statement-barrier-p
+					 pos< here))
+				   (not (c-in-literal))
+				   ))))
+			 nil)
+			(t t))))))
+	(if (and (eq braceassignp 'dontknow)
+		 (/= (c-backward-token-2 1 t lim) 0))
+	    (setq braceassignp nil)))
+
+      (cond
+       (braceassignp
+	;; We've hit the beginning of the aggregate list.
+	(c-beginning-of-statement-1 containing-sexp)
+	(point))
+       ((and after-type-id-pos
+	     (save-excursion
+	       (when (eq (char-after) ?\;)
+		 (c-forward-token-2 1 t))
+	       (setq bufpos (point))
+	       (when (looking-at c-opt-<>-sexp-key)
+		 (c-forward-token-2)
+		 (when (and (eq (char-after) ?<)
+			    (c-get-char-property (point) 'syntax-table))
+		   (c-go-list-forward nil after-type-id-pos)
+		   (c-forward-syntactic-ws)))
+	       (and
+		(or (not (looking-at c-class-key))
+		    (save-excursion
+		      (goto-char (match-end 1))
+		      (c-forward-syntactic-ws)
+		      (not (eq (point) after-type-id-pos))))
+		(progn
+		  (setq res
+			(c-forward-decl-or-cast-1
+			 (save-excursion (c-backward-syntactic-ws) (point))
+			 nil nil))
+		  (and (consp res)
+		       (eq (car res) after-type-id-pos))))))
+	bufpos)
+       ((eq (char-after) ?\;)
+	;; Brace lists can't contain a semicolon, so we're done.
+	;; (setq containing-sexp nil)
+	nil)
+       ((and (setq macro-start (point))
+	     (c-forward-to-cpp-define-body)
+	     (eq (point) start))
+	;; We've a macro whose expansion starts with the '{'.
+	;; Heuristically, if we have a ';' in it we've not got a
+	;; brace list, otherwise we have.
+	(let ((macro-end (progn (c-end-of-macro) (point))))
+	  (goto-char start)
+	  (forward-char)
+	  (if (and (c-syntactic-re-search-forward "[;,]" macro-end t t)
+		   (eq (char-before) ?\;))
+	      nil
+	    macro-start)))
+       (t t)) ;; The caller can go up one level.
+      )))
+
 (defun c-inside-bracelist-p (containing-sexp paren-state)
   ;; return the buffer position of the beginning of the brace list
   ;; statement if we're inside a brace list, otherwise return nil.
@@ -9807,13 +9993,9 @@ comment at the start of cc-engine.el for more info."
      (c-backward-over-enum-header))
    ;; this will pick up array/aggregate init lists, even if they are nested.
    (save-excursion
-     (let ((class-key
-	    ;; Pike can have class definitions anywhere, so we must
-	    ;; check for the class key here.
-	    (and (c-major-mode-is 'pike-mode)
-		 c-decl-block-key))
-	   bufpos braceassignp lim next-containing macro-start)
-       (while (and (not bufpos)
+     (let ((bufpos t)
+	   lim next-containing)
+       (while (and (eq bufpos t)
 		   containing-sexp)
 	 (when paren-state
 	   (if (consp (car paren-state))
@@ -9823,113 +10005,22 @@ comment at the start of cc-engine.el for more info."
 	   (when paren-state
 	     (setq next-containing (car paren-state)
 		   paren-state (cdr paren-state))))
+
 	 (goto-char containing-sexp)
 	 (if (c-looking-at-inexpr-block next-containing next-containing)
 	     ;; We're in an in-expression block of some kind.  Do not
 	     ;; check nesting.  We deliberately set the limit to the
 	     ;; containing sexp, so that c-looking-at-inexpr-block
 	     ;; doesn't check for an identifier before it.
-	     (setq containing-sexp nil)
-	   ;; see if the open brace is preceded by = or [...] in
-	   ;; this statement, but watch out for operator=
-	   (setq braceassignp 'dontknow)
-	   (c-backward-token-2 1 t lim)
-	   ;; Checks to do only on the first sexp before the brace.
-	   (when (and c-opt-inexpr-brace-list-key
-		      (eq (char-after) ?\[))
-	     ;; In Java, an initialization brace list may follow
-	     ;; directly after "new Foo[]", so check for a "new"
-	     ;; earlier.
-	     (while (eq braceassignp 'dontknow)
-	       (setq braceassignp
-		     (cond ((/= (c-backward-token-2 1 t lim) 0) nil)
-			   ((looking-at c-opt-inexpr-brace-list-key) t)
-			   ((looking-at "\\sw\\|\\s_\\|[.[]")
-			    ;; Carry on looking if this is an
-			    ;; identifier (may contain "." in Java)
-			    ;; or another "[]" sexp.
-			    'dontknow)
-			   (t nil)))))
-	   ;; Checks to do on all sexps before the brace, up to the
-	   ;; beginning of the statement.
-	   (while (eq braceassignp 'dontknow)
-	     (cond ((eq (char-after) ?\;)
-		    (setq braceassignp nil))
-		   ((and class-key
-			 (looking-at class-key))
-		    (setq braceassignp nil))
-		   ((eq (char-after) ?=)
-		    ;; We've seen a =, but must check earlier tokens so
-		    ;; that it isn't something that should be ignored.
-		    (setq braceassignp 'maybe)
-		    (while (and (eq braceassignp 'maybe)
-				(zerop (c-backward-token-2 1 t lim)))
-		      (setq braceassignp
-			    (cond
-			     ;; Check for operator =
-			     ((and c-opt-op-identifier-prefix
-				   (looking-at c-opt-op-identifier-prefix))
-			      nil)
-			     ;; Check for `<opchar>= in Pike.
-			     ((and (c-major-mode-is 'pike-mode)
-				   (or (eq (char-after) ?`)
-				       ;; Special case for Pikes
-				       ;; `[]=, since '[' is not in
-				       ;; the punctuation class.
-				       (and (eq (char-after) ?\[)
-					    (eq (char-before) ?`))))
-			      nil)
-			     ((looking-at "\\s.") 'maybe)
-			     ;; make sure we're not in a C++ template
-			     ;; argument assignment
-			     ((and
-			       (c-major-mode-is 'c++-mode)
-			       (save-excursion
-				 (let ((here (point))
-				       (pos< (progn
-					       (skip-chars-backward "^<>")
-					       (point))))
-				   (and (eq (char-before) ?<)
-					(not (c-crosses-statement-barrier-p
-					      pos< here))
-					(not (c-in-literal))
-					))))
-			      nil)
-			     (t t))))))
-	     (if (and (eq braceassignp 'dontknow)
-		      (/= (c-backward-token-2 1 t lim) 0))
-		 (setq braceassignp nil)))
-	   (cond
-	    (braceassignp
-	     ;; We've hit the beginning of the aggregate list.
-	     (c-beginning-of-statement-1
-	      (c-most-enclosing-brace paren-state))
-	     (setq bufpos (point)))
-	    ((eq (char-after) ?\;)
-	     ;; Brace lists can't contain a semicolon, so we're done.
-	     (setq containing-sexp nil))
-	    ((and (setq macro-start (point))
-		  (c-forward-to-cpp-define-body)
-		  (eq (point) containing-sexp))
-	     ;; We've a macro whose expansion starts with the '{'.
-	     ;; Heuristically, if we have a ';' in it we've not got a
-	     ;; brace list, otherwise we have.
-	     (let ((macro-end (progn (c-end-of-macro) (point))))
-	       (goto-char containing-sexp)
-	       (forward-char)
-	       (if (and (c-syntactic-re-search-forward "[;,]" macro-end t t)
-			(eq (char-before) ?\;))
-		   (setq bufpos nil
-			 containing-sexp nil)
-		 (setq bufpos macro-start))))
-	    (t
-	     ;; Go up one level
+	     (setq bufpos nil)
+	   (when (or (not (eq (char-after) ?{))
+		     (eq (setq bufpos (c-looking-at-or-maybe-in-bracelist
+				       next-containing lim))
+			 t))
 	     (setq containing-sexp next-containing
 		   lim nil
-		   next-containing nil)))))
-
-       bufpos))
-   ))
+		   next-containing nil))))
+       (and (numberp bufpos) bufpos)))))
 
 (defun c-looking-at-special-brace-list (&optional lim)
   ;; If we're looking at the start of a pike-style list, i.e., `({ })',
@@ -10156,7 +10247,19 @@ comment at the start of cc-engine.el for more info."
 		      (and (> (point) (or lim (point-min)))
 			   (c-on-identifier)))
 		    (and c-special-brace-lists
-			 (c-looking-at-special-brace-list)))
+			 (c-looking-at-special-brace-list))
+		    (and (c-major-mode-is 'c++-mode)
+			 (save-excursion
+			   (goto-char block-follows)
+			   (if (c-go-list-forward)
+			       (progn
+				 (backward-char)
+				 (c-syntactic-skip-backward
+				  "^;," block-follows t)
+				 (not (eq (char-before) ?\;)))
+			     (or (not (c-syntactic-re-search-forward
+				       "[;,]" nil t t))
+				 (not (eq (char-before) ?\;)))))))
 		nil
 	      (cons 'inexpr-statement (point)))))
 
@@ -10565,10 +10668,10 @@ comment at the start of cc-engine.el for more info."
 
        ;; CASE B.2: brace-list-open
        ((or (consp special-brace-list)
-	    (save-excursion
-	      (goto-char beg-of-same-or-containing-stmt)
-	      (c-syntactic-re-search-forward "=\\([^=]\\|$\\)"
-					     indent-point t t t)))
+	    (numberp
+	     (c-looking-at-or-maybe-in-bracelist
+	      containing-sexp beg-of-same-or-containing-stmt))
+	    )
 	;; The most semantically accurate symbol here is
 	;; brace-list-open, but we normally report it simply as a
 	;; statement-cont.  The reason is that one normally adjusts
@@ -10601,6 +10704,14 @@ comment at the start of cc-engine.el for more info."
 	(c-add-stmt-syntax 'defun-open nil t
 			   containing-sexp paren-state))
 
+       ;; CASE B.5: We have a C++11 "return \n { ..... }"  Note that we're
+       ;; not at the "{", currently.
+       ((progn (goto-char indent-point)
+	       (backward-sexp)
+	       (looking-at c-return-key))
+	(c-add-stmt-syntax 'statement-cont nil t
+			   containing-sexp paren-state))
+
        ;; CASE B.4: Continued statement with block open.  The most
        ;; accurate analysis is perhaps `statement-cont' together with
        ;; `block-open' but we play DWIM and use `substatement-open'
@@ -11120,7 +11231,14 @@ comment at the start of cc-engine.el for more info."
 				    (looking-at c-opt-inexpr-brace-list-key)
 				    (setq tmpsymbol 'topmost-intro-cont)))
 			     (looking-at "=\\([^=]\\|$\\)"))
-			   (looking-at c-brace-list-key))
+			   (looking-at c-brace-list-key)
+			   (looking-at c-return-key)
+			   (save-excursion
+			     (and (c-forward-type)
+				  (looking-at c-identifier-start)
+				  (not (looking-at c-keywords-regexp))
+				  (c-forward-token-2)
+				  (eq (point) (c-point 'boi indent-point)))))
 		       (save-excursion
 			 (while (and (< (point) indent-point)
 				     (zerop (c-forward-token-2 1 t))
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index ae18d0a9436..60b8b6db3cc 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -1166,7 +1166,8 @@ casts and declarations are fontified.  Used on level 2 and higher."
 	  ;; `parse-sexp-lookup-properties' (when it exists).
 	  (parse-sexp-lookup-properties
 	   (cc-eval-when-compile
-	     (boundp 'parse-sexp-lookup-properties))))
+	     (boundp 'parse-sexp-lookup-properties))
+	   ))
 
       ;; Below we fontify a whole declaration even when it crosses the limit,
       ;; to avoid gaps when jit/lazy-lock fontifies the file a block at a
@@ -1204,7 +1205,8 @@ casts and declarations are fontified.  Used on level 2 and higher."
 	 (setq start-pos (point))
 	 (when
 	  ;; The result of the form below is true when we don't recognize a
-	  ;; declaration or cast.
+	  ;; declaration or cast, and we don't recognise a "non-decl",
+	  ;; typically a brace list.
 	  (if (or (and (eq (get-text-property (point) 'face)
 			   'font-lock-keyword-face)
 		       (looking-at c-not-decl-init-keywords))
@@ -1220,7 +1222,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
 	    ;; (e.g. "for (").
 	    (let ((type (and (> match-pos (point-min))
 			     (c-get-char-property (1- match-pos) 'c-type))))
-	      (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?<)))
+	      (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?< ?{)))
 		     (setq context nil
 			   c-restricted-<>-arglists nil))
 		    ;; A control flow expression or a decltype
@@ -1242,6 +1244,10 @@ casts and declarations are fontified.  Used on level 2 and higher."
 		    ((eq type 'c-decl-arg-start)
 		     (setq context 'decl
 			   c-restricted-<>-arglists nil))
+		    ;; We're inside (probably) a brace list.
+		    ((eq type 'c-not-decl)
+		     (setq context 'not-decl
+			   c-restricted-<>-arglists nil))
 		    ;; Inside a C++11 lambda function arglist.
 		    ((and (c-major-mode-is 'c++-mode)
 			  (eq (char-before match-pos) ?\()
@@ -1255,7 +1261,20 @@ casts and declarations are fontified.  Used on level 2 and higher."
 			   c-restricted-<>-arglists nil)
 		     (c-put-char-property (1- match-pos) 'c-type
 					  'c-decl-arg-start))
-
+		    ;; We're inside an brace list.
+		    ((and (eq (char-before match-pos) ?{)
+			  (save-excursion
+			    (goto-char (1- match-pos))
+			    (numberp
+			     (c-looking-at-or-maybe-in-bracelist nil))))
+		     (setq context 'not-decl
+			   c-restricted-<>-arglists nil)
+		     (c-put-char-property (1- match-pos) 'c-type
+					  'c-not-decl))
+		    ;; We're inside an "ordinary" open brace.
+		    ((eq (char-before match-pos) ?{)
+		     (setq context nil
+			   c-restricted-<>-arglists nil))
 		    ;; Inside an angle bracket arglist.
 		    ((or (eq type 'c-<>-arg-sep)
 			 (eq (char-before match-pos) ?<))
@@ -1301,123 +1320,131 @@ casts and declarations are fontified.  Used on level 2 and higher."
 	      (c-forward-syntactic-ws))
 
 	    ;; Now analyze the construct.
-	    (setq decl-or-cast (c-forward-decl-or-cast-1
-				match-pos context last-cast-end))
-
-	    ;; Ensure that c-<>-arg-sep c-type properties are in place on the
-	    ;; commas separating the arguments inside template/generic <..>s.
-	    (when (and (eq (char-before match-pos) ?<)
-		       (> match-pos max-<>-end))
-	      (save-excursion
-		(goto-char match-pos)
-		(c-backward-token-2)
-		(if (and
-		     (eq (char-after) ?<)
-		     (let ((c-restricted-<>-arglists
-			    (save-excursion
-			      (c-backward-token-2)
-			      (and
-			       (not (looking-at c-opt-<>-sexp-key))
-			       (progn (c-backward-syntactic-ws)
-				      (memq (char-before) '(?\( ?,)))
-			       (not (eq (c-get-char-property (1- (point))
-							     'c-type)
-					'c-decl-arg-start))))))
-		       (c-forward-<>-arglist nil)))
-		    (setq max-<>-end (point)))))
-
-	    (cond
-	     ((eq decl-or-cast 'cast)
-	      ;; Save the position after the previous cast so we can feed
-	      ;; it to `c-forward-decl-or-cast-1' in the next round.  That
-	      ;; helps it discover cast chains like "(a) (b) c".
-	      (setq last-cast-end (point))
-	      (c-fontify-recorded-types-and-refs)
-	      nil)
+	    (if (eq context 'not-decl)
+		(progn
+		  (setq decl-or-cast nil)
+		  (if (c-syntactic-re-search-forward
+		       "," (min limit (point-max)) 'at-limit t)
+		      (c-put-char-property (1- (point)) 'c-type 'c-not-decl))
+		  nil)
+	      (setq decl-or-cast
+		    (c-forward-decl-or-cast-1
+		     match-pos context last-cast-end))
+
+	      ;; Ensure that c-<>-arg-sep c-type properties are in place on the
+	      ;; commas separating the arguments inside template/generic <..>s.
+	      (when (and (eq (char-before match-pos) ?<)
+			 (> match-pos max-<>-end))
+		(save-excursion
+		  (goto-char match-pos)
+		  (c-backward-token-2)
+		  (if (and
+		       (eq (char-after) ?<)
+		       (let ((c-restricted-<>-arglists
+			      (save-excursion
+				(c-backward-token-2)
+				(and
+				 (not (looking-at c-opt-<>-sexp-key))
+				 (progn (c-backward-syntactic-ws)
+					(memq (char-before) '(?\( ?,)))
+				 (not (eq (c-get-char-property (1- (point))
+							       'c-type)
+					  'c-decl-arg-start))))))
+			 (c-forward-<>-arglist nil)))
+		      (setq max-<>-end (point)))))
+
+	      (cond
+	       ((eq decl-or-cast 'cast)
+		;; Save the position after the previous cast so we can feed
+		;; it to `c-forward-decl-or-cast-1' in the next round.  That
+		;; helps it discover cast chains like "(a) (b) c".
+		(setq last-cast-end (point))
+		(c-fontify-recorded-types-and-refs)
+		nil)
+
+	       (decl-or-cast
+		;; We've found a declaration.
+
+		;; Set `max-type-decl-end' or `max-type-decl-end-before-token'
+		;; under the assumption that we're after the first type decl
+		;; expression in the declaration now.  That's not really true;
+		;; we could also be after a parenthesized initializer
+		;; expression in C++, but this is only used as a last resort
+		;; to slant ambiguous expression/declarations, and overall
+		;; it's worth the risk to occasionally fontify an expression
+		;; as a declaration in an initializer expression compared to
+		;; getting ambiguous things in normal function prototypes
+		;; fontified as expressions.
+		(if inside-macro
+		    (when (> (point) max-type-decl-end-before-token)
+		      (setq max-type-decl-end-before-token (point)))
+		  (when (> (point) max-type-decl-end)
+		    (setq max-type-decl-end (point))))
+
+		;; Do we have an expression as the second or third clause of
+		;; a "for" paren expression?
+		(if (save-excursion
+		      (and
+		       (car (cddr decl-or-cast)) ; maybe-expression flag.
+		       (goto-char start-pos)
+		       (c-go-up-list-backward)
+		       (eq (char-after) ?\()
+		       (progn (c-backward-syntactic-ws)
+			      (c-simple-skip-symbol-backward))
+		       (looking-at c-paren-stmt-key)
+		       (progn (goto-char match-pos)
+			      (while (and (eq (char-before) ?\))
+					  (c-go-list-backward))
+				(c-backward-syntactic-ws))
+			      (eq (char-before) ?\;))))
+		    ;; We've got an expression in "for" parens.  Remove the
+		    ;; "type" that would spuriously get fontified.
+		    (let ((elt (and (consp c-record-type-identifiers)
+				    (assq (cadr (cddr decl-or-cast))
+					  c-record-type-identifiers))))
+		      (when elt
+			(setq c-record-type-identifiers
+			      (c-delq-from-dotted-list
+			       elt c-record-type-identifiers)))
+		      t)
+		  ;; Back up to the type to fontify the declarator(s).
+		  (goto-char (car decl-or-cast))
+
+		  (let ((decl-list
+			 (if context
+			     ;; Should normally not fontify a list of
+			     ;; declarators inside an arglist, but the first
+			     ;; argument in the ';' separated list of a "for"
+			     ;; statement is an exception.
+			     (when (eq (char-before match-pos) ?\()
+			       (save-excursion
+				 (goto-char (1- match-pos))
+				 (c-backward-syntactic-ws)
+				 (and (c-simple-skip-symbol-backward)
+				      (looking-at c-paren-stmt-key))))
+			   t)))
+
+		    ;; Fix the `c-decl-id-start' or `c-decl-type-start' property
+		    ;; before the first declarator if it's a list.
+		    ;; `c-font-lock-declarators' handles the rest.
+		    (when decl-list
+		      (save-excursion
+			(c-backward-syntactic-ws)
+			(unless (bobp)
+			  (c-put-char-property (1- (point)) 'c-type
+					       (if (cadr decl-or-cast)
+						   'c-decl-type-start
+						 'c-decl-id-start)))))
+
+		    (c-font-lock-declarators
+		     (min limit (point-max)) decl-list (cadr decl-or-cast)))
+
+		  ;; A declaration has been successfully identified, so do all the
+		  ;; fontification of types and refs that've been recorded.
+		  (c-fontify-recorded-types-and-refs)
+		  nil))
 
-	     (decl-or-cast
-	      ;; We've found a declaration.
-
-	      ;; Set `max-type-decl-end' or `max-type-decl-end-before-token'
-	      ;; under the assumption that we're after the first type decl
-	      ;; expression in the declaration now.  That's not really true;
-	      ;; we could also be after a parenthesized initializer
-	      ;; expression in C++, but this is only used as a last resort
-	      ;; to slant ambiguous expression/declarations, and overall
-	      ;; it's worth the risk to occasionally fontify an expression
-	      ;; as a declaration in an initializer expression compared to
-	      ;; getting ambiguous things in normal function prototypes
-	      ;; fontified as expressions.
-	      (if inside-macro
-		  (when (> (point) max-type-decl-end-before-token)
-		    (setq max-type-decl-end-before-token (point)))
-		(when (> (point) max-type-decl-end)
-		  (setq max-type-decl-end (point))))
-
-	      ;; Do we have an expression as the second or third clause of
-	      ;; a "for" paren expression?
-	      (if (save-excursion
-		    (and
-		     (car (cddr decl-or-cast)) ; maybe-expression flag.
-		     (goto-char start-pos)
-		     (c-go-up-list-backward)
-		     (eq (char-after) ?\()
-		     (progn (c-backward-syntactic-ws)
-			    (c-simple-skip-symbol-backward))
-		     (looking-at c-paren-stmt-key)
-		     (progn (goto-char match-pos)
-			    (while (and (eq (char-before) ?\))
-					(c-go-list-backward))
-			      (c-backward-syntactic-ws))
-			    (eq (char-before) ?\;))))
-		  ;; We've got an expression in "for" parens.  Remove the
-		  ;; "type" that would spuriously get fontified.
-		  (let ((elt (and (consp c-record-type-identifiers)
-				  (assq (cadr (cddr decl-or-cast))
-					c-record-type-identifiers))))
-		    (when elt
-		      (setq c-record-type-identifiers
-			    (c-delq-from-dotted-list
-			     elt c-record-type-identifiers)))
-		    t)
-	      ;; Back up to the type to fontify the declarator(s).
-	      (goto-char (car decl-or-cast))
-
-	      (let ((decl-list
-		     (if context
-			 ;; Should normally not fontify a list of
-			 ;; declarators inside an arglist, but the first
-			 ;; argument in the ';' separated list of a "for"
-			 ;; statement is an exception.
-			 (when (eq (char-before match-pos) ?\()
-			   (save-excursion
-			     (goto-char (1- match-pos))
-			     (c-backward-syntactic-ws)
-			     (and (c-simple-skip-symbol-backward)
-				  (looking-at c-paren-stmt-key))))
-		       t)))
-
-		;; Fix the `c-decl-id-start' or `c-decl-type-start' property
-		;; before the first declarator if it's a list.
-		;; `c-font-lock-declarators' handles the rest.
-		(when decl-list
-		  (save-excursion
-		    (c-backward-syntactic-ws)
-		    (unless (bobp)
-		      (c-put-char-property (1- (point)) 'c-type
-					   (if (cadr decl-or-cast)
-					       'c-decl-type-start
-					     'c-decl-id-start)))))
-
-		(c-font-lock-declarators
-		 (min limit (point-max)) decl-list (cadr decl-or-cast)))
-
-	      ;; A declaration has been successfully identified, so do all the
-	      ;; fontification of types and refs that've been recorded.
-	      (c-fontify-recorded-types-and-refs)
-	      nil))
-
-	     (t t)))
+	       (t t))))
 
 	  ;; It was a false alarm.  Check if we're in a label (or other
 	  ;; construct with `:' except bitfield) instead.
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index 1d9b8d3f0a4..e1ccc7924ab 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -1772,6 +1772,16 @@ the appropriate place for that."
 	 "array" "float" "function" "int" "mapping" "mixed" "multiset"
 	 "object" "program" "string" "this_program" "void"))
 
+(c-lang-defconst c-return-kwds
+  "Keywords which return a value to the calling function."
+  t '("return")
+  idl nil)
+
+(c-lang-defconst c-return-key
+  ;; Adorned regexp matching `c-return-kwds'.
+  t (c-make-keywords-re t (c-lang-const c-return-kwds)))
+(c-lang-defvar c-return-key (c-lang-const c-return-key))
+
 (c-lang-defconst c-primitive-type-key
   ;; An adorned regexp that matches `c-primitive-type-kwds'.
   t (c-make-keywords-re t (c-lang-const c-primitive-type-kwds)))
@@ -3150,6 +3160,13 @@ list."
   c t)
 (c-lang-defvar c-recognize-knr-p (c-lang-const c-recognize-knr-p))
 
+(c-lang-defconst c-pre-id-bracelist-key
+  "A regexp matching tokens which, preceding an identifier, signify a bracelist.
+"
+  t "\\<\\>"
+  c++ "new\\([^[:alnum:]_$]\\|$\\)\\|&&?\\(\\S.\\|$\\)")
+(c-lang-defvar c-pre-id-bracelist-key (c-lang-const c-pre-id-bracelist-key))
+
 (c-lang-defconst c-recognize-typeless-decls
   "Non-nil means function declarations without return type should be
 recognized.  That can introduce an ambiguity with parenthesized macro
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 694a510677a..5b324d6d24c 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -1351,10 +1351,10 @@ Note that the style variables are always made local to the buffer."
 
 (defun c-fl-decl-start (pos)
   ;; If the beginning of the line containing POS is in the middle of a "local"
-  ;; declaration (i.e. one which does not start outside of braces enclosing
-  ;; POS, such as a struct), return the beginning of that declaration.
-  ;; Otherwise return nil.  Note that declarations, in this sense, can be
-  ;; nested.
+  ;; declaration, return the beginning of that declaration.  Otherwise return
+  ;; nil.  Note that declarations, in this sense, can be nested.  (A local
+  ;; declaration is one which does not start outside of struct braces (and
+  ;; similar) enclosing POS.  Brace list braces here are not "similar".
   ;;
   ;; This function is called indirectly from font locking stuff - either from
   ;; c-after-change (to prepare for after-change font-locking) or from font
@@ -1402,7 +1402,12 @@ Note that the style variables are always made local to the buffer."
 		    (and (eq (char-before) ?\<)
 			 (eq (c-get-char-property
 			      (1- (point)) 'syntax-table)
-			     c-<-as-paren-syntax)))))
+			     c-<-as-paren-syntax))
+		    (and (eq (char-before) ?{)
+			 (save-excursion
+			   (backward-char)
+			   (numberp (c-looking-at-or-maybe-in-bracelist nil))))
+		    )))
 	 (not (bobp)))
       (backward-char))			; back over (, [, <.
     (when (and capture-opener (< capture-opener new-pos))
-- 
2.39.5