unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Alan Mackenzie <acm@muc.de>
To: Daniel Colascione <dancol@dancol.org>
Cc: Emacs developers <emacs-devel@gnu.org>
Subject: Re: cc-mode uniform initialization support
Date: Mon, 4 Jul 2016 18:32:40 +0000	[thread overview]
Message-ID: <20160704183240.GA2375@acm.fritz.box> (raw)
In-Reply-To: <55D4CC9B.7020302@dancol.org>

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).



  parent reply	other threads:[~2016-07-04 18:32 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2016-07-22 21:09   ` Alan Mackenzie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160704183240.GA2375@acm.fritz.box \
    --to=acm@muc.de \
    --cc=dancol@dancol.org \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).