diff options
| author | Stefan Monnier | 2020-11-25 14:49:55 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2020-11-25 14:49:55 -0500 |
| commit | 1eb168fa9765ff62361b279a480388674e1b9745 (patch) | |
| tree | aeaef63ff37bcb083cc8d5d30a82c06225f21c88 /src | |
| parent | d148d0259a4d3ad3da2f5bdf121e1f5836b3522b (diff) | |
| download | emacs-1eb168fa9765ff62361b279a480388674e1b9745.tar.gz emacs-1eb168fa9765ff62361b279a480388674e1b9745.zip | |
(defvar): Detect defining a variable currently lexically bound
* src/eval.c (lexbound_p): New function.
(Finternal__define_uninitialized_variable): Use it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/src/eval.c b/src/eval.c index 76708e6e7e2..3f9dcf6be6d 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -691,6 +691,45 @@ default_toplevel_binding (Lisp_Object symbol) | |||
| 691 | return binding; | 691 | return binding; |
| 692 | } | 692 | } |
| 693 | 693 | ||
| 694 | /* Look for a lexical-binding of SYMBOL somewhere up the stack. | ||
| 695 | This will only find bindings created with interpreted code, since once | ||
| 696 | compiled names of lexical variables are basically gone anyway. */ | ||
| 697 | static bool | ||
| 698 | lexbound_p (Lisp_Object symbol) | ||
| 699 | { | ||
| 700 | union specbinding *pdl = specpdl_ptr; | ||
| 701 | while (pdl > specpdl) | ||
| 702 | { | ||
| 703 | switch ((--pdl)->kind) | ||
| 704 | { | ||
| 705 | case SPECPDL_LET_DEFAULT: | ||
| 706 | case SPECPDL_LET: | ||
| 707 | if (EQ (specpdl_symbol (pdl), Qinternal_interpreter_environment)) | ||
| 708 | { | ||
| 709 | Lisp_Object env = specpdl_old_value (pdl); | ||
| 710 | if (CONSP (env) && !NILP (Fassq (symbol, env))) | ||
| 711 | return true; | ||
| 712 | } | ||
| 713 | break; | ||
| 714 | |||
| 715 | case SPECPDL_UNWIND: | ||
| 716 | case SPECPDL_UNWIND_ARRAY: | ||
| 717 | case SPECPDL_UNWIND_PTR: | ||
| 718 | case SPECPDL_UNWIND_INT: | ||
| 719 | case SPECPDL_UNWIND_INTMAX: | ||
| 720 | case SPECPDL_UNWIND_EXCURSION: | ||
| 721 | case SPECPDL_UNWIND_VOID: | ||
| 722 | case SPECPDL_BACKTRACE: | ||
| 723 | case SPECPDL_LET_LOCAL: | ||
| 724 | break; | ||
| 725 | |||
| 726 | default: | ||
| 727 | emacs_abort (); | ||
| 728 | } | ||
| 729 | } | ||
| 730 | return false; | ||
| 731 | } | ||
| 732 | |||
| 694 | DEFUN ("default-toplevel-value", Fdefault_toplevel_value, Sdefault_toplevel_value, 1, 1, 0, | 733 | DEFUN ("default-toplevel-value", Fdefault_toplevel_value, Sdefault_toplevel_value, 1, 1, 0, |
| 695 | doc: /* Return SYMBOL's toplevel default value. | 734 | doc: /* Return SYMBOL's toplevel default value. |
| 696 | "Toplevel" means outside of any let binding. */) | 735 | "Toplevel" means outside of any let binding. */) |
| @@ -726,6 +765,15 @@ This is like `defvar' and `defconst' but without affecting the variable's | |||
| 726 | value. */) | 765 | value. */) |
| 727 | (Lisp_Object symbol, Lisp_Object doc) | 766 | (Lisp_Object symbol, Lisp_Object doc) |
| 728 | { | 767 | { |
| 768 | if (!XSYMBOL (symbol)->u.s.declared_special | ||
| 769 | && lexbound_p (symbol)) | ||
| 770 | /* This test tries to catch the situation where we do | ||
| 771 | (let ((<foo-var> ...)) ...(<foo-function> ...)....) | ||
| 772 | and where the `foo` package only gets loaded when <foo-function> | ||
| 773 | is called, so the outer `let` incorrectly made the binding lexical | ||
| 774 | because the <foo-var> wasn't yet declared as dynamic at that point. */ | ||
| 775 | error ("Defining as dynamic an already lexical var"); | ||
| 776 | |||
| 729 | XSYMBOL (symbol)->u.s.declared_special = true; | 777 | XSYMBOL (symbol)->u.s.declared_special = true; |
| 730 | if (!NILP (doc)) | 778 | if (!NILP (doc)) |
| 731 | { | 779 | { |