From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.bugs Subject: bug#16910: 24.3; c++ mode: autoindent stops working Date: Sun, 2 Mar 2014 14:38:00 +0000 Message-ID: <20140302143800.GB3768@acm.acm> References: <874n3j2ogh.fsf@practicealgebra.net> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1393771346 4278 80.91.229.3 (2 Mar 2014 14:42:26 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 2 Mar 2014 14:42:26 +0000 (UTC) Cc: 16910@debbugs.gnu.org To: admin@practicealgebra.net Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sun Mar 02 15:42:32 2014 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1WK7b2-00059H-Pl for geb-bug-gnu-emacs@m.gmane.org; Sun, 02 Mar 2014 15:42:29 +0100 Original-Received: from localhost ([::1]:35710 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WK7b2-0003Xs-E8 for geb-bug-gnu-emacs@m.gmane.org; Sun, 02 Mar 2014 09:42:28 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:33667) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WK7ar-0003Vd-St for bug-gnu-emacs@gnu.org; Sun, 02 Mar 2014 09:42:25 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WK7ak-0005r9-F1 for bug-gnu-emacs@gnu.org; Sun, 02 Mar 2014 09:42:17 -0500 Original-Received: from debbugs.gnu.org ([140.186.70.43]:46440) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WK7ac-0005pK-6O; Sun, 02 Mar 2014 09:42:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.80) (envelope-from ) id 1WK7ab-0002cl-TY; Sun, 02 Mar 2014 09:42:02 -0500 X-Loop: help-debbugs@gnu.org In-Reply-To: <874n3j2ogh.fsf@practicealgebra.net> Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Sun, 02 Mar 2014 14:42:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 16910 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: moreinfo Original-Received: via spool by 16910-submit@debbugs.gnu.org id=B16910.139377130410062 (code B ref 16910); Sun, 02 Mar 2014 14:42:01 +0000 Original-Received: (at 16910) by debbugs.gnu.org; 2 Mar 2014 14:41:44 +0000 Original-Received: from localhost ([127.0.0.1]:47622 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.80) (envelope-from ) id 1WK7aJ-0002cC-IQ for submit@debbugs.gnu.org; Sun, 02 Mar 2014 09:41:44 -0500 Original-Received: from colin.muc.de ([193.149.48.1]:48572 helo=mail.muc.de) by debbugs.gnu.org with esmtp (Exim 4.80) (envelope-from ) id 1WK7aE-0002br-5V for 16910@debbugs.gnu.org; Sun, 02 Mar 2014 09:41:39 -0500 Original-Received: (qmail 1811 invoked by uid 3782); 2 Mar 2014 14:41:36 -0000 Original-Received: from acm.muc.de (pD9518496.dip0.t-ipconnect.de [217.81.132.150]) by colin.muc.de (tmda-ofmipd) with ESMTP; Sun, 02 Mar 2014 15:41:34 +0100 Original-Received: (qmail 4847 invoked by uid 1000); 2 Mar 2014 14:38:00 -0000 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-Delivery-Agent: TMDA/1.1.12 (Macallan) X-Primary-Address: acm@muc.de X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.15 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:86474 Archived-At: 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).