summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp
diff options
context:
space:
mode:
authorNoam Postavsky <npostavs@gmail.com>2018-01-20 11:27:23 -0500
committerNoam Postavsky <npostavs@gmail.com>2018-03-25 07:56:35 -0400
commit1d47d777ef24c0be9153b0a1c8ba21918fa1025a (patch)
tree7593519d0bd65a885f8daeaaa3f15b2b9eb58301 /lisp/emacs-lisp
parentd73d1384aa6d647a930b4dfe3e91505da4ffee21 (diff)
downloademacs-1d47d777ef24c0be9153b0a1c8ba21918fa1025a.tar.gz
emacs-1d47d777ef24c0be9153b0a1c8ba21918fa1025a.tar.bz2
emacs-1d47d777ef24c0be9153b0a1c8ba21918fa1025a.zip
Allow `&rest' or `&optional' without following variable (Bug#29165)
This is sometimes convenient when writing macros, so that the empty variable case doesn't need to be handled specially. Older versions of Emacs accepted this in some cases (especially the interpreter in Emacs 25 and below was very accepting). | interpreted/compiled | | arglist | 25 & earlier | 26 | 27 | |---------------------------+--------------+-----+-----| | (&rest) | y/n | n/n | y/y | | (&rest &rest) | y/n | n/n | n/n | | (&rest &rest x) | y/n | n/n | n/n | | (&rest x &rest) | y/n | n/n | n/n | | (&rest x &rest y) | y/n | n/n | n/n | |---------------------------+--------------+-----+-----| | (&optional) | y/n | n/n | y/y | | (&optional &optional) | y/n | n/n | n/n | | (&optional x &optional) | y/n | n/n | n/n | | (&optional x &optional y) | y/y | n/n | n/n | |---------------------------+--------------+-----+-----| | (&optional &rest) | y/n | n/n | y/y | | (&optional x &rest) | y/n | n/n | y/y | | (&optional &rest y) | y/y | n/n | y/y | |---------------------------+--------------+-----+-----| | (&rest &optional) | y/n | n/n | n/n | | (&rest &optional y) | y/n | n/n | n/n | | (&rest x &optional y) | y/n | n/n | n/n | The values in the table above can be produced with the following code: (with-current-buffer (get-buffer-create "*ck-args*") (erase-buffer) (dolist (arglist '((&rest) (&rest &rest) (&rest &rest x) (&rest x &rest) (&rest x &rest y) (&optional) (&optional &optional) (&optional x &optional) (&optional x &optional y) (&optional &rest) (&optional x &rest) (&optional &rest y) (&rest &optional) (&rest &optional y) (&rest x &optional y))) (insert (format "%c/%c\n" (condition-case err (progn (funcall `(lambda ,arglist 'ok)) ?y) (error ?n)) (condition-case err (progn (byte-compile-check-lambda-list arglist) ?y) (error ?n)))) (display-buffer (current-buffer)))) * src/eval.c (funcall_lambda): * lisp/emacs-lisp/bytecomp.el (byte-compile-check-lambda-list): Don't check for missing variables after `&rest' and `&optional'. * test/src/eval-tests.el (eval-tests--bugs-24912-and-24913) (eval-tests-accept-empty-optional-rest): Update tests accordingly. * etc/NEWS: Update announcement accordingly. * doc/lispref/functions.texi (Argument List): Update manual to indicate that variable names are optional.
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r--lisp/emacs-lisp/bytecomp.el11
1 files changed, 4 insertions, 7 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 07476f1ac96..78d3071b168 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -2737,15 +2737,12 @@ If FORM is a lambda or a macro, byte-compile it as a function."
(macroexp--const-symbol-p arg t))
(error "Invalid lambda variable %s" arg))
((eq arg '&rest)
- (unless (cdr list)
- (error "&rest without variable name"))
(when (cddr list)
- (error "Garbage following &rest VAR in lambda-list")))
+ (error "Garbage following &rest VAR in lambda-list"))
+ (when (memq (cadr list) '(&optional &rest))
+ (error "%s following &rest in lambda-list" (cadr list))))
((eq arg '&optional)
- (when (or (null (cdr list))
- (memq (cadr list) '(&optional &rest)))
- (error "Variable name missing after &optional"))
- (when (memq '&optional (cddr list))
+ (when (memq '&optional (cdr list))
(error "Duplicate &optional")))
((memq arg vars)
(byte-compile-warn "repeated variable %s in lambda-list" arg))