2021-09-26 01:53:56 +02:00
|
|
|
|
;;; bytecomp-tests.el --- Tests for bytecomp.el -*- lexical-binding:t -*-
|
2008-11-30 05:57:33 +00:00
|
|
|
|
|
2022-01-01 02:45:51 -05:00
|
|
|
|
;; Copyright (C) 2008-2022 Free Software Foundation, Inc.
|
2008-11-30 05:57:33 +00:00
|
|
|
|
|
2016-09-24 12:53:46 +03:00
|
|
|
|
;; Author: Shigeru Fukaya <shigeru.fukaya@gmail.com>
|
|
|
|
|
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
|
2008-11-30 05:57:33 +00:00
|
|
|
|
;; Created: November 2008
|
|
|
|
|
;; Keywords: internal
|
|
|
|
|
;; Human-Keywords: internal
|
|
|
|
|
|
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
|
|
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
;; (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
2017-09-13 15:52:52 -07:00
|
|
|
|
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
2008-11-30 05:57:33 +00:00
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
2011-02-14 16:21:42 -05:00
|
|
|
|
(require 'ert)
|
2020-11-30 22:42:08 +01:00
|
|
|
|
(require 'ert-x)
|
2017-02-15 21:03:05 +05:30
|
|
|
|
(require 'cl-lib)
|
2019-05-17 11:25:06 +02:00
|
|
|
|
(require 'subr-x)
|
2018-03-26 21:56:33 -04:00
|
|
|
|
(require 'bytecomp)
|
2011-02-14 16:21:42 -05:00
|
|
|
|
|
2008-11-30 05:57:33 +00:00
|
|
|
|
;;; Code:
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(defvar bytecomp-test-var nil)
|
|
|
|
|
|
|
|
|
|
(defun bytecomp-test-get-var ()
|
|
|
|
|
bytecomp-test-var)
|
|
|
|
|
|
|
|
|
|
(defun bytecomp-test-identity (x)
|
2022-07-13 13:00:31 +02:00
|
|
|
|
"Identity, but hidden from some optimizations."
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
x)
|
|
|
|
|
|
2021-09-22 11:03:30 +02:00
|
|
|
|
(defmacro bytecomp-test-loop (outer1 outer2 inner1 inner2)
|
|
|
|
|
"Exercise constant propagation inside `while' loops.
|
|
|
|
|
OUTER1, OUTER2, INNER1 and INNER2 are forms placed in the outer and
|
|
|
|
|
inner loops respectively."
|
|
|
|
|
`(let ((x 1) (i 3) (res nil))
|
|
|
|
|
(while (> i 0)
|
|
|
|
|
(let ((y 2) (j 2))
|
|
|
|
|
(setq res (cons (list 'outer x y) res))
|
|
|
|
|
(while (> j 0)
|
|
|
|
|
(setq res (cons (list 'inner x y) res))
|
|
|
|
|
,inner1
|
|
|
|
|
,inner2
|
|
|
|
|
(setq j (1- j)))
|
|
|
|
|
,outer1
|
|
|
|
|
,outer2)
|
|
|
|
|
(setq i (1- i)))
|
|
|
|
|
res))
|
|
|
|
|
|
2022-09-22 14:15:56 +02:00
|
|
|
|
(defvar bytecomp-tests--xx nil)
|
|
|
|
|
|
2021-04-09 18:42:12 +02:00
|
|
|
|
(defconst bytecomp-tests--test-cases
|
2008-11-30 05:57:33 +00:00
|
|
|
|
'(
|
|
|
|
|
;; some functional tests
|
|
|
|
|
(let ((a most-positive-fixnum) (b 1) (c 1.0)) (+ a b c))
|
|
|
|
|
(let ((a most-positive-fixnum) (b -2) (c 1.0)) (- a b c))
|
|
|
|
|
(let ((a most-positive-fixnum) (b 2) (c 1.0)) (* a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b c))
|
|
|
|
|
(let ((a (+ 1 (expt 2 -64))) (b (expt 2 -65))) (+ a -1 b))
|
|
|
|
|
(let ((a (+ 1 (expt 2 -64))) (b (expt 2 -65))) (- a 1 (- b)))
|
2018-03-23 12:57:39 -07:00
|
|
|
|
(let ((a (expt 2 -1074)) (b 0.125)) (* a 8 b))
|
2008-11-30 05:57:33 +00:00
|
|
|
|
(let ((a 1.0)) (* a 0))
|
|
|
|
|
(let ((a 1.0)) (* a 2.0 0))
|
|
|
|
|
(let ((a 1.0)) (/ 0 a))
|
|
|
|
|
(let ((a 1.0)) (/ 3 a 2))
|
|
|
|
|
(let ((a most-positive-fixnum) (b 2.0)) (* a 2 b))
|
|
|
|
|
(let ((a 3) (b 2)) (/ a b 1.0))
|
2020-08-03 15:29:41 +02:00
|
|
|
|
(let ((a -0.0)) (+ a))
|
|
|
|
|
(let ((a -0.0)) (- a))
|
|
|
|
|
(let ((a -0.0)) (* a))
|
|
|
|
|
(let ((a -0.0)) (min a))
|
|
|
|
|
(let ((a -0.0)) (max a))
|
2008-11-30 05:57:33 +00:00
|
|
|
|
(/ 3 -1)
|
|
|
|
|
(+ 4 3 2 1)
|
|
|
|
|
(+ 4 3 2.0 1)
|
|
|
|
|
(- 4 3 2 1) ; not new, for reference
|
|
|
|
|
(- 4 3 2.0 1) ; not new, for reference
|
|
|
|
|
(* 4 3 2 1)
|
|
|
|
|
(* 4 3 2.0 1)
|
|
|
|
|
(/ 4 3 2 1)
|
|
|
|
|
(/ 4 3 2.0 1)
|
|
|
|
|
(let ((a 3) (b 2)) (+ a b 1))
|
|
|
|
|
(let ((a 3) (b 2)) (+ a b -1))
|
|
|
|
|
(let ((a 3) (b 2)) (- a b 1))
|
|
|
|
|
(let ((a 3) (b 2)) (- a b -1))
|
|
|
|
|
(let ((a 3) (b 2)) (+ a b a 1))
|
|
|
|
|
(let ((a 3) (b 2)) (+ a b a -1))
|
|
|
|
|
(let ((a 3) (b 2)) (- a b a 1))
|
|
|
|
|
(let ((a 3) (b 2)) (- a b a -1))
|
|
|
|
|
(let ((a 3) (b 2)) (* a b -1))
|
|
|
|
|
(let ((a 3) (b 2)) (* a -1))
|
|
|
|
|
(let ((a 3) (b 2)) (/ a b 1))
|
|
|
|
|
(let ((a 3) (b 2)) (/ (+ a b) 1))
|
|
|
|
|
|
|
|
|
|
;; coverage test
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 2 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 2 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 2.0 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 2.0 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0.0 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0.0 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0.0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ c 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0.0 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a b 0 c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0 a b))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 0 a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 1 2 3))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 3.0 2.0 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 3.0 2.0 1 4))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 1 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ -1 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ c 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ c -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 1 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ -1 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a b 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a b 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a b -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a b 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ 1 a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a b c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a b c 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (+ a b c -1))
|
|
|
|
|
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (-))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 2 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 2 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 2.0 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 2.0 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0.0 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0.0 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0.0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- c 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0.0 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a b 0 c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0 a b))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 0 a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 1 2 3))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 3.0 2.0 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 3.0 2.0 1 4))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 1 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- -1 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- c 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- c -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 1 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- -1 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a b 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a b 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a b -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a b 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- 1 a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a b c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a b c 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (- a b c -1))
|
|
|
|
|
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (*))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 2 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 2 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 2.0 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 2.0 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0.0 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0.0 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0.0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* c 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0.0 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a b 0 c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0 a b))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 0 a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 1 2 3))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 3.0 2.0 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 3.0 2.0 1 4))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 1 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* -1 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* c 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* c -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 1 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* -1 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a b 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a b 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a b -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a b 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* 1 a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a b c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a b c 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (* a b c -1))
|
|
|
|
|
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 2 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 2 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 2.0 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 2.0 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0.0 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0.0 2.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0.0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ c 0.0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0.0 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b 0 c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0 a b))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 0 a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 1 2 3))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 3.0 2.0 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 3.0 2.0 1 4))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 1 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ -1 a))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ c 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ c -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 1 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ -1 c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b 1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b -1))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b 2))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ 1 a b c))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b c 0))
|
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b c 1))
|
2017-02-15 21:03:05 +05:30
|
|
|
|
(let ((a 3) (b 2) (c 1.0)) (/ a b c -1))
|
2018-03-23 12:57:39 -07:00
|
|
|
|
|
|
|
|
|
(let ((a t)) (logand 0 a))
|
|
|
|
|
|
2017-02-15 21:03:05 +05:30
|
|
|
|
;; Test switch bytecode
|
2017-02-07 19:35:20 +05:30
|
|
|
|
(let ((a 3)) (cond ((eq a 1) 'one) ((eq a 2) 'two) ((eq a 3) 'three) (t t)))
|
|
|
|
|
(let ((a 'three)) (cond ((eq a 'one) 1) ((eq a 2) 'two) ((eq a 'three) 3)
|
|
|
|
|
(t t)))
|
|
|
|
|
(let ((a 2)) (cond ((eq a 'one) 1) ((eq a 1) 'one) ((eq a 2) 'two)
|
2017-02-13 13:18:54 +05:30
|
|
|
|
(t nil)))
|
|
|
|
|
(let ((a 2.0)) (cond ((eql a 2) 'incorrect) ((eql a 2.00) 'correct)))
|
|
|
|
|
(let ((a "foobar")) (cond ((equal "notfoobar" a) 'incorrect)
|
|
|
|
|
((equal 1 a) 'incorrect)
|
|
|
|
|
((equal a "foobar") 'correct)
|
2017-02-15 21:03:05 +05:30
|
|
|
|
(t 'incorrect)))
|
|
|
|
|
(let ((a "foobar") (l t)) (pcase a
|
|
|
|
|
("bar" 'incorrect)
|
|
|
|
|
("foobar" (while l
|
|
|
|
|
a (setq l nil))
|
|
|
|
|
'correct)))
|
|
|
|
|
(let ((a 'foobar) (l t)) (cl-case a
|
|
|
|
|
('foo 'incorrect)
|
|
|
|
|
('bar 'incorrect)
|
|
|
|
|
('foobar (while l
|
|
|
|
|
a (setq l nil))
|
|
|
|
|
'correct)))
|
|
|
|
|
(let ((a 'foobar) (l t)) (cond
|
|
|
|
|
((eq a 'bar) 'incorrect)
|
|
|
|
|
((eq a 'foo) 'incorrect)
|
|
|
|
|
((eq a 'bar) 'incorrect)
|
|
|
|
|
(t (while l
|
|
|
|
|
a (setq l nil))
|
|
|
|
|
'correct)))
|
|
|
|
|
(let ((a 'foobar) (l t)) (cond
|
|
|
|
|
((eq a 'bar) 'incorrect)
|
|
|
|
|
((eq a 'foo) 'incorrect)
|
|
|
|
|
((eq a 'foobar)
|
|
|
|
|
(while l
|
|
|
|
|
a (setq l nil))
|
|
|
|
|
'correct)
|
2017-04-22 21:51:43 +05:30
|
|
|
|
(t 'incorrect)))
|
|
|
|
|
(let ((a))
|
|
|
|
|
(cond ((eq a 'foo) 'incorrect)
|
|
|
|
|
(t)))
|
|
|
|
|
(let ((a))
|
|
|
|
|
(cond ((eq a 'foo) 'incorrect)
|
2018-06-16 07:44:58 -07:00
|
|
|
|
('correct)))
|
|
|
|
|
;; Bug#31734
|
|
|
|
|
(let ((variable 0))
|
|
|
|
|
(cond
|
|
|
|
|
((eq variable 'default)
|
|
|
|
|
(message "equal"))
|
|
|
|
|
(t
|
2019-05-17 11:25:06 +02:00
|
|
|
|
(message "not equal"))))
|
|
|
|
|
;; Bug#35770
|
|
|
|
|
(let ((x 'a)) (cond ((eq x 'a) 'correct)
|
|
|
|
|
((eq x 'b) 'incorrect)
|
|
|
|
|
((eq x 'a) 'incorrect)
|
|
|
|
|
((eq x 'c) 'incorrect)))
|
|
|
|
|
(let ((x #x10000000000000000))
|
|
|
|
|
(cond ((eql x #x10000000000000000) 'correct)
|
|
|
|
|
((eql x #x10000000000000001) 'incorrect)
|
|
|
|
|
((eql x #x10000000000000000) 'incorrect)
|
|
|
|
|
((eql x #x10000000000000002) 'incorrect)))
|
|
|
|
|
(let ((x "a")) (cond ((equal x "a") 'correct)
|
|
|
|
|
((equal x "b") 'incorrect)
|
|
|
|
|
((equal x "a") 'incorrect)
|
2019-05-22 12:36:03 +02:00
|
|
|
|
((equal x "c") 'incorrect)))
|
|
|
|
|
;; Multi-value clauses
|
|
|
|
|
(mapcar (lambda (x) (cond ((eq x 'a) 11)
|
|
|
|
|
((memq x '(b a c d)) 22)
|
|
|
|
|
((eq x 'c) 33)
|
|
|
|
|
((eq x 'e) 44)
|
|
|
|
|
((memq x '(d f g)) 55)
|
|
|
|
|
(t 99)))
|
|
|
|
|
'(a b c d e f g h))
|
|
|
|
|
(mapcar (lambda (x) (cond ((eql x 1) 11)
|
|
|
|
|
((memq x '(a b c)) 22)
|
|
|
|
|
((memql x '(2 1 4 1e-3)) 33)
|
|
|
|
|
((eq x 'd) 44)
|
|
|
|
|
((eql x #x10000000000000000))))
|
|
|
|
|
'(1 2 4 1e-3 a b c d 1.0 #x10000000000000000))
|
|
|
|
|
(mapcar (lambda (x) (cond ((eq x 'a) 11)
|
|
|
|
|
((memq x '(b d)) 22)
|
|
|
|
|
((equal x '(a . b)) 33)
|
|
|
|
|
((member x '(b c 1.5 2.5 "X" (d))) 44)
|
|
|
|
|
((eql x 3.14) 55)
|
|
|
|
|
((memql x '(9 0.5 1.5 q)) 66)
|
|
|
|
|
(t 99)))
|
|
|
|
|
'(a b c d (d) (a . b) "X" 0.5 1.5 3.14 9 9.0))
|
2019-06-07 17:04:10 +02:00
|
|
|
|
;; Multi-switch cond form
|
|
|
|
|
(mapcar (lambda (p) (let ((x (car p)) (y (cadr p)))
|
|
|
|
|
(cond ((consp x) 11)
|
|
|
|
|
((eq x 'a) 22)
|
|
|
|
|
((memql x '(b 7 a -3)) 33)
|
|
|
|
|
((equal y "a") 44)
|
|
|
|
|
((memq y '(c d e)) 55)
|
|
|
|
|
((booleanp x) 66)
|
|
|
|
|
((eq x 'q) 77)
|
|
|
|
|
((memq x '(r s)) 88)
|
|
|
|
|
((eq x 't) 99)
|
|
|
|
|
(t 999))))
|
|
|
|
|
'((a c) (b c) (7 c) (-3 c) (nil nil) (t c) (q c) (r c) (s c)
|
2020-02-21 12:16:20 +01:00
|
|
|
|
(t c) (x "a") (x "c") (x c) (x d) (x e)))
|
|
|
|
|
|
2021-04-07 13:11:43 +02:00
|
|
|
|
(mapcar (lambda (x) (ignore-errors (cond ((member '(a . b) x) 1)
|
|
|
|
|
((equal x '(c)) 2))))
|
2020-08-19 14:59:29 +02:00
|
|
|
|
'(((a . b)) a b (c) (d)))
|
2021-04-07 13:11:43 +02:00
|
|
|
|
(mapcar (lambda (x) (ignore-errors (cond ((memq '(a . b) x) 1)
|
|
|
|
|
((equal x '(c)) 2))))
|
2020-08-19 14:59:29 +02:00
|
|
|
|
'(((a . b)) a b (c) (d)))
|
2021-04-07 13:11:43 +02:00
|
|
|
|
(mapcar (lambda (x) (ignore-errors (cond ((member '(a b) x) 1)
|
|
|
|
|
((equal x '(c)) 2))))
|
2020-08-19 14:59:29 +02:00
|
|
|
|
'(((a b)) a b (c) (d)))
|
2021-04-07 13:11:43 +02:00
|
|
|
|
(mapcar (lambda (x) (ignore-errors (cond ((memq '(a b) x) 1)
|
|
|
|
|
((equal x '(c)) 2))))
|
2020-10-31 14:16:25 +01:00
|
|
|
|
'(((a b)) a b (c) (d)))
|
|
|
|
|
|
|
|
|
|
(assoc 'b '((a 1) (b 2) (c 3)))
|
|
|
|
|
(assoc "b" '(("a" 1) ("b" 2) ("c" 3)))
|
|
|
|
|
(let ((x '((a 1) (b 2) (c 3)))) (assoc 'c x))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(assoc 'a '((a 1) (b 2) (c 3)) (lambda (u v) (not (equal u v))))
|
|
|
|
|
|
|
|
|
|
;; Constprop test cases
|
|
|
|
|
(let ((a 'alpha) (b (concat "be" "ta")) (c nil) (d t) (e :gamma)
|
|
|
|
|
(f '(delta epsilon)))
|
|
|
|
|
(list a b c d e f))
|
|
|
|
|
|
|
|
|
|
(let ((x 1) (y (+ 3 4)))
|
|
|
|
|
(list
|
|
|
|
|
(let (q (y x) (z y))
|
|
|
|
|
(if q x (list x y z)))))
|
|
|
|
|
|
|
|
|
|
(let* ((x 3) (y (* x 2)) (x (1+ y)))
|
|
|
|
|
x)
|
|
|
|
|
|
|
|
|
|
(let ((x 1) (bytecomp-test-var 2) (y 3))
|
2021-04-07 13:11:43 +02:00
|
|
|
|
(list x bytecomp-test-var (bytecomp-test-get-var) y))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
|
|
|
|
|
(progn
|
|
|
|
|
(defvar d)
|
|
|
|
|
(let ((x 'a) (y 'b)) (list x y)))
|
|
|
|
|
|
|
|
|
|
(let ((x 2))
|
|
|
|
|
(list x (setq x 13) (setq x (* x 2)) x))
|
|
|
|
|
|
|
|
|
|
(let ((x 'a) (y 'b))
|
|
|
|
|
(setq y x
|
|
|
|
|
x (cons 'c y)
|
|
|
|
|
y x)
|
|
|
|
|
(list x y))
|
|
|
|
|
|
|
|
|
|
(let ((x 3))
|
|
|
|
|
(let ((y x) z)
|
|
|
|
|
(setq x 5)
|
|
|
|
|
(setq y (+ y 8))
|
|
|
|
|
(setq z (if (bytecomp-test-identity t)
|
|
|
|
|
(progn
|
|
|
|
|
(setq x (+ x 1))
|
|
|
|
|
(list x y))
|
|
|
|
|
(setq x (+ x 2))
|
|
|
|
|
(list x y)))
|
|
|
|
|
(list x y z)))
|
|
|
|
|
|
|
|
|
|
(let ((i 1) (s 0) (x 13))
|
|
|
|
|
(while (< i 5)
|
|
|
|
|
(setq s (+ s i))
|
|
|
|
|
(setq i (1+ i)))
|
|
|
|
|
(list s x i))
|
|
|
|
|
|
|
|
|
|
(let ((x 2))
|
2021-04-09 18:42:12 +02:00
|
|
|
|
(list (or (bytecomp-test-identity 'a) (setq x 3)) x))
|
2021-04-09 18:59:09 +02:00
|
|
|
|
|
2021-08-05 11:50:25 +02:00
|
|
|
|
(mapcar (lambda (b)
|
|
|
|
|
(let ((a nil))
|
|
|
|
|
(+ 0
|
|
|
|
|
(progn
|
|
|
|
|
(setq a b)
|
|
|
|
|
(setq b 1)
|
|
|
|
|
a))))
|
|
|
|
|
'(10))
|
|
|
|
|
|
2021-04-09 18:59:09 +02:00
|
|
|
|
(let* ((x 1)
|
|
|
|
|
(y (condition-case x
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(arith-error x))))
|
|
|
|
|
(list x y))
|
2021-04-11 12:38:37 +02:00
|
|
|
|
|
|
|
|
|
(funcall
|
|
|
|
|
(condition-case x
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(arith-error (prog1 (lambda (y) (+ y x))
|
|
|
|
|
(setq x 10))))
|
|
|
|
|
4)
|
2021-04-07 11:31:07 +02:00
|
|
|
|
|
2021-09-22 11:03:30 +02:00
|
|
|
|
;; Loop constprop: set the inner and outer variables in the inner
|
|
|
|
|
;; and outer loops, all combinations.
|
|
|
|
|
(bytecomp-test-loop nil nil nil nil )
|
|
|
|
|
(bytecomp-test-loop nil nil nil (setq x 6))
|
|
|
|
|
(bytecomp-test-loop nil nil (setq x 5) nil )
|
|
|
|
|
(bytecomp-test-loop nil nil (setq x 5) (setq x 6))
|
|
|
|
|
(bytecomp-test-loop nil (setq x 4) nil nil )
|
|
|
|
|
(bytecomp-test-loop nil (setq x 4) nil (setq x 6))
|
|
|
|
|
(bytecomp-test-loop nil (setq x 4) (setq x 5) nil )
|
|
|
|
|
(bytecomp-test-loop nil (setq x 4) (setq x 5) (setq x 6))
|
|
|
|
|
(bytecomp-test-loop (setq x 3) nil nil nil )
|
|
|
|
|
(bytecomp-test-loop (setq x 3) nil nil (setq x 6))
|
|
|
|
|
(bytecomp-test-loop (setq x 3) nil (setq x 5) nil )
|
|
|
|
|
(bytecomp-test-loop (setq x 3) nil (setq x 5) (setq x 6))
|
|
|
|
|
(bytecomp-test-loop (setq x 3) (setq x 4) nil nil )
|
|
|
|
|
(bytecomp-test-loop (setq x 3) (setq x 4) nil (setq x 6))
|
|
|
|
|
(bytecomp-test-loop (setq x 3) (setq x 4) (setq x 5) nil )
|
|
|
|
|
(bytecomp-test-loop (setq x 3) (setq x 4) (setq x 5) (setq x 6))
|
|
|
|
|
|
2021-04-07 11:31:07 +02:00
|
|
|
|
;; No error, no success handler.
|
|
|
|
|
(condition-case x
|
|
|
|
|
(list 42)
|
|
|
|
|
(error (cons 'bad x)))
|
|
|
|
|
;; Error, no success handler.
|
|
|
|
|
(condition-case x
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(error (cons 'bad x)))
|
|
|
|
|
;; No error, success handler.
|
|
|
|
|
(condition-case x
|
|
|
|
|
(list 42)
|
|
|
|
|
(error (cons 'bad x))
|
|
|
|
|
(:success (cons 'good x)))
|
|
|
|
|
;; Error, success handler.
|
|
|
|
|
(condition-case x
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(error (cons 'bad x))
|
|
|
|
|
(:success (cons 'good x)))
|
|
|
|
|
;; Verify that the success code is not subject to the error handlers.
|
|
|
|
|
(condition-case x
|
|
|
|
|
(list 42)
|
|
|
|
|
(error (cons 'bad x))
|
|
|
|
|
(:success (/ (car x) 0)))
|
|
|
|
|
;; Check variable scoping on success.
|
|
|
|
|
(let ((x 2))
|
|
|
|
|
(condition-case x
|
|
|
|
|
(list x)
|
|
|
|
|
(error (list 'bad x))
|
|
|
|
|
(:success (list 'good x))))
|
|
|
|
|
;; Check variable scoping on failure.
|
|
|
|
|
(let ((x 2))
|
|
|
|
|
(condition-case x
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(error (list 'bad x))
|
|
|
|
|
(:success (list 'good x))))
|
|
|
|
|
;; Check capture of mutated result variable.
|
|
|
|
|
(funcall
|
|
|
|
|
(condition-case x
|
|
|
|
|
3
|
|
|
|
|
(:success (prog1 (lambda (y) (+ y x))
|
|
|
|
|
(setq x 10))))
|
|
|
|
|
4)
|
|
|
|
|
;; Check for-effect context, on error.
|
|
|
|
|
(let ((f (lambda (x)
|
|
|
|
|
(condition-case nil
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(error 'bad)
|
|
|
|
|
(:success 'good))
|
|
|
|
|
(1+ x))))
|
|
|
|
|
(funcall f 3))
|
|
|
|
|
;; Check for-effect context, on success.
|
|
|
|
|
(let ((f (lambda (x)
|
|
|
|
|
(condition-case nil
|
|
|
|
|
nil
|
|
|
|
|
(error 'bad)
|
|
|
|
|
(:success 'good))
|
|
|
|
|
(1+ x))))
|
|
|
|
|
(funcall f 3))
|
2021-07-27 17:26:26 +02:00
|
|
|
|
|
|
|
|
|
;; Check `not' in cond switch (bug#49746).
|
|
|
|
|
(mapcar (lambda (x) (cond ((equal x "a") 1)
|
|
|
|
|
((member x '("b" "c")) 2)
|
|
|
|
|
((not x) 3)))
|
|
|
|
|
'("a" "b" "c" "d" nil))
|
2021-07-29 15:35:55 +02:00
|
|
|
|
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; `let' and `let*' optimizations with body being constant or variable
|
2021-07-29 15:35:55 +02:00
|
|
|
|
(let* (a
|
|
|
|
|
(b (progn (setq a (cons 1 a)) 2))
|
|
|
|
|
(c (1+ b))
|
|
|
|
|
(d (list a c)))
|
|
|
|
|
d)
|
|
|
|
|
(let ((a nil))
|
|
|
|
|
(let ((b (progn (setq a (cons 1 a)) 2))
|
|
|
|
|
(c (progn (setq a (cons 3 a))))
|
|
|
|
|
(d (list a)))
|
|
|
|
|
d))
|
|
|
|
|
(let* ((_a 1)
|
|
|
|
|
(_b 2))
|
|
|
|
|
'z)
|
|
|
|
|
(let ((_a 1)
|
|
|
|
|
(_b 2))
|
|
|
|
|
'z)
|
2021-09-25 12:15:21 +02:00
|
|
|
|
(let (x y)
|
|
|
|
|
y)
|
|
|
|
|
(let* (x y)
|
|
|
|
|
y)
|
|
|
|
|
(let (x y)
|
|
|
|
|
'a)
|
|
|
|
|
(let* (x y)
|
|
|
|
|
'a)
|
2021-07-28 21:07:58 +02:00
|
|
|
|
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; Check empty-list optimizations.
|
2021-07-28 21:07:58 +02:00
|
|
|
|
(mapcar (lambda (x) (member x nil)) '("a" 2 nil))
|
|
|
|
|
(mapcar (lambda (x) (memql x nil)) '(a 2 nil))
|
|
|
|
|
(mapcar (lambda (x) (memq x nil)) '(a nil))
|
|
|
|
|
(let ((n 0))
|
|
|
|
|
(list (mapcar (lambda (x) (member (setq n (1+ n)) nil)) '(a "nil"))
|
|
|
|
|
n))
|
|
|
|
|
(mapcar (lambda (x) (assoc x nil)) '("a" nil))
|
|
|
|
|
(mapcar (lambda (x) (assq x nil)) '(a nil))
|
|
|
|
|
(mapcar (lambda (x) (rassoc x nil)) '("a" nil))
|
|
|
|
|
(mapcar (lambda (x) (rassq x nil)) '(a nil))
|
|
|
|
|
(let ((n 0))
|
|
|
|
|
(list (mapcar (lambda (x) (assoc (setq n (1+ n)) nil)) '(a "nil"))
|
|
|
|
|
n))
|
2021-07-30 13:44:07 +02:00
|
|
|
|
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; Exercise variable-aliasing optimizations.
|
2021-07-30 13:44:07 +02:00
|
|
|
|
(let ((a (list 1)))
|
|
|
|
|
(let ((b a))
|
|
|
|
|
(let ((a (list 2)))
|
|
|
|
|
(list a b))))
|
|
|
|
|
|
|
|
|
|
(let ((a (list 1)))
|
|
|
|
|
(let ((a (list 2))
|
|
|
|
|
(b a))
|
|
|
|
|
(list a b)))
|
|
|
|
|
|
|
|
|
|
(let* ((a (list 1))
|
|
|
|
|
(b a)
|
|
|
|
|
(a (list 2)))
|
|
|
|
|
(condition-case a
|
|
|
|
|
(list a b)
|
|
|
|
|
(error (list 'error a b))))
|
|
|
|
|
|
|
|
|
|
(let* ((a (list 1))
|
|
|
|
|
(b a)
|
|
|
|
|
(a (list 2)))
|
|
|
|
|
(condition-case a
|
|
|
|
|
(/ 0)
|
|
|
|
|
(error (list 'error a b))))
|
|
|
|
|
|
|
|
|
|
(let* ((a (list 1))
|
|
|
|
|
(b a)
|
|
|
|
|
(a (list 2))
|
|
|
|
|
(f (list (lambda (x) (list x a)))))
|
|
|
|
|
(funcall (car f) 3))
|
|
|
|
|
|
|
|
|
|
(let* ((a (list 1))
|
|
|
|
|
(b a)
|
|
|
|
|
(f (list (lambda (x) (setq a x)))))
|
|
|
|
|
(funcall (car f) 3)
|
|
|
|
|
(list a b))
|
|
|
|
|
|
|
|
|
|
(let* ((a (list 1))
|
|
|
|
|
(b a)
|
|
|
|
|
(a (list 2))
|
|
|
|
|
(f (list (lambda (x) (setq a x)))))
|
|
|
|
|
(funcall (car f) 3)
|
|
|
|
|
(list a b))
|
2021-11-02 14:48:55 +01:00
|
|
|
|
|
|
|
|
|
(cond)
|
|
|
|
|
(mapcar (lambda (x) (cond ((= x 0)))) '(0 1))
|
2021-11-22 16:56:38 +01:00
|
|
|
|
|
|
|
|
|
;; These expressions give different results in lexbind and dynbind modes,
|
|
|
|
|
;; but in each the compiler and interpreter should agree!
|
|
|
|
|
;; (They look much the same but come in pairs exercising both the
|
|
|
|
|
;; `let' and `let*' paths.)
|
|
|
|
|
(let ((f (lambda (x)
|
|
|
|
|
(lambda ()
|
|
|
|
|
(let ((g (lambda () x)))
|
|
|
|
|
(let ((x 'a))
|
|
|
|
|
(list x (funcall g))))))))
|
|
|
|
|
(funcall (funcall f 'b)))
|
|
|
|
|
(let ((f (lambda (x)
|
|
|
|
|
(lambda ()
|
|
|
|
|
(let ((g (lambda () x)))
|
|
|
|
|
(let* ((x 'a))
|
|
|
|
|
(list x (funcall g))))))))
|
|
|
|
|
(funcall (funcall f 'b)))
|
|
|
|
|
(let ((f (lambda (x)
|
|
|
|
|
(lambda ()
|
|
|
|
|
(let ((g (lambda () x)))
|
|
|
|
|
(setq x (list x x))
|
|
|
|
|
(let ((x 'a))
|
|
|
|
|
(list x (funcall g))))))))
|
|
|
|
|
(funcall (funcall f 'b)))
|
|
|
|
|
(let ((f (lambda (x)
|
|
|
|
|
(lambda ()
|
|
|
|
|
(let ((g (lambda () x)))
|
|
|
|
|
(setq x (list x x))
|
|
|
|
|
(let* ((x 'a))
|
|
|
|
|
(list x (funcall g))))))))
|
|
|
|
|
(funcall (funcall f 'b)))
|
|
|
|
|
(let ((f (lambda (x)
|
|
|
|
|
(let ((g (lambda () x))
|
|
|
|
|
(h (lambda () (setq x (list x x)))))
|
|
|
|
|
(let ((x 'a))
|
|
|
|
|
(list x (funcall g) (funcall h)))))))
|
|
|
|
|
(funcall (funcall f 'b)))
|
|
|
|
|
(let ((f (lambda (x)
|
|
|
|
|
(let ((g (lambda () x))
|
|
|
|
|
(h (lambda () (setq x (list x x)))))
|
|
|
|
|
(let* ((x 'a))
|
|
|
|
|
(list x (funcall g) (funcall h)))))))
|
|
|
|
|
(funcall (funcall f 'b)))
|
2021-12-11 22:11:08 +01:00
|
|
|
|
|
|
|
|
|
;; Test constant-propagation of access to captured variables.
|
|
|
|
|
(let* ((x 2)
|
|
|
|
|
(f (lambda ()
|
|
|
|
|
(let ((y x)) (list y 3 y)))))
|
|
|
|
|
(funcall f))
|
2022-09-22 14:15:56 +02:00
|
|
|
|
|
|
|
|
|
;; Test rewriting of `set' to `setq' (only done on dynamic variables).
|
|
|
|
|
(let ((xx 1)) (set 'xx 2) xx)
|
|
|
|
|
(let ((bytecomp-tests--xx 1))
|
|
|
|
|
(set 'bytecomp-tests--xx 2)
|
|
|
|
|
bytecomp-tests--xx)
|
|
|
|
|
(let ((aaa 1)) (set (make-local-variable 'aaa) 2) aaa)
|
|
|
|
|
(let ((bytecomp-tests--xx 1))
|
|
|
|
|
(set (make-local-variable 'bytecomp-tests--xx) 2)
|
|
|
|
|
bytecomp-tests--xx)
|
2021-04-09 18:42:12 +02:00
|
|
|
|
)
|
|
|
|
|
"List of expressions for cross-testing interpreted and compiled code.")
|
2017-02-07 19:35:20 +05:30
|
|
|
|
|
2021-04-09 18:42:12 +02:00
|
|
|
|
(defconst bytecomp-tests--test-cases-lexbind-only
|
|
|
|
|
`(
|
|
|
|
|
;; This would infloop (and exhaust stack) with dynamic binding.
|
|
|
|
|
(let ((f #'car))
|
|
|
|
|
(let ((f (lambda (x) (cons (funcall f x) (cdr x)))))
|
|
|
|
|
(funcall f '(1 . 2))))
|
|
|
|
|
)
|
|
|
|
|
"List of expressions for cross-testing interpreted and compiled code.
|
|
|
|
|
These are only tested with lexical binding.")
|
|
|
|
|
|
|
|
|
|
(defun bytecomp-tests--eval-interpreted (form)
|
|
|
|
|
"Evaluate FORM using the Lisp interpreter, returning errors as a
|
|
|
|
|
special value."
|
|
|
|
|
(condition-case err
|
|
|
|
|
(eval form lexical-binding)
|
|
|
|
|
(error (list 'bytecomp-check-error (car err)))))
|
|
|
|
|
|
|
|
|
|
(defun bytecomp-tests--eval-compiled (form)
|
|
|
|
|
"Evaluate FORM using the Lisp byte-code compiler, returning errors as a
|
|
|
|
|
special value."
|
2011-02-14 16:21:42 -05:00
|
|
|
|
(let ((warning-minimum-log-level :emergency)
|
2021-04-09 18:42:12 +02:00
|
|
|
|
(byte-compile-warnings nil))
|
|
|
|
|
(condition-case err
|
|
|
|
|
(funcall (byte-compile (list 'lambda nil form)))
|
|
|
|
|
(error (list 'bytecomp-check-error (car err))))))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-tests-lexbind ()
|
|
|
|
|
"Check that various expressions behave the same when interpreted and
|
|
|
|
|
byte-compiled. Run with lexical binding."
|
|
|
|
|
(let ((lexical-binding t))
|
|
|
|
|
(dolist (form (append bytecomp-tests--test-cases-lexbind-only
|
|
|
|
|
bytecomp-tests--test-cases))
|
|
|
|
|
(ert-info ((prin1-to-string form) :prefix "form: ")
|
|
|
|
|
(should (equal (bytecomp-tests--eval-interpreted form)
|
|
|
|
|
(bytecomp-tests--eval-compiled form)))))))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-tests-dynbind ()
|
|
|
|
|
"Check that various expressions behave the same when interpreted and
|
|
|
|
|
byte-compiled. Run with dynamic binding."
|
|
|
|
|
(let ((lexical-binding nil))
|
|
|
|
|
(dolist (form bytecomp-tests--test-cases)
|
|
|
|
|
(ert-info ((prin1-to-string form) :prefix "form: ")
|
|
|
|
|
(should (equal (bytecomp-tests--eval-interpreted form)
|
|
|
|
|
(bytecomp-tests--eval-compiled form)))))))
|
2011-02-14 16:21:42 -05:00
|
|
|
|
|
2014-04-22 00:04:34 -07:00
|
|
|
|
(defun test-byte-comp-compile-and-load (compile &rest forms)
|
Prefer `declare` over a `put` of `list-indent-function`.
While at it, I enabled lexical-binding in the affected files.
* lisp/cedet/semantic/sb.el: Enable lexical-binding.
(semantic-sb-with-tag-buffer): Use `declare`.
* lisp/cedet/semantic/bovine/el.el: Enable lexical-binding.
(semantic-elisp-setup-form-parser): Use `declare`.
* lisp/emacs-lisp/ert.el:
* lisp/emacs-lisp/ert-x.el: Remove redundant `put`.
* lisp/emulation/cua-rect.el: Enable lexical-binding.
(cua--rectangle-operation, cua--rectangle-aux-replace): Use `declare`.
* lisp/mh-e/mh-acros.el: Enable lexical-binding.
(mh-do-in-gnu-emacs, mh-do-in-xemacs, mh-funcall-if-exists, defun-mh)
(defmacro-mh, with-mh-folder-updating, mh-in-show-buffer)
(mh-do-at-event-location, mh-iterate-on-messages-in-region)
(mh-iterate-on-range): Use `declare`.
* lisp/mh-e/mh-compat.el: Enable lexical-binding.
(mh-flet): Use `declare`.
* lisp/mh-e/mh-e.el: Enable lexical-binding.
(defgroup-mh, defcustom-mh, defface-mh): Use `declare`.
* lisp/net/sieve.el: Enable lexical-binding. Remove redundant :group args.
(sieve-activate, sieve-remove, sieve-edit-script): Remove unused arg
from the interactive spec.
(sieve-deactivate-all): Remove unused var `name`.
(sieve-change-region): Use `declare`.
* lisp/obsolete/fast-lock.el: Enable lexical-binding.
Remove redundant :group args. Remove XEmacs compat code.
(save-buffer-state): Remove macro.
(fast-lock-add-properties): Use `with-silent-modifications` instead.
* lisp/obsolete/lazy-lock.el: Enable lexical-binding.
Remove redundant :group args.
(do-while): Use `declare`.
(save-buffer-state): Remove macro.
(lazy-lock-fontify-rest-after-change, lazy-lock-defer-line-after-change)
(lazy-lock-defer-rest-after-change, lazy-lock-after-fontify-buffer)
(lazy-lock-after-unfontify-buffer, lazy-lock-fontify-region):
Use `with-silent-modifications` instead.
* lisp/obsolete/pgg.el: Enable lexical-binding. Remove XEmacs compat code.
(pgg-save-coding-system, pgg-as-lbt, pgg-process-when-success):
Use `declare`.
(pgg-add-passphrase-to-cache): Remove unused var `new-timer`.
(pgg-decrypt-region): Remove unused var `buf`.
* lisp/org/org-agenda.el (org-let, org-let2): Move from org-macs and
use `declare`.
* lisp/org/org-macs.el (org-let, org-let2): Move these functions that
are inherently harmful to your karma to the only package that uses them.
(org-scroll): Use `pcase` to avoid `eval` and use more readable syntax
for those integers standing for events.
* lisp/progmodes/antlr-mode.el: Enable lexical-binding.
(save-buffer-state-x): Use `declare` and `with-silent-modifications`.
* lisp/international/mule-util.el (with-coding-priority):
* lisp/cedet/ede/proj-comp.el (proj-comp-insert-variable-once):
* lisp/org/org-element.el (org-element-map):
* test/lisp/emacs-lisp/bytecomp-tests.el (test-byte-comp-compile-and-load):
* test/lisp/emacs-lisp/generator-tests.el (cps-testcase): Use `declare`.
2021-02-22 11:54:17 -05:00
|
|
|
|
(declare (indent 1))
|
2021-11-08 01:21:06 +01:00
|
|
|
|
(ert-with-temp-file elfile
|
|
|
|
|
:suffix ".el"
|
|
|
|
|
(ert-with-temp-file elcfile
|
|
|
|
|
:suffix ".elc"
|
|
|
|
|
(with-temp-buffer
|
2022-06-06 10:47:42 +02:00
|
|
|
|
(insert ";;; -*- lexical-binding: t -*-\n")
|
2021-11-08 01:21:06 +01:00
|
|
|
|
(dolist (form forms)
|
|
|
|
|
(print form (current-buffer)))
|
|
|
|
|
(write-region (point-min) (point-max) elfile nil 'silent))
|
|
|
|
|
(if compile
|
|
|
|
|
(let ((byte-compile-dest-file-function
|
|
|
|
|
(lambda (e) elcfile)))
|
|
|
|
|
(byte-compile-file elfile)))
|
|
|
|
|
(load elfile nil 'nomessage))))
|
2014-04-21 02:34:21 -07:00
|
|
|
|
|
|
|
|
|
(ert-deftest test-byte-comp-macro-expansion ()
|
2014-04-22 00:04:34 -07:00
|
|
|
|
(test-byte-comp-compile-and-load t
|
2014-04-21 02:34:21 -07:00
|
|
|
|
'(progn (defmacro abc (arg) 1) (defun def () (abc 2))))
|
|
|
|
|
(should (equal (funcall 'def) 1)))
|
|
|
|
|
|
|
|
|
|
(ert-deftest test-byte-comp-macro-expansion-eval-and-compile ()
|
2014-04-22 00:04:34 -07:00
|
|
|
|
(test-byte-comp-compile-and-load t
|
2014-04-21 02:34:21 -07:00
|
|
|
|
'(eval-and-compile (defmacro abc (arg) -1) (defun def () (abc 2))))
|
|
|
|
|
(should (equal (funcall 'def) -1)))
|
|
|
|
|
|
|
|
|
|
(ert-deftest test-byte-comp-macro-expansion-eval-when-compile ()
|
|
|
|
|
;; Make sure we interpret eval-when-compile forms properly. CLISP
|
|
|
|
|
;; and SBCL interpreter eval-when-compile (well, the CL equivalent)
|
|
|
|
|
;; in the same way.
|
2014-04-22 00:04:34 -07:00
|
|
|
|
(test-byte-comp-compile-and-load t
|
2014-04-21 02:34:21 -07:00
|
|
|
|
'(eval-when-compile
|
|
|
|
|
(defmacro abc (arg) -10)
|
|
|
|
|
(defun abc-1 () (abc 2)))
|
|
|
|
|
'(defmacro abc-2 () (abc-1))
|
|
|
|
|
'(defun def () (abc-2)))
|
|
|
|
|
(should (equal (funcall 'def) -10)))
|
|
|
|
|
|
|
|
|
|
(ert-deftest test-byte-comp-macro-expand-lexical-override ()
|
|
|
|
|
;; Intuitively, one might expect the defmacro to override the
|
|
|
|
|
;; macrolet since macrolet's is explicitly called out as being
|
|
|
|
|
;; equivalent to toplevel, but CLISP and SBCL both evaluate the form
|
|
|
|
|
;; this way, so we should too.
|
2014-04-22 00:04:34 -07:00
|
|
|
|
(test-byte-comp-compile-and-load t
|
2014-04-21 02:34:21 -07:00
|
|
|
|
'(require 'cl-lib)
|
|
|
|
|
'(cl-macrolet ((m () 4))
|
|
|
|
|
(defmacro m () 5)
|
|
|
|
|
(defun def () (m))))
|
|
|
|
|
(should (equal (funcall 'def) 4)))
|
2011-02-14 16:21:42 -05:00
|
|
|
|
|
2020-12-02 11:29:26 +01:00
|
|
|
|
|
|
|
|
|
;;;; Warnings.
|
|
|
|
|
|
2014-11-08 12:46:21 -05:00
|
|
|
|
(ert-deftest bytecomp-tests--warnings ()
|
|
|
|
|
(with-current-buffer (get-buffer-create "*Compile-Log*")
|
|
|
|
|
(let ((inhibit-read-only t)) (erase-buffer)))
|
2020-08-19 14:43:11 +01:00
|
|
|
|
(mapc #'fmakunbound '(my-test0 my--test11 my--test12 my--test2))
|
2014-11-08 12:46:21 -05:00
|
|
|
|
(test-byte-comp-compile-and-load t
|
|
|
|
|
'(progn
|
|
|
|
|
(defun my-test0 ()
|
|
|
|
|
(my--test11 3)
|
|
|
|
|
(my--test12 3)
|
|
|
|
|
(my--test2 5))
|
|
|
|
|
(defmacro my--test11 (arg) (+ arg 1))
|
|
|
|
|
(eval-and-compile
|
|
|
|
|
(defmacro my--test12 (arg) (+ arg 1))
|
|
|
|
|
(defun my--test2 (arg) (+ arg 1)))))
|
|
|
|
|
(with-current-buffer (get-buffer-create "*Compile-Log*")
|
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
;; Should warn that mt--test1[12] are first used as functions.
|
2015-06-21 20:27:48 +03:00
|
|
|
|
;; The second alternative is for when the file name is so long
|
|
|
|
|
;; that pretty-printing starts the message on the next line.
|
|
|
|
|
(should (or (re-search-forward "my--test11:\n.*macro" nil t)
|
|
|
|
|
(re-search-forward "my--test11:\n.*:\n.*macro" nil t)))
|
|
|
|
|
(should (or (re-search-forward "my--test12:\n.*macro" nil t)
|
|
|
|
|
(re-search-forward "my--test12:\n.*:\n.*macro" nil t)))
|
2014-11-08 12:46:21 -05:00
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
;; Should not warn that mt--test2 is not known to be defined.
|
|
|
|
|
(should-not (re-search-forward "my--test2" nil t))))
|
|
|
|
|
|
2022-12-17 14:48:34 +01:00
|
|
|
|
(defmacro bytecomp--with-warning-test (re-warning form)
|
2020-11-22 07:19:11 +01:00
|
|
|
|
(declare (indent 1))
|
|
|
|
|
`(with-current-buffer (get-buffer-create "*Compile-Log*")
|
|
|
|
|
(let ((inhibit-read-only t)) (erase-buffer))
|
2022-12-17 14:48:34 +01:00
|
|
|
|
(let ((text-quoting-style 'grave)
|
|
|
|
|
(macroexp--warned
|
|
|
|
|
(make-hash-table :test #'equal :weakness 'key)) ; oh dear
|
|
|
|
|
(form ,form))
|
|
|
|
|
(ert-info ((prin1-to-string form) :prefix "form: ")
|
|
|
|
|
(byte-compile form)
|
|
|
|
|
(ert-info ((prin1-to-string (buffer-string)) :prefix "buffer: ")
|
|
|
|
|
(should (re-search-forward
|
|
|
|
|
(string-replace " " "[ \n]+" ,re-warning))))))))
|
2020-11-22 07:19:11 +01:00
|
|
|
|
|
2019-05-27 20:36:41 -04:00
|
|
|
|
(ert-deftest bytecomp-warn-wrong-args ()
|
2020-11-22 07:19:11 +01:00
|
|
|
|
(bytecomp--with-warning-test "remq.*3.*2"
|
|
|
|
|
'(remq 1 2 3)))
|
2019-05-27 20:36:41 -04:00
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-warn-wrong-args-subr ()
|
2020-11-22 07:19:11 +01:00
|
|
|
|
(bytecomp--with-warning-test "safe-length.*3.*1"
|
|
|
|
|
'(safe-length 1 2 3)))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-warn-variable-lacks-prefix ()
|
|
|
|
|
(bytecomp--with-warning-test "foo.*lacks a prefix"
|
|
|
|
|
'(defvar foo nil)))
|
2019-05-27 20:36:41 -04:00
|
|
|
|
|
2020-12-06 12:44:19 +01:00
|
|
|
|
(defvar bytecomp-tests--docstring (make-string 100 ?x))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-warn-wide-docstring/defconst ()
|
|
|
|
|
(bytecomp--with-warning-test "defconst.*foo.*wider than.*characters"
|
|
|
|
|
`(defconst foo t ,bytecomp-tests--docstring)))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-warn-wide-docstring/defvar ()
|
|
|
|
|
(bytecomp--with-warning-test "defvar.*foo.*wider than.*characters"
|
|
|
|
|
`(defvar foo t ,bytecomp-tests--docstring)))
|
|
|
|
|
|
Warn about unmatchable constant args to `eq`, `memq` etc
Add a byte-compiler warning about attempts to compare literal values
with undefined identity relation to other values. For example:
(eq x 2.0)
(memq x '("a" (b) [c]))
Such incomparable values include all literal conses, strings, vectors,
records and (except for eql and memql) floats and bignums.
The warning currently applies to eq, eql, memq, memql, assq, rassq,
remq and delq.
* lisp/emacs-lisp/bytecomp.el (bytecomp--dodgy-eq-arg)
(bytecomp--value-type-description, bytecomp--arg-type-description)
(bytecomp--warn-dodgy-eq-arg, bytecomp--check-eq-args)
(bytecomp--check-memq-args): New.
(eq, eql, memq, memql, assq, rassq, remq, delq):
Set compiler-macro property.
* lisp/emacs-lisp/byte-run.el (with-suppressed-warnings):
Amend doc string.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp--with-warning-test): Fix text-quoting-style and expand
re-warning so that it doesn't need to be a literal.
(bytecomp-warn-dodgy-args-eq, bytecomp-warn-dodgy-args-memq):
New tests.
2022-12-14 17:48:17 +01:00
|
|
|
|
(ert-deftest bytecomp-warn-dodgy-args-eq ()
|
|
|
|
|
(dolist (fn '(eq eql))
|
|
|
|
|
(cl-flet ((msg (type arg)
|
|
|
|
|
(format
|
|
|
|
|
"`%s' called with literal %s that may never match (arg %d)"
|
|
|
|
|
fn type arg)))
|
|
|
|
|
(bytecomp--with-warning-test (msg "list" 1) `(,fn '(a) 'x))
|
|
|
|
|
(bytecomp--with-warning-test (msg "string" 2) `(,fn 'x "a"))
|
|
|
|
|
(bytecomp--with-warning-test (msg "vector" 2) `(,fn 'x [a]))
|
2022-12-17 14:48:34 +01:00
|
|
|
|
(bytecomp--with-warning-test (msg "function" 2) `(,fn 'x (lambda () 1)))
|
|
|
|
|
(bytecomp--with-warning-test (msg "function" 2) `(,fn 'x #'(lambda () 1)))
|
Warn about unmatchable constant args to `eq`, `memq` etc
Add a byte-compiler warning about attempts to compare literal values
with undefined identity relation to other values. For example:
(eq x 2.0)
(memq x '("a" (b) [c]))
Such incomparable values include all literal conses, strings, vectors,
records and (except for eql and memql) floats and bignums.
The warning currently applies to eq, eql, memq, memql, assq, rassq,
remq and delq.
* lisp/emacs-lisp/bytecomp.el (bytecomp--dodgy-eq-arg)
(bytecomp--value-type-description, bytecomp--arg-type-description)
(bytecomp--warn-dodgy-eq-arg, bytecomp--check-eq-args)
(bytecomp--check-memq-args): New.
(eq, eql, memq, memql, assq, rassq, remq, delq):
Set compiler-macro property.
* lisp/emacs-lisp/byte-run.el (with-suppressed-warnings):
Amend doc string.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp--with-warning-test): Fix text-quoting-style and expand
re-warning so that it doesn't need to be a literal.
(bytecomp-warn-dodgy-args-eq, bytecomp-warn-dodgy-args-memq):
New tests.
2022-12-14 17:48:17 +01:00
|
|
|
|
(unless (eq fn 'eql)
|
|
|
|
|
(bytecomp--with-warning-test (msg "integer" 2) `(,fn 'x #x10000000000))
|
|
|
|
|
(bytecomp--with-warning-test (msg "float" 2) `(,fn 'x 1.0))))))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-warn-dodgy-args-memq ()
|
|
|
|
|
(dolist (fn '(memq memql remq delq assq rassq))
|
|
|
|
|
(cl-labels
|
|
|
|
|
((msg1 (type)
|
|
|
|
|
(format
|
|
|
|
|
"`%s' called with literal %s that may never match (arg 1)"
|
|
|
|
|
fn type))
|
|
|
|
|
(msg2 (type)
|
|
|
|
|
(format
|
|
|
|
|
"`%s' called with literal %s that may never match (element 2 of arg 2)"
|
|
|
|
|
fn type))
|
|
|
|
|
(lst (elt)
|
|
|
|
|
(cond ((eq fn 'assq) `((a . 1) (,elt . 2) (c . 3)))
|
|
|
|
|
((eq fn 'rassq) `((1 . a) (2 . ,elt) (3 . c)))
|
|
|
|
|
(t `(a ,elt c))))
|
|
|
|
|
(form2 (elt)
|
|
|
|
|
`(,fn 'x ',(lst elt))))
|
|
|
|
|
|
|
|
|
|
(bytecomp--with-warning-test (msg1 "list") `(,fn '(a) '(x)))
|
|
|
|
|
(bytecomp--with-warning-test (msg1 "string") `(,fn "a" '(x)))
|
|
|
|
|
(bytecomp--with-warning-test (msg1 "vector") `(,fn [a] '(x)))
|
2022-12-17 14:48:34 +01:00
|
|
|
|
(bytecomp--with-warning-test (msg1 "function") `(,fn (lambda () 1) '(x)))
|
|
|
|
|
(bytecomp--with-warning-test (msg1 "function") `(,fn #'(lambda () 1) '(x)))
|
Warn about unmatchable constant args to `eq`, `memq` etc
Add a byte-compiler warning about attempts to compare literal values
with undefined identity relation to other values. For example:
(eq x 2.0)
(memq x '("a" (b) [c]))
Such incomparable values include all literal conses, strings, vectors,
records and (except for eql and memql) floats and bignums.
The warning currently applies to eq, eql, memq, memql, assq, rassq,
remq and delq.
* lisp/emacs-lisp/bytecomp.el (bytecomp--dodgy-eq-arg)
(bytecomp--value-type-description, bytecomp--arg-type-description)
(bytecomp--warn-dodgy-eq-arg, bytecomp--check-eq-args)
(bytecomp--check-memq-args): New.
(eq, eql, memq, memql, assq, rassq, remq, delq):
Set compiler-macro property.
* lisp/emacs-lisp/byte-run.el (with-suppressed-warnings):
Amend doc string.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp--with-warning-test): Fix text-quoting-style and expand
re-warning so that it doesn't need to be a literal.
(bytecomp-warn-dodgy-args-eq, bytecomp-warn-dodgy-args-memq):
New tests.
2022-12-14 17:48:17 +01:00
|
|
|
|
(unless (eq fn 'memql)
|
|
|
|
|
(bytecomp--with-warning-test (msg1 "integer") `(,fn #x10000000000 '(x)))
|
|
|
|
|
(bytecomp--with-warning-test (msg1 "float") `(,fn 1.0 '(x))))
|
|
|
|
|
|
|
|
|
|
(bytecomp--with-warning-test (msg2 "list") (form2 '(b)))
|
|
|
|
|
(bytecomp--with-warning-test (msg2 "list") (form2 ''b))
|
|
|
|
|
(bytecomp--with-warning-test (msg2 "string") (form2 "b"))
|
|
|
|
|
(bytecomp--with-warning-test (msg2 "vector") (form2 [b]))
|
|
|
|
|
(unless (eq fn 'memql)
|
|
|
|
|
(bytecomp--with-warning-test (msg2 "integer") (form2 #x10000000000))
|
|
|
|
|
(bytecomp--with-warning-test (msg2 "float") (form2 1.0))))))
|
|
|
|
|
|
2020-11-30 22:42:08 +01:00
|
|
|
|
(defmacro bytecomp--define-warning-file-test (file re-warning &optional reverse)
|
2020-12-01 13:34:17 +01:00
|
|
|
|
`(ert-deftest ,(intern (format "bytecomp/%s" file)) ()
|
2020-11-30 22:42:08 +01:00
|
|
|
|
(with-current-buffer (get-buffer-create "*Compile-Log*")
|
|
|
|
|
(let ((inhibit-read-only t)) (erase-buffer))
|
|
|
|
|
(byte-compile-file ,(ert-resource-file file))
|
|
|
|
|
(ert-info ((buffer-string) :prefix "buffer: ")
|
2021-04-09 18:49:16 +02:00
|
|
|
|
(,(if reverse 'should-not 'should)
|
2021-12-06 21:48:40 +01:00
|
|
|
|
(re-search-forward ,re-warning nil t))))))
|
2020-11-30 22:42:08 +01:00
|
|
|
|
|
2020-12-01 13:34:17 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "error-lexical-var-with-add-hook.el"
|
|
|
|
|
"add-hook.*lexical var")
|
2020-11-30 22:42:08 +01:00
|
|
|
|
|
2020-12-01 13:34:17 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "error-lexical-var-with-remove-hook.el"
|
|
|
|
|
"remove-hook.*lexical var")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "error-lexical-var-with-run-hook-with-args-until-failure.el"
|
|
|
|
|
"args-until-failure.*lexical var")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "error-lexical-var-with-run-hook-with-args-until-success.el"
|
|
|
|
|
"args-until-success.*lexical var")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "error-lexical-var-with-run-hook-with-args.el"
|
|
|
|
|
"args.*lexical var")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "error-lexical-var-with-symbol-value.el"
|
|
|
|
|
"symbol-value.*lexical var")
|
|
|
|
|
|
2020-12-03 17:08:28 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-autoload-not-on-top-level.el"
|
|
|
|
|
"compiler ignores.*autoload.*")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-callargs.el"
|
|
|
|
|
"with 2 arguments, but accepts only 1")
|
|
|
|
|
|
2021-07-22 15:00:17 +02:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-callargs-defsubst.el"
|
|
|
|
|
"with 2 arguments, but accepts only 1")
|
|
|
|
|
|
2020-12-03 17:08:28 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-defcustom-nogroup.el"
|
|
|
|
|
"fails to specify containing group")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-defcustom-notype.el"
|
|
|
|
|
"fails to specify type")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-defvar-lacks-prefix.el"
|
|
|
|
|
"var.*foo.*lacks a prefix")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-format.el"
|
|
|
|
|
"called with 2 args to fill 1 format field")
|
|
|
|
|
|
2020-12-01 13:34:17 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-free-setq.el"
|
|
|
|
|
"free.*foo")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-free-variable-reference.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"free variable .bar")
|
2020-11-30 22:42:08 +01:00
|
|
|
|
|
2020-12-03 17:08:28 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-make-variable-buffer-local.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"make-variable-buffer-local. not called at toplevel")
|
2020-12-03 17:08:28 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-interactive-only.el"
|
|
|
|
|
"next-line.*interactive use only.*forward-line")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-lambda-malformed-interactive-spec.el"
|
2022-09-09 19:43:28 +02:00
|
|
|
|
"malformed .interactive. specification")
|
2020-12-03 17:08:28 +01:00
|
|
|
|
|
2020-12-01 04:46:33 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-obsolete-defun.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"foo-obsolete. is an obsolete function (as of 99.99)")
|
2020-12-01 04:46:33 +01:00
|
|
|
|
|
|
|
|
|
(defvar bytecomp--tests-obsolete-var nil)
|
|
|
|
|
(make-obsolete-variable 'bytecomp--tests-obsolete-var nil "99.99")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-obsolete-hook.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"bytecomp--tests-obsolete-var. is an obsolete variable (as of 99.99)")
|
2020-12-01 04:46:33 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-obsolete-variable-same-file.el"
|
|
|
|
|
"foo-obs.*obsolete.*99.99" t)
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-obsolete-variable.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"bytecomp--tests-obsolete-var. is an obsolete variable (as of 99.99)")
|
2020-12-01 04:46:33 +01:00
|
|
|
|
|
2020-12-22 05:44:47 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-obsolete-variable-bound.el"
|
|
|
|
|
"bytecomp--tests-obs.*obsolete.*99.99" t)
|
|
|
|
|
|
2020-12-03 17:08:28 +01:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-redefine-defun-as-macro.el"
|
|
|
|
|
"as both function and macro")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-redefine-macro-as-defun.el"
|
|
|
|
|
"as both function and macro")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-redefine-defun.el"
|
|
|
|
|
"defined multiple")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-save-excursion.el"
|
|
|
|
|
"with-current.*rather than save-excursion")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-variable-let-bind-constant.el"
|
|
|
|
|
"let-bind constant")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-variable-let-bind-nonvariable.el"
|
|
|
|
|
"let-bind nonvariable")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-variable-set-constant.el"
|
2022-06-03 20:31:10 +02:00
|
|
|
|
"attempt to set constant")
|
2020-12-03 17:08:28 +01:00
|
|
|
|
|
2022-06-03 20:31:10 +02:00
|
|
|
|
(bytecomp--define-warning-file-test "warn-variable-setq-nonvariable.el"
|
|
|
|
|
"attempt to set non-variable")
|
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test "warn-variable-setq-odd.el"
|
|
|
|
|
"odd number of arguments")
|
|
|
|
|
|
2020-12-06 12:44:19 +01:00
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-autoload.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"autoload .foox. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-custom-declare-variable.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"custom-declare-variable .foo. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-defalias.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defalias .foo. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-defconst.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defconst .foo-bar. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-define-abbrev-table.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"define-abbrev-table .foo. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-define-obsolete-function-alias.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defalias .foo. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-define-obsolete-variable-alias.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defvaralias .foo. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-defun.el"
|
2021-12-06 21:51:37 +01:00
|
|
|
|
"Warning: docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-defvar.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defvar .foo-bar. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-defvaralias.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defvaralias .foo-bar. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-ignore-fill-column.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defvar .foo-bar. docstring wider than .* characters" 'reverse)
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
2022-09-16 22:24:20 +02:00
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-ignore-function-signature.el"
|
|
|
|
|
"defvar .foo-bar. docstring wider than .* characters" 'reverse)
|
|
|
|
|
|
2020-12-06 12:44:19 +01:00
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-ignore-override.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defvar .foo-bar. docstring wider than .* characters" 'reverse)
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
2021-11-22 08:08:11 +01:00
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-ignore-substitutions.el"
|
|
|
|
|
"defvar .foo-bar. docstring wider than .* characters" 'reverse)
|
|
|
|
|
|
2020-12-06 12:44:19 +01:00
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-ignore.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defvar .foo-bar. docstring wider than .* characters" 'reverse)
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-multiline-first.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defvar .foo-bar. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"warn-wide-docstring-multiline.el"
|
2021-04-09 18:49:16 +02:00
|
|
|
|
"defvar .foo-bar. docstring wider than .* characters")
|
2020-12-06 12:44:19 +01:00
|
|
|
|
|
2021-01-21 13:15:05 -05:00
|
|
|
|
(bytecomp--define-warning-file-test
|
|
|
|
|
"nowarn-inline-after-defvar.el"
|
|
|
|
|
"Lexical argument shadows" 'reverse)
|
|
|
|
|
|
2020-12-02 11:29:26 +01:00
|
|
|
|
|
|
|
|
|
;;;; Macro expansion.
|
|
|
|
|
|
|
|
|
|
(ert-deftest test-eager-load-macro-expansion ()
|
|
|
|
|
(test-byte-comp-compile-and-load nil
|
|
|
|
|
'(progn (defmacro abc (arg) 1) (defun def () (abc 2))))
|
|
|
|
|
(should (equal (funcall 'def) 1)))
|
|
|
|
|
|
|
|
|
|
(ert-deftest test-eager-load-macro-expansion-eval-and-compile ()
|
|
|
|
|
(test-byte-comp-compile-and-load nil
|
|
|
|
|
'(eval-and-compile (defmacro abc (arg) -1) (defun def () (abc 2))))
|
|
|
|
|
(should (equal (funcall 'def) -1)))
|
|
|
|
|
|
2014-04-22 00:04:34 -07:00
|
|
|
|
(ert-deftest test-eager-load-macro-expansion-eval-when-compile ()
|
|
|
|
|
;; Make sure we interpret eval-when-compile forms properly. CLISP
|
|
|
|
|
;; and SBCL interpreter eval-when-compile (well, the CL equivalent)
|
|
|
|
|
;; in the same way.
|
|
|
|
|
(test-byte-comp-compile-and-load nil
|
|
|
|
|
'(eval-when-compile
|
|
|
|
|
(defmacro abc (arg) -10)
|
|
|
|
|
(defun abc-1 () (abc 2)))
|
|
|
|
|
'(defmacro abc-2 () (abc-1))
|
|
|
|
|
'(defun def () (abc-2)))
|
|
|
|
|
(should (equal (funcall 'def) -10)))
|
|
|
|
|
|
|
|
|
|
(ert-deftest test-eager-load-macro-expand-lexical-override ()
|
|
|
|
|
;; Intuitively, one might expect the defmacro to override the
|
|
|
|
|
;; macrolet since macrolet's is explicitly called out as being
|
|
|
|
|
;; equivalent to toplevel, but CLISP and SBCL both evaluate the form
|
|
|
|
|
;; this way, so we should too.
|
|
|
|
|
(test-byte-comp-compile-and-load nil
|
|
|
|
|
'(require 'cl-lib)
|
|
|
|
|
'(cl-macrolet ((m () 4))
|
|
|
|
|
(defmacro m () 5)
|
|
|
|
|
(defun def () (m))))
|
|
|
|
|
(should (equal (funcall 'def) 4)))
|
|
|
|
|
|
2015-06-30 22:38:35 +02:00
|
|
|
|
(defmacro bytecomp-tests--with-temp-file (file-name-var &rest body)
|
|
|
|
|
(declare (indent 1))
|
|
|
|
|
(cl-check-type file-name-var symbol)
|
Prefer ert-with-temp-(directory|file)
* test/lisp/abbrev-tests.el (read-write-abbrev-file-test)
(read-write-abbrev-file-test-with-props)
(abbrev-edit-save-to-file-test):
* test/lisp/auth-source-tests.el (auth-source-test-netrc-create-secret)
(auth-source-delete):
* test/lisp/autoinsert-tests.el (autoinsert-tests-auto-insert-file):
* test/lisp/bookmark-tests.el (with-bookmark-test-save-load):
* test/lisp/buff-menu-tests.el (buff-menu-24962):
* test/lisp/calendar/icalendar-tests.el (icalendar-tests--do-test-export):
* test/lisp/calendar/todo-mode-tests.el (with-todo-test):
* test/lisp/dired-tests.el
(dired-test-bug27243-01, dired-test-bug27243-02)
(dired-test-bug27243-03, dired-test-bug27631)
(dired-test-bug27968, dired-test-with-temp-dirs):
* test/lisp/dired-x-tests.el (dired-test-bug25942):
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--with-temp-file):
* test/lisp/emacs-lisp/check-declare-tests.el (check-declare-tests-scan)
(check-declare-tests-verify-mismatch):
* test/lisp/emacs-lisp/edebug-tests.el (edebug-tests-with-normal-env):
* test/lisp/emacs-lisp/package-tests.el (with-package-test)
(package-test-signed):
* test/lisp/emacs-lisp/testcover-tests.el (testcover-tests-markup-region)
(testcover-tests-run-test-case):
* test/lisp/emulation/viper-tests.el (viper-test-undo-kmacro):
* test/lisp/epg-tests.el (with-epg-tests):
* test/lisp/eshell/em-hist-tests.el (eshell-write-readonly-history):
* test/lisp/eshell/em-ls-tests.el (em-ls-test-bug27631):
* test/lisp/ffap-tests.el (ffap-tests-25243):
* test/lisp/files-tests.el (files-tests-bug-18141)
(files-tests-read-file-in-~, files-tests-make-directory)
(files-tests-copy-directory, files-tests-executable-find)
(files-tests-dont-rewrite-precious-files)
(files-tests--save-some-buffers):
* test/lisp/ls-lisp-tests.el (ls-lisp-test-bug27631):
* test/lisp/mail/uudecode-tests.el (uudecode-tests-decode-region-internal)
(uudecode-tests-decode-region-external):
* test/lisp/net/browse-url-tests.el (browse-url-tests-delete-temp-file):
* test/lisp/progmodes/elisp-mode-tests.el (xref--case-insensitive):
* test/lisp/progmodes/etags-tests.el (etags-buffer-local-tags-table-list):
* test/lisp/progmodes/flymake-tests.el (ruby-backend):
* test/lisp/progmodes/python-tests.el (python-tests-with-temp-file):
* test/lisp/progmodes/sql-tests.el (with-sql-test-connect-harness):
* test/lisp/saveplace-tests.el (saveplace-test-save-place-to-alist/file)
(saveplace-test-forget-unreadable-files)
(saveplace-test-place-alist-to-file):
* test/lisp/so-long-tests/spelling-tests.el:
* test/lisp/textmodes/reftex-tests.el (reftex-locate-bibliography-files)
(reftex-parse-from-file-test):
* test/lisp/thumbs-tests.el (thumbs-tests-thumbsdir/create-if-missing):
* test/lisp/vc/vc-bzr-tests.el (vc-bzr-test-bug9726)
(vc-bzr-test-bug9781, vc-bzr-test-faulty-bzr-autoloads):
* test/lisp/vc/diff-mode-tests.el (diff-mode-test-ignore-trailing-dashes):
* test/lisp/vc/ediff-ptch-tests.el (ediff-ptch-test-bug26084):
* test/lisp/wdired-tests.el (wdired-test-bug32173-01)
(wdired-test-bug32173-02, wdired-test-symlink-name)
(wdired-test-unfinished-edit-01, wdired-test-bug34915)
(wdired-test-bug39280):
* test/src/buffer-tests.el (test-kill-buffer-auto-save-default):
* test/src/filelock-tests.el (filelock-tests--fixture):
* test/src/inotify-tests.el (inotify-file-watch-simple):
* test/src/undo-tests.el (undo-test-file-modified): Prefer
'ert-with-temp-(directory|file)' to using 'make-temp-file' directly.
In some cases, this is just cleanup, but in several cases this fixes
bugs where an error would have lead to us not cleaning up.
2021-11-06 23:20:59 +01:00
|
|
|
|
`(ert-with-temp-file ,file-name-var
|
2015-06-30 22:38:35 +02:00
|
|
|
|
(unwind-protect
|
|
|
|
|
(progn ,@body)
|
2017-08-14 17:23:18 -04:00
|
|
|
|
(let ((elc (concat ,file-name-var ".elc")))
|
|
|
|
|
(if (file-exists-p elc) (delete-file elc))))))
|
2015-06-30 22:38:35 +02:00
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-tests--unescaped-char-literals ()
|
|
|
|
|
"Check that byte compiling warns about unescaped character
|
|
|
|
|
literals (Bug#20852)."
|
|
|
|
|
(should (boundp 'lread--unescaped-character-literals))
|
2019-06-04 21:26:06 -04:00
|
|
|
|
(let ((byte-compile-error-on-warn t)
|
|
|
|
|
(byte-compile-debug t))
|
|
|
|
|
(bytecomp-tests--with-temp-file source
|
|
|
|
|
(write-region "(list ?) ?( ?; ?\" ?[ ?])" nil source)
|
|
|
|
|
(bytecomp-tests--with-temp-file destination
|
|
|
|
|
(let* ((byte-compile-dest-file-function (lambda (_) destination))
|
|
|
|
|
(err (should-error (byte-compile-file source))))
|
|
|
|
|
(should (equal (cdr err)
|
|
|
|
|
`(,(concat "unescaped character literals "
|
|
|
|
|
"`?\"', `?(', `?)', `?;', `?[', `?]' "
|
|
|
|
|
"detected, "
|
|
|
|
|
"`?\\\"', `?\\(', `?\\)', `?\\;', `?\\[', "
|
|
|
|
|
"`?\\]' expected!")))))))
|
|
|
|
|
;; But don't warn in subsequent compilations (Bug#36068).
|
|
|
|
|
(bytecomp-tests--with-temp-file source
|
|
|
|
|
(write-region "(list 1 2 3)" nil source)
|
|
|
|
|
(bytecomp-tests--with-temp-file destination
|
|
|
|
|
(let ((byte-compile-dest-file-function (lambda (_) destination)))
|
|
|
|
|
(should (byte-compile-file source)))))))
|
2015-06-30 22:38:35 +02:00
|
|
|
|
|
2017-07-14 00:32:34 -04:00
|
|
|
|
(ert-deftest bytecomp-tests-function-put ()
|
|
|
|
|
"Check `function-put' operates during compilation."
|
|
|
|
|
(bytecomp-tests--with-temp-file source
|
|
|
|
|
(dolist (form '((function-put 'bytecomp-tests--foo 'foo 1)
|
|
|
|
|
(function-put 'bytecomp-tests--foo 'bar 2)
|
|
|
|
|
(defmacro bytecomp-tests--foobar ()
|
|
|
|
|
`(cons ,(function-get 'bytecomp-tests--foo 'foo)
|
|
|
|
|
,(function-get 'bytecomp-tests--foo 'bar)))
|
|
|
|
|
(defvar bytecomp-tests--foobar 1)
|
|
|
|
|
(setq bytecomp-tests--foobar (bytecomp-tests--foobar))))
|
|
|
|
|
(print form (current-buffer)))
|
|
|
|
|
(write-region (point-min) (point-max) source nil 'silent)
|
2020-09-22 00:16:22 +02:00
|
|
|
|
(byte-compile-file source)
|
|
|
|
|
(load source)
|
2017-07-14 00:32:34 -04:00
|
|
|
|
(should (equal bytecomp-tests--foobar (cons 1 2)))))
|
|
|
|
|
|
2017-10-12 16:02:39 -07:00
|
|
|
|
(ert-deftest bytecomp-tests--test-no-warnings-with-advice ()
|
|
|
|
|
(defun f ())
|
|
|
|
|
(define-advice f (:around (oldfun &rest args) test)
|
|
|
|
|
(apply oldfun args))
|
|
|
|
|
(with-current-buffer (get-buffer-create "*Compile-Log*")
|
|
|
|
|
(let ((inhibit-read-only t)) (erase-buffer)))
|
|
|
|
|
(test-byte-comp-compile-and-load t '(defun f ()))
|
|
|
|
|
(with-current-buffer (get-buffer-create "*Compile-Log*")
|
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
(should-not (search-forward "Warning" nil t))))
|
|
|
|
|
|
2018-03-26 21:56:33 -04:00
|
|
|
|
(ert-deftest bytecomp-test-featurep-warnings ()
|
|
|
|
|
(let ((byte-compile-log-buffer (generate-new-buffer " *Compile-Log*")))
|
|
|
|
|
(unwind-protect
|
|
|
|
|
(progn
|
|
|
|
|
(with-temp-buffer
|
|
|
|
|
(insert "\
|
|
|
|
|
\(defun foo ()
|
|
|
|
|
(an-undefined-function))
|
|
|
|
|
|
|
|
|
|
\(defun foo1 ()
|
|
|
|
|
(if (featurep 'xemacs)
|
|
|
|
|
(some-undefined-function-if)))
|
|
|
|
|
|
|
|
|
|
\(defun foo2 ()
|
|
|
|
|
(and (featurep 'xemacs)
|
|
|
|
|
(some-undefined-function-and)))
|
|
|
|
|
|
|
|
|
|
\(defun foo3 ()
|
|
|
|
|
(if (not (featurep 'emacs))
|
|
|
|
|
(some-undefined-function-not)))
|
|
|
|
|
|
|
|
|
|
\(defun foo4 ()
|
|
|
|
|
(or (featurep 'emacs)
|
|
|
|
|
(some-undefined-function-or)))
|
|
|
|
|
")
|
|
|
|
|
(byte-compile-from-buffer (current-buffer)))
|
|
|
|
|
(with-current-buffer byte-compile-log-buffer
|
|
|
|
|
(should (search-forward "an-undefined-function" nil t))
|
|
|
|
|
(should-not (search-forward "some-undefined-function" nil t))))
|
|
|
|
|
(if (buffer-live-p byte-compile-log-buffer)
|
|
|
|
|
(kill-buffer byte-compile-log-buffer)))))
|
|
|
|
|
|
2019-05-17 11:25:06 +02:00
|
|
|
|
(ert-deftest bytecomp-test--switch-duplicates ()
|
|
|
|
|
"Check that duplicates in switches are eliminated correctly (bug#35770)."
|
2019-07-09 03:25:13 -07:00
|
|
|
|
:expected-result (if byte-compile-cond-use-jump-table :passed :failed)
|
2019-05-17 11:25:06 +02:00
|
|
|
|
(dolist (params
|
|
|
|
|
'(((lambda (x)
|
|
|
|
|
(cond ((eq x 'a) 111)
|
|
|
|
|
((eq x 'b) 222)
|
|
|
|
|
((eq x 'a) 333)
|
|
|
|
|
((eq x 'c) 444)))
|
|
|
|
|
(a b c)
|
|
|
|
|
string<)
|
|
|
|
|
((lambda (x)
|
|
|
|
|
(cond ((eql x #x10000000000000000) 111)
|
|
|
|
|
((eql x #x10000000000000001) 222)
|
|
|
|
|
((eql x #x10000000000000000) 333)
|
|
|
|
|
((eql x #x10000000000000002) 444)))
|
|
|
|
|
(#x10000000000000000 #x10000000000000001 #x10000000000000002)
|
|
|
|
|
<)
|
|
|
|
|
((lambda (x)
|
|
|
|
|
(cond ((equal x "a") 111)
|
|
|
|
|
((equal x "b") 222)
|
|
|
|
|
((equal x "a") 333)
|
|
|
|
|
((equal x "c") 444)))
|
|
|
|
|
("a" "b" "c")
|
|
|
|
|
string<)))
|
|
|
|
|
(let* ((lisp (nth 0 params))
|
|
|
|
|
(keys (nth 1 params))
|
|
|
|
|
(lessp (nth 2 params))
|
|
|
|
|
(bc (byte-compile lisp))
|
|
|
|
|
(lap (byte-decompile-bytecode (aref bc 1) (aref bc 2)))
|
|
|
|
|
;; Assume the first constant is the switch table.
|
|
|
|
|
(table (cadr (assq 'byte-constant lap))))
|
|
|
|
|
(should (hash-table-p table))
|
|
|
|
|
(should (equal (sort (hash-table-keys table) lessp) keys))
|
|
|
|
|
(should (member '(byte-constant 111) lap))
|
|
|
|
|
(should (member '(byte-constant 222) lap))
|
|
|
|
|
(should-not (member '(byte-constant 333) lap))
|
|
|
|
|
(should (member '(byte-constant 444) lap)))))
|
|
|
|
|
|
2019-06-12 15:59:19 +02:00
|
|
|
|
(defun test-suppression (form suppress match)
|
|
|
|
|
(let ((lexical-binding t)
|
|
|
|
|
(byte-compile-log-buffer (generate-new-buffer " *Compile-Log*")))
|
|
|
|
|
;; Check that we get a warning without suppression.
|
|
|
|
|
(with-current-buffer byte-compile-log-buffer
|
2019-06-16 17:35:36 -07:00
|
|
|
|
(setq-local fill-column 9999)
|
|
|
|
|
(setq-local warning-fill-column fill-column)
|
2019-06-12 15:59:19 +02:00
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(erase-buffer)))
|
|
|
|
|
(test-byte-comp-compile-and-load t form)
|
|
|
|
|
(with-current-buffer byte-compile-log-buffer
|
|
|
|
|
(unless match
|
|
|
|
|
(error "%s" (buffer-string)))
|
|
|
|
|
(goto-char (point-min))
|
2019-06-12 16:48:33 -07:00
|
|
|
|
(should (string-match match (buffer-string))))
|
2019-06-12 15:59:19 +02:00
|
|
|
|
;; And that it's gone now.
|
|
|
|
|
(with-current-buffer byte-compile-log-buffer
|
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(erase-buffer)))
|
|
|
|
|
(test-byte-comp-compile-and-load t
|
|
|
|
|
`(with-suppressed-warnings ,suppress
|
|
|
|
|
,form))
|
|
|
|
|
(with-current-buffer byte-compile-log-buffer
|
|
|
|
|
(goto-char (point-min))
|
2019-06-12 16:48:33 -07:00
|
|
|
|
(should-not (string-match match (buffer-string))))
|
2019-06-12 15:59:19 +02:00
|
|
|
|
;; Also check that byte compiled forms are identical.
|
|
|
|
|
(should (equal (byte-compile form)
|
|
|
|
|
(byte-compile
|
|
|
|
|
`(with-suppressed-warnings ,suppress ,form))))))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-test--with-suppressed-warnings ()
|
|
|
|
|
(test-suppression
|
|
|
|
|
'(defvar prefixless)
|
|
|
|
|
'((lexical prefixless))
|
|
|
|
|
"global/dynamic var .prefixless. lacks")
|
|
|
|
|
|
2022-06-06 10:47:42 +02:00
|
|
|
|
;; FIXME: These messages cannot be suppressed reliably right now,
|
|
|
|
|
;; but attempting mutate `nil' or `5' is a rather daft thing to do
|
|
|
|
|
;; in the first place. Preventing mutation of constants such as
|
|
|
|
|
;; `most-positive-fixnum' makes more sense but the compiler doesn't
|
|
|
|
|
;; warn about that at all right now (it's caught at runtime, and we
|
|
|
|
|
;; allow writing the same value).
|
|
|
|
|
;;
|
|
|
|
|
;; (test-suppression
|
|
|
|
|
;; '(defun foo()
|
|
|
|
|
;; (let ((nil t))
|
|
|
|
|
;; (message-mail)))
|
|
|
|
|
;; '((constants nil))
|
|
|
|
|
;; "Warning: attempt to let-bind constant .nil.")
|
2019-06-12 15:59:19 +02:00
|
|
|
|
|
|
|
|
|
(test-suppression
|
|
|
|
|
'(progn
|
|
|
|
|
(defun obsolete ()
|
|
|
|
|
(declare (obsolete foo "22.1")))
|
|
|
|
|
(defun zot ()
|
|
|
|
|
(obsolete)))
|
|
|
|
|
'((obsolete obsolete))
|
|
|
|
|
"Warning: .obsolete. is an obsolete function")
|
|
|
|
|
|
|
|
|
|
(test-suppression
|
|
|
|
|
'(progn
|
|
|
|
|
(defun wrong-params (foo &optional unused)
|
|
|
|
|
(ignore unused)
|
|
|
|
|
foo)
|
|
|
|
|
(defun zot ()
|
|
|
|
|
(wrong-params 1 2 3)))
|
|
|
|
|
'((callargs wrong-params))
|
2022-05-22 20:16:01 +02:00
|
|
|
|
"Warning: .wrong-params. called with")
|
2019-06-12 15:59:19 +02:00
|
|
|
|
|
|
|
|
|
(test-byte-comp-compile-and-load nil
|
|
|
|
|
(defvar obsolete-variable nil)
|
|
|
|
|
(make-obsolete-variable 'obsolete-variable nil "24.1"))
|
|
|
|
|
(test-suppression
|
|
|
|
|
'(defun zot ()
|
|
|
|
|
obsolete-variable)
|
|
|
|
|
'((obsolete obsolete-variable))
|
|
|
|
|
"obsolete")
|
|
|
|
|
|
2020-11-22 03:24:26 +01:00
|
|
|
|
(test-suppression
|
|
|
|
|
'(defun zot ()
|
|
|
|
|
(next-line))
|
|
|
|
|
'((interactive-only next-line))
|
|
|
|
|
"interactive use only")
|
|
|
|
|
|
2019-06-12 15:59:19 +02:00
|
|
|
|
(test-suppression
|
|
|
|
|
'(defun zot ()
|
|
|
|
|
(mapcar #'list '(1 2 3))
|
|
|
|
|
nil)
|
|
|
|
|
'((mapcar mapcar))
|
|
|
|
|
"Warning: .mapcar. called for effect")
|
|
|
|
|
|
|
|
|
|
(test-suppression
|
|
|
|
|
'(defun zot ()
|
|
|
|
|
free-variable)
|
|
|
|
|
'((free-vars free-variable))
|
|
|
|
|
"Warning: reference to free variable")
|
|
|
|
|
|
|
|
|
|
(test-suppression
|
|
|
|
|
'(defun zot ()
|
|
|
|
|
(save-excursion
|
|
|
|
|
(set-buffer (get-buffer-create "foo"))
|
|
|
|
|
nil))
|
|
|
|
|
'((suspicious set-buffer))
|
|
|
|
|
"Warning: Use .with-current-buffer. rather than"))
|
|
|
|
|
|
2020-12-13 17:13:50 +01:00
|
|
|
|
(ert-deftest bytecomp-tests--not-writable-directory ()
|
|
|
|
|
"Test that byte compilation works if the output directory isn't
|
|
|
|
|
writable (Bug#44631)."
|
2021-11-08 01:21:06 +01:00
|
|
|
|
(ert-with-temp-directory directory
|
|
|
|
|
(let* ((input-file (expand-file-name "test.el" directory))
|
|
|
|
|
(output-file (expand-file-name "test.elc" directory))
|
|
|
|
|
(byte-compile-dest-file-function
|
|
|
|
|
(lambda (_) output-file))
|
|
|
|
|
(byte-compile-error-on-warn t))
|
2021-11-09 05:28:48 +01:00
|
|
|
|
(unwind-protect
|
|
|
|
|
(progn
|
|
|
|
|
(write-region "" nil input-file nil nil nil 'excl)
|
|
|
|
|
(write-region "" nil output-file nil nil nil 'excl)
|
|
|
|
|
(set-file-modes input-file #o400)
|
|
|
|
|
(set-file-modes output-file #o200)
|
|
|
|
|
(set-file-modes directory #o500)
|
|
|
|
|
(should (byte-compile-file input-file))
|
|
|
|
|
(should (file-regular-p output-file))
|
|
|
|
|
(should (cl-plusp (file-attribute-size
|
|
|
|
|
(file-attributes output-file)))))
|
|
|
|
|
;; Allow the directory to be deleted.
|
|
|
|
|
(set-file-modes directory #o777)))))
|
2020-12-13 17:13:50 +01:00
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-tests--dest-mountpoint ()
|
|
|
|
|
"Test that byte compilation works if the destination file is a
|
|
|
|
|
mountpoint (Bug#44631)."
|
|
|
|
|
(let ((bwrap (executable-find "bwrap"))
|
|
|
|
|
(emacs (expand-file-name invocation-name invocation-directory)))
|
|
|
|
|
(skip-unless bwrap)
|
|
|
|
|
(skip-unless (file-executable-p bwrap))
|
|
|
|
|
(skip-unless (not (file-remote-p bwrap)))
|
|
|
|
|
(skip-unless (file-executable-p emacs))
|
|
|
|
|
(skip-unless (not (file-remote-p emacs)))
|
2021-11-08 01:21:06 +01:00
|
|
|
|
(ert-with-temp-directory directory
|
|
|
|
|
(let* ((input-file (expand-file-name "test.el" directory))
|
|
|
|
|
(output-file (expand-file-name "test.elc" directory))
|
|
|
|
|
(unquoted-file (file-name-unquote output-file))
|
|
|
|
|
(byte-compile-dest-file-function
|
|
|
|
|
(lambda (_) output-file))
|
|
|
|
|
(byte-compile-error-on-warn t))
|
|
|
|
|
(should-not (file-remote-p input-file))
|
|
|
|
|
(should-not (file-remote-p output-file))
|
|
|
|
|
(write-region "" nil input-file nil nil nil 'excl)
|
|
|
|
|
(write-region "" nil output-file nil nil nil 'excl)
|
2021-11-09 05:28:48 +01:00
|
|
|
|
(unwind-protect
|
|
|
|
|
(progn
|
|
|
|
|
(set-file-modes input-file #o400)
|
|
|
|
|
(set-file-modes output-file #o200)
|
|
|
|
|
(set-file-modes directory #o500)
|
|
|
|
|
(with-temp-buffer
|
|
|
|
|
(let ((status (call-process
|
|
|
|
|
bwrap nil t nil
|
|
|
|
|
"--ro-bind" "/" "/"
|
|
|
|
|
"--bind" unquoted-file unquoted-file
|
|
|
|
|
emacs "--quick" "--batch" "--load=bytecomp"
|
|
|
|
|
(format "--eval=%S"
|
|
|
|
|
`(setq byte-compile-dest-file-function
|
|
|
|
|
(lambda (_) ,output-file)
|
|
|
|
|
byte-compile-error-on-warn t))
|
|
|
|
|
"--funcall=batch-byte-compile" input-file)))
|
|
|
|
|
(unless (eql status 0)
|
|
|
|
|
(ert-fail `((status . ,status)
|
|
|
|
|
(output . ,(buffer-string)))))))
|
|
|
|
|
(should (file-regular-p output-file))
|
|
|
|
|
(should (cl-plusp (file-attribute-size
|
|
|
|
|
(file-attributes output-file)))))
|
|
|
|
|
;; Allow the directory to be deleted.
|
|
|
|
|
(set-file-modes directory #o777))))))
|
2020-12-13 17:13:50 +01:00
|
|
|
|
|
2020-12-17 12:06:15 +01:00
|
|
|
|
(ert-deftest bytecomp-tests--target-file-no-directory ()
|
|
|
|
|
"Check that Bug#45287 is fixed."
|
2021-11-08 01:21:06 +01:00
|
|
|
|
(ert-with-temp-directory directory
|
|
|
|
|
(let* ((default-directory directory)
|
|
|
|
|
(byte-compile-dest-file-function (lambda (_) "test.elc"))
|
|
|
|
|
(byte-compile-error-on-warn t))
|
|
|
|
|
(write-region "" nil "test.el" nil nil nil 'excl)
|
|
|
|
|
(should (byte-compile-file "test.el"))
|
|
|
|
|
(should (file-regular-p "test.elc"))
|
|
|
|
|
(should (cl-plusp (file-attribute-size
|
|
|
|
|
(file-attributes "test.elc")))))))
|
2020-12-17 12:06:15 +01:00
|
|
|
|
|
2021-02-10 14:26:49 +01:00
|
|
|
|
(defun bytecomp-tests--get-vars ()
|
|
|
|
|
(list (ignore-errors (symbol-value 'bytecomp-tests--var1))
|
|
|
|
|
(ignore-errors (symbol-value 'bytecomp-tests--var2))))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-local-defvar ()
|
|
|
|
|
"Check that local `defvar' declarations work correctly, both
|
|
|
|
|
interpreted and compiled."
|
|
|
|
|
(let ((lexical-binding t))
|
|
|
|
|
(let ((fun '(lambda ()
|
|
|
|
|
(defvar bytecomp-tests--var1)
|
|
|
|
|
(let ((bytecomp-tests--var1 'a) ; dynamic
|
|
|
|
|
(bytecomp-tests--var2 'b)) ; still lexical
|
|
|
|
|
(ignore bytecomp-tests--var2) ; avoid warning
|
|
|
|
|
(bytecomp-tests--get-vars)))))
|
|
|
|
|
(should (listp fun)) ; Guard against overzealous refactoring!
|
|
|
|
|
(should (equal (funcall (eval fun t)) '(a nil)))
|
|
|
|
|
(should (equal (funcall (byte-compile fun)) '(a nil)))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
;; `progn' does not constitute a lexical scope for `defvar' (bug#46387).
|
|
|
|
|
(let ((fun '(lambda ()
|
|
|
|
|
(progn
|
|
|
|
|
(defvar bytecomp-tests--var1)
|
|
|
|
|
(defvar bytecomp-tests--var2))
|
|
|
|
|
(let ((bytecomp-tests--var1 'c)
|
|
|
|
|
(bytecomp-tests--var2 'd))
|
|
|
|
|
(bytecomp-tests--get-vars)))))
|
|
|
|
|
(should (listp fun))
|
|
|
|
|
(should (equal (funcall (eval fun t)) '(c d)))
|
|
|
|
|
(should (equal (funcall (byte-compile fun)) '(c d))))))
|
|
|
|
|
|
2021-02-28 19:43:09 +00:00
|
|
|
|
(ert-deftest bytecomp-reify-function ()
|
|
|
|
|
"Check that closures that modify their bound variables are
|
|
|
|
|
compiled correctly."
|
|
|
|
|
(cl-letf ((lexical-binding t)
|
|
|
|
|
((symbol-function 'counter) nil))
|
|
|
|
|
(let ((x 0))
|
|
|
|
|
(defun counter () (cl-incf x))
|
|
|
|
|
(should (equal (counter) 1))
|
|
|
|
|
(should (equal (counter) 2))
|
|
|
|
|
;; byte compiling should not cause counter to always return the
|
|
|
|
|
;; same value (bug#46834)
|
|
|
|
|
(byte-compile 'counter)
|
|
|
|
|
(should (equal (counter) 3))
|
|
|
|
|
(should (equal (counter) 4)))
|
|
|
|
|
(let ((x 0))
|
|
|
|
|
(let ((x 1))
|
|
|
|
|
(defun counter () x)
|
|
|
|
|
(should (equal (counter) 1))
|
|
|
|
|
;; byte compiling should not cause the outer binding to shadow
|
|
|
|
|
;; the inner one (bug#46834)
|
|
|
|
|
(byte-compile 'counter)
|
|
|
|
|
(should (equal (counter) 1))))))
|
|
|
|
|
|
2021-03-09 11:04:03 -05:00
|
|
|
|
(ert-deftest bytecomp-string-vs-docstring ()
|
|
|
|
|
;; Don't confuse a string return value for a docstring.
|
|
|
|
|
(let ((lexical-binding t))
|
|
|
|
|
(should (equal (funcall (byte-compile '(lambda (x) "foo")) 'dummy) "foo"))))
|
|
|
|
|
|
2021-04-07 11:31:07 +02:00
|
|
|
|
(ert-deftest bytecomp-condition-case-success ()
|
|
|
|
|
;; No error, no success handler.
|
|
|
|
|
(should (equal (condition-case x
|
|
|
|
|
(list 42)
|
|
|
|
|
(error (cons 'bad x)))
|
|
|
|
|
'(42)))
|
|
|
|
|
;; Error, no success handler.
|
|
|
|
|
(should (equal (condition-case x
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(error (cons 'bad x)))
|
|
|
|
|
'(bad arith-error)))
|
|
|
|
|
;; No error, success handler.
|
|
|
|
|
(should (equal (condition-case x
|
|
|
|
|
(list 42)
|
|
|
|
|
(error (cons 'bad x))
|
|
|
|
|
(:success (cons 'good x)))
|
|
|
|
|
'(good 42)))
|
|
|
|
|
;; Error, success handler.
|
|
|
|
|
(should (equal (condition-case x
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(error (cons 'bad x))
|
|
|
|
|
(:success (cons 'good x)))
|
|
|
|
|
'(bad arith-error)))
|
|
|
|
|
;; Verify that the success code is not subject to the error handlers.
|
|
|
|
|
(should-error (condition-case x
|
|
|
|
|
(list 42)
|
|
|
|
|
(error (cons 'bad x))
|
|
|
|
|
(:success (/ (car x) 0)))
|
|
|
|
|
:type 'arith-error)
|
|
|
|
|
;; Check variable scoping.
|
|
|
|
|
(let ((x 2))
|
|
|
|
|
(should (equal (condition-case x
|
|
|
|
|
(list x)
|
|
|
|
|
(error (list 'bad x))
|
|
|
|
|
(:success (list 'good x)))
|
|
|
|
|
'(good (2))))
|
|
|
|
|
(should (equal (condition-case x
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(error (list 'bad x))
|
|
|
|
|
(:success (list 'good x)))
|
|
|
|
|
'(bad (arith-error)))))
|
|
|
|
|
;; Check capture of mutated result variable.
|
|
|
|
|
(should (equal (funcall
|
|
|
|
|
(condition-case x
|
|
|
|
|
3
|
|
|
|
|
(:success (prog1 (lambda (y) (+ y x))
|
|
|
|
|
(setq x 10))))
|
|
|
|
|
4)
|
|
|
|
|
14))
|
|
|
|
|
;; Check for-effect context, on error.
|
|
|
|
|
(should (equal (let ((f (lambda (x)
|
|
|
|
|
(condition-case nil
|
|
|
|
|
(/ 1 0)
|
|
|
|
|
(error 'bad)
|
|
|
|
|
(:success 'good))
|
|
|
|
|
(1+ x))))
|
|
|
|
|
(funcall f 3))
|
|
|
|
|
4))
|
|
|
|
|
;; Check for-effect context, on success.
|
|
|
|
|
(should (equal (let ((f (lambda (x)
|
|
|
|
|
(condition-case nil
|
|
|
|
|
nil
|
|
|
|
|
(error 'bad)
|
|
|
|
|
(:success 'good))
|
|
|
|
|
(1+ x))))
|
|
|
|
|
(funcall f 3))
|
|
|
|
|
4)))
|
|
|
|
|
|
2021-05-27 14:03:14 +02:00
|
|
|
|
(declare-function bc-test-alpha-f (ert-resource-file "bc-test-alpha.el"))
|
|
|
|
|
|
|
|
|
|
(ert-deftest bytecomp-defsubst ()
|
|
|
|
|
;; Check that lexical variables don't leak into inlined code. See
|
|
|
|
|
;; https://lists.gnu.org/archive/html/emacs-devel/2021-05/msg01227.html
|
|
|
|
|
|
|
|
|
|
;; First, remove any trace of the functions and package defined:
|
|
|
|
|
(fmakunbound 'bc-test-alpha-f)
|
|
|
|
|
(fmakunbound 'bc-test-beta-f)
|
|
|
|
|
(setq features (delq 'bc-test-beta features))
|
|
|
|
|
;; Byte-compile one file that uses a function from another file that isn't
|
|
|
|
|
;; compiled.
|
|
|
|
|
(let ((file (ert-resource-file "bc-test-alpha.el"))
|
|
|
|
|
(load-path (cons (ert-resource-directory) load-path)))
|
|
|
|
|
(byte-compile-file file)
|
|
|
|
|
(load-file (concat file "c"))
|
|
|
|
|
(should (equal (bc-test-alpha-f 'a) '(nil a)))))
|
|
|
|
|
|
2021-09-24 17:45:37 +02:00
|
|
|
|
(ert-deftest bytecomp-tests-byte-compile--wide-docstring-p/func-arg-list ()
|
|
|
|
|
(should-not (byte-compile--wide-docstring-p "\
|
|
|
|
|
\(dbus-register-property BUS SERVICE PATH INTERFACE PROPERTY ACCESS \
|
|
|
|
|
[TYPE] VALUE &optional EMITS-SIGNAL DONT-REGISTER-SERVICE)" fill-column))
|
|
|
|
|
(should-not (byte-compile--wide-docstring-p "\
|
|
|
|
|
(fn CMD FLAGS FIS &key (BUF (cvs-temp-buffer)) DONT-CHANGE-DISC CVSARGS \
|
|
|
|
|
POSTPROC)" fill-column))
|
|
|
|
|
;; Bug#49007
|
|
|
|
|
(should-not (byte-compile--wide-docstring-p "\
|
|
|
|
|
(fn (THIS rudel-protocol-backend) TRANSPORT \
|
|
|
|
|
INFO INFO-CALLBACK &optional PROGRESS-CALLBACK)" fill-column))
|
|
|
|
|
(should-not (byte-compile--wide-docstring-p "\
|
|
|
|
|
\(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] \
|
|
|
|
|
[:tags \\='(TAG...)] BODY...)" fill-column))
|
|
|
|
|
(should-not (byte-compile--wide-docstring-p "\
|
2021-09-30 17:08:46 +02:00
|
|
|
|
(make-soap-xs-element &key NAME NAMESPACE-TAG ID TYPE^ OPTIONAL? MULTIPLE? \
|
2021-09-24 17:45:37 +02:00
|
|
|
|
REFERENCE SUBSTITUTION-GROUP ALTERNATIVES IS-GROUP)" fill-column))
|
|
|
|
|
(should-not (byte-compile--wide-docstring-p "\
|
|
|
|
|
(fn NAME FIXTURE INPUT &key SKIP-PAIR-STRING EXPECTED-STRING \
|
|
|
|
|
EXPECTED-POINT BINDINGS (MODES \\='\\='(ruby-mode js-mode python-mode)) \
|
|
|
|
|
(TEST-IN-COMMENTS t) (TEST-IN-STRINGS t) (TEST-IN-CODE t) \
|
|
|
|
|
(FIXTURE-FN \\='#\\='electric-pair-mode))" fill-column)))
|
|
|
|
|
|
2022-05-11 12:51:11 +02:00
|
|
|
|
(defun test-bytecomp-defgroup-choice ()
|
|
|
|
|
(should-not (byte-compile--suspicious-defcustom-choice 'integer))
|
|
|
|
|
(should-not (byte-compile--suspicious-defcustom-choice
|
|
|
|
|
'(choice (const :tag "foo" bar))))
|
|
|
|
|
(should (byte-compile--suspicious-defcustom-choice
|
|
|
|
|
'(choice (const :tag "foo" 'bar)))))
|
2021-09-24 17:45:37 +02:00
|
|
|
|
|
2022-06-08 10:03:55 +02:00
|
|
|
|
(ert-deftest bytecomp-function-attributes ()
|
|
|
|
|
;; Check that `byte-compile' keeps the declarations, interactive spec and
|
|
|
|
|
;; doc string of the function (bug#55830).
|
|
|
|
|
(let ((fname 'bytecomp-test-fun))
|
|
|
|
|
(fset fname nil)
|
|
|
|
|
(put fname 'pure nil)
|
|
|
|
|
(put fname 'lisp-indent-function nil)
|
|
|
|
|
(eval `(defun ,fname (x)
|
|
|
|
|
"tata"
|
|
|
|
|
(declare (pure t) (indent 1))
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(list 'toto x))
|
|
|
|
|
t)
|
|
|
|
|
(let ((bc (byte-compile fname)))
|
|
|
|
|
(should (byte-code-function-p bc))
|
|
|
|
|
(should (equal (funcall bc 'titi) '(toto titi)))
|
|
|
|
|
(should (equal (aref bc 5) "P"))
|
|
|
|
|
(should (equal (get fname 'pure) t))
|
|
|
|
|
(should (equal (get fname 'lisp-indent-function) 1))
|
|
|
|
|
(should (equal (aref bc 4) "tata\n\n(fn X)")))))
|
|
|
|
|
|
2022-06-17 17:06:05 +02:00
|
|
|
|
(ert-deftest bytecomp-fun-attr-warn ()
|
|
|
|
|
;; Check that warnings are emitted when doc strings, `declare' and
|
|
|
|
|
;; `interactive' forms don't come in the proper order, or more than once.
|
|
|
|
|
(let* ((filename "fun-attr-warn.el")
|
|
|
|
|
(el (ert-resource-file filename))
|
|
|
|
|
(elc (concat el "c"))
|
|
|
|
|
(text-quoting-style 'grave))
|
|
|
|
|
(with-current-buffer (get-buffer-create "*Compile-Log*")
|
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(erase-buffer))
|
|
|
|
|
(byte-compile-file el)
|
|
|
|
|
(let ((expected
|
|
|
|
|
'("70:4: Warning: `declare' after `interactive'"
|
|
|
|
|
"74:4: Warning: Doc string after `interactive'"
|
|
|
|
|
"79:4: Warning: Doc string after `interactive'"
|
|
|
|
|
"84:4: Warning: Doc string after `declare'"
|
|
|
|
|
"89:4: Warning: Doc string after `declare'"
|
|
|
|
|
"96:4: Warning: `declare' after `interactive'"
|
|
|
|
|
"102:4: Warning: `declare' after `interactive'"
|
|
|
|
|
"108:4: Warning: `declare' after `interactive'"
|
|
|
|
|
"106:4: Warning: Doc string after `interactive'"
|
|
|
|
|
"114:4: Warning: `declare' after `interactive'"
|
|
|
|
|
"112:4: Warning: Doc string after `interactive'"
|
|
|
|
|
"118:4: Warning: Doc string after `interactive'"
|
|
|
|
|
"119:4: Warning: `declare' after `interactive'"
|
|
|
|
|
"124:4: Warning: Doc string after `interactive'"
|
|
|
|
|
"125:4: Warning: `declare' after `interactive'"
|
|
|
|
|
"130:4: Warning: Doc string after `declare'"
|
|
|
|
|
"136:4: Warning: Doc string after `declare'"
|
|
|
|
|
"142:4: Warning: Doc string after `declare'"
|
|
|
|
|
"148:4: Warning: Doc string after `declare'"
|
|
|
|
|
"159:4: Warning: More than one doc string"
|
|
|
|
|
"165:4: Warning: More than one doc string"
|
|
|
|
|
"171:4: Warning: More than one doc string"
|
|
|
|
|
"178:4: Warning: More than one doc string"
|
|
|
|
|
"186:4: Warning: More than one doc string"
|
|
|
|
|
"192:4: Warning: More than one doc string"
|
|
|
|
|
"200:4: Warning: More than one doc string"
|
|
|
|
|
"206:4: Warning: More than one doc string"
|
|
|
|
|
"215:4: Warning: More than one `declare' form"
|
|
|
|
|
"222:4: Warning: More than one `declare' form"
|
|
|
|
|
"230:4: Warning: More than one `declare' form"
|
|
|
|
|
"237:4: Warning: More than one `declare' form"
|
|
|
|
|
"244:4: Warning: More than one `interactive' form"
|
|
|
|
|
"251:4: Warning: More than one `interactive' form"
|
|
|
|
|
"258:4: Warning: More than one `interactive' form"
|
|
|
|
|
"257:4: Warning: `declare' after `interactive'"
|
|
|
|
|
"265:4: Warning: More than one `interactive' form"
|
|
|
|
|
"264:4: Warning: `declare' after `interactive'")))
|
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
(let ((actual nil))
|
|
|
|
|
(while (re-search-forward
|
|
|
|
|
(rx bol (* (not ":")) ":"
|
|
|
|
|
(group (+ digit) ":" (+ digit) ": Warning: "
|
|
|
|
|
(or "More than one " (+ nonl) " form"
|
|
|
|
|
(: (+ nonl) " after " (+ nonl))))
|
|
|
|
|
eol)
|
|
|
|
|
nil t)
|
|
|
|
|
(push (match-string 1) actual))
|
|
|
|
|
(setq actual (nreverse actual))
|
|
|
|
|
(should (equal actual expected)))))))
|
|
|
|
|
|
2022-06-21 19:10:14 +02:00
|
|
|
|
(ert-deftest byte-compile-file/no-byte-compile ()
|
|
|
|
|
(let* ((src-file (ert-resource-file "no-byte-compile.el"))
|
|
|
|
|
(dest-file (make-temp-file "bytecomp-tests-" nil ".elc"))
|
|
|
|
|
(byte-compile-dest-file-function (lambda (_) dest-file)))
|
|
|
|
|
(should (eq (byte-compile-file src-file) 'no-byte-compile))
|
|
|
|
|
(should-not (file-exists-p dest-file))))
|
|
|
|
|
|
2022-06-17 17:06:05 +02:00
|
|
|
|
|
2011-02-14 16:21:42 -05:00
|
|
|
|
;; Local Variables:
|
|
|
|
|
;; no-byte-compile: t
|
|
|
|
|
;; End:
|
2008-11-30 05:57:33 +00:00
|
|
|
|
|
2016-09-24 12:01:44 +03:00
|
|
|
|
(provide 'bytecomp-tests)
|
2021-09-26 01:53:56 +02:00
|
|
|
|
;;; bytecomp-tests.el ends here
|