diff options
| author | Paul Eggert | 2020-01-07 11:23:11 -0800 |
|---|---|---|
| committer | Paul Eggert | 2020-01-07 11:29:42 -0800 |
| commit | 724af7671590cd91df37f64df6be73f6dca0144d (patch) | |
| tree | 075df63dcdc3653ff710ce49a5f238c165d0f0c1 /src | |
| parent | f950b078a6f2fd011312e9471998edf6b5fb957e (diff) | |
| download | emacs-724af7671590cd91df37f64df6be73f6dca0144d.tar.gz emacs-724af7671590cd91df37f64df6be73f6dca0144d.zip | |
Fix sxhash-equal on bytecodes, markers, etc.
Problem reported by Pip Cet (Bug#38912#14).
* doc/lispref/objects.texi (Equality Predicates):
Document better when ‘equal’ looks inside objects.
* doc/lispref/windows.texi (Window Configurations):
Don’t say that ‘equal’ looks inside window configurations.
* etc/NEWS: Mention the change.
* src/fns.c (internal_equal):
Do not look inside window configurations.
(sxhash_obj): Hash markers, byte-code function objects,
char-tables, and font objects consistently with Fequal.
* src/window.c (compare_window_configurations):
Now static. Remove last argument. Caller changed.
* test/lisp/ffap-tests.el (ffap-other-window--bug-25352):
Use compare-window-configurations, not ‘equal’.
* test/src/fns-tests.el (test-sxhash-equal): New test.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fns.c | 52 | ||||
| -rw-r--r-- | src/lisp.h | 4 | ||||
| -rw-r--r-- | src/window.c | 21 | ||||
| -rw-r--r-- | src/window.h | 1 |
4 files changed, 38 insertions, 40 deletions
| @@ -2434,6 +2434,9 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | |||
| 2434 | same size. */ | 2434 | same size. */ |
| 2435 | if (ASIZE (o2) != size) | 2435 | if (ASIZE (o2) != size) |
| 2436 | return false; | 2436 | return false; |
| 2437 | |||
| 2438 | /* Compare bignums, overlays, markers, and boolvectors | ||
| 2439 | specially, by comparing their values. */ | ||
| 2437 | if (BIGNUMP (o1)) | 2440 | if (BIGNUMP (o1)) |
| 2438 | return mpz_cmp (*xbignum_val (o1), *xbignum_val (o2)) == 0; | 2441 | return mpz_cmp (*xbignum_val (o1), *xbignum_val (o2)) == 0; |
| 2439 | if (OVERLAYP (o1)) | 2442 | if (OVERLAYP (o1)) |
| @@ -2454,7 +2457,6 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | |||
| 2454 | && (XMARKER (o1)->buffer == 0 | 2457 | && (XMARKER (o1)->buffer == 0 |
| 2455 | || XMARKER (o1)->bytepos == XMARKER (o2)->bytepos)); | 2458 | || XMARKER (o1)->bytepos == XMARKER (o2)->bytepos)); |
| 2456 | } | 2459 | } |
| 2457 | /* Boolvectors are compared much like strings. */ | ||
| 2458 | if (BOOL_VECTOR_P (o1)) | 2460 | if (BOOL_VECTOR_P (o1)) |
| 2459 | { | 2461 | { |
| 2460 | EMACS_INT size = bool_vector_size (o1); | 2462 | EMACS_INT size = bool_vector_size (o1); |
| @@ -2465,11 +2467,6 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, | |||
| 2465 | return false; | 2467 | return false; |
| 2466 | return true; | 2468 | return true; |
| 2467 | } | 2469 | } |
| 2468 | if (WINDOW_CONFIGURATIONP (o1)) | ||
| 2469 | { | ||
| 2470 | eassert (equal_kind != EQUAL_NO_QUIT); | ||
| 2471 | return compare_window_configurations (o1, o2, false); | ||
| 2472 | } | ||
| 2473 | 2470 | ||
| 2474 | /* Aside from them, only true vectors, char-tables, compiled | 2471 | /* Aside from them, only true vectors, char-tables, compiled |
| 2475 | functions, and fonts (font-spec, font-entity, font-object) | 2472 | functions, and fonts (font-spec, font-entity, font-object) |
| @@ -4703,22 +4700,35 @@ sxhash_obj (Lisp_Object obj, int depth) | |||
| 4703 | hash = sxhash_string (SSDATA (obj), SBYTES (obj)); | 4700 | hash = sxhash_string (SSDATA (obj), SBYTES (obj)); |
| 4704 | break; | 4701 | break; |
| 4705 | 4702 | ||
| 4706 | /* This can be everything from a vector to an overlay. */ | ||
| 4707 | case Lisp_Vectorlike: | 4703 | case Lisp_Vectorlike: |
| 4708 | if (BIGNUMP (obj)) | 4704 | { |
| 4709 | hash = sxhash_bignum (obj); | 4705 | enum pvec_type pvec_type = PSEUDOVECTOR_TYPE (XVECTOR (obj)); |
| 4710 | else if (VECTORP (obj) || RECORDP (obj)) | 4706 | if (! (PVEC_NORMAL_VECTOR < pvec_type && pvec_type < PVEC_COMPILED)) |
| 4711 | /* According to the CL HyperSpec, two arrays are equal only if | 4707 | { |
| 4712 | they are `eq', except for strings and bit-vectors. In | 4708 | /* According to the CL HyperSpec, two arrays are equal only if |
| 4713 | Emacs, this works differently. We have to compare element | 4709 | they are 'eq', except for strings and bit-vectors. In |
| 4714 | by element. Same for records. */ | 4710 | Emacs, this works differently. We have to compare element |
| 4715 | hash = sxhash_vector (obj, depth); | 4711 | by element. Same for pseudovectors that internal_equal |
| 4716 | else if (BOOL_VECTOR_P (obj)) | 4712 | examines the Lisp contents of. */ |
| 4717 | hash = sxhash_bool_vector (obj); | 4713 | hash = sxhash_vector (obj, depth); |
| 4718 | else | 4714 | break; |
| 4719 | /* Others are `equal' if they are `eq', so let's take their | 4715 | } |
| 4720 | address as hash. */ | 4716 | else if (pvec_type == PVEC_BIGNUM) |
| 4721 | hash = XHASH (obj); | 4717 | hash = sxhash_bignum (obj); |
| 4718 | else if (pvec_type == PVEC_MARKER) | ||
| 4719 | { | ||
| 4720 | ptrdiff_t bytepos | ||
| 4721 | = XMARKER (obj)->buffer ? XMARKER (obj)->bytepos : 0; | ||
| 4722 | hash = sxhash_combine ((intptr_t) XMARKER (obj)->buffer, bytepos); | ||
| 4723 | hash = SXHASH_REDUCE (hash); | ||
| 4724 | } | ||
| 4725 | else if (pvec_type == PVEC_BOOL_VECTOR) | ||
| 4726 | hash = sxhash_bool_vector (obj); | ||
| 4727 | else | ||
| 4728 | /* Others are 'equal' if they are 'eq', so take their | ||
| 4729 | address as hash. */ | ||
| 4730 | hash = XHASH (obj); | ||
| 4731 | } | ||
| 4722 | break; | 4732 | break; |
| 4723 | 4733 | ||
| 4724 | case Lisp_Cons: | 4734 | case Lisp_Cons: |
diff --git a/src/lisp.h b/src/lisp.h index 1a1ae0399be..3681b7b2a7c 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -1069,7 +1069,7 @@ DEFINE_GDB_SYMBOL_END (PSEUDOVECTOR_FLAG) | |||
| 1069 | with PVEC_TYPE_MASK to indicate the actual type. */ | 1069 | with PVEC_TYPE_MASK to indicate the actual type. */ |
| 1070 | enum pvec_type | 1070 | enum pvec_type |
| 1071 | { | 1071 | { |
| 1072 | PVEC_NORMAL_VECTOR, | 1072 | PVEC_NORMAL_VECTOR, /* Should be first, for sxhash_obj. */ |
| 1073 | PVEC_FREE, | 1073 | PVEC_FREE, |
| 1074 | PVEC_BIGNUM, | 1074 | PVEC_BIGNUM, |
| 1075 | PVEC_MARKER, | 1075 | PVEC_MARKER, |
| @@ -1094,7 +1094,7 @@ enum pvec_type | |||
| 1094 | PVEC_CONDVAR, | 1094 | PVEC_CONDVAR, |
| 1095 | PVEC_MODULE_FUNCTION, | 1095 | PVEC_MODULE_FUNCTION, |
| 1096 | 1096 | ||
| 1097 | /* These should be last, check internal_equal to see why. */ | 1097 | /* These should be last, for internal_equal and sxhash_obj. */ |
| 1098 | PVEC_COMPILED, | 1098 | PVEC_COMPILED, |
| 1099 | PVEC_CHAR_TABLE, | 1099 | PVEC_CHAR_TABLE, |
| 1100 | PVEC_SUB_CHAR_TABLE, | 1100 | PVEC_SUB_CHAR_TABLE, |
diff --git a/src/window.c b/src/window.c index ff17cd88f38..8cdad27b664 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -7976,19 +7976,17 @@ foreach_window_1 (struct window *w, bool (*fn) (struct window *, void *), | |||
| 7976 | /* Return true if window configurations CONFIGURATION1 and CONFIGURATION2 | 7976 | /* Return true if window configurations CONFIGURATION1 and CONFIGURATION2 |
| 7977 | describe the same state of affairs. This is used by Fequal. | 7977 | describe the same state of affairs. This is used by Fequal. |
| 7978 | 7978 | ||
| 7979 | IGNORE_POSITIONS means ignore non-matching scroll positions | 7979 | Ignore non-matching scroll positions and the like. |
| 7980 | and the like. | ||
| 7981 | 7980 | ||
| 7982 | This ignores a couple of things like the dedication status of | 7981 | This ignores a couple of things like the dedication status of |
| 7983 | window, combination_limit and the like. This might have to be | 7982 | window, combination_limit and the like. This might have to be |
| 7984 | fixed. */ | 7983 | fixed. */ |
| 7985 | 7984 | ||
| 7986 | bool | 7985 | static bool |
| 7987 | compare_window_configurations (Lisp_Object configuration1, | 7986 | compare_window_configurations (Lisp_Object configuration1, |
| 7988 | Lisp_Object configuration2, | 7987 | Lisp_Object configuration2) |
| 7989 | bool ignore_positions) | ||
| 7990 | { | 7988 | { |
| 7991 | register struct save_window_data *d1, *d2; | 7989 | struct save_window_data *d1, *d2; |
| 7992 | struct Lisp_Vector *sws1, *sws2; | 7990 | struct Lisp_Vector *sws1, *sws2; |
| 7993 | ptrdiff_t i; | 7991 | ptrdiff_t i; |
| 7994 | 7992 | ||
| @@ -8006,9 +8004,6 @@ compare_window_configurations (Lisp_Object configuration1, | |||
| 8006 | || d1->frame_menu_bar_lines != d2->frame_menu_bar_lines | 8004 | || d1->frame_menu_bar_lines != d2->frame_menu_bar_lines |
| 8007 | || !EQ (d1->selected_frame, d2->selected_frame) | 8005 | || !EQ (d1->selected_frame, d2->selected_frame) |
| 8008 | || !EQ (d1->f_current_buffer, d2->f_current_buffer) | 8006 | || !EQ (d1->f_current_buffer, d2->f_current_buffer) |
| 8009 | || (!ignore_positions | ||
| 8010 | && (!EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window) | ||
| 8011 | || !EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))) | ||
| 8012 | || !EQ (d1->focus_frame, d2->focus_frame) | 8007 | || !EQ (d1->focus_frame, d2->focus_frame) |
| 8013 | /* Verify that the two configurations have the same number of windows. */ | 8008 | /* Verify that the two configurations have the same number of windows. */ |
| 8014 | || sws1->header.size != sws2->header.size) | 8009 | || sws1->header.size != sws2->header.size) |
| @@ -8041,12 +8036,6 @@ compare_window_configurations (Lisp_Object configuration1, | |||
| 8041 | equality. */ | 8036 | equality. */ |
| 8042 | || !EQ (sw1->parent, sw2->parent) | 8037 | || !EQ (sw1->parent, sw2->parent) |
| 8043 | || !EQ (sw1->prev, sw2->prev) | 8038 | || !EQ (sw1->prev, sw2->prev) |
| 8044 | || (!ignore_positions | ||
| 8045 | && (!EQ (sw1->hscroll, sw2->hscroll) | ||
| 8046 | || !EQ (sw1->min_hscroll, sw2->min_hscroll) | ||
| 8047 | || !EQ (sw1->start_at_line_beg, sw2->start_at_line_beg) | ||
| 8048 | || NILP (Fequal (sw1->start, sw2->start)) | ||
| 8049 | || NILP (Fequal (sw1->pointm, sw2->pointm)))) | ||
| 8050 | || !EQ (sw1->left_margin_cols, sw2->left_margin_cols) | 8039 | || !EQ (sw1->left_margin_cols, sw2->left_margin_cols) |
| 8051 | || !EQ (sw1->right_margin_cols, sw2->right_margin_cols) | 8040 | || !EQ (sw1->right_margin_cols, sw2->right_margin_cols) |
| 8052 | || !EQ (sw1->left_fringe_width, sw2->left_fringe_width) | 8041 | || !EQ (sw1->left_fringe_width, sw2->left_fringe_width) |
| @@ -8071,7 +8060,7 @@ This function ignores details such as the values of point | |||
| 8071 | and scrolling positions. */) | 8060 | and scrolling positions. */) |
| 8072 | (Lisp_Object x, Lisp_Object y) | 8061 | (Lisp_Object x, Lisp_Object y) |
| 8073 | { | 8062 | { |
| 8074 | if (compare_window_configurations (x, y, true)) | 8063 | if (compare_window_configurations (x, y)) |
| 8075 | return Qt; | 8064 | return Qt; |
| 8076 | return Qnil; | 8065 | return Qnil; |
| 8077 | } | 8066 | } |
diff --git a/src/window.h b/src/window.h index aa8d2c8d1d2..167d1be7abb 100644 --- a/src/window.h +++ b/src/window.h | |||
| @@ -1184,7 +1184,6 @@ extern Lisp_Object window_list (void); | |||
| 1184 | extern Lisp_Object window_parameter (struct window *, Lisp_Object parameter); | 1184 | extern Lisp_Object window_parameter (struct window *, Lisp_Object parameter); |
| 1185 | extern struct window *decode_live_window (Lisp_Object); | 1185 | extern struct window *decode_live_window (Lisp_Object); |
| 1186 | extern struct window *decode_any_window (Lisp_Object); | 1186 | extern struct window *decode_any_window (Lisp_Object); |
| 1187 | extern bool compare_window_configurations (Lisp_Object, Lisp_Object, bool); | ||
| 1188 | extern void mark_window_cursors_off (struct window *); | 1187 | extern void mark_window_cursors_off (struct window *); |
| 1189 | extern bool window_wants_mode_line (struct window *); | 1188 | extern bool window_wants_mode_line (struct window *); |
| 1190 | extern bool window_wants_header_line (struct window *); | 1189 | extern bool window_wants_header_line (struct window *); |