summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/bytecomp.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp/bytecomp.el')
-rw-r--r--lisp/emacs-lisp/bytecomp.el78
1 files changed, 66 insertions, 12 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 966990bac96..cbda16d051b 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -268,6 +268,13 @@ This option is enabled by default because it reduces Emacs memory usage."
(defconst byte-compile-log-buffer "*Compile-Log*"
"Name of the byte-compiler's log buffer.")
+(defvar byte-compile--known-dynamic-vars nil
+ "Variables known to be declared as dynamic, for warning purposes.
+Each element is (VAR . FILE), indicating that VAR is declared in FILE.")
+
+(defvar byte-compile--seen-defvars nil
+ "All dynamic variable declarations seen so far.")
+
(defcustom byte-optimize-log nil
"If non-nil, the byte-compiler will log its optimizations.
If this is `source', then only source-level optimizations will be logged.
@@ -284,13 +291,13 @@ The information is logged to `byte-compile-log-buffer'."
;; This needs to be autoloaded because it needs to be available to
;; Emacs before the byte compiler is loaded, otherwise Emacs will not
;; know that this variable is marked as safe until it is too late.
-;; (See https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00261.html )
+;; (See https://lists.gnu.org/r/emacs-devel/2018-01/msg00261.html )
;;;###autoload(put 'byte-compile-error-on-warn 'safe-local-variable 'booleanp)
(defconst byte-compile-warning-types
'(redefine callargs free-vars unresolved
obsolete noruntime cl-functions interactive-only
- make-local mapcar constants suspicious lexical)
+ make-local mapcar constants suspicious lexical lexical-dynamic)
"The list of warning types used when `byte-compile-warnings' is t.")
(defcustom byte-compile-warnings t
"List of warnings that the byte-compiler should issue (t for all).
@@ -310,6 +317,8 @@ Elements of the list may be:
interactive-only
commands that normally shouldn't be called from Lisp code.
lexical global/dynamic variables lacking a prefix.
+ lexical-dynamic
+ lexically bound variable declared dynamic elsewhere
make-local calls to make-variable-buffer-local that may be incorrect.
mapcar mapcar called for effect.
constants let-binding of, or assignment to, constants/nonvariables.
@@ -1836,10 +1845,9 @@ compile FILENAME. If optional argument ARG is 0, it compiles
the input file even if the `.elc' file does not exist.
Any other non-nil value of ARG means to ask the user.
-If optional argument LOAD is non-nil, loads the file after compiling.
-
If compilation is needed, this functions returns the result of
`byte-compile-file'; otherwise it returns `no-byte-compile'."
+ (declare (advertised-calling-convention (filename &optional force arg) "28.1"))
(interactive
(let ((file buffer-file-name)
(file-name nil)
@@ -1868,11 +1876,24 @@ If compilation is needed, this functions returns the result of
(progn
(if (and noninteractive (not byte-compile-verbose))
(message "Compiling %s..." filename))
- (byte-compile-file filename load))
+ (byte-compile-file filename)
+ (when load
+ (load (if (file-exists-p dest) dest filename))))
(when load
(load (if (file-exists-p dest) dest filename)))
'no-byte-compile)))
+(defun byte-compile--load-dynvars (file)
+ (and file (not (equal file ""))
+ (with-temp-buffer
+ (insert-file-contents file)
+ (goto-char (point-min))
+ (let ((vars nil)
+ var)
+ (while (ignore-errors (setq var (read (current-buffer))))
+ (push var vars))
+ vars))))
+
(defvar byte-compile-level 0 ; bug#13787
"Depth of a recursive byte compilation.")
@@ -1881,8 +1902,10 @@ If compilation is needed, this functions returns the result of
"Compile a file of Lisp code named FILENAME into a file of byte code.
The output file's name is generated by passing FILENAME to the
function `byte-compile-dest-file' (which see).
-With prefix arg (noninteractively: 2nd arg), LOAD the file after compiling.
-The value is non-nil if there were no errors, nil if errors."
+The value is non-nil if there were no errors, nil if errors.
+
+See also `emacs-lisp-byte-compile-and-load'."
+ (declare (advertised-calling-convention (filename) "28.1"))
;; (interactive "fByte compile file: \nP")
(interactive
(let ((file buffer-file-name)
@@ -1911,8 +1934,11 @@ The value is non-nil if there were no errors, nil if errors."
(let ((byte-compile-current-file filename)
(byte-compile-current-group nil)
(set-auto-coding-for-load t)
+ (byte-compile--seen-defvars nil)
+ (byte-compile--known-dynamic-vars
+ (byte-compile--load-dynvars (getenv "EMACS_DYNVARS_FILE")))
target-file input-buffer output-buffer
- byte-compile-dest-file)
+ byte-compile-dest-file byte-compiler-error-flag)
(setq target-file (byte-compile-dest-file filename))
(setq byte-compile-dest-file target-file)
(with-current-buffer
@@ -1974,7 +2000,6 @@ The value is non-nil if there were no errors, nil if errors."
'no-byte-compile)
(when byte-compile-verbose
(message "Compiling %s..." filename))
- (setq byte-compiler-error-flag nil)
;; It is important that input-buffer not be current at this call,
;; so that the value of point set in input-buffer
;; within byte-compile-from-buffer lingers in that buffer.
@@ -2035,8 +2060,17 @@ The value is non-nil if there were no errors, nil if errors."
filename))))
(save-excursion
(display-call-tree filename)))
+ (let ((gen-dynvars (getenv "EMACS_GENERATE_DYNVARS")))
+ (when (and gen-dynvars (not (equal gen-dynvars ""))
+ byte-compile--seen-defvars)
+ (let ((dynvar-file (concat target-file ".dynvars")))
+ (message "Generating %s" dynvar-file)
+ (with-temp-buffer
+ (dolist (var (delete-dups byte-compile--seen-defvars))
+ (insert (format "%S\n" (cons var filename))))
+ (write-region (point-min) (point-max) dynvar-file)))))
(if load
- (load target-file))
+ (load target-file))
t))))
;;; compiling a single function
@@ -2425,7 +2459,8 @@ list that represents a doc string reference.
(setq byte-compile-lexical-variables
(delq sym byte-compile-lexical-variables))
(byte-compile-warn "Variable `%S' declared after its first use" sym))
- (push sym byte-compile-bound-variables))
+ (push sym byte-compile-bound-variables)
+ (push sym byte-compile--seen-defvars))
(defun byte-compile-file-form-defvar (form)
(let ((sym (nth 1 form)))
@@ -2831,6 +2866,16 @@ If FORM is a lambda or a macro, byte-compile it as a function."
(ash nonrest 8)
(ash rest 7)))))
+(defun byte-compile--warn-lexical-dynamic (var context)
+ (when (byte-compile-warning-enabled-p 'lexical-dynamic var)
+ (byte-compile-warn
+ "`%s' lexically bound in %s here but declared dynamic in: %s"
+ var context
+ (mapconcat #'identity
+ (mapcan (lambda (v) (and (eq var (car v))
+ (list (cdr v))))
+ byte-compile--known-dynamic-vars)
+ ", "))))
(defun byte-compile-lambda (fun &optional add-lambda reserved-csts)
"Byte-compile a lambda-expression and return a valid function.
@@ -2859,6 +2904,10 @@ for symbols generated by the byte compiler itself."
(if (cdr body)
(setq body (cdr body))))))
(int (assq 'interactive body)))
+ (when lexical-binding
+ (dolist (var arglistvars)
+ (when (assq var byte-compile--known-dynamic-vars)
+ (byte-compile--warn-lexical-dynamic var 'lambda))))
;; Process the interactive spec.
(when int
(byte-compile-set-symbol-position 'interactive)
@@ -3174,7 +3223,8 @@ for symbols generated by the byte compiler itself."
(t "."))))
(if (eq (car-safe (symbol-function (car form))) 'macro)
(byte-compile-report-error
- (format "Forgot to expand macro %s in %S" (car form) form)))
+ (format "`%s' defined after use in %S (missing `require' of a library file?)"
+ (car form) form)))
(if (and handler
;; Make sure that function exists.
(and (functionp handler)
@@ -4378,6 +4428,8 @@ Return non-nil if the TOS value was popped."
;; VAR is a simple stack-allocated lexical variable.
(progn (push (assq var init-lexenv)
byte-compile--lexical-environment)
+ (when (assq var byte-compile--known-dynamic-vars)
+ (byte-compile--warn-lexical-dynamic var 'let))
nil)
;; VAR should be dynamically bound.
(while (assq var byte-compile--lexical-environment)
@@ -5206,6 +5258,8 @@ and corresponding effects."
byte-compile-variable-ref))))
nil)
+(make-obsolete-variable 'bytecomp-load-hook
+ "use `with-eval-after-load' instead." "28.1")
(run-hooks 'bytecomp-load-hook)
;;; bytecomp.el ends here