Thibault Polge writes: > This sexp: > > (let ((:k 1)) :k) > > evals to 1 in Emacs 25.3.1, 26.3, and HEAD > (d36adb544d984b91c70f6194da01344e4b2b6fc9) if and only if > `lexical-binding` is t. > > If lexical-binding is nil, it raises an error, as I'd expect it to. > > This is in contradiction with documentation at (info "Constant variables > (elisp)"). The issue also appears if the symbol's been interned with > (intern ":k") Thanks, I can reproduce this on current master. I'm very new to Emacs internals, but decided to dig in. The problem is that a keyword ":a" has that: (a1) XSYMBOL (tem)->u.s.declared_special == false (a2) XSYMBOL (tem)->u.s.trapped_write == SYMBOL_NOWRITE However, in eval.c line 972, where "let" is defined, we lexically bind a symbol under the above conditions: if (!NILP (lexenv) && SYMBOLP (var) && !XSYMBOL (var)->u.s.declared_special && NILP (Fmemq (var, Vinternal_interpreter_environment))) /* Lexically bind VAR by adding it to the lexenv alist. */ lexenv = Fcons (Fcons (var, tem), lexenv); This is what causes the bug. In contrast, "nil" and "t" has that: (b1) XSYMBOL (tem)->u.s.declared_special == true This makes the above check fail, and we defer to the dynamic binding code which refuses to bind them. 1. One possible fix is to add a check for (b), and refuse to bind it if it's true. The attached patch does that. 2. I'm not sure, but it seems to me that keywords *should* perhaps have declared_special == TRUE. That should be set for anything that should never be lexically bound -- right? If this is correct, then I guess we should make sure that it gets set properly, probably already in read1? In plain language, either we (1) change the test in "let" or we (2) change how keyword symbols gets initialized to pass the existing test. Or maybe we should do both..? Please, if someone could check my findings or point me in the right direction here, that would be very helpful. Or even provide a proper fix if mine is completely wrong. :-) Best regards, Stefan Kangas