From: Alan Mackenzie Date: Fri, 20 Aug 2021 21:12:37 +0000 (+0000) Subject: Fix c-tentative-buffer-changes to be nestable in c-save-buffer-state X-Git-Tag: emacs-28.0.90~1409 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=13824c44d28427931a7e3284adec9a3a38cd2323;p=emacs.git Fix c-tentative-buffer-changes to be nestable in c-save-buffer-state * lisp/progmodes/cc-defs.el (c-tentative-buffer-changes) (c-tnt-chng-record-state, c-tnt-chng-cleanup): Enhance such that a buffer-undo-list of t is handled specially, so that a nil isn't consed onto it. Thus garbage collection can't later remove the (nil . t) from the end of the buffer-undo-list, causing an infinite loop. --- diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index 01bd64cb5c3..3cb1912b730 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -660,19 +660,27 @@ even when the buffer is read-only, and without interference from various buffer change hooks." (declare (indent 0) (debug t)) `(let (-tnt-chng-keep - -tnt-chng-state) + -tnt-chng-state + (old-undo-list buffer-undo-list)) (unwind-protect ;; Insert an undo boundary for use with `undo-more'. We ;; don't use `undo-boundary' since it doesn't insert one ;; unconditionally. - (setq buffer-undo-list (cons nil buffer-undo-list) - -tnt-chng-state (c-tnt-chng-record-state) + (setq buffer-undo-list + (if (eq old-undo-list t) + nil + (cons nil buffer-undo-list)) + old-undo-list (if (eq old-undo-list t) + t + buffer-undo-list) + -tnt-chng-state (c-tnt-chng-record-state + old-undo-list) -tnt-chng-keep (progn ,@body)) (c-tnt-chng-cleanup -tnt-chng-keep -tnt-chng-state)))) -(defun c-tnt-chng-record-state () +(defun c-tnt-chng-record-state (old-undo-list) ;; Used internally in `c-tentative-buffer-changes'. - (vector buffer-undo-list ; 0 + (vector old-undo-list ; 0 (current-buffer) ; 1 ;; No need to use markers for the point and mark; if the ;; undo got out of synch we're hosed anyway. @@ -690,18 +698,26 @@ various buffer change hooks." (setq buffer-undo-list (cdr saved-undo-list)) (if keep - ;; Find and remove the undo boundary. - (let ((p buffer-undo-list)) - (while (not (eq (cdr p) saved-undo-list)) - (setq p (cdr p))) - (setcdr p (cdr saved-undo-list))) - - ;; `primitive-undo' will remove the boundary. - (setq saved-undo-list (cdr saved-undo-list)) - (let ((undo-in-progress t)) - (while (not (eq (setq buffer-undo-list - (primitive-undo 1 buffer-undo-list)) - saved-undo-list)))) + (if (eq saved-undo-list t) + (progn + (c-benign-error + "Can't save additional undo list in c-tnt-chng-cleanup") + (setq buffer-undo-list t)) + ;; Find and remove the undo boundary. + (let ((p buffer-undo-list)) + (while (not (eq (cdr p) saved-undo-list)) + (setq p (cdr p))) + (setcdr p (cdr saved-undo-list)))) + + (let ((undo-in-progress t) + (end-undo-list (if (eq saved-undo-list t) + nil + ;; `primitive-undo' will remove the boundary. + (cdr saved-undo-list)))) + (while (not (eq buffer-undo-list end-undo-list)) + (setq buffer-undo-list (primitive-undo 1 buffer-undo-list)))) + (if (eq saved-undo-list t) + (setq buffer-undo-list t)) (when (buffer-live-p (elt saved-state 1)) (set-buffer (elt saved-state 1))