unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: "Mattias Engdegård" <mattiase@acm.org>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: Lars Ingebrigtsen <larsi@gnus.org>,
	50268@debbugs.gnu.org, Noam Postavsky <npostavs@gmail.com>
Subject: bug#50268: 28.0.50; Assertion warning during native compilation
Date: Thu, 23 Sep 2021 13:09:02 +0200	[thread overview]
Message-ID: <F800EA86-4915-47DB-AB92-CF5364193370@acm.org> (raw)
In-Reply-To: <jwv35pw6p4c.fsf-monnier+emacs@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 150 bytes --]

23 sep. 2021 kl. 03.46 skrev Stefan Monnier <monnier@iro.umontreal.ca>:

> Not all of it, no.  Only the part which makes (&rest) acceptable.

Patch.


[-- Attachment #2: 0001-Renege-on-anonymous-rest-bug-50268-bug-50720.patch --]
[-- Type: application/octet-stream, Size: 7575 bytes --]

From c69c3b8c97e9aa9ff350b009c06b4e3e8842ba83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Thu, 23 Sep 2021 12:43:41 +0200
Subject: [PATCH] Renege on anonymous &rest (bug#50268, bug#50720)

Allowing &rest without a variable name following turned out not to be
very useful, and it never worked properly.  Disallow it.

* lisp/emacs-lisp/bytecomp.el (byte-compile-check-lambda-list):
* src/eval.c (funcall_lambda):
Signal error for &rest without variable name.
* doc/lispref/functions.texi (Argument List): Adjust manual.
* etc/NEWS (file): Announce.
* test/src/eval-tests.el (eval-tests--bugs-24912-and-24913):
Extend test, also checking with and without lexical binding.
(eval-tests-accept-empty-optional-rest): Reduce to...
(eval-tests-accept-empty-optional): ...this, again checking
with and without lexical binding.
---
 doc/lispref/functions.texi  |  2 +-
 etc/NEWS                    |  7 +++++
 lisp/emacs-lisp/bytecomp.el |  2 ++
 src/eval.c                  |  9 ++++--
 test/src/eval-tests.el      | 57 +++++++++++++++++++++----------------
 5 files changed, 49 insertions(+), 28 deletions(-)

diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index 77d1465c87..c856557c3c 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -378,7 +378,7 @@ Argument List
 @group
 (@var{required-vars}@dots{}
  @r{[}&optional @r{[}@var{optional-vars}@dots{}@r{]}@r{]}
- @r{[}&rest @r{[}@var{rest-var}@r{]}@r{]})
+ @r{[}&rest @var{rest-var}@r{]})
 @end group
 @end example
 
diff --git a/etc/NEWS b/etc/NEWS
index fb7a7f628a..cf3f90304d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3215,6 +3215,13 @@ local variable would not be heeded.  This has now changed, and a file
 with a 'lexical-binding' cookie is always heeded.  To revert to the
 old behavior, set 'permanently-enabled-local-variables' to nil.
 
++++
+** '&rest' in argument lists must always be followed by a variable name.
+Omitting the variable name after '&rest' was previously tolerated in
+some cases but not consistently so; it could lead to crashes or
+outright wrong results.  Since the utility was marginal at best, it is
+now an error to omit the variable.
+
 ---
 ** 'kill-all-local-variables' has changed how it handles non-symbol hooks.
 The function is documented to eliminate all buffer-local bindings
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index be74195778..d7da7a2149 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -2930,6 +2930,8 @@ byte-compile-check-lambda-list
 		   (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"))
                (when (memq (cadr list) '(&optional &rest))
diff --git a/src/eval.c b/src/eval.c
index 2bb7cfe600..66d34808f8 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3245,6 +3245,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
     emacs_abort ();
 
   i = optional = rest = 0;
+  bool previous_rest = false;
   for (; CONSP (syms_left); syms_left = XCDR (syms_left))
     {
       maybe_quit ();
@@ -3255,13 +3256,14 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
 
       if (EQ (next, Qand_rest))
         {
-          if (rest)
+          if (rest || previous_rest)
             xsignal1 (Qinvalid_function, fun);
           rest = 1;
+	  previous_rest = true;
         }
       else if (EQ (next, Qand_optional))
         {
-          if (optional || rest)
+          if (optional || rest || previous_rest)
             xsignal1 (Qinvalid_function, fun);
           optional = 1;
         }
@@ -3287,10 +3289,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
 	  else
 	    /* Dynamically bind NEXT.  */
 	    specbind (next, arg);
+	  previous_rest = false;
 	}
     }
 
-  if (!NILP (syms_left))
+  if (!NILP (syms_left) || previous_rest)
     xsignal1 (Qinvalid_function, fun);
   else if (i < nargs)
     xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (nargs));
diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el
index b2b7dfefda..3c3e703341 100644
--- a/test/src/eval-tests.el
+++ b/test/src/eval-tests.el
@@ -39,31 +39,40 @@ byte-compile-debug
 (ert-deftest eval-tests--bugs-24912-and-24913 ()
   "Check that Emacs doesn't accept weird argument lists.
 Bug#24912 and Bug#24913."
-  (dolist (args '((&rest &optional)
-                  (&rest a &optional) (&rest &optional a)
-                  (&optional &optional) (&optional &optional a)
-                  (&optional a &optional b)
-                  (&rest &rest) (&rest &rest a)
-                  (&rest a &rest b)))
-    (should-error (eval `(funcall (lambda ,args)) t) :type 'invalid-function)
-    (should-error (byte-compile-check-lambda-list args))
-    (let ((byte-compile-debug t))
-      (ert-info ((format "bytecomp: args = %S" args))
-       (should-error (eval `(byte-compile (lambda ,args)) t))))))
-
-(ert-deftest eval-tests-accept-empty-optional-rest ()
-  "Check that Emacs accepts empty &optional and &rest arglists.
+  (dolist (lb '(t false))
+    (ert-info ((prin1-to-string lb) :prefix "lexical-binding: ")
+      (let ((lexical-binding lb))
+        (dolist (args '((&rest &optional)
+                        (&rest a &optional) (&rest &optional a)
+                        (&optional &optional) (&optional &optional a)
+                        (&optional a &optional b)
+                        (&rest &rest) (&rest &rest a)
+                        (&rest a &rest b)
+                        (&rest) (&optional &rest)
+                        ))
+          (ert-info ((prin1-to-string args) :prefix "args: ")
+            (should-error
+             (eval `(funcall (lambda ,args)) lb) :type 'invalid-function)
+            (should-error (byte-compile-check-lambda-list args))
+            (let ((byte-compile-debug t))
+              (should-error (eval `(byte-compile (lambda ,args)) lb)))))))))
+
+(ert-deftest eval-tests-accept-empty-optional ()
+  "Check that Emacs accepts empty &optional arglists.
 Bug#24912."
-  (dolist (args '((&optional) (&rest) (&optional &rest)
-                  (&optional &rest a) (&optional a &rest)))
-    (let ((fun `(lambda ,args 'ok)))
-      (ert-info ("eval")
-        (should (eq (funcall (eval fun t)) 'ok)))
-      (ert-info ("byte comp check")
-        (byte-compile-check-lambda-list args))
-      (ert-info ("bytecomp")
-        (let ((byte-compile-debug t))
-          (should (eq (funcall (byte-compile fun)) 'ok)))))))
+  (dolist (lb '(t false))
+    (ert-info ((prin1-to-string lb) :prefix "lexical-binding: ")
+      (let ((lexical-binding lb))
+        (dolist (args '((&optional) (&optional &rest a)))
+          (ert-info ((prin1-to-string args) :prefix "args: ")
+            (let ((fun `(lambda ,args 'ok)))
+              (ert-info ("eval")
+                (should (eq (funcall (eval fun lb)) 'ok)))
+              (ert-info ("byte comp check")
+                (byte-compile-check-lambda-list args))
+              (ert-info ("bytecomp")
+                (let ((byte-compile-debug t))
+                  (should (eq (funcall (byte-compile fun)) 'ok)))))))))))
 
 
 (dolist (form '(let let*))
-- 
2.21.1 (Apple Git-122.3)


  parent reply	other threads:[~2021-09-23 11:09 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-21 11:15 bug#50720: unnamed &rest broken Mattias Engdegård
2021-09-21 16:11 ` bug#50720: bug#50268: 28.0.50; Assertion warning during native compilation Lars Ingebrigtsen
2021-09-21 16:22   ` Mattias Engdegård
2021-09-21 17:09     ` Noam Postavsky
2021-09-21 17:53       ` Eli Zaretskii
2021-09-21 19:32         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-22  5:43           ` Eli Zaretskii
2021-09-23  1:46             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-23  6:38               ` Eli Zaretskii
2021-09-23 11:09               ` Mattias Engdegård [this message]
2021-09-23 21:03                 ` Lars Ingebrigtsen
2021-09-24  6:07                   ` Eli Zaretskii
2021-09-25  0:51                     ` Lars Ingebrigtsen
2021-09-25 18:37                     ` Mattias Engdegård
2021-09-21 16:26   ` Eli Zaretskii
  -- strict thread matches above, loose matches on Subject: below --
2021-08-30 14:05 Michael Welsh Duggan
2021-09-04 14:00 ` Michael Welsh Duggan
2021-09-05 15:31   ` Michael Welsh Duggan
2021-09-20 22:12     ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21  7:50       ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 12:17         ` Basil L. Contovounesios via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 15:56           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=F800EA86-4915-47DB-AB92-CF5364193370@acm.org \
    --to=mattiase@acm.org \
    --cc=50268@debbugs.gnu.org \
    --cc=larsi@gnus.org \
    --cc=monnier@iro.umontreal.ca \
    --cc=npostavs@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).