unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* cc-mode uniform initialization support
@ 2015-08-19 18:36 Daniel Colascione
  2015-08-20 16:49 ` Alan Mackenzie
  2016-07-04 18:32 ` Alan Mackenzie
  0 siblings, 2 replies; 5+ messages in thread
From: Daniel Colascione @ 2015-08-19 18:36 UTC (permalink / raw)
  To: Emacs developers; +Cc: Alan Mackenzie

[-- Attachment #1: Type: text/plain, Size: 2699 bytes --]

Recent versions of C++ support using {} to indicate an initialization
value. For example,

  1 int foo{5};
  2 int bar = {5};
  3 mumble_t mumble{
  4  foo,
  5    bar
  6 };
  7 return {mumble, foo}; // Type inferred from function declaration

Working with code written in this style is a nightmare right now because
cc-mode recognizes line 4 as defun-block-intro, leading to line 5 being
indented spuriously, since cc-mode thinks it's a statement continuation.
In reality, the construct starting at line 3 is a brace list, but
there's no syntactic clue to tell us that. (We can, of course, look for
an "=", but an "=" is no longer required for a brace list.)

I don't see a way around needing to use awful heuristics to distinguish
the cases. Does anyone have a better idea? Keep in mind that code like
this is common too:

  foo({
    abc,
    def
  });

And plenty of people define macros that accept blocks:

  MY_FOREACH {
    statement1;
    statement2;
  }

diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 06b03a2..84f3ad7 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -8725,6 +8725,34 @@ comment at the start of cc-engine.el for more info."
    (save-excursion
      (goto-char containing-sexp)
      (c-backward-over-enum-header))
+   ;; Detect C++11 uniform initialization.  This bit is necessarily
+   ;; heuristic, since there are few syntactic clues to go
+   ;; on. Initializer lists can now stand in for any value at all when
+   ;; the compiler can infer the type to build from the
+   ;; initializer list.
+   (save-excursion
+     (goto-char containing-sexp)
+     (and
+      (eq (char-after) ?\{)
+      (progn (c-backward-sws)
+            (or
+             ;; After a comma means universal initialization
+             (eq (char-before) ?\,)
+             ;; Er, we use GCC statement expressions most often in
+             ;; macros, so if we see ({ outside of one, think of it
+             ;; as uniform initialization.
+             (and (eq (char-before) ?\()
+                  (save-excursion
+                    (not (c-beginning-of-macro))))
+             ;; foo{} versus foo {. Yuck.
+             (and (not (bobp))
+                  (prog1
+                      (backward-char)
+                    (looking-at "\\(\\w\\|\\s_\\){")
+                    (forward-char)))
+             ;; Special case for return {...}
+             (looking-back "\\_<return\\=" (point-at-bol))))
+      containing-sexp))
    ;; this will pick up array/aggregate init lists, even if they are
nested.
    (save-excursion
      (let ((class-key


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: cc-mode uniform initialization support
  2015-08-19 18:36 cc-mode uniform initialization support Daniel Colascione
@ 2015-08-20 16:49 ` Alan Mackenzie
  2015-08-30  0:54   ` Daniel Colascione
  2016-07-04 18:32 ` Alan Mackenzie
  1 sibling, 1 reply; 5+ messages in thread
From: Alan Mackenzie @ 2015-08-20 16:49 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: Emacs developers

Hello, Daniel.

On Wed, Aug 19, 2015 at 11:36:11AM -0700, Daniel Colascione wrote:
> Recent versions of C++ support using {} to indicate an initialization
> value. For example,

>   1 int foo{5};
>   2 int bar = {5};
>   3 mumble_t mumble{
>   4  foo,
>   5    bar
>   6 };
>   7 return {mumble, foo}; // Type inferred from function declaration

Yes.

> Working with code written in this style is a nightmare right now because
> cc-mode recognizes line 4 as defun-block-intro, leading to line 5 being
> indented spuriously, since cc-mode thinks it's a statement continuation.
> In reality, the construct starting at line 3 is a brace list, but
> there's no syntactic clue to tell us that.

How about the fact that there's no argument list (in parens)?  Is that
not sufficient to distinguish a brace list from a defun?

> (We can, of course, look for an "=", but an "=" is no longer required
> for a brace list.)

> I don't see a way around needing to use awful heuristics to distinguish
> the cases. Does anyone have a better idea? Keep in mind that code like
> this is common too:

>   foo({
>     abc,
>     def
>   });

> And plenty of people define macros that accept blocks:

>   MY_FOREACH {
>     statement1;
>     statement2;
>   }

I've had a look at your patch, and after correcting it (so that at the
indicated lines, the result of the `looking-at' is returned rather than
the result of `backward-char' (which is nil)), tried it out.  It does
indeed appear to work on the example code you gave.

However, it gives lots of errors in the test suite, including in some
C++ test files (namely decls-15.cc, inexprstat-2.cc, inher-9.cc), so it
needs some refinement.  There are also a few niggly details where the
patch isn't quite correct, but they should be easy enough to correct.

Why do you distinguish between "\\w{" and "\\w {" in the `looking-at'
form?

> diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
> index 06b03a2..84f3ad7 100644
> --- a/lisp/progmodes/cc-engine.el
> +++ b/lisp/progmodes/cc-engine.el
> @@ -8725,6 +8725,34 @@ comment at the start of cc-engine.el for more info."
>     (save-excursion
>       (goto-char containing-sexp)
>       (c-backward-over-enum-header))
> +   ;; Detect C++11 uniform initialization.  This bit is necessarily
> +   ;; heuristic, since there are few syntactic clues to go
> +   ;; on. Initializer lists can now stand in for any value at all when
> +   ;; the compiler can infer the type to build from the
> +   ;; initializer list.
> +   (save-excursion
> +     (goto-char containing-sexp)
> +     (and
> +      (eq (char-after) ?\{)
> +      (progn (c-backward-sws)
> +            (or
> +             ;; After a comma means universal initialization
> +             (eq (char-before) ?\,)
> +             ;; Er, we use GCC statement expressions most often in
> +             ;; macros, so if we see ({ outside of one, think of it
> +             ;; as uniform initialization.
> +             (and (eq (char-before) ?\()
> +                  (save-excursion
> +                    (not (c-beginning-of-macro))))
> +             ;; foo{} versus foo {. Yuck.
> +             (and (not (bobp))
> +                  (prog1                       <===================
> +                      (backward-char)          <===================
> +                    (looking-at "\\(\\w\\|\\s_\\){")
> +                    (forward-char)))
> +             ;; Special case for return {...}
> +             (looking-back "\\_<return\\=" (point-at-bol))))
> +      containing-sexp))
>     ;; this will pick up array/aggregate init lists, even if they are nested.
>     (save-excursion
>       (let ((class-key

-- 
Alan Mackenzie (Nuremberg, Germany).



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: cc-mode uniform initialization support
  2015-08-20 16:49 ` Alan Mackenzie
@ 2015-08-30  0:54   ` Daniel Colascione
  0 siblings, 0 replies; 5+ messages in thread
From: Daniel Colascione @ 2015-08-30  0:54 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: Emacs developers

[-- Attachment #1: Type: text/plain, Size: 3340 bytes --]

On 08/20/2015 09:49 AM, Alan Mackenzie wrote:
> Hello, Daniel.
> 
> On Wed, Aug 19, 2015 at 11:36:11AM -0700, Daniel Colascione wrote:
>> Recent versions of C++ support using {} to indicate an initialization
>> value. For example,
> 
>>   1 int foo{5};
>>   2 int bar = {5};
>>   3 mumble_t mumble{
>>   4  foo,
>>   5    bar
>>   6 };
>>   7 return {mumble, foo}; // Type inferred from function declaration
> 
> Yes.
> 
>> Working with code written in this style is a nightmare right now because
>> cc-mode recognizes line 4 as defun-block-intro, leading to line 5 being
>> indented spuriously, since cc-mode thinks it's a statement continuation.
>> In reality, the construct starting at line 3 is a brace list, but
>> there's no syntactic clue to tell us that.
> 
> How about the fact that there's no argument list (in parens)?  Is that
> not sufficient to distinguish a brace list from a defun?

I don't think so. In the _same_ codebase, we have code that looks like this:

SCOPE_EXIT {
  statement1,
    statement1_cont;
  statement2;
};

and

foo("foo", something{
  item1,
  item2});

Lots of codebases have SCOPE_EXIT-like things: the Linux kernel, for
example, has a bunch of custom LIST_FOREACH-like macros, so we can't
just check whether the word before the "{" is a keyword.  The check for
whitespace before the "{" in my patch is a really hacky heuristic for
distinguishing the two cases. It works for the coding style I work with,
but it's not very good in general.

It's unfortunate that C++ overloaded "{" this way, since it makes it
hard to locally determine what's going on syntactically.

How about these rules? We'll assume we have a brace-list if:

1) we see "({" outside a macro definition, as in "foo({bar,qux})", or

2) we see a "{" preceded by "return", as in "return {1,2}" (say, in a
function declared to return std::pair<int,int>), or

3) we see a "{" preceded by a ",", as in "foo(foo, {bar})" (do we need
to look for operators generally?), or

4) we see a "{" preceded by an identifier not in ALL CAPS.

---

Do we need a separate c++11-mode so users can choose between c++-mode
with the old heuristics and the new one with the hacks I've described?
#1 and #4 might be controversial.

>> (We can, of course, look for an "=", but an "=" is no longer required
>> for a brace list.)
> 
>> I don't see a way around needing to use awful heuristics to distinguish
>> the cases. Does anyone have a better idea? Keep in mind that code like
>> this is common too:
> 
>>   foo({
>>     abc,
>>     def
>>   });
> 
>> And plenty of people define macros that accept blocks:
> 
>>   MY_FOREACH {
>>     statement1;
>>     statement2;
>>   }
> 
> I've had a look at your patch, and after correcting it (so that at the
> indicated lines, the result of the `looking-at' is returned rather than
> the result of `backward-char' (which is nil)), tried it out.  It does
> indeed appear to work on the example code you gave.
> 
> However, it gives lots of errors in the test suite, including in some
> C++ test files (namely decls-15.cc, inexprstat-2.cc, inher-9.cc), so it
> needs some refinement.  There are also a few niggly details where the
> patch isn't quite correct, but they should be easy enough to correct.

Thanks.

>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: cc-mode uniform initialization support
  2015-08-19 18:36 cc-mode uniform initialization support Daniel Colascione
  2015-08-20 16:49 ` Alan Mackenzie
@ 2016-07-04 18:32 ` Alan Mackenzie
  2016-07-22 21:09   ` Alan Mackenzie
  1 sibling, 1 reply; 5+ messages in thread
From: Alan Mackenzie @ 2016-07-04 18:32 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: Emacs developers

Hello again, Daniel.

On Wed, Aug 19, 2015 at 11:36:11AM -0700, Daniel Colascione wrote:
> Recent versions of C++ support using {} to indicate an initialization
> value. For example,

>   1 int foo{5};
>   2 int bar = {5};
>   3 mumble_t mumble{
>   4  foo,
>   5    bar
>   6 };
>   7 return {mumble, foo}; // Type inferred from function declaration

> Working with code written in this style is a nightmare right now because
> cc-mode recognizes line 4 as defun-block-intro, leading to line 5 being
> indented spuriously, since cc-mode thinks it's a statement continuation.
> In reality, the construct starting at line 3 is a brace list, but
> there's no syntactic clue to tell us that. (We can, of course, look for
> an "=", but an "=" is no longer required for a brace list.)

There _is_ such a syntactic clue: two adjacent identifiers preceding an
opening brace indicate a brace list.  :-)

(By the way, your writing that there was no clue put me off looking for
it for quite some time. ;-)

I've constructed an entirely new fix for this, the first version of
which is below.  


> I don't see a way around needing to use awful heuristics to distinguish
> the cases. Does anyone have a better idea? Keep in mind that code like
> this is common too:

>   foo({
>     abc,
>     def
>   });

I'm not sure how my patch handles this.

> And plenty of people define macros that accept blocks:

>   MY_FOREACH {
>     statement1;
>     statement2;
>   }

But a single identifier before an open brace stays as a statement block.

Could you try out this patch, please, and let me know of any problems, or
lack thereof (more likely the former).  Any further test files that you
can send me will be gratefully received.



diff -r 2fcfc6e054b3 cc-engine.el
--- a/cc-engine.el	Sun Jul 03 17:54:20 2016 +0000
+++ b/cc-engine.el	Mon Jul 04 18:16:57 2016 +0000
@@ -9777,7 +9777,6 @@
    (save-excursion
      (goto-char containing-sexp)
      (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
@@ -9807,70 +9806,81 @@
 	   (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.
+	   (if (and (c-major-mode-is 'c++-mode)
+		    (cond
+		     ((and (looking-at c-symbol-start)
+			   (not (looking-at c-keywords-regexp)))
+		      (c-backward-syntactic-ws)
+		      (c-backward-token-2)
+		      (or (and (looking-at c-symbol-start)
+			       (not (looking-at c-keywords-regexp)))
+			  (looking-at c-pre-id-bracelist-key)))
+		     ((looking-at c-return-key))))
+	       (setq bufpos containing-sexp)
+	     (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)
-	       (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 ((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.
@@ -11031,7 +11041,14 @@
 				    (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 -r 2fcfc6e054b3 cc-langs.el
--- a/cc-langs.el	Sun Jul 03 17:54:20 2016 +0000
+++ b/cc-langs.el	Mon Jul 04 18:16:57 2016 +0000
@@ -1726,6 +1726,17 @@
 	 "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)))
@@ -3096,6 +3107,13 @@
   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 things 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


-- 
Alan Mackenzie (Nuremberg, Germany).



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: cc-mode uniform initialization support
  2016-07-04 18:32 ` Alan Mackenzie
@ 2016-07-22 21:09   ` Alan Mackenzie
  0 siblings, 0 replies; 5+ messages in thread
From: Alan Mackenzie @ 2016-07-22 21:09 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: Emacs developers

Hello, Daniel.

On Mon, Jul 04, 2016 at 06:32:40PM +0000, Alan Mackenzie wrote:
> On Wed, Aug 19, 2015 at 11:36:11AM -0700, Daniel Colascione wrote:
> > Recent versions of C++ support using {} to indicate an initialization
> > value. For example,

> >   1 int foo{5};
> >   2 int bar = {5};
> >   3 mumble_t mumble{
> >   4  foo,
> >   5    bar
> >   6 };
> >   7 return {mumble, foo}; // Type inferred from function declaration

> > Working with code written in this style is a nightmare right now because
> > cc-mode recognizes line 4 as defun-block-intro, leading to line 5 being
> > indented spuriously, since cc-mode thinks it's a statement continuation.
> > In reality, the construct starting at line 3 is a brace list, but
> > there's no syntactic clue to tell us that. (We can, of course, look for
> > an "=", but an "=" is no longer required for a brace list.)

[ .... ]

> I've constructed an entirely new fix for this, the first version of
> which is below.  

And now please find a much more mature version of the fix, below.  It
fails to trigger the regression test suite, yet seems to behave
reasonably with the following test file (expanded from the one you
supplied earler):

#########################################################################
int foo{5};
int bar = {5};
vec_int foo({
        abc,
        def
    });

mumble_t mumble
{
    foo,
    bar
};
return {mumble, foo}; // Type inferred from function declaration

vec_int foo({
        abc,
        def
    });
#########################################################################

[ .... ]

The patch should handle a lot of varieties of C++ uniform initialisation,
possibly all varieties (though this is unlikely).  Would you try it out
on real code, please, and let me know how it works.  Of particular
interest are any failing cases, and any circumstances where there is a
substantial slowdown caused by the patch.

I'm sure I don't need to say this, but please recompile all of the
cc-*.el files after applying the patch, so that the new macros in
cc-langs.el take full effect.



diff -r 2fcfc6e054b3 cc-engine.el
--- a/cc-engine.el	Sun Jul 03 17:54:20 2016 +0000
+++ b/cc-engine.el	Fri Jul 22 20:47:38 2016 +0000
@@ -7333,10 +7333,10 @@
   ;; 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))
@@ -8084,6 +8084,8 @@
 			      backup-maybe-typeless
 			      (when c-recognize-typeless-decls
 				(not context)))
+;;;; (2016-07-05): the next two conditions foul up font locking of a line
+;;;; ending in "({".  FIXME!!!
 			  (setq pos (c-up-list-forward (point)))
 			  (eq (char-before pos) ?\)))
 		 (c-fdoc-shift-type-backward)
@@ -9784,9 +9786,11 @@
 	    ;; check for the class key here.
 	    (and (c-major-mode-is 'pike-mode)
 		 c-decl-block-key))
-	   bufpos braceassignp lim next-containing macro-start)
+	   bufpos braceassignp lim next-containing macro-start res
+	   after-type-id-pos)
        (while (and (not bufpos)
 		   containing-sexp)
+	 (setq after-type-id-pos nil)
 	 (when paren-state
 	   (if (consp (car paren-state))
 	       (setq lim (cdr (car paren-state))
@@ -9805,8 +9809,32 @@
 	   ;; 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)
+	   (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)
+		      (point))
+		     ((and (looking-at c-symbol-start)
+			   (not (looking-at c-keywords-regexp)))
+		      (setq after-type-id-pos (point))
+		      (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))
+		       (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
@@ -9877,6 +9905,24 @@
 	     (c-beginning-of-statement-1
 	      (c-most-enclosing-brace paren-state))
 	     (setq bufpos (point)))
+	    ((and after-type-id-pos
+		  (save-excursion
+		    (if (eq (char-after) ?\;)
+			(c-forward-token-2 1 t))
+		    (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))))))
+	     (setq bufpos (point)))
 	    ((eq (char-after) ?\;)
 	     ;; Brace lists can't contain a semicolon, so we're done.
 	     (setq containing-sexp nil))
@@ -10079,7 +10125,19 @@
 		      (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))))
 
@@ -11031,7 +11089,14 @@
 				    (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 -r 2fcfc6e054b3 cc-langs.el
--- a/cc-langs.el	Sun Jul 03 17:54:20 2016 +0000
+++ b/cc-langs.el	Fri Jul 22 20:47:38 2016 +0000
@@ -1726,6 +1726,16 @@
 	 "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)))
@@ -3096,6 +3106,13 @@
   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 things 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




-- 
Alan Mackenzie (Nuremberg, Germany).



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-07-22 21:09 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-19 18:36 cc-mode uniform initialization support Daniel Colascione
2015-08-20 16:49 ` Alan Mackenzie
2015-08-30  0:54   ` Daniel Colascione
2016-07-04 18:32 ` Alan Mackenzie
2016-07-22 21:09   ` Alan Mackenzie

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).