]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix c-tentative-buffer-changes to be nestable in c-save-buffer-state
authorAlan Mackenzie <acm@muc.de>
Fri, 20 Aug 2021 21:12:37 +0000 (21:12 +0000)
committerAlan Mackenzie <acm@muc.de>
Fri, 20 Aug 2021 21:12:37 +0000 (21:12 +0000)
* 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.

lisp/progmodes/cc-defs.el

index 01bd64cb5c3bdcd048858b3ceb4b6cd7de750532..3cb1912b730fc778e98bb67b3231edf5b8e84f80 100644 (file)
@@ -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))