From c21103bb76e6997064917b23b8fdfbf0a1149375 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= Date: Mon, 21 Aug 2023 13:50:03 +0200 Subject: [PATCH] Explicitly disallow named-let in code using dynamic binding There is no point in permitting named-let to be used in dynbound code; our code transforms are simply not valid in that context, and it's not worth the trouble to make it work (to the extent that it is at all possible). (Bug#59576) * lisp/emacs-lisp/subr-x.el (named-let): Error if used with dynamic binding. * doc/lispref/variables.texi (Local Variables): Amend manual. --- doc/lispref/variables.texi | 4 ++-- lisp/emacs-lisp/subr-x.el | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 55761ff75e2..93930d17587 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -351,8 +351,8 @@ A function call is in the tail position if it's the very last thing done so that the value returned by the call is the value of @var{body} itself, as is the case in the recursive call to @code{sum} above. -@strong{Warning:} @code{named-let} works as expected only when -lexical-binding is enabled. @xref{Lexical Binding}. +@code{named-let} can only be used when lexical-binding is enabled. +@xref{Lexical Binding}. @end defspec Here is a complete list of the other facilities that create local diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index 78dc58e0bcd..572822351b1 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -312,9 +312,13 @@ it makes no sense to convert it to a string using Like `let', bind variables in BINDINGS and then evaluate BODY, but with the twist that BODY can evaluate itself recursively by calling NAME, where the arguments passed to NAME are used -as the new values of the bound variables in the recursive invocation." +as the new values of the bound variables in the recursive invocation. + +This construct can only be used with lexical binding." (declare (indent 2) (debug (symbolp (&rest (symbolp form)) body))) (require 'cl-lib) + (unless lexical-binding + (error "`named-let' requires lexical binding")) (let ((fargs (mapcar (lambda (b) (if (consp b) (car b) b)) bindings)) (aargs (mapcar (lambda (b) (if (consp b) (cadr b))) bindings))) ;; According to the Scheme semantics of named let, `name' is not in scope -- 2.39.5