diff options
| author | Stefan Monnier | 2018-03-23 11:29:06 -0400 |
|---|---|---|
| committer | Noam Postavsky | 2018-06-03 12:48:14 -0400 |
| commit | ed962f2b8a2f63c7dbf31ec5df3c915703dd571d (patch) | |
| tree | 880aa4dab830e5e7699e6eace5c0a1097a091baa /src | |
| parent | 3ba5fc2bbec3f0f64c7afc1b05c9016710805463 (diff) | |
| download | emacs-ed962f2b8a2f63c7dbf31ec5df3c915703dd571d.tar.gz emacs-ed962f2b8a2f63c7dbf31ec5df3c915703dd571d.zip | |
Fix bug#30846, along with misc cleanups found along the way
* test/src/data-tests.el (data-tests-kill-all-local-variables): New test.
* src/buffer.c (swap_out_buffer_local_variables): Remove.
Fuse the body of its loop into that of reset_buffer_local_variables.
(Fkill_buffer, Fkill_all_local_variables): Don't call it any more.
(reset_buffer_local_variables): Make sure the buffer's local binding
is swapped out before removing it from the alist (bug#30846).
Call watchers before actually killing the var.
* src/data.c (Fmake_local_variable): Simplify.
Use swap_in_global_binding to swap out any local binding, instead of
a mix of find_symbol_value followed by messing with where&found.
Don't call swap_in_symval_forwarding since the currently swapped
binding is never one we've modified.
(Fkill_local_variable): Use swap_in_global_binding rather than messing
with where&found to try and trick find_symbol_value into doing the same.
* src/alloc.c (mark_localized_symbol): 'where' can't be a frame any more.
(cherry picked from commit 3ddff080341580eb6fc18d907181e9cc2301f62d)
Diffstat (limited to 'src')
| -rw-r--r-- | src/alloc.c | 8 | ||||
| -rw-r--r-- | src/buffer.c | 55 | ||||
| -rw-r--r-- | src/data.c | 36 | ||||
| -rw-r--r-- | src/lisp.h | 19 |
4 files changed, 38 insertions, 80 deletions
diff --git a/src/alloc.c b/src/alloc.c index 09d61b7e5f3..7baaa512c20 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -6334,12 +6334,8 @@ mark_localized_symbol (struct Lisp_Symbol *ptr) | |||
| 6334 | { | 6334 | { |
| 6335 | struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (ptr); | 6335 | struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (ptr); |
| 6336 | Lisp_Object where = blv->where; | 6336 | Lisp_Object where = blv->where; |
| 6337 | /* If the value is set up for a killed buffer or deleted | 6337 | /* If the value is set up for a killed buffer restore its global binding. */ |
| 6338 | frame, restore its global binding. If the value is | 6338 | if ((BUFFERP (where) && !BUFFER_LIVE_P (XBUFFER (where)))) |
| 6339 | forwarded to a C variable, either it's not a Lisp_Object | ||
| 6340 | var, or it's staticpro'd already. */ | ||
| 6341 | if ((BUFFERP (where) && !BUFFER_LIVE_P (XBUFFER (where))) | ||
| 6342 | || (FRAMEP (where) && !FRAME_LIVE_P (XFRAME (where)))) | ||
| 6343 | swap_in_global_binding (ptr); | 6339 | swap_in_global_binding (ptr); |
| 6344 | mark_object (blv->where); | 6340 | mark_object (blv->where); |
| 6345 | mark_object (blv->valcell); | 6341 | mark_object (blv->valcell); |
diff --git a/src/buffer.c b/src/buffer.c index 9b54e4b7787..b0cee717036 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -108,7 +108,6 @@ int last_per_buffer_idx; | |||
| 108 | static void call_overlay_mod_hooks (Lisp_Object list, Lisp_Object overlay, | 108 | static void call_overlay_mod_hooks (Lisp_Object list, Lisp_Object overlay, |
| 109 | bool after, Lisp_Object arg1, | 109 | bool after, Lisp_Object arg1, |
| 110 | Lisp_Object arg2, Lisp_Object arg3); | 110 | Lisp_Object arg2, Lisp_Object arg3); |
| 111 | static void swap_out_buffer_local_variables (struct buffer *b); | ||
| 112 | static void reset_buffer_local_variables (struct buffer *, bool); | 111 | static void reset_buffer_local_variables (struct buffer *, bool); |
| 113 | 112 | ||
| 114 | /* Alist of all buffer names vs the buffers. This used to be | 113 | /* Alist of all buffer names vs the buffers. This used to be |
| @@ -991,10 +990,29 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too) | |||
| 991 | else | 990 | else |
| 992 | { | 991 | { |
| 993 | Lisp_Object tmp, last = Qnil; | 992 | Lisp_Object tmp, last = Qnil; |
| 993 | Lisp_Object buffer; | ||
| 994 | XSETBUFFER (buffer, b); | ||
| 995 | |||
| 994 | for (tmp = BVAR (b, local_var_alist); CONSP (tmp); tmp = XCDR (tmp)) | 996 | for (tmp = BVAR (b, local_var_alist); CONSP (tmp); tmp = XCDR (tmp)) |
| 995 | { | 997 | { |
| 996 | Lisp_Object local_var = XCAR (XCAR (tmp)); | 998 | Lisp_Object local_var = XCAR (XCAR (tmp)); |
| 997 | Lisp_Object prop = Fget (local_var, Qpermanent_local); | 999 | Lisp_Object prop = Fget (local_var, Qpermanent_local); |
| 1000 | Lisp_Object sym = local_var; | ||
| 1001 | |||
| 1002 | /* Watchers are run *before* modifying the var. */ | ||
| 1003 | if (XSYMBOL (local_var)->u.s.trapped_write == SYMBOL_TRAPPED_WRITE) | ||
| 1004 | notify_variable_watchers (local_var, Qnil, | ||
| 1005 | Qmakunbound, Fcurrent_buffer ()); | ||
| 1006 | |||
| 1007 | eassert (XSYMBOL (sym)->u.s.redirect == SYMBOL_LOCALIZED); | ||
| 1008 | /* Need not do anything if some other buffer's binding is | ||
| 1009 | now cached. */ | ||
| 1010 | if (EQ (SYMBOL_BLV (XSYMBOL (sym))->where, buffer)) | ||
| 1011 | { | ||
| 1012 | /* Symbol is set up for this buffer's old local value: | ||
| 1013 | swap it out! */ | ||
| 1014 | swap_in_global_binding (XSYMBOL (sym)); | ||
| 1015 | } | ||
| 998 | 1016 | ||
| 999 | if (!NILP (prop)) | 1017 | if (!NILP (prop)) |
| 1000 | { | 1018 | { |
| @@ -1034,10 +1052,6 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too) | |||
| 1034 | bset_local_var_alist (b, XCDR (tmp)); | 1052 | bset_local_var_alist (b, XCDR (tmp)); |
| 1035 | else | 1053 | else |
| 1036 | XSETCDR (last, XCDR (tmp)); | 1054 | XSETCDR (last, XCDR (tmp)); |
| 1037 | |||
| 1038 | if (XSYMBOL (local_var)->u.s.trapped_write == SYMBOL_TRAPPED_WRITE) | ||
| 1039 | notify_variable_watchers (local_var, Qnil, | ||
| 1040 | Qmakunbound, Fcurrent_buffer ()); | ||
| 1041 | } | 1055 | } |
| 1042 | } | 1056 | } |
| 1043 | 1057 | ||
| @@ -1867,7 +1881,6 @@ cleaning up all windows currently displaying the buffer to be killed. */) | |||
| 1867 | won't be protected from GC. They would be protected | 1881 | won't be protected from GC. They would be protected |
| 1868 | if they happened to remain cached in their symbols. | 1882 | if they happened to remain cached in their symbols. |
| 1869 | This gets rid of them for certain. */ | 1883 | This gets rid of them for certain. */ |
| 1870 | swap_out_buffer_local_variables (b); | ||
| 1871 | reset_buffer_local_variables (b, 1); | 1884 | reset_buffer_local_variables (b, 1); |
| 1872 | 1885 | ||
| 1873 | bset_name (b, Qnil); | 1886 | bset_name (b, Qnil); |
| @@ -2737,11 +2750,6 @@ the normal hook `change-major-mode-hook'. */) | |||
| 2737 | { | 2750 | { |
| 2738 | run_hook (Qchange_major_mode_hook); | 2751 | run_hook (Qchange_major_mode_hook); |
| 2739 | 2752 | ||
| 2740 | /* Make sure none of the bindings in local_var_alist | ||
| 2741 | remain swapped in, in their symbols. */ | ||
| 2742 | |||
| 2743 | swap_out_buffer_local_variables (current_buffer); | ||
| 2744 | |||
| 2745 | /* Actually eliminate all local bindings of this buffer. */ | 2753 | /* Actually eliminate all local bindings of this buffer. */ |
| 2746 | 2754 | ||
| 2747 | reset_buffer_local_variables (current_buffer, 0); | 2755 | reset_buffer_local_variables (current_buffer, 0); |
| @@ -2753,31 +2761,6 @@ the normal hook `change-major-mode-hook'. */) | |||
| 2753 | return Qnil; | 2761 | return Qnil; |
| 2754 | } | 2762 | } |
| 2755 | 2763 | ||
| 2756 | /* Make sure no local variables remain set up with buffer B | ||
| 2757 | for their current values. */ | ||
| 2758 | |||
| 2759 | static void | ||
| 2760 | swap_out_buffer_local_variables (struct buffer *b) | ||
| 2761 | { | ||
| 2762 | Lisp_Object oalist, alist, buffer; | ||
| 2763 | |||
| 2764 | XSETBUFFER (buffer, b); | ||
| 2765 | oalist = BVAR (b, local_var_alist); | ||
| 2766 | |||
| 2767 | for (alist = oalist; CONSP (alist); alist = XCDR (alist)) | ||
| 2768 | { | ||
| 2769 | Lisp_Object sym = XCAR (XCAR (alist)); | ||
| 2770 | eassert (XSYMBOL (sym)->u.s.redirect == SYMBOL_LOCALIZED); | ||
| 2771 | /* Need not do anything if some other buffer's binding is | ||
| 2772 | now cached. */ | ||
| 2773 | if (EQ (SYMBOL_BLV (XSYMBOL (sym))->where, buffer)) | ||
| 2774 | { | ||
| 2775 | /* Symbol is set up for this buffer's old local value: | ||
| 2776 | swap it out! */ | ||
| 2777 | swap_in_global_binding (XSYMBOL (sym)); | ||
| 2778 | } | ||
| 2779 | } | ||
| 2780 | } | ||
| 2781 | 2764 | ||
| 2782 | /* Find all the overlays in the current buffer that contain position POS. | 2765 | /* Find all the overlays in the current buffer that contain position POS. |
| 2783 | Return the number found, and store them in a vector in *VEC_PTR. | 2766 | Return the number found, and store them in a vector in *VEC_PTR. |
diff --git a/src/data.c b/src/data.c index 45b2bf73026..4bee194e296 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -1188,7 +1188,7 @@ swap_in_global_binding (struct Lisp_Symbol *symbol) | |||
| 1188 | 1188 | ||
| 1189 | /* Indicate that the global binding is set up now. */ | 1189 | /* Indicate that the global binding is set up now. */ |
| 1190 | set_blv_where (blv, Qnil); | 1190 | set_blv_where (blv, Qnil); |
| 1191 | set_blv_found (blv, 0); | 1191 | set_blv_found (blv, false); |
| 1192 | } | 1192 | } |
| 1193 | 1193 | ||
| 1194 | /* Set up the buffer-local symbol SYMBOL for validity in the current buffer. | 1194 | /* Set up the buffer-local symbol SYMBOL for validity in the current buffer. |
| @@ -1257,7 +1257,6 @@ find_symbol_value (Lisp_Object symbol) | |||
| 1257 | swap_in_symval_forwarding (sym, blv); | 1257 | swap_in_symval_forwarding (sym, blv); |
| 1258 | return blv->fwd ? do_symval_forwarding (blv->fwd) : blv_value (blv); | 1258 | return blv->fwd ? do_symval_forwarding (blv->fwd) : blv_value (blv); |
| 1259 | } | 1259 | } |
| 1260 | /* FALLTHROUGH */ | ||
| 1261 | case SYMBOL_FORWARDED: | 1260 | case SYMBOL_FORWARDED: |
| 1262 | return do_symval_forwarding (SYMBOL_FWD (sym)); | 1261 | return do_symval_forwarding (SYMBOL_FWD (sym)); |
| 1263 | default: emacs_abort (); | 1262 | default: emacs_abort (); |
| @@ -1366,7 +1365,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, | |||
| 1366 | tem1 = assq_no_quit (symbol, | 1365 | tem1 = assq_no_quit (symbol, |
| 1367 | BVAR (XBUFFER (where), local_var_alist)); | 1366 | BVAR (XBUFFER (where), local_var_alist)); |
| 1368 | set_blv_where (blv, where); | 1367 | set_blv_where (blv, where); |
| 1369 | blv->found = 1; | 1368 | blv->found = true; |
| 1370 | 1369 | ||
| 1371 | if (NILP (tem1)) | 1370 | if (NILP (tem1)) |
| 1372 | { | 1371 | { |
| @@ -1381,7 +1380,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, | |||
| 1381 | if (bindflag || !blv->local_if_set | 1380 | if (bindflag || !blv->local_if_set |
| 1382 | || let_shadows_buffer_binding_p (sym)) | 1381 | || let_shadows_buffer_binding_p (sym)) |
| 1383 | { | 1382 | { |
| 1384 | blv->found = 0; | 1383 | blv->found = false; |
| 1385 | tem1 = blv->defcell; | 1384 | tem1 = blv->defcell; |
| 1386 | } | 1385 | } |
| 1387 | /* If it's a local_if_set, being set not bound, | 1386 | /* If it's a local_if_set, being set not bound, |
| @@ -1796,7 +1795,7 @@ make_blv (struct Lisp_Symbol *sym, bool forwarded, | |||
| 1796 | blv->local_if_set = 0; | 1795 | blv->local_if_set = 0; |
| 1797 | set_blv_defcell (blv, tem); | 1796 | set_blv_defcell (blv, tem); |
| 1798 | set_blv_valcell (blv, tem); | 1797 | set_blv_valcell (blv, tem); |
| 1799 | set_blv_found (blv, 0); | 1798 | set_blv_found (blv, false); |
| 1800 | return blv; | 1799 | return blv; |
| 1801 | } | 1800 | } |
| 1802 | 1801 | ||
| @@ -1946,30 +1945,17 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) | |||
| 1946 | CALLN (Fmessage, format, SYMBOL_NAME (variable)); | 1945 | CALLN (Fmessage, format, SYMBOL_NAME (variable)); |
| 1947 | } | 1946 | } |
| 1948 | 1947 | ||
| 1949 | /* Swap out any local binding for some other buffer, and make | 1948 | if (BUFFERP (blv->where) && current_buffer == XBUFFER (blv->where)) |
| 1950 | sure the current value is permanently recorded, if it's the | 1949 | /* Make sure the current value is permanently recorded, if it's the |
| 1951 | default value. */ | 1950 | default value. */ |
| 1952 | find_symbol_value (variable); | 1951 | swap_in_global_binding (sym); |
| 1953 | 1952 | ||
| 1954 | bset_local_var_alist | 1953 | bset_local_var_alist |
| 1955 | (current_buffer, | 1954 | (current_buffer, |
| 1956 | Fcons (Fcons (variable, XCDR (blv->defcell)), | 1955 | Fcons (Fcons (variable, XCDR (blv->defcell)), |
| 1957 | BVAR (current_buffer, local_var_alist))); | 1956 | BVAR (current_buffer, local_var_alist))); |
| 1958 | |||
| 1959 | /* Make sure symbol does not think it is set up for this buffer; | ||
| 1960 | force it to look once again for this buffer's value. */ | ||
| 1961 | if (current_buffer == XBUFFER (blv->where)) | ||
| 1962 | set_blv_where (blv, Qnil); | ||
| 1963 | set_blv_found (blv, 0); | ||
| 1964 | } | 1957 | } |
| 1965 | 1958 | ||
| 1966 | /* If the symbol forwards into a C variable, then load the binding | ||
| 1967 | for this buffer now. If C code modifies the variable before we | ||
| 1968 | load the binding in, then that new value will clobber the default | ||
| 1969 | binding the next time we unload it. */ | ||
| 1970 | if (blv->fwd) | ||
| 1971 | swap_in_symval_forwarding (sym, blv); | ||
| 1972 | |||
| 1973 | return variable; | 1959 | return variable; |
| 1974 | } | 1960 | } |
| 1975 | 1961 | ||
| @@ -2031,11 +2017,7 @@ From now on the default value will apply in this buffer. Return VARIABLE. */) | |||
| 2031 | { | 2017 | { |
| 2032 | Lisp_Object buf; XSETBUFFER (buf, current_buffer); | 2018 | Lisp_Object buf; XSETBUFFER (buf, current_buffer); |
| 2033 | if (EQ (buf, blv->where)) | 2019 | if (EQ (buf, blv->where)) |
| 2034 | { | 2020 | swap_in_global_binding (sym); |
| 2035 | set_blv_where (blv, Qnil); | ||
| 2036 | blv->found = 0; | ||
| 2037 | find_symbol_value (variable); | ||
| 2038 | } | ||
| 2039 | } | 2021 | } |
| 2040 | 2022 | ||
| 2041 | return variable; | 2023 | return variable; |
diff --git a/src/lisp.h b/src/lisp.h index cd6d07288e0..56ad8b814b6 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2587,18 +2587,15 @@ struct Lisp_Buffer_Objfwd | |||
| 2587 | in the buffer structure itself. They are handled differently, | 2587 | in the buffer structure itself. They are handled differently, |
| 2588 | using struct Lisp_Buffer_Objfwd.) | 2588 | using struct Lisp_Buffer_Objfwd.) |
| 2589 | 2589 | ||
| 2590 | The `realvalue' slot holds the variable's current value, or a | 2590 | The `valcell' slot holds the variable's current value (unless `fwd' |
| 2591 | forwarding pointer to where that value is kept. This value is the | 2591 | is set). This value is the one that corresponds to the loaded binding. |
| 2592 | one that corresponds to the loaded binding. To read or set the | 2592 | To read or set the variable, you must first make sure the right binding |
| 2593 | variable, you must first make sure the right binding is loaded; | 2593 | is loaded; then you can access the value in (or through) `valcell'. |
| 2594 | then you can access the value in (or through) `realvalue'. | 2594 | |
| 2595 | 2595 | `where' is the buffer for which the loaded binding was found. | |
| 2596 | `where' is the buffer for which the loaded binding was found. If | 2596 | If it has changed, to make sure the right binding is loaded it is |
| 2597 | it has changed, to make sure the right binding is loaded it is | ||
| 2598 | necessary to find which binding goes with the current buffer, then | 2597 | necessary to find which binding goes with the current buffer, then |
| 2599 | load it. To load it, first unload the previous binding, then copy | 2598 | load it. To load it, first unload the previous binding. |
| 2600 | the value of the new binding into `realvalue' (or through it). | ||
| 2601 | Also update LOADED-BINDING to point to the newly loaded binding. | ||
| 2602 | 2599 | ||
| 2603 | `local_if_set' indicates that merely setting the variable creates a | 2600 | `local_if_set' indicates that merely setting the variable creates a |
| 2604 | local binding for the current buffer. Otherwise the latter, setting | 2601 | local binding for the current buffer. Otherwise the latter, setting |