Subject: bug#13813: 24.3.50; eval-and-compile in macro inhibits let-binding of variable

From: Stefan Monnier <[email-masked]>
Date: Mon, 25 Feb 2013 15:53:21 -0500

> Recipe:
> * Create a file test.el with the following contents:

> (defvar myflag nil)
> (defmacro mytestmacro ()
>   "An eval-and-compile test."
>   `(eval-and-compile (mytestfun)))
> (defun mytestfun ()
>   (when myflag
>     (message "foo")))
> (let ((myflag t))
>   ;; Should display "foo"
>   (mytestmacro))

> * Now call with Emacs from trunk:
>   emacs --batch -l test.el
> * "foo" should be displayed, but isn't. The Emacs 24.2.93 pretest
>   however works as expected.

OK, you got me, I admit it, my recent change to eval-and-compile makes
it a lie.  Basically, there are now 3 different times:
- compile-time
- load-time (aka "eager-macroexpansion")
- eval-time

Most eval-and-compile are used for definitions which are used in macros
(hence needed for both compile-time and load-time).  For this reason,
I changed recently eval-and-compile to be (in effect)
eval-during-load-and-compile.  I could turn it into
a eval-during-eval-load-and-compile, but then your above test would run
`mytestfun' twice (once with myflag=nil and then once with myflag=t)
which I don't think would please everyone either.

> * Note the following:
>   - It works if you just 'setq' the 'myflag' variable

But not if you (progn (setq myflag t) (mytestmacro)).  The issue is
whether the setq takes place in a separate top-level expression, in
which case it's run before eager-macroexpansion of the expression that
does the (mytestmacro).

>   - The same problem occurs with `eval-when-compile', but everything
>     works with `progn'.

Yes, it's basically the same problem.

> And yes, Stefan, this bug turned up in the EIEIO test suite. :-)

Could you give some details, so we can better assess the best solution?
BTW, I think eval-and-compile should only be used to wrap definitions.
Anything else is asking for trouble.

        Stefan