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: Fri, 22 Jul 2016 21:09:57 +0000	[thread overview]
Message-ID: <20160722210957.GA3814@acm.fritz.box> (raw)
In-Reply-To: <20160704183240.GA2375@acm.fritz.box>

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



      reply	other threads:[~2016-07-22 21:09 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
2016-07-22 21:09   ` Alan Mackenzie [this message]

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=20160722210957.GA3814@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).