diff options
| author | Stefan Monnier | 2013-08-02 17:16:33 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2013-08-02 17:16:33 -0400 |
| commit | a104f656c8217b027866d32e8d7bf024a671e3cc (patch) | |
| tree | b62ddfb915099ba3398b2f0b1f9ddc0ed6203102 /src | |
| parent | 185e3b5a2f3dc2b5163eb1fe97499c6af1edaa9c (diff) | |
| download | emacs-a104f656c8217b027866d32e8d7bf024a671e3cc.tar.gz emacs-a104f656c8217b027866d32e8d7bf024a671e3cc.zip | |
Make defvar affect the default binding outside of any let.
* src/eval.c (default_toplevel_binding): New function.
(Fdefvar): Use it.
(unbind_to, backtrace_eval_unrewind): Do a bit of CSE simplification.
(Fdefault_toplevel_value, Fset_default_toplevel_value): New subrs.
(syms_of_eval): Export them.
* src/data.c (Fdefault_value): Micro cleanup.
* src/term.c (init_tty): Use "false".
* lisp/custom.el (custom-initialize-default, custom-initialize-set)
(custom-initialize-reset, custom-initialize-changed): Affect the
toplevel-default-value (bug#6275, bug#14586).
* lisp/emacs-lisp/advice.el (ad-compile-function): Undo previous workaround
for bug#6275.
* test/automated/core-elisp-tests.el: New file.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 10 | ||||
| -rw-r--r-- | src/data.c | 4 | ||||
| -rw-r--r-- | src/eval.c | 124 | ||||
| -rw-r--r-- | src/term.c | 24 |
4 files changed, 105 insertions, 57 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 2a511d2fc8a..c6e349010a7 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,13 @@ | |||
| 1 | 2013-08-02 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * eval.c (default_toplevel_binding): New function. | ||
| 4 | (Fdefvar): Use it. | ||
| 5 | (unbind_to, backtrace_eval_unrewind): Do a bit of CSE simplification. | ||
| 6 | (Fdefault_toplevel_value, Fset_default_toplevel_value): New subrs. | ||
| 7 | (syms_of_eval): Export them. | ||
| 8 | * data.c (Fdefault_value): Micro cleanup. | ||
| 9 | * term.c (init_tty): Use "false". | ||
| 10 | |||
| 1 | 2013-08-02 Dmitry Antipov <dmantipov@yandex.ru> | 11 | 2013-08-02 Dmitry Antipov <dmantipov@yandex.ru> |
| 2 | 12 | ||
| 3 | Fix X GC leak in GTK and raw (no toolkit) X ports. | 13 | Fix X GC leak in GTK and raw (no toolkit) X ports. |
diff --git a/src/data.c b/src/data.c index f04d6da618f..d1e43ac1b5f 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -1384,9 +1384,7 @@ for this variable. The default value is meaningful for variables with | |||
| 1384 | local bindings in certain buffers. */) | 1384 | local bindings in certain buffers. */) |
| 1385 | (Lisp_Object symbol) | 1385 | (Lisp_Object symbol) |
| 1386 | { | 1386 | { |
| 1387 | register Lisp_Object value; | 1387 | Lisp_Object value = default_value (symbol); |
| 1388 | |||
| 1389 | value = default_value (symbol); | ||
| 1390 | if (!EQ (value, Qunbound)) | 1388 | if (!EQ (value, Qunbound)) |
| 1391 | return value; | 1389 | return value; |
| 1392 | 1390 | ||
diff --git a/src/eval.c b/src/eval.c index cb716690e3c..8ee259110f4 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -658,6 +658,51 @@ The return value is BASE-VARIABLE. */) | |||
| 658 | return base_variable; | 658 | return base_variable; |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | static union specbinding * | ||
| 662 | default_toplevel_binding (Lisp_Object symbol) | ||
| 663 | { | ||
| 664 | union specbinding *binding = NULL; | ||
| 665 | union specbinding *pdl = specpdl_ptr; | ||
| 666 | while (pdl > specpdl) | ||
| 667 | { | ||
| 668 | switch ((--pdl)->kind) | ||
| 669 | { | ||
| 670 | case SPECPDL_LET_DEFAULT: | ||
| 671 | case SPECPDL_LET: | ||
| 672 | if (EQ (specpdl_symbol (pdl), symbol)) | ||
| 673 | binding = pdl; | ||
| 674 | break; | ||
| 675 | } | ||
| 676 | } | ||
| 677 | return binding; | ||
| 678 | } | ||
| 679 | |||
| 680 | DEFUN ("default-toplevel-value", Fdefault_toplevel_value, Sdefault_toplevel_value, 1, 1, 0, | ||
| 681 | doc: /* Return SYMBOL's toplevel default value. | ||
| 682 | "Toplevel" means outside of any let binding. */) | ||
| 683 | (Lisp_Object symbol) | ||
| 684 | { | ||
| 685 | union specbinding *binding = default_toplevel_binding (symbol); | ||
| 686 | Lisp_Object value | ||
| 687 | = binding ? specpdl_old_value (binding) : Fdefault_value (symbol); | ||
| 688 | if (!EQ (value, Qunbound)) | ||
| 689 | return value; | ||
| 690 | xsignal1 (Qvoid_variable, symbol); | ||
| 691 | } | ||
| 692 | |||
| 693 | DEFUN ("set-default-toplevel-value", Fset_default_toplevel_value, | ||
| 694 | Sset_default_toplevel_value, 2, 2, 0, | ||
| 695 | doc: /* Set SYMBOL's toplevel default value to VALUE. | ||
| 696 | "Toplevel" means outside of any let binding. */) | ||
| 697 | (Lisp_Object symbol, Lisp_Object value) | ||
| 698 | { | ||
| 699 | union specbinding *binding = default_toplevel_binding (symbol); | ||
| 700 | if (binding) | ||
| 701 | set_specpdl_old_value (binding, value); | ||
| 702 | else | ||
| 703 | Fset_default (symbol, value); | ||
| 704 | return Qnil; | ||
| 705 | } | ||
| 661 | 706 | ||
| 662 | DEFUN ("defvar", Fdefvar, Sdefvar, 1, UNEVALLED, 0, | 707 | DEFUN ("defvar", Fdefvar, Sdefvar, 1, UNEVALLED, 0, |
| 663 | doc: /* Define SYMBOL as a variable, and return SYMBOL. | 708 | doc: /* Define SYMBOL as a variable, and return SYMBOL. |
| @@ -706,18 +751,10 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */) | |||
| 706 | else | 751 | else |
| 707 | { /* Check if there is really a global binding rather than just a let | 752 | { /* Check if there is really a global binding rather than just a let |
| 708 | binding that shadows the global unboundness of the var. */ | 753 | binding that shadows the global unboundness of the var. */ |
| 709 | union specbinding *pdl = specpdl_ptr; | 754 | union specbinding *binding = default_toplevel_binding (sym); |
| 710 | while (pdl > specpdl) | 755 | if (binding && EQ (specpdl_old_value (binding), Qunbound)) |
| 711 | { | 756 | { |
| 712 | if ((--pdl)->kind >= SPECPDL_LET | 757 | set_specpdl_old_value (binding, eval_sub (XCAR (tail))); |
| 713 | && EQ (specpdl_symbol (pdl), sym) | ||
| 714 | && EQ (specpdl_old_value (pdl), Qunbound)) | ||
| 715 | { | ||
| 716 | message_with_string | ||
| 717 | ("Warning: defvar ignored because %s is let-bound", | ||
| 718 | SYMBOL_NAME (sym), 1); | ||
| 719 | break; | ||
| 720 | } | ||
| 721 | } | 758 | } |
| 722 | } | 759 | } |
| 723 | tail = XCDR (tail); | 760 | tail = XCDR (tail); |
| @@ -3311,19 +3348,21 @@ unbind_to (ptrdiff_t count, Lisp_Object value) | |||
| 3311 | case SPECPDL_BACKTRACE: | 3348 | case SPECPDL_BACKTRACE: |
| 3312 | break; | 3349 | break; |
| 3313 | case SPECPDL_LET: | 3350 | case SPECPDL_LET: |
| 3314 | /* If variable has a trivial value (no forwarding), we can | 3351 | { /* If variable has a trivial value (no forwarding), we can |
| 3315 | just set it. No need to check for constant symbols here, | 3352 | just set it. No need to check for constant symbols here, |
| 3316 | since that was already done by specbind. */ | 3353 | since that was already done by specbind. */ |
| 3317 | if (XSYMBOL (specpdl_symbol (specpdl_ptr))->redirect | 3354 | struct Lisp_Symbol *sym = XSYMBOL (specpdl_symbol (specpdl_ptr)); |
| 3318 | == SYMBOL_PLAINVAL) | 3355 | if (sym->redirect == SYMBOL_PLAINVAL) |
| 3319 | SET_SYMBOL_VAL (XSYMBOL (specpdl_symbol (specpdl_ptr)), | 3356 | { |
| 3320 | specpdl_old_value (specpdl_ptr)); | 3357 | SET_SYMBOL_VAL (sym, specpdl_old_value (specpdl_ptr)); |
| 3321 | else | 3358 | break; |
| 3322 | /* NOTE: we only ever come here if make_local_foo was used for | 3359 | } |
| 3323 | the first time on this var within this let. */ | 3360 | else |
| 3324 | Fset_default (specpdl_symbol (specpdl_ptr), | 3361 | { /* FALLTHROUGH!! |
| 3325 | specpdl_old_value (specpdl_ptr)); | 3362 | NOTE: we only ever come here if make_local_foo was used for |
| 3326 | break; | 3363 | the first time on this var within this let. */ |
| 3364 | } | ||
| 3365 | } | ||
| 3327 | case SPECPDL_LET_DEFAULT: | 3366 | case SPECPDL_LET_DEFAULT: |
| 3328 | Fset_default (specpdl_symbol (specpdl_ptr), | 3367 | Fset_default (specpdl_symbol (specpdl_ptr), |
| 3329 | specpdl_old_value (specpdl_ptr)); | 3368 | specpdl_old_value (specpdl_ptr)); |
| @@ -3511,24 +3550,23 @@ backtrace_eval_unrewind (int distance) | |||
| 3511 | case SPECPDL_BACKTRACE: | 3550 | case SPECPDL_BACKTRACE: |
| 3512 | break; | 3551 | break; |
| 3513 | case SPECPDL_LET: | 3552 | case SPECPDL_LET: |
| 3514 | /* If variable has a trivial value (no forwarding), we can | 3553 | { /* If variable has a trivial value (no forwarding), we can |
| 3515 | just set it. No need to check for constant symbols here, | 3554 | just set it. No need to check for constant symbols here, |
| 3516 | since that was already done by specbind. */ | 3555 | since that was already done by specbind. */ |
| 3517 | if (XSYMBOL (specpdl_symbol (tmp))->redirect | 3556 | struct Lisp_Symbol *sym = XSYMBOL (specpdl_symbol (tmp)); |
| 3518 | == SYMBOL_PLAINVAL) | 3557 | if (sym->redirect == SYMBOL_PLAINVAL) |
| 3519 | { | 3558 | { |
| 3520 | struct Lisp_Symbol *sym = XSYMBOL (specpdl_symbol (tmp)); | 3559 | Lisp_Object old_value = specpdl_old_value (tmp); |
| 3521 | Lisp_Object old_value = specpdl_old_value (tmp); | 3560 | set_specpdl_old_value (tmp, SYMBOL_VAL (sym)); |
| 3522 | set_specpdl_old_value (tmp, SYMBOL_VAL (sym)); | 3561 | SET_SYMBOL_VAL (sym, old_value); |
| 3523 | SET_SYMBOL_VAL (sym, old_value); | 3562 | break; |
| 3524 | break; | 3563 | } |
| 3525 | } | 3564 | else |
| 3526 | else | 3565 | { /* FALLTHROUGH!! |
| 3527 | { | 3566 | NOTE: we only ever come here if make_local_foo was used for |
| 3528 | /* FALLTHROUGH! | 3567 | the first time on this var within this let. */ |
| 3529 | NOTE: we only ever come here if make_local_foo was used for | 3568 | } |
| 3530 | the first time on this var within this let. */ | 3569 | } |
| 3531 | } | ||
| 3532 | case SPECPDL_LET_DEFAULT: | 3570 | case SPECPDL_LET_DEFAULT: |
| 3533 | { | 3571 | { |
| 3534 | Lisp_Object sym = specpdl_symbol (tmp); | 3572 | Lisp_Object sym = specpdl_symbol (tmp); |
| @@ -3796,6 +3834,8 @@ alist of active lexical bindings. */); | |||
| 3796 | defsubr (&Ssetq); | 3834 | defsubr (&Ssetq); |
| 3797 | defsubr (&Squote); | 3835 | defsubr (&Squote); |
| 3798 | defsubr (&Sfunction); | 3836 | defsubr (&Sfunction); |
| 3837 | defsubr (&Sdefault_toplevel_value); | ||
| 3838 | defsubr (&Sset_default_toplevel_value); | ||
| 3799 | defsubr (&Sdefvar); | 3839 | defsubr (&Sdefvar); |
| 3800 | defsubr (&Sdefvaralias); | 3840 | defsubr (&Sdefvaralias); |
| 3801 | defsubr (&Sdefconst); | 3841 | defsubr (&Sdefconst); |
diff --git a/src/term.c b/src/term.c index 376d6e7831a..f5f4882161e 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -2933,7 +2933,7 @@ dissociate_if_controlling_tty (int fd) | |||
| 2933 | 2933 | ||
| 2934 | TERMINAL_TYPE is the termcap type of the device, e.g. "vt100". | 2934 | TERMINAL_TYPE is the termcap type of the device, e.g. "vt100". |
| 2935 | 2935 | ||
| 2936 | If MUST_SUCCEED is true, then all errors are fatal. */ | 2936 | If MUST_SUCCEED is true, then all errors are fatal. */ |
| 2937 | 2937 | ||
| 2938 | struct terminal * | 2938 | struct terminal * |
| 2939 | init_tty (const char *name, const char *terminal_type, bool must_succeed) | 2939 | init_tty (const char *name, const char *terminal_type, bool must_succeed) |
| @@ -2944,7 +2944,7 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed) | |||
| 2944 | int status; | 2944 | int status; |
| 2945 | struct tty_display_info *tty = NULL; | 2945 | struct tty_display_info *tty = NULL; |
| 2946 | struct terminal *terminal = NULL; | 2946 | struct terminal *terminal = NULL; |
| 2947 | bool ctty = 0; /* True if asked to open controlling tty. */ | 2947 | bool ctty = false; /* True if asked to open controlling tty. */ |
| 2948 | 2948 | ||
| 2949 | if (!terminal_type) | 2949 | if (!terminal_type) |
| 2950 | maybe_fatal (must_succeed, 0, | 2950 | maybe_fatal (must_succeed, 0, |
| @@ -3031,7 +3031,7 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed) | |||
| 3031 | tty->termcap_term_buffer = xmalloc (buffer_size); | 3031 | tty->termcap_term_buffer = xmalloc (buffer_size); |
| 3032 | 3032 | ||
| 3033 | /* On some systems, tgetent tries to access the controlling | 3033 | /* On some systems, tgetent tries to access the controlling |
| 3034 | terminal. */ | 3034 | terminal. */ |
| 3035 | block_tty_out_signal (); | 3035 | block_tty_out_signal (); |
| 3036 | status = tgetent (tty->termcap_term_buffer, terminal_type); | 3036 | status = tgetent (tty->termcap_term_buffer, terminal_type); |
| 3037 | unblock_tty_out_signal (); | 3037 | unblock_tty_out_signal (); |
| @@ -3101,13 +3101,13 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\ | |||
| 3101 | Right (tty) = tgetstr ("nd", address); | 3101 | Right (tty) = tgetstr ("nd", address); |
| 3102 | Down (tty) = tgetstr ("do", address); | 3102 | Down (tty) = tgetstr ("do", address); |
| 3103 | if (!Down (tty)) | 3103 | if (!Down (tty)) |
| 3104 | Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */ | 3104 | Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do". */ |
| 3105 | if (tgetflag ("bs")) | 3105 | if (tgetflag ("bs")) |
| 3106 | Left (tty) = "\b"; /* can't possibly be longer! */ | 3106 | Left (tty) = "\b"; /* Can't possibly be longer! */ |
| 3107 | else /* (Actually, "bs" is obsolete...) */ | 3107 | else /* (Actually, "bs" is obsolete...) */ |
| 3108 | Left (tty) = tgetstr ("le", address); | 3108 | Left (tty) = tgetstr ("le", address); |
| 3109 | if (!Left (tty)) | 3109 | if (!Left (tty)) |
| 3110 | Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */ | 3110 | Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le". */ |
| 3111 | tty->TS_pad_char = tgetstr ("pc", address); | 3111 | tty->TS_pad_char = tgetstr ("pc", address); |
| 3112 | tty->TS_repeat = tgetstr ("rp", address); | 3112 | tty->TS_repeat = tgetstr ("rp", address); |
| 3113 | tty->TS_end_standout_mode = tgetstr ("se", address); | 3113 | tty->TS_end_standout_mode = tgetstr ("se", address); |
| @@ -3229,7 +3229,7 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\ | |||
| 3229 | don't think we're losing anything by turning it off. */ | 3229 | don't think we're losing anything by turning it off. */ |
| 3230 | terminal->line_ins_del_ok = 0; | 3230 | terminal->line_ins_del_ok = 0; |
| 3231 | 3231 | ||
| 3232 | tty->TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */ | 3232 | tty->TN_max_colors = 16; /* Must be non-zero for tty-display-color-p. */ |
| 3233 | #endif /* DOS_NT */ | 3233 | #endif /* DOS_NT */ |
| 3234 | 3234 | ||
| 3235 | #ifdef HAVE_GPM | 3235 | #ifdef HAVE_GPM |
| @@ -3325,16 +3325,16 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\ | |||
| 3325 | tty->Wcm->cm_tab = 0; | 3325 | tty->Wcm->cm_tab = 0; |
| 3326 | /* We can't support standout mode, because it uses magic cookies. */ | 3326 | /* We can't support standout mode, because it uses magic cookies. */ |
| 3327 | tty->TS_standout_mode = 0; | 3327 | tty->TS_standout_mode = 0; |
| 3328 | /* But that means we cannot rely on ^M to go to column zero! */ | 3328 | /* But that means we cannot rely on ^M to go to column zero! */ |
| 3329 | CR (tty) = 0; | 3329 | CR (tty) = 0; |
| 3330 | /* LF can't be trusted either -- can alter hpos */ | 3330 | /* LF can't be trusted either -- can alter hpos. */ |
| 3331 | /* if move at column 0 thru a line with TS_standout_mode */ | 3331 | /* If move at column 0 thru a line with TS_standout_mode. */ |
| 3332 | Down (tty) = 0; | 3332 | Down (tty) = 0; |
| 3333 | } | 3333 | } |
| 3334 | 3334 | ||
| 3335 | tty->specified_window = FrameRows (tty); | 3335 | tty->specified_window = FrameRows (tty); |
| 3336 | 3336 | ||
| 3337 | if (Wcm_init (tty) == -1) /* can't do cursor motion */ | 3337 | if (Wcm_init (tty) == -1) /* Can't do cursor motion. */ |
| 3338 | { | 3338 | { |
| 3339 | maybe_fatal (must_succeed, terminal, | 3339 | maybe_fatal (must_succeed, terminal, |
| 3340 | "Terminal type \"%s\" is not powerful enough to run Emacs", | 3340 | "Terminal type \"%s\" is not powerful enough to run Emacs", |