aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNoam Postavsky2018-01-20 11:27:23 -0500
committerNoam Postavsky2018-03-25 07:56:35 -0400
commit1d47d777ef24c0be9153b0a1c8ba21918fa1025a (patch)
tree7593519d0bd65a885f8daeaaa3f15b2b9eb58301 /src
parentd73d1384aa6d647a930b4dfe3e91505da4ffee21 (diff)
downloademacs-1d47d777ef24c0be9153b0a1c8ba21918fa1025a.tar.gz
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 'src')
-rw-r--r--src/eval.c10
1 files changed, 3 insertions, 7 deletions
diff --git a/src/eval.c b/src/eval.c
index 08a73b1e4a5..a6e1d86c4ab 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3035,7 +3035,6 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3035 emacs_abort (); 3035 emacs_abort ();
3036 3036
3037 i = optional = rest = 0; 3037 i = optional = rest = 0;
3038 bool previous_optional_or_rest = false;
3039 for (; CONSP (syms_left); syms_left = XCDR (syms_left)) 3038 for (; CONSP (syms_left); syms_left = XCDR (syms_left))
3040 { 3039 {
3041 maybe_quit (); 3040 maybe_quit ();
@@ -3046,17 +3045,15 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3046 3045
3047 if (EQ (next, Qand_rest)) 3046 if (EQ (next, Qand_rest))
3048 { 3047 {
3049 if (rest || previous_optional_or_rest) 3048 if (rest)
3050 xsignal1 (Qinvalid_function, fun); 3049 xsignal1 (Qinvalid_function, fun);
3051 rest = 1; 3050 rest = 1;
3052 previous_optional_or_rest = true;
3053 } 3051 }
3054 else if (EQ (next, Qand_optional)) 3052 else if (EQ (next, Qand_optional))
3055 { 3053 {
3056 if (optional || rest || previous_optional_or_rest) 3054 if (optional || rest)
3057 xsignal1 (Qinvalid_function, fun); 3055 xsignal1 (Qinvalid_function, fun);
3058 optional = 1; 3056 optional = 1;
3059 previous_optional_or_rest = true;
3060 } 3057 }
3061 else 3058 else
3062 { 3059 {
@@ -3080,11 +3077,10 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3080 else 3077 else
3081 /* Dynamically bind NEXT. */ 3078 /* Dynamically bind NEXT. */
3082 specbind (next, arg); 3079 specbind (next, arg);
3083 previous_optional_or_rest = false;
3084 } 3080 }
3085 } 3081 }
3086 3082
3087 if (!NILP (syms_left) || previous_optional_or_rest) 3083 if (!NILP (syms_left))
3088 xsignal1 (Qinvalid_function, fun); 3084 xsignal1 (Qinvalid_function, fun);
3089 else if (i < nargs) 3085 else if (i < nargs)
3090 xsignal2 (Qwrong_number_of_arguments, fun, make_number (nargs)); 3086 xsignal2 (Qwrong_number_of_arguments, fun, make_number (nargs));