Subject: bug#50720: unnamed &rest broken

From: Mattias Engdegård <[email-masked]>
Date: Tue, 21 Sep 2021 13:15:54 +0200

The interpreter and compiler allow &rest to be used without a variable name following but the generated byte code is completely broken:

(funcall (byte-compile (lambda (&rest) 'ta)))

crashes, and

(defun boo (a &rest)
  (if a a (list 1 2 3 4)))

(boo 'hiss)
=> hiss        ; interpreted
=> (1 2 3 4)   ; compiled

The reason is that the compiler generates code from the argument variable list but the byte-code interpreter will only look at the signature code which was generated from the actual signature:

(byte-compile (lambda (&rest) 'ta))
=> #[128 "\300\207" [ta] 1 "..."]

The 128 indicates zero positional parameters and a &rest argument, and the 1 is the maximum stack size required which is wrong; 2 stack slots are needed and that's what we get if naming the argument:

(byte-compile (lambda (&rest _r) 'ta))
=> #[128 "\300\207" [ta] 2 "..."]

In the `boo` case above, it is clear that the compiler doesn't expect any &rest param to have been pushed at all so the stack offsets are wrong.

Now, either we fix this bug or we stop pretending that unnamed &rest arguments work at all and signal an error, because it's clear from the above that they can't have seen much use.