emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: cc-mode uniform initialization support


From: Alan Mackenzie
Subject: Re: cc-mode uniform initialization support
Date: Mon, 4 Jul 2016 18:32:40 +0000
User-agent: Mutt/1.5.24 (2015-08-30)

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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]