diff options
| author | Mattias EngdegÄrd | 2019-05-17 11:25:06 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2019-05-27 13:25:27 +0200 |
| commit | 68b374a62d8b7b98fd0b144ae83077d698e20bdb (patch) | |
| tree | e67783a51e27c314b7ddbc734b865beba0c8913a | |
| parent | 457b02440510a594e3ff6f17cc6846a3a467a6a1 (diff) | |
| download | emacs-68b374a62d8b7b98fd0b144ae83077d698e20bdb.tar.gz emacs-68b374a62d8b7b98fd0b144ae83077d698e20bdb.zip | |
Correctly eliminate duplicate cases in switch compilation
Fix code mistakes that prevented the correct elimination of duplicated
cases when compiling a `cond' form to a switch bytecode, as in
(cond ((eq x 'a) 1)
((eq x 'b) 2)
((eq x 'a) 3) ; should be elided
((eq x 'c) 4))
Sometimes, this caused the bytecode to use the wrong branch (bug#35770).
* lisp/emacs-lisp/bytecomp.el (byte-compile-cond-vars): Return obj2 eval'ed.
(byte-compile-cond-jump-table-info):
Discard redundant condition. Use `obj2' as evaluated.
Discard duplicated cases instead of failing the table generation.
* test/lisp/emacs-lisp/bytecomp-tests.el (toplevel): Require subr-x.
(byte-opt-testsuite-arith-data, bytecomp-test--switch-duplicates): Test.
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 13 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/bytecomp-tests.el | 55 |
2 files changed, 60 insertions, 8 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index e76baf5ed0d..ce348ed3131 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -4091,8 +4091,8 @@ that suppresses all warnings during execution of BODY." | |||
| 4091 | ;; and the other is a constant expression whose value can be | 4091 | ;; and the other is a constant expression whose value can be |
| 4092 | ;; compared with `eq' (with `macroexp-const-p'). | 4092 | ;; compared with `eq' (with `macroexp-const-p'). |
| 4093 | (or | 4093 | (or |
| 4094 | (and (symbolp obj1) (macroexp-const-p obj2) (cons obj1 obj2)) | 4094 | (and (symbolp obj1) (macroexp-const-p obj2) (cons obj1 (eval obj2))) |
| 4095 | (and (symbolp obj2) (macroexp-const-p obj1) (cons obj2 obj1)))) | 4095 | (and (symbolp obj2) (macroexp-const-p obj1) (cons obj2 (eval obj1))))) |
| 4096 | 4096 | ||
| 4097 | (defconst byte-compile--default-val (cons nil nil) "A unique object.") | 4097 | (defconst byte-compile--default-val (cons nil nil) "A unique object.") |
| 4098 | 4098 | ||
| @@ -4121,12 +4121,11 @@ Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))" | |||
| 4121 | (unless prev-test | 4121 | (unless prev-test |
| 4122 | (setq prev-test test)) | 4122 | (setq prev-test test)) |
| 4123 | (if (and obj1 (memq test '(eq eql equal)) | 4123 | (if (and obj1 (memq test '(eq eql equal)) |
| 4124 | (consp condition) | ||
| 4125 | (eq test prev-test) | 4124 | (eq test prev-test) |
| 4126 | (eq obj1 prev-var) | 4125 | (eq obj1 prev-var)) |
| 4127 | ;; discard duplicate clauses | 4126 | ;; discard duplicate clauses |
| 4128 | (not (assq obj2 cases))) | 4127 | (unless (assoc obj2 cases test) |
| 4129 | (push (list (if (consp obj2) (eval obj2) obj2) body) cases) | 4128 | (push (list obj2 body) cases)) |
| 4130 | (if (and (macroexp-const-p condition) condition) | 4129 | (if (and (macroexp-const-p condition) condition) |
| 4131 | (progn (push (list byte-compile--default-val | 4130 | (progn (push (list byte-compile--default-val |
| 4132 | (or body `(,condition))) | 4131 | (or body `(,condition))) |
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el index 5fb64ff2881..ed100020def 100644 --- a/test/lisp/emacs-lisp/bytecomp-tests.el +++ b/test/lisp/emacs-lisp/bytecomp-tests.el | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | (require 'ert) | 28 | (require 'ert) |
| 29 | (require 'cl-lib) | 29 | (require 'cl-lib) |
| 30 | (require 'subr-x) | ||
| 30 | (require 'bytecomp) | 31 | (require 'bytecomp) |
| 31 | 32 | ||
| 32 | ;;; Code: | 33 | ;;; Code: |
| @@ -296,7 +297,21 @@ | |||
| 296 | ((eq variable 'default) | 297 | ((eq variable 'default) |
| 297 | (message "equal")) | 298 | (message "equal")) |
| 298 | (t | 299 | (t |
| 299 | (message "not equal"))))) | 300 | (message "not equal")))) |
| 301 | ;; Bug#35770 | ||
| 302 | (let ((x 'a)) (cond ((eq x 'a) 'correct) | ||
| 303 | ((eq x 'b) 'incorrect) | ||
| 304 | ((eq x 'a) 'incorrect) | ||
| 305 | ((eq x 'c) 'incorrect))) | ||
| 306 | (let ((x #x10000000000000000)) | ||
| 307 | (cond ((eql x #x10000000000000000) 'correct) | ||
| 308 | ((eql x #x10000000000000001) 'incorrect) | ||
| 309 | ((eql x #x10000000000000000) 'incorrect) | ||
| 310 | ((eql x #x10000000000000002) 'incorrect))) | ||
| 311 | (let ((x "a")) (cond ((equal x "a") 'correct) | ||
| 312 | ((equal x "b") 'incorrect) | ||
| 313 | ((equal x "a") 'incorrect) | ||
| 314 | ((equal x "c") 'incorrect)))) | ||
| 300 | "List of expression for test. | 315 | "List of expression for test. |
| 301 | Each element will be executed by interpreter and with | 316 | Each element will be executed by interpreter and with |
| 302 | bytecompiled code, and their results compared.") | 317 | bytecompiled code, and their results compared.") |
| @@ -613,6 +628,44 @@ literals (Bug#20852)." | |||
| 613 | (if (buffer-live-p byte-compile-log-buffer) | 628 | (if (buffer-live-p byte-compile-log-buffer) |
| 614 | (kill-buffer byte-compile-log-buffer))))) | 629 | (kill-buffer byte-compile-log-buffer))))) |
| 615 | 630 | ||
| 631 | (ert-deftest bytecomp-test--switch-duplicates () | ||
| 632 | "Check that duplicates in switches are eliminated correctly (bug#35770)." | ||
| 633 | (dolist (params | ||
| 634 | '(((lambda (x) | ||
| 635 | (cond ((eq x 'a) 111) | ||
| 636 | ((eq x 'b) 222) | ||
| 637 | ((eq x 'a) 333) | ||
| 638 | ((eq x 'c) 444))) | ||
| 639 | (a b c) | ||
| 640 | string<) | ||
| 641 | ((lambda (x) | ||
| 642 | (cond ((eql x #x10000000000000000) 111) | ||
| 643 | ((eql x #x10000000000000001) 222) | ||
| 644 | ((eql x #x10000000000000000) 333) | ||
| 645 | ((eql x #x10000000000000002) 444))) | ||
| 646 | (#x10000000000000000 #x10000000000000001 #x10000000000000002) | ||
| 647 | <) | ||
| 648 | ((lambda (x) | ||
| 649 | (cond ((equal x "a") 111) | ||
| 650 | ((equal x "b") 222) | ||
| 651 | ((equal x "a") 333) | ||
| 652 | ((equal x "c") 444))) | ||
| 653 | ("a" "b" "c") | ||
| 654 | string<))) | ||
| 655 | (let* ((lisp (nth 0 params)) | ||
| 656 | (keys (nth 1 params)) | ||
| 657 | (lessp (nth 2 params)) | ||
| 658 | (bc (byte-compile lisp)) | ||
| 659 | (lap (byte-decompile-bytecode (aref bc 1) (aref bc 2))) | ||
| 660 | ;; Assume the first constant is the switch table. | ||
| 661 | (table (cadr (assq 'byte-constant lap)))) | ||
| 662 | (should (hash-table-p table)) | ||
| 663 | (should (equal (sort (hash-table-keys table) lessp) keys)) | ||
| 664 | (should (member '(byte-constant 111) lap)) | ||
| 665 | (should (member '(byte-constant 222) lap)) | ||
| 666 | (should-not (member '(byte-constant 333) lap)) | ||
| 667 | (should (member '(byte-constant 444) lap))))) | ||
| 668 | |||
| 616 | ;; Local Variables: | 669 | ;; Local Variables: |
| 617 | ;; no-byte-compile: t | 670 | ;; no-byte-compile: t |
| 618 | ;; End: | 671 | ;; End: |