aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Stephani2021-03-18 12:40:08 +0100
committerPhilipp Stephani2021-04-10 18:19:49 +0200
commit53dfd85a7f971875e716a55f010ee508bce89eed (patch)
tree3eb0b220ff838287f4d6cd3cd45d19794aceecf7
parentb72571ca49dd16be174f02ed14b460c136c9aaf2 (diff)
downloademacs-53dfd85a7f971875e716a55f010ee508bce89eed.tar.gz
emacs-53dfd85a7f971875e716a55f010ee508bce89eed.zip
Edebug: Disable backtracking when hitting a &define keyword.
Edebug doesn't deal well with backtracking out of definitions, see Bug#41988. Rather than trying to support this rare situation (e.g. by implementing a multipass parser), prevent it by adding an implicit gate. * lisp/emacs-lisp/edebug.el (edebug--match-&-spec-op): Disable backtracking when hitting a &define keyword. * test/lisp/emacs-lisp/edebug-tests.el (edebug-tests-duplicate-&define): New unit test. (edebug-tests--duplicate-&define): New helper macro. * doc/lispref/edebug.texi (Backtracking): Mention &define in the list of constructs that disable backtracking. * etc/NEWS: Document new behavior.
-rw-r--r--doc/lispref/edebug.texi10
-rw-r--r--etc/NEWS3
-rw-r--r--lisp/emacs-lisp/edebug.el18
-rw-r--r--test/lisp/emacs-lisp/edebug-tests.el25
4 files changed, 43 insertions, 13 deletions
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index 8942f55affb..323130f2378 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -1510,11 +1510,11 @@ form specifications (that is, @code{form}, @code{body}, @code{def-form}, and
1510must be in the form itself rather than at a higher level. 1510must be in the form itself rather than at a higher level.
1511 1511
1512Backtracking is also disabled after successfully matching a quoted 1512Backtracking is also disabled after successfully matching a quoted
1513symbol or string specification, since this usually indicates a 1513symbol, string specification, or @code{&define} keyword, since this
1514recognized construct. But if you have a set of alternative constructs that 1514usually indicates a recognized construct. But if you have a set of
1515all begin with the same symbol, you can usually work around this 1515alternative constructs that all begin with the same symbol, you can
1516constraint by factoring the symbol out of the alternatives, e.g., 1516usually work around this constraint by factoring the symbol out of the
1517@code{["foo" &or [first case] [second case] ...]}. 1517alternatives, e.g., @code{["foo" &or [first case] [second case] ...]}.
1518 1518
1519Most needs are satisfied by these two ways that backtracking is 1519Most needs are satisfied by these two ways that backtracking is
1520automatically disabled, but occasionally it is useful to explicitly 1520automatically disabled, but occasionally it is useful to explicitly
diff --git a/etc/NEWS b/etc/NEWS
index a0f05d8cf15..9ae37404823 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2524,6 +2524,9 @@ back in Emacs 23.1. The affected functions are: 'make-obsolete',
2524 2524
2525** The 'values' variable is now obsolete. 2525** The 'values' variable is now obsolete.
2526 2526
2527** The '&define' keyword in an Edebug specification now disables
2528backtracking.
2529
2527 2530
2528* Lisp Changes in Emacs 28.1 2531* Lisp Changes in Emacs 28.1
2529 2532
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index f1455ffe73b..365bc748741 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -1942,14 +1942,16 @@ a sequence of elements."
1942 ;; Normally, &define is interpreted specially other places. 1942 ;; Normally, &define is interpreted specially other places.
1943 ;; This should only be called inside of a spec list to match the remainder 1943 ;; This should only be called inside of a spec list to match the remainder
1944 ;; of the current list. e.g. ("lambda" &define args def-body) 1944 ;; of the current list. e.g. ("lambda" &define args def-body)
1945 (edebug-make-form-wrapper 1945 (prog1 (edebug-make-form-wrapper
1946 cursor 1946 cursor
1947 (edebug-before-offset cursor) 1947 (edebug-before-offset cursor)
1948 ;; Find the last offset in the list. 1948 ;; Find the last offset in the list.
1949 (let ((offsets (edebug-cursor-offsets cursor))) 1949 (let ((offsets (edebug-cursor-offsets cursor)))
1950 (while (consp offsets) (setq offsets (cdr offsets))) 1950 (while (consp offsets) (setq offsets (cdr offsets)))
1951 offsets) 1951 offsets)
1952 specs)) 1952 specs)
1953 ;; Stop backtracking here (Bug#41988).
1954 (setq edebug-gate t)))
1953 1955
1954(cl-defmethod edebug--match-&-spec-op ((_ (eql &name)) cursor specs) 1956(cl-defmethod edebug--match-&-spec-op ((_ (eql &name)) cursor specs)
1955 "Compute the name for `&name SPEC FUN` spec operator. 1957 "Compute the name for `&name SPEC FUN` spec operator.
diff --git a/test/lisp/emacs-lisp/edebug-tests.el b/test/lisp/emacs-lisp/edebug-tests.el
index dcb261c2eb9..7d45432e57e 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -1061,5 +1061,30 @@ backtracking (Bug#42701)."
1061 "edebug-anon10001" 1061 "edebug-anon10001"
1062 "edebug-tests-duplicate-symbol-backtrack")))))) 1062 "edebug-tests-duplicate-symbol-backtrack"))))))
1063 1063
1064(defmacro edebug-tests--duplicate-&define (_arg)
1065 "Helper macro for the ERT test `edebug-tests-duplicate-&define'.
1066The Edebug specification is similar to the one used by `cl-flet'
1067previously; see Bug#41988."
1068 (declare (debug (&or (&define name function-form) (defun)))))
1069
1070(ert-deftest edebug-tests-duplicate-&define ()
1071 "Check that Edebug doesn't backtrack out of `&define' forms.
1072This avoids potential duplicate definitions (Bug#41988)."
1073 (with-temp-buffer
1074 (print '(defun edebug-tests-duplicate-&define ()
1075 (edebug-tests--duplicate-&define
1076 (edebug-tests-duplicate-&define-inner () nil)))
1077 (current-buffer))
1078 (let* ((edebug-all-defs t)
1079 (edebug-initial-mode 'Go-nonstop)
1080 (instrumented-names ())
1081 (edebug-new-definition-function
1082 (lambda (name)
1083 (when (memq name instrumented-names)
1084 (error "Duplicate definition of `%s'" name))
1085 (push name instrumented-names)
1086 (edebug-new-definition name))))
1087 (should-error (eval-buffer) :type 'invalid-read-syntax))))
1088
1064(provide 'edebug-tests) 1089(provide 'edebug-tests)
1065;;; edebug-tests.el ends here 1090;;; edebug-tests.el ends here