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.
This commit is contained in:
Mattias Engdegård 2019-05-17 11:25:06 +02:00
parent 457b024405
commit 68b374a62d
2 changed files with 60 additions and 8 deletions

View file

@ -4091,8 +4091,8 @@ that suppresses all warnings during execution of BODY."
;; and the other is a constant expression whose value can be
;; compared with `eq' (with `macroexp-const-p').
(or
(and (symbolp obj1) (macroexp-const-p obj2) (cons obj1 obj2))
(and (symbolp obj2) (macroexp-const-p obj1) (cons obj2 obj1))))
(and (symbolp obj1) (macroexp-const-p obj2) (cons obj1 (eval obj2)))
(and (symbolp obj2) (macroexp-const-p obj1) (cons obj2 (eval obj1)))))
(defconst byte-compile--default-val (cons nil nil) "A unique object.")
@ -4121,12 +4121,11 @@ Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))"
(unless prev-test
(setq prev-test test))
(if (and obj1 (memq test '(eq eql equal))
(consp condition)
(eq test prev-test)
(eq obj1 prev-var)
;; discard duplicate clauses
(not (assq obj2 cases)))
(push (list (if (consp obj2) (eval obj2) obj2) body) cases)
(eq obj1 prev-var))
;; discard duplicate clauses
(unless (assoc obj2 cases test)
(push (list obj2 body) cases))
(if (and (macroexp-const-p condition) condition)
(progn (push (list byte-compile--default-val
(or body `(,condition)))