bug-gnu-emacs
[Top][All Lists]
Advanced

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

bug#16910: 24.3; c++ mode: autoindent stops working


From: Alan Mackenzie
Subject: bug#16910: 24.3; c++ mode: autoindent stops working
Date: Sun, 2 Mar 2014 14:38:00 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

Hi, Andrew.

> Hi-

> While editing files in c++ mode, autoindent sometimes stops working
> after a while. Saving, making a trivial change and then immediately
> reverting sometimes solves the problem, but usually not. I'm afraid I
> can't give a recipe, since I myself don't understand when it happens; it
> seems unpredictable. But (some of) the error messages from emacs (which
> appear in the echo area) are below.

>              -Andrew Warshall


> In GNU Emacs 24.3.1 (i686-pc-linux-gnu, GTK+ Version 3.10.7)
> of 2014-02-24 on warshall

[ .... ]

> Recent messages:
> c-parse-state inconsistency at 1692: using cache: ((1415 . 1506) 220), from 
> scratch: nil
> Old state:
> (setq c-state-cache '((1415 . 1506) 220)  c-state-cache-good-pos 1636  
> c-state-nonlit-pos-cache '(3001)  c-state-nonlit-pos-cache-limit 1  
> c-state-semi-nonlit-pos-cache nil  c-state-semi-nonlit-pos-cache-limit 1  
> c-state-brace-pair-desert '(220 . 322)  c-state-point-min 1  
> c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  
> c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil  
> c-parse-state-point 1764)
> c-parse-state inconsistency at 1417: using cache: (1415 (1001 . 1156) 220), 
> from scratch: nil
> Old state:
> (setq c-state-cache '((1415 . 1506) 220)  c-state-cache-good-pos 1636  
> c-state-nonlit-pos-cache '(3001)  c-state-nonlit-pos-cache-limit 1  
> c-state-semi-nonlit-pos-cache nil  c-state-semi-nonlit-pos-cache-limit 1  
> c-state-brace-pair-desert '(220 . 322)  c-state-point-min 1  
> c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  
> c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil  
> c-parse-state-point 1692)
> c-parse-state inconsistency at 1417: using cache: (1415 (1001 . 1156) 220), 
> from scratch: nil
> Old state:
> (setq c-state-cache '(1415 (1001 . 1156) 220)  c-state-cache-good-pos 1416  
> c-state-nonlit-pos-cache '(3001)  c-state-nonlit-pos-cache-limit 1  
> c-state-semi-nonlit-pos-cache nil  c-state-semi-nonlit-pos-cache-limit 1  
> c-state-brace-pair-desert '(220 . 322)  c-state-point-min 1  
> c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  
> c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil  
> c-parse-state-point 1417)

These debug messages originate from a particular CC Mode function
`c-parse-state' which crawls through the buffer recording the position of
certain near and enclosing braces/brackets/parentheses.  Somewhere, e.g.
in your .emacs, you presumably have toggled `c-toggle-parse-state-debug'
to get this output.

`c-parse-state' in Emacs 24.3 was buggy.  The latest version, which will
be getting released along with Emacs 24.4, is less buggy.  I suggest you
apply the following patch to ..../emacs-24.3/lisp/progmodes/cc-engine.el
to bring that file up to the latest state, which should hopefully make CC
Mode indentation run more smoothly, or even correctly.  After applying
the patch, recompile cc-engine.el with either M-x byte-compile-file, or
(from the command line)

    emacs -Q -batch -f batch-byte-compile cc-engine.el

.


--- cc-engine.el        2013-04-26 12:35:20.000000000 +0000
+++ cc-engine.el.new    2014-02-02 16:16:42.000000000 +0000
@@ -2180,32 +2187,46 @@
 ;; reduced by buffer changes, and increased by invocations of
 ;; `c-state-literal-at'.  FIXME!!!
 
-(defsubst c-state-pp-to-literal (from to)
+(defsubst c-state-pp-to-literal (from to &optional not-in-delimiter)
   ;; Do a parse-partial-sexp from FROM to TO, returning either
   ;;     (STATE TYPE (BEG . END))     if TO is in a literal; or
   ;;     (STATE)                      otherwise,
   ;; where STATE is the parsing state at TO, TYPE is the type of the literal
   ;; (one of 'c, 'c++, 'string) and (BEG . END) is the boundaries of the 
literal.
   ;;
+  ;; Unless NOT-IN-DELIMITER is non-nil, when TO is inside a two-character
+  ;; comment opener, this is recognized as being in a comment literal.
+  ;;
   ;; Only elements 3 (in a string), 4 (in a comment), 5 (following a quote),
   ;; 7 (comment type) and 8 (start of comment/string) (and possibly 9) of
   ;; STATE are valid.
   (save-excursion
     (let ((s (parse-partial-sexp from to))
-         ty)
-      (when (or (nth 3 s) (nth 4 s))   ; in a string or comment
+         ty co-st)
+      (cond
+       ((or (nth 3 s) (nth 4 s))       ; in a string or comment
        (setq ty (cond
                  ((nth 3 s) 'string)
-                 ((eq (nth 7 s) t) 'c++)
+                 ((nth 7 s) 'c++)
                  (t 'c)))
        (parse-partial-sexp (point) (point-max)
-                           nil                  ; TARGETDEPTH
-                           nil                  ; STOPBEFORE
-                           s                    ; OLDSTATE
-                           'syntax-table))      ; stop at end of literal
-      (if ty
-         `(,s ,ty (,(nth 8 s) . ,(point)))
-       `(,s)))))
+                           nil            ; TARGETDEPTH
+                           nil            ; STOPBEFORE
+                           s              ; OLDSTATE
+                           'syntax-table) ; stop at end of literal
+       `(,s ,ty (,(nth 8 s) . ,(point))))
+
+       ((and (not not-in-delimiter)    ; inside a comment starter
+            (not (bobp))
+            (progn (backward-char)
+                   (and (not (looking-at "\\s!"))
+                        (looking-at c-comment-start-regexp))))
+       (setq ty (if (looking-at c-block-comment-start-regexp) 'c 'c++)
+             co-st (point))
+       (forward-comment 1)
+       `(,s ,ty (,co-st . ,(point))))
+
+       (t `(,s))))))
 
 (defun c-state-safe-place (here)
   ;; Return a buffer position before HERE which is "safe", i.e. outside any
@@ -2280,25 +2301,25 @@
        (while (and c (> (car c) c-state-semi-nonlit-pos-cache-limit))
          (setq c (cdr c)))
        (setq c-state-semi-nonlit-pos-cache c)
-       
+
        (while (and c (> (car c) here))
          (setq high-pos (car c))
          (setq c (cdr c)))
        (setq pos (or (car c) (point-min)))
-       
+
        (unless high-pos
          (while
              ;; Add an element to `c-state-semi-nonlit-pos-cache' each 
iteration.
              (and
               (<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
-              
+
               ;; Test for being in a literal.  If so, go to after it.
               (progn
                 (setq lit (car (cddr (c-state-pp-to-literal pos npos))))
                 (or (null lit)
                     (prog1 (<= (cdr lit) here)
                       (setq npos (cdr lit))))))
-              
+
            (setq pos npos)
            (setq c-state-semi-nonlit-pos-cache
                  (cons pos c-state-semi-nonlit-pos-cache))))
@@ -2532,8 +2553,11 @@
   ;; The return value is a list, one of the following:
   ;;
   ;; o - ('forward START-POINT) - scan forward from START-POINT,
-  ;;    which is not less than the highest position in `c-state-cache' below 
here.
+  ;;    which is not less than the highest position in `c-state-cache' below 
HERE,
+  ;;     which is after GOOD-POS.
   ;; o - ('backward nil) - scan backwards (from HERE).
+  ;; o - ('back-and-forward START-POINT) - like 'forward, but when HERE is 
earlier
+  ;;     than GOOD-POS.
   ;; o - ('IN-LIT nil) - point is inside the literal containing point-min.
   (let ((cache-pos (c-get-cache-scan-pos here))        ; highest position 
below HERE in cache (or 1)
        strategy            ; 'forward, 'backward, or 'IN-LIT.
@@ -2548,9 +2572,9 @@
      ((< (- good-pos here) (- here cache-pos)) ; FIXME!!! ; apply some sort of 
weighting.
       (setq strategy 'backward))
      (t
-      (setq strategy 'forward
+      (setq strategy 'back-and-forward
            start-point cache-pos)))
-    (list strategy (and (eq strategy 'forward) start-point))))
+    (list strategy start-point)))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2606,11 +2630,11 @@
   ;; OLD:   {                       (.)    {...........}
   ;;                                       ^             ^
   ;;                                     FROM          HERE
-  ;;                                     
+  ;;
   ;; NEW:   {             {....}    (.)    {.........
   ;;                         ^           ^           ^
   ;;                LOWER BRACE PAIR   HERE   or   HERE
-  ;;                                       
+  ;;
   ;; This routine should be fast.  Since it can get called a LOT, we maintain
   ;; `c-state-brace-pair-desert', a small cache of "failures", such that we
   ;; reduce the time wasted in repeated fruitless searches in brace deserts.
@@ -2822,9 +2846,10 @@
 
 (defun c-remove-stale-state-cache (start-point here pps-point)
   ;; Remove stale entries from the `c-cache-state', i.e. those which will
-  ;; not be in it when it is amended for position HERE.  Additionally, the
-  ;; "outermost" open-brace entry before HERE will be converted to a cons if
-  ;; the matching close-brace is scanned.
+  ;; not be in it when it is amended for position HERE.  This may involve
+  ;; replacing a CONS element for a brace pair containing HERE with its car.
+  ;; Additionally, the "outermost" open-brace entry before HERE will be
+  ;; converted to a cons if the matching close-brace is below HERE.
   ;;
   ;; START-POINT is a "maximal" "safe position" - there must be no open
   ;; parens/braces/brackets between START-POINT and HERE.
@@ -2835,7 +2860,7 @@
   ;; adjust it to get outside a string/comment.         (Sorry about this!  
The code
   ;; needs to be FAST).
   ;;
-  ;; Return a list (GOOD-POS SCAN-BACK-POS PPS-STATE), where
+  ;; Return a list (GOOD-POS SCAN-BACK-POS CONS-SEPARATED PPS-STATE), where
   ;; o - GOOD-POS is a position where the new value `c-state-cache' is known
   ;;   to be good (we aim for this to be as high as possible);
   ;; o - SCAN-BACK-POS, if not nil, indicates there may be a brace pair
@@ -2843,6 +2868,9 @@
   ;;   position to scan backwards from.  It is the position of the "{" of the
   ;;   last element to be removed from `c-state-cache', when that elt is a
   ;;   cons, otherwise nil.
+  ;; o - CONS-SEPARATED is t when a cons element in `c-state-cache' has been
+  ;;   replaced by its car because HERE lies inside the brace pair represented
+  ;;   by the cons.
   ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
   (save-excursion
     (save-restriction
@@ -2870,6 +2898,7 @@
             pos
             upper-lim     ; ,beyond which `c-state-cache' entries are removed
             scan-back-pos
+            cons-separated
             pair-beg pps-point-state target-depth)
 
        ;; Remove entries beyond HERE.  Also remove any entries inside
@@ -2891,7 +2920,8 @@
                   (consp (car c-state-cache))
                   (> (cdar c-state-cache) upper-lim))
          (setcar c-state-cache (caar c-state-cache))
-         (setq scan-back-pos (car c-state-cache)))
+         (setq scan-back-pos (car c-state-cache)
+               cons-separated t))
 
        ;; The next loop jumps forward out of a nested level of parens each
        ;; time round; the corresponding elements in `c-state-cache' are
@@ -2907,7 +2937,7 @@
                    start-point))
        (goto-char pos)
        (while (and c-state-cache
-                   (or (numberp (car c-state-cache)) ; Have we a { at all? 
+                   (or (numberp (car c-state-cache)) ; Have we a { at all?
                        (cdr c-state-cache))
                    (< (point) here))
          (cond
@@ -2963,7 +2993,7 @@
          (setq c-state-cache (cons (cons pair-beg pos)
                                    c-state-cache)))
 
-       (list pos scan-back-pos pps-state)))))
+       (list pos scan-back-pos cons-separated pps-state)))))
 
 (defun c-remove-stale-state-cache-backwards (here)
   ;; Strip stale elements of `c-state-cache' by moving backwards through the
@@ -3143,10 +3173,13 @@
   ;; This function is called from c-after-change.
 
   ;; The caches of non-literals:
-  (if (< here c-state-nonlit-pos-cache-limit)
-      (setq c-state-nonlit-pos-cache-limit here))
-  (if (< here c-state-semi-nonlit-pos-cache-limit)
-      (setq c-state-semi-nonlit-pos-cache-limit here))
+  ;; Note that we use "<=" for the possibility of the second char of a two-char
+  ;; comment opener being typed; this would invalidate any cache position at
+  ;; HERE.
+  (if (<= here c-state-nonlit-pos-cache-limit)
+      (setq c-state-nonlit-pos-cache-limit (1- here)))
+  (if (<= here c-state-semi-nonlit-pos-cache-limit)
+      (setq c-state-semi-nonlit-pos-cache-limit (1- here)))
 
   ;; `c-state-cache':
   ;; Case 1: if `here' is in a literal containing point-min, everything
@@ -3160,7 +3193,8 @@
     ;; Truncate `c-state-cache' and set `c-state-cache-good-pos' to a value
     ;; below `here'.  To maintain its consistency, we may need to insert a new
     ;; brace pair.
-    (let ((here-bol (c-point 'bol here))
+    (let (open-paren-in-column-0-is-defun-start
+         (here-bol (c-point 'bol here))
          too-high-pa             ; recorded {/(/[ next above here, or nil.
          dropped-cons            ; was the last removed element a brace pair?
          pa)
@@ -3231,6 +3265,7 @@
   ;; This function might do hidden buffer changes.
   (let* ((here (point))
         (here-bopl (c-point 'bopl))
+        open-paren-in-column-0-is-defun-start
         strategy            ; 'forward, 'backward etc..
         ;; Candidate positions to start scanning from:
         cache-pos           ; highest position below HERE already existing in
@@ -3240,6 +3275,7 @@
                     ; are no open parens/braces between it and HERE.
         bopl-state
         res
+        cons-separated
         scan-backward-pos scan-forward-p) ; used for 'backward.
     ;; If POINT-MIN has changed, adjust the cache
     (unless (= (point-min) c-state-point-min)
@@ -3252,13 +3288,15 @@
 
     ;; SCAN!
     (cond
-     ((eq strategy 'forward)
+     ((memq strategy '(forward back-and-forward))
       (setq res (c-remove-stale-state-cache start-point here here-bopl))
       (setq cache-pos (car res)
            scan-backward-pos (cadr res)
-           bopl-state (car (cddr res))) ; will be nil if (< here-bopl
+           cons-separated (car (cddr res)) 
+           bopl-state (cadr (cddr res))) ; will be nil if (< here-bopl
                                        ; start-point)
-      (if scan-backward-pos
+      (if (and scan-backward-pos
+              (or cons-separated (eq strategy 'forward))) ;scan-backward-pos
          (c-append-lower-brace-pair-to-state-cache scan-backward-pos here))
       (setq good-pos
            (c-append-to-state-cache cache-pos here))



-- 
Alan Mackenzie (Nuremberg, Germany).





reply via email to

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