summaryrefslogtreecommitdiff
path: root/lisp/progmodes/cc-defs.el
diff options
context:
space:
mode:
authorAlan Mackenzie <acm@muc.de>2021-08-20 21:12:37 +0000
committerAlan Mackenzie <acm@muc.de>2021-08-20 21:12:37 +0000
commit13824c44d28427931a7e3284adec9a3a38cd2323 (patch)
tree01ac8626d8f2f4cbd8c4f11d0cf9f8dbbbf39549 /lisp/progmodes/cc-defs.el
parent681faf9f0bc41972932b72ef34c026419b6eb54d (diff)
downloademacs-13824c44d28427931a7e3284adec9a3a38cd2323.tar.gz
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.
Diffstat (limited to 'lisp/progmodes/cc-defs.el')
-rw-r--r--lisp/progmodes/cc-defs.el50
1 files changed, 33 insertions, 17 deletions
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))