diff options
Diffstat (limited to 'lisp/emacs-lisp/bytecomp.el')
-rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 708 |
1 files changed, 397 insertions, 311 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 9273626c805..905d99a5971 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -124,17 +124,11 @@ (require 'backquote) (require 'macroexp) (require 'cconv) -(require 'cl-lib) - -;; During bootstrap, cl-loaddefs.el is not created yet, so loading cl-lib -;; doesn't setup autoloads for things like cl-every, which is why we have to -;; require cl-extra as well (bug#18804). -(or (fboundp 'cl-every) - (require 'cl-extra)) - -(or (fboundp 'defsubst) - ;; This really ought to be loaded already! - (load "byte-run")) +(eval-when-compile (require 'compile)) +;; Refrain from using cl-lib at run-time here, since it otherwise prevents +;; us from emitting warnings when compiling files which use cl-lib without +;; requiring it! (bug#30635) +(eval-when-compile (require 'cl-lib)) ;; The feature of compiling in a specific target Emacs version ;; has been turned off because compile time options are a bad idea. @@ -148,7 +142,6 @@ If you change this, you might want to set `byte-compile-dest-file-function'. \(Note that the assumption of a \".elc\" suffix for compiled files is hard-coded in various places in Emacs.)" ;; Eg is_elc in Fload. - :group 'bytecomp :type 'regexp) (defcustom byte-compile-dest-file-function nil @@ -158,7 +151,6 @@ file name, and return the name of the compiled file. \(Note that the assumption that the source and compiled files are found in the same directory is hard-coded in various places in Emacs.)" ;; Eg load-prefer-newer, documentation lookup IIRC. - :group 'bytecomp :type '(choice (const nil) function) :version "23.2") @@ -212,7 +204,6 @@ otherwise adds \".elc\"." (defcustom byte-compile-verbose (and (not noninteractive) (> baud-rate search-slow-speed)) "Non-nil means print messages describing progress of byte-compiler." - :group 'bytecomp :type 'boolean) (defcustom byte-optimize t @@ -222,7 +213,6 @@ Possible values are: t - all optimizations `source' - source-level optimizations only `byte' - code-level optimizations only" - :group 'bytecomp :type '(choice (const :tag "none" nil) (const :tag "all" t) (const :tag "source-level" source) @@ -231,13 +221,11 @@ Possible values are: (defcustom byte-compile-delete-errors nil "If non-nil, the optimizer may delete forms that may signal an error. This includes variable references and calls to functions such as `car'." - :group 'bytecomp :type 'boolean) -(defcustom byte-compile-cond-use-jump-table nil +(defcustom byte-compile-cond-use-jump-table t "Compile `cond' clauses to a jump table implementation (using a hash-table)." - :version "26.3" ;; Disabled due to Bug#35770. - :group 'bytecomp + :version "26.1" :type 'boolean) (defvar byte-compile-dynamic nil @@ -252,6 +240,7 @@ For example, add -*-byte-compile-dynamic: t;-*- on the first line. When this option is true, if you load the compiled file and then move it, the functions you loaded will not be able to run.") +(make-obsolete-variable 'byte-compile-dynamic "not worthwhile any more." "27.1") ;;;###autoload(put 'byte-compile-dynamic 'safe-local-variable 'booleanp) (defvar byte-compile-disable-print-circle nil @@ -273,7 +262,6 @@ in the source file. For example, add this to the first line: You can also set the variable globally. This option is enabled by default because it reduces Emacs memory usage." - :group 'bytecomp :type 'boolean) ;;;###autoload(put 'byte-compile-dynamic-docstrings 'safe-local-variable 'booleanp) @@ -285,7 +273,6 @@ This option is enabled by default because it reduces Emacs memory usage." If this is `source', then only source-level optimizations will be logged. If it is `byte', then only byte-level optimizations will be logged. The information is logged to `byte-compile-log-buffer'." - :group 'bytecomp :type '(choice (const :tag "none" nil) (const :tag "all" t) (const :tag "source-level" source) @@ -293,7 +280,6 @@ The information is logged to `byte-compile-log-buffer'." (defcustom byte-compile-error-on-warn nil "If true, the byte-compiler reports warnings with `error'." - :group 'bytecomp :type 'boolean) ;; This needs to be autoloaded because it needs to be available to ;; Emacs before the byte compiler is loaded, otherwise Emacs will not @@ -331,24 +317,32 @@ Elements of the list may be: If the list begins with `not', then the remaining elements specify warnings to suppress. For example, (not mapcar) will suppress warnings about mapcar." - :group 'bytecomp :type `(choice (const :tag "All" t) (set :menu-tag "Some" ,@(mapcar (lambda (x) `(const ,x)) byte-compile-warning-types)))) +(defvar byte-compile--suppressed-warnings nil + "Dynamically bound by `with-suppressed-warnings' to suppress warnings.") + ;;;###autoload (put 'byte-compile-warnings 'safe-local-variable (lambda (v) (or (symbolp v) (null (delq nil (mapcar (lambda (x) (not (symbolp x))) v)))))) -(defun byte-compile-warning-enabled-p (warning) +(defun byte-compile-warning-enabled-p (warning &optional symbol) "Return non-nil if WARNING is enabled, according to `byte-compile-warnings'." - (or (eq byte-compile-warnings t) - (if (eq (car byte-compile-warnings) 'not) - (not (memq warning byte-compile-warnings)) - (memq warning byte-compile-warnings)))) + (let ((suppress nil)) + (dolist (elem byte-compile--suppressed-warnings) + (when (and (eq (car elem) warning) + (memq symbol (cdr elem))) + (setq suppress t))) + (and (not suppress) + (or (eq byte-compile-warnings t) + (if (eq (car byte-compile-warnings) 'not) + (not (memq warning byte-compile-warnings)) + (memq warning byte-compile-warnings)))))) ;;;###autoload (defun byte-compile-disable-warning (warning) @@ -401,17 +395,16 @@ else the global value will be modified." "Non-nil means collect call-graph information when compiling. This records which functions were called and from where. If the value is t, compilation displays the call graph when it finishes. -If the value is neither t nor nil, compilation asks you whether to display -the graph. +If the value is neither t nor nil, compilation asks you whether to +display the graph. -The call tree only lists functions called, not macros used. Those functions -which the byte-code interpreter knows about directly (eq, cons, etc.) are -not reported. +The call tree only lists functions called, not macros used. Those +functions which the byte-code interpreter knows about directly (eq, +cons, etc.) are not reported. -The call tree also lists those functions which are not known to be called -\(that is, to which no calls have been compiled). Functions which can be -invoked interactively are excluded from this list." - :group 'bytecomp +The call tree also lists those functions which are not known to be +called (that is, to which no calls have been compiled). Functions +which can be invoked interactively are excluded from this list." :type '(choice (const :tag "Yes" t) (const :tag "No" nil) (other :tag "Ask" lambda))) @@ -429,7 +422,6 @@ FUNCTION.") "If non-nil, sort the call tree. The values `name', `callers', `calls', `calls+callers' specify different fields to sort on." - :group 'bytecomp :type '(choice (const name) (const callers) (const calls) (const calls+callers) (const nil))) @@ -508,7 +500,23 @@ Return the compile-time value of FORM." form macroexpand-all-environment))) (eval expanded lexical-binding) - expanded)))))) + expanded))))) + (with-suppressed-warnings + . ,(lambda (warnings &rest body) + ;; We let-bind `byte-compile--suppressed-warnings' here in order + ;; to affect warnings emitted during macroexpansion. + ;; Later `internal--with-suppressed-warnings' binds it again, this + ;; time in order to affect warnings emitted during the + ;; compilation itself. + (let ((byte-compile--suppressed-warnings + (append warnings byte-compile--suppressed-warnings))) + ;; This function doesn't exist, but is just a placeholder + ;; symbol to hook up with the + ;; `byte-hunk-handler'/`byte-defop-compiler-1' machinery. + `(internal--with-suppressed-warnings + ',warnings + ,(macroexpand-all `(progn ,@body) + macroexpand-all-environment)))))) "The default macro-environment passed to macroexpand by the compiler. Placing a macro here will cause a macro to have different semantics when expanded by the compiler as when expanded by the interpreter.") @@ -842,7 +850,7 @@ all the arguments. (defmacro byte-compile-push-bytecode-const2 (opcode const2 bytes pc) "Push OPCODE and the two-byte constant CONST2 onto BYTES, and add 3 to PC. CONST2 may be evaluated multiple times." - `(byte-compile-push-bytecodes ,opcode (logand ,const2 255) (lsh ,const2 -8) + `(byte-compile-push-bytecodes ,opcode (logand ,const2 255) (ash ,const2 -8) ,bytes ,pc)) (defun byte-compile-lapcode (lap) @@ -932,9 +940,9 @@ CONST2 may be evaluated multiple times." ;; Splits PC's value into 2 bytes. The jump address is ;; "reconstructed" by the `FETCH2' macro in `bytecode.c'. (setcar (cdr bytes-tail) (logand pc 255)) - (setcar bytes-tail (lsh pc -8)) + (setcar bytes-tail (ash pc -8)) ;; FIXME: Replace this by some workaround. - (if (> (car bytes-tail) 255) (error "Bytecode overflow"))) + (or (<= 0 (car bytes-tail) 255) (error "Bytecode overflow"))) ;; Similarly, replace TAGs in all jump tables with the correct PC index. (dolist (hash-table byte-compile-jump-tables) @@ -1013,6 +1021,50 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." ;;; byte compiler messages +(defun emacs-lisp-compilation-file-name-or-buffer (str) + "Return file name or buffer given by STR. +If STR is a \"normal\" filename, just return it. +If STR is something like \"Buffer foo.el\", return #<buffer foo.el> +\(if it is still live) or the string \"foo.el\" otherwise." + (if (string-match "Buffer \\(.*\\)\\'" str) + (or (get-buffer (match-string-no-properties 1 str)) + (match-string-no-properties 1 str)) + str)) + +(defconst emacs-lisp-compilation-parse-errors-filename-function + #'emacs-lisp-compilation-file-name-or-buffer + "The value for `compilation-parse-errors-filename-function' for when +we go into emacs-lisp-compilation-mode.") + +(defcustom emacs-lisp-compilation-search-path '(nil) + "Directories to search for files named in byte-compile error messages. +Value should be a list of directory names, not file names of +directories. The value nil as an element means the byte-compile +message buffer `default-directory'." + :version "27.1" + :type '(repeat (choice (const :tag "Default" nil) + (string :tag "Directory")))) + +(defvar emacs-lisp-compilation-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "g" 'emacs-lisp-compilation-recompile) + map)) + +(defvar emacs-lisp-compilation--current-file nil) + +(define-compilation-mode emacs-lisp-compilation-mode "elisp-compile" + "The variant of `compilation-mode' used for emacs-lisp compilation buffers." + (setq-local emacs-lisp-compilation--current-file nil)) + +(defun emacs-lisp-compilation-recompile () + "Recompile the previously byte-compiled file." + (interactive) + (unless emacs-lisp-compilation--current-file + (error "No previously compiled file")) + (unless (stringp emacs-lisp-compilation--current-file) + (error "Only files can be recompiled")) + (byte-compile-file emacs-lisp-compilation--current-file)) + (defvar byte-compile-current-form nil) (defvar byte-compile-dest-file nil) (defvar byte-compile-current-file nil) @@ -1172,7 +1224,7 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (with-current-buffer (get-buffer-create byte-compile-log-buffer) (goto-char (point-max)) (let* ((inhibit-read-only t) - (dir (and byte-compile-current-file + (dir (and (stringp byte-compile-current-file) (file-name-directory byte-compile-current-file))) (was-same (equal default-directory dir)) pt) @@ -1187,10 +1239,10 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (insert "\f\nCompiling " (if (stringp byte-compile-current-file) (concat "file " byte-compile-current-file) - (concat "buffer " + (concat "in buffer " (buffer-name byte-compile-current-file))) " at " (current-time-string) "\n") - (insert "\f\nCompiling no file at " (current-time-string) "\n")) + (insert "\f\nCompiling internal form(s) at " (current-time-string) "\n")) (when dir (setq default-directory dir) (unless was-same @@ -1199,7 +1251,9 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (setq byte-compile-last-logged-file byte-compile-current-file byte-compile-last-warned-form nil) ;; Do this after setting default-directory. - (unless (derived-mode-p 'compilation-mode) (compilation-mode)) + (unless (derived-mode-p 'compilation-mode) + (emacs-lisp-compilation-mode)) + (setq emacs-lisp-compilation--current-file byte-compile-current-file) (compilation-forget-errors) pt)))) @@ -1246,7 +1300,7 @@ function directly; use `byte-compile-warn' or (defun byte-compile-warn-obsolete (symbol) "Warn that SYMBOL (a variable or function) is obsolete." - (when (byte-compile-warning-enabled-p 'obsolete) + (when (byte-compile-warning-enabled-p 'obsolete symbol) (let* ((funcp (get symbol 'byte-obsolete-info)) (msg (macroexp--obsolete-warning symbol @@ -1357,7 +1411,8 @@ when printing the error message." (defun byte-compile-function-warn (f nargs def) (byte-compile-set-symbol-position f) - (when (get f 'byte-obsolete-info) + (when (and (get f 'byte-obsolete-info) + (byte-compile-warning-enabled-p 'obsolete f)) (byte-compile-warn-obsolete f)) ;; Check to see if the function will be available at runtime @@ -1561,7 +1616,10 @@ extra args." (while syms (setq s (symbol-name (pop syms)) L (+ L (length s) 2)) - (if (< L (1- fill-column)) + (if (< L (1- (buffer-local-value 'fill-column + (or (get-buffer + byte-compile-log-buffer) + (current-buffer))))) (setq str (concat str " " s (and syms ","))) (setq str (concat str "\n " s (and syms ",")) L (+ (length s) 4)))) @@ -1706,8 +1764,8 @@ that already has a `.elc' file." (with-current-buffer (get-buffer-create byte-compile-log-buffer) (setq default-directory (expand-file-name directory)) ;; compilation-mode copies value of default-directory. - (unless (eq major-mode 'compilation-mode) - (compilation-mode)) + (unless (derived-mode-p 'compilation-mode) + (emacs-lisp-compilation-mode)) (let ((directories (list default-directory)) (default-directory default-directory) (skip-count 0) @@ -1739,8 +1797,8 @@ that already has a `.elc' file." (file-name-nondirectory source)))) (progn (cl-incf (pcase (byte-recompile-file source force arg) - (`no-byte-compile skip-count) - (`t file-count) + ('no-byte-compile skip-count) + ('t file-count) (_ fail-count))) (or noninteractive (message "Checking %s..." directory)) @@ -1990,7 +2048,7 @@ With argument ARG, insert value in current buffer after the form." (save-excursion (end-of-defun) (beginning-of-defun) - (let* ((byte-compile-current-file nil) + (let* ((byte-compile-current-file (current-buffer)) (byte-compile-current-buffer (current-buffer)) (byte-compile-read-position (point)) (byte-compile-last-position byte-compile-read-position) @@ -2071,20 +2129,10 @@ With argument ARG, insert value in current buffer after the form." (not (eobp))) (setq byte-compile-read-position (point) byte-compile-last-position byte-compile-read-position) - (let* ((lread--old-style-backquotes nil) - (lread--unescaped-character-literals nil) - (form (read inbuffer))) - ;; Warn about the use of old-style backquotes. - (when lread--old-style-backquotes - (byte-compile-warn "!! The file uses old-style backquotes !! -This functionality has been obsolete for more than 10 years already -and will be removed soon. See (elisp)Backquote in the manual.")) - (when lread--unescaped-character-literals - (byte-compile-warn - "unescaped character literals %s detected!" - (mapconcat (lambda (char) (format "`?%c'" char)) - (sort lread--unescaped-character-literals #'<) - ", "))) + (let* ((lread--unescaped-character-literals nil) + (form (read inbuffer)) + (warning (byte-run--unescaped-character-literals-warning))) + (when warning (byte-compile-warn "%s" warning)) (byte-compile-toplevel-file-form form))) ;; Compile pending forms at end of file. (byte-compile-flush-pending) @@ -2411,7 +2459,7 @@ list that represents a doc string reference. (defun byte-compile--declare-var (sym) (when (and (symbolp sym) (not (string-match "[-*/:$]" (symbol-name sym))) - (byte-compile-warning-enabled-p 'lexical)) + (byte-compile-warning-enabled-p 'lexical sym)) (byte-compile-warn "global/dynamic var `%s' lacks a prefix" sym)) (when (memq sym byte-compile-lexical-variables) @@ -2441,6 +2489,16 @@ list that represents a doc string reference. (defun byte-compile-file-form-defvar-function (form) (pcase-let (((or `',name (let name nil)) (nth 1 form))) (if name (byte-compile--declare-var name))) + ;; Variable aliases are better declared before the corresponding variable, + ;; since it makes it more likely that only one of the two vars has a value + ;; before the `defvaralias' gets executed, which avoids the need to + ;; merge values. + (pcase form + (`(defvaralias ,_ ',newname . ,_) + (when (memq newname byte-compile-bound-variables) + (if (byte-compile-warning-enabled-p 'suspicious) + (byte-compile-warn + "Alias for `%S' should be declared before its referent" newname))))) (byte-compile-keep-pending form)) (put 'custom-declare-variable 'byte-hunk-handler @@ -2486,9 +2544,8 @@ list that represents a doc string reference. (put 'progn 'byte-hunk-handler 'byte-compile-file-form-progn) (put 'prog1 'byte-hunk-handler 'byte-compile-file-form-progn) -(put 'prog2 'byte-hunk-handler 'byte-compile-file-form-progn) (defun byte-compile-file-form-progn (form) - (mapc 'byte-compile-file-form (cdr form)) + (mapc #'byte-compile-file-form (cdr form)) ;; Return nil so the forms are not output twice. nil) @@ -2500,6 +2557,21 @@ list that represents a doc string reference. (mapc 'byte-compile-file-form (cdr form)) nil)) +(put 'internal--with-suppressed-warnings 'byte-hunk-handler + 'byte-compile-file-form-with-suppressed-warnings) +(defun byte-compile-file-form-with-suppressed-warnings (form) + ;; cf byte-compile-file-form-progn. + (let ((byte-compile--suppressed-warnings + (append (cadadr form) byte-compile--suppressed-warnings))) + (mapc 'byte-compile-file-form (cddr form)) + nil)) + +;; Automatically evaluate define-obsolete-function-alias etc at top-level. +(put 'make-obsolete 'byte-hunk-handler 'byte-compile-file-form-make-obsolete) +(defun byte-compile-file-form-make-obsolete (form) + (prog1 (byte-compile-keep-pending form) + (apply 'make-obsolete (mapcar 'eval (cdr form))))) + ;; This handler is not necessary, but it makes the output from dont-compile ;; and similar macros cleaner. (put 'eval 'byte-hunk-handler 'byte-compile-file-form-eval) @@ -2532,7 +2604,7 @@ not to take responsibility for the actual compilation of the code." (setq byte-compile-call-tree (cons (list name nil nil) byte-compile-call-tree)))) - (if (byte-compile-warning-enabled-p 'redefine) + (if (byte-compile-warning-enabled-p 'redefine name) (byte-compile-arglist-warn name arglist macro)) (if byte-compile-verbose @@ -2544,7 +2616,7 @@ not to take responsibility for the actual compilation of the code." ;; This also silences "multiple definition" warnings for defmethods. nil) (that-one - (if (and (byte-compile-warning-enabled-p 'redefine) + (if (and (byte-compile-warning-enabled-p 'redefine name) ;; Don't warn when compiling the stubs in byte-run... (not (assq name byte-compile-initial-macro-environment))) (byte-compile-warn @@ -2552,7 +2624,7 @@ not to take responsibility for the actual compilation of the code." name)) (setcdr that-one nil)) (this-one - (when (and (byte-compile-warning-enabled-p 'redefine) + (when (and (byte-compile-warning-enabled-p 'redefine name) ;; Hack: Don't warn when compiling the magic internal ;; byte-compiler macros in byte-run.el... (not (assq name byte-compile-initial-macro-environment))) @@ -2561,7 +2633,7 @@ not to take responsibility for the actual compilation of the code." name))) ((eq (car-safe (symbol-function name)) (if macro 'lambda 'macro)) - (when (byte-compile-warning-enabled-p 'redefine) + (when (byte-compile-warning-enabled-p 'redefine name) (byte-compile-warn "%s `%s' being redefined as a %s" (if macro "function" "macro") name @@ -2726,7 +2798,11 @@ If FORM is a lambda or a macro, byte-compile it as a function." (setq fun (byte-compile-top-level fun nil 'eval)) (if macro (push 'macro fun)) (if (symbolp form) - (fset form fun) + ;; byte-compile-top-level returns an *expression* equivalent to the + ;; `fun' expression, so we need to evaluate it, tho normally + ;; this is not needed because the expression is just a constant + ;; byte-code object, which is self-evaluating. + (fset form (eval fun t)) fun))))))) (defun byte-compile-sexp (sexp) @@ -2746,15 +2822,12 @@ If FORM is a lambda or a macro, byte-compile it as a function." (macroexp--const-symbol-p arg t)) (error "Invalid lambda variable %s" arg)) ((eq arg '&rest) - (unless (cdr list) - (error "&rest without variable name")) (when (cddr list) - (error "Garbage following &rest VAR in lambda-list"))) + (error "Garbage following &rest VAR in lambda-list")) + (when (memq (cadr list) '(&optional &rest)) + (error "%s following &rest in lambda-list" (cadr list)))) ((eq arg '&optional) - (when (or (null (cdr list)) - (memq (cadr list) '(&optional &rest))) - (error "Variable name missing after &optional")) - (when (memq '&optional (cddr list)) + (when (memq '&optional (cdr list)) (error "Duplicate &optional"))) ((memq arg vars) (byte-compile-warn "repeated variable %s in lambda-list" arg)) @@ -2795,8 +2868,8 @@ If FORM is a lambda or a macro, byte-compile it as a function." (if (> mandatory 127) (byte-compile-report-error "Too many (>127) mandatory arguments") (logior mandatory - (lsh nonrest 8) - (lsh rest 7))))) + (ash nonrest 8) + (ash rest 7))))) (defun byte-compile-lambda (fun &optional add-lambda reserved-csts) @@ -2847,9 +2920,10 @@ for symbols generated by the byte compiler itself." (setq form (cdr form))) (setq form (car form))) (if (and (eq (car-safe form) 'list) - ;; The spec is evalled in callint.c in dynamic-scoping - ;; mode, so just leaving the form unchanged would mean - ;; it won't be eval'd in the right mode. + ;; For code using lexical-binding, form is not + ;; valid lisp, but rather an intermediate form + ;; which may include "calls" to + ;; internal-make-closure (Bug#29988). (not lexical-binding)) nil (setq int `(interactive ,newform))))) @@ -2930,7 +3004,6 @@ for symbols generated by the byte compiler itself." lexenv reserved-csts) ;; OUTPUT-TYPE advises about how form is expected to be used: ;; 'eval or nil -> a single form, - ;; 'progn or t -> a list of forms, ;; 'lambda -> body of a lambda, ;; 'file -> used at file-level. (let ((byte-compile--for-effect for-effect) @@ -2961,6 +3034,7 @@ for symbols generated by the byte compiler itself." (byte-compile-out-toplevel byte-compile--for-effect output-type))) (defun byte-compile-out-toplevel (&optional for-effect output-type) + ;; OUTPUT-TYPE can be like that of `byte-compile-top-level'. (if for-effect ;; The stack is empty. Push a value to be returned from (byte-code ..). (if (eq (car (car byte-compile-output)) 'byte-discard) @@ -2989,12 +3063,8 @@ for symbols generated by the byte compiler itself." ;; Note that even (quote foo) must be parsed just as any subr by the ;; interpreter, so quote should be compiled into byte-code in some contexts. ;; What to leave uncompiled: - ;; lambda -> never. we used to leave it uncompiled if the body was - ;; a single atom, but that causes confusion if the docstring - ;; uses the (file . pos) syntax. Besides, now that we have - ;; the Lisp_Compiled type, the compiled form is faster. + ;; lambda -> never. The compiled form is always faster. ;; eval -> atom, quote or (function atom atom atom) - ;; progn -> as <<same-as-eval>> or (progn <<same-as-eval>> atom) ;; file -> as progn, but takes both quotes and atoms, and longer forms. (let (rest (maycall (not (eq output-type 'lambda))) ; t if we may make a funcall. @@ -3024,8 +3094,9 @@ for symbols generated by the byte compiler itself." (null (nthcdr 3 rest)) (setq tmp (get (car (car rest)) 'byte-opcode-invert)) (or (null (cdr rest)) - (and (memq output-type '(file progn t)) + (and (eq output-type 'file) (cdr (cdr rest)) + (eql (length body) (cdr (car rest))) ;bug#34757 (eq (car (nth 1 rest)) 'byte-discard) (progn (setq rest (cdr rest)) t)))) (setq maycall nil) ; Only allow one real function call. @@ -3120,9 +3191,15 @@ for symbols generated by the byte compiler itself." (when (assq var byte-compile-lexical-variables) (byte-compile-report-error (format-message "%s cannot use lexical var `%s'" fn var)))))) - (when (macroexp--const-symbol-p fn) + ;; Warn about using obsolete hooks. + (if (memq fn '(add-hook remove-hook)) + (let ((hook (car-safe (cdr form)))) + (if (eq (car-safe hook) 'quote) + (byte-compile-check-variable (cadr hook) nil)))) + (when (and (byte-compile-warning-enabled-p 'suspicious) + (macroexp--const-symbol-p fn)) (byte-compile-warn "`%s' called as a function" fn)) - (when (and (byte-compile-warning-enabled-p 'interactive-only) + (when (and (byte-compile-warning-enabled-p 'interactive-only fn) interactive-only) (byte-compile-warn "`%s' is for interactive use only%s" fn @@ -3163,8 +3240,8 @@ for symbols generated by the byte compiler itself." (byte-compile-discard)))) (defun byte-compile-normal-call (form) - (when (and (byte-compile-warning-enabled-p 'callargs) - (symbolp (car form))) + (when (and (symbolp (car form)) + (byte-compile-warning-enabled-p 'callargs (car form))) (if (memq (car form) '(custom-declare-group custom-declare-variable custom-declare-face)) @@ -3173,7 +3250,7 @@ for symbols generated by the byte compiler itself." (if byte-compile-generate-call-tree (byte-compile-annotate-call-tree form)) (when (and byte-compile--for-effect (eq (car form) 'mapcar) - (byte-compile-warning-enabled-p 'mapcar)) + (byte-compile-warning-enabled-p 'mapcar 'mapcar)) (byte-compile-set-symbol-position 'mapcar) (byte-compile-warn "`mapcar' called for effect; use `mapc' or `dolist' instead")) @@ -3253,7 +3330,7 @@ for symbols generated by the byte compiler itself." (fun (car form)) (fargs (aref fun 0)) (start-depth byte-compile-depth) - (fmax2 (if (numberp fargs) (lsh fargs -7))) ;2*max+rest. + (fmax2 (if (numberp fargs) (ash fargs -7))) ;2*max+rest. ;; (fmin (if (numberp fargs) (logand fargs 127))) (alen (length (cdr form))) (dynbinds ()) @@ -3272,8 +3349,8 @@ for symbols generated by the byte compiler itself." (cl-assert (listp fargs)) (while fargs (pcase (car fargs) - (`&optional (setq fargs (cdr fargs))) - (`&rest (setq fmax2 (+ (* 2 (length dynbinds)) 1)) + ('&optional (setq fargs (cdr fargs))) + ('&rest (setq fmax2 (+ (* 2 (length dynbinds)) 1)) (push (cadr fargs) dynbinds) (setq fargs nil)) (_ (push (pop fargs) dynbinds)))) @@ -3309,7 +3386,8 @@ for symbols generated by the byte compiler itself." (when (symbolp var) (byte-compile-set-symbol-position var)) (cond ((or (not (symbolp var)) (macroexp--const-symbol-p var)) - (when (byte-compile-warning-enabled-p 'constants) + (when (byte-compile-warning-enabled-p 'constants + (and (symbolp var) var)) (byte-compile-warn (if (eq access-type 'let-bind) "attempt to let-bind %s `%s'" "variable reference to %s `%s'") @@ -3320,8 +3398,8 @@ for symbols generated by the byte compiler itself." (not (memq var byte-compile-not-obsolete-vars)) (not (memq var byte-compile-global-not-obsolete-vars)) (or (pcase (nth 1 od) - (`set (not (eq access-type 'reference))) - (`get (eq access-type 'reference)) + ('set (not (eq access-type 'reference))) + ('get (eq access-type 'reference)) (_ t))))) (byte-compile-warn-obsolete var)))) @@ -3346,7 +3424,7 @@ for symbols generated by the byte compiler itself." ;; VAR is lexically bound (byte-compile-stack-ref (cdr lex-binding)) ;; VAR is dynamically bound - (unless (or (not (byte-compile-warning-enabled-p 'free-vars)) + (unless (or (not (byte-compile-warning-enabled-p 'free-vars var)) (boundp var) (memq var byte-compile-bound-variables) (memq var byte-compile-free-references)) @@ -3362,7 +3440,7 @@ for symbols generated by the byte compiler itself." ;; VAR is lexically bound. (byte-compile-stack-set (cdr lex-binding)) ;; VAR is dynamically bound. - (unless (or (not (byte-compile-warning-enabled-p 'free-vars)) + (unless (or (not (byte-compile-warning-enabled-p 'free-vars var)) (boundp var) (memq var byte-compile-bound-variables) (memq var byte-compile-free-assignments)) @@ -3509,7 +3587,7 @@ If it is nil, then the handler is \"byte-compile-SYMBOL.\"" (byte-defop-compiler (>= byte-geq) 2-and) (byte-defop-compiler get 2) (byte-defop-compiler nth 2) -(byte-defop-compiler substring 2-3) +(byte-defop-compiler substring 1-3) (byte-defop-compiler (move-marker byte-set-marker) 2-3) (byte-defop-compiler set-marker 2-3) (byte-defop-compiler match-beginning 1) @@ -3577,7 +3655,8 @@ These implicitly `and' together a bunch of two-arg bytecodes." (cond ((< l 3) (byte-compile-form `(progn ,(nth 1 form) t))) ((= l 3) (byte-compile-two-args form)) - ((cl-every #'macroexp-copyable-p (nthcdr 2 form)) + ;; Don't use `cl-every' here (see comment where we require cl-lib). + ((not (memq nil (mapcar #'macroexp-copyable-p (nthcdr 2 form)))) (byte-compile-form `(and (,(car form) ,(nth 1 form) ,(nth 2 form)) (,(car form) ,@(nthcdr 2 form))))) (t (byte-compile-normal-call form))))) @@ -3846,7 +3925,7 @@ discarding." (defun byte-compile-function-form (form) (let ((f (nth 1 form))) (when (and (symbolp f) - (byte-compile-warning-enabled-p 'callargs)) + (byte-compile-warning-enabled-p 'callargs f)) (byte-compile-function-warn f t (byte-compile-fdefinition f nil))) (byte-compile-constant (if (eq 'lambda (car-safe f)) @@ -3884,7 +3963,6 @@ discarding." (byte-defop-compiler-1 setq) -(byte-defop-compiler-1 setq-default) (byte-defop-compiler-1 quote) (defun byte-compile-setq (form) @@ -3909,34 +3987,21 @@ discarding." (byte-compile-form nil byte-compile--for-effect))) (setq byte-compile--for-effect nil))) -(defun byte-compile-setq-default (form) - (setq form (cdr form)) - (if (null form) ; (setq-default), with no arguments - (byte-compile-form nil byte-compile--for-effect) - (if (> (length form) 2) - (let ((setters ())) - (while (consp form) - (push `(setq-default ,(pop form) ,(pop form)) setters)) - (byte-compile-form (cons 'progn (nreverse setters)))) - (let ((var (car form))) - (and (or (not (symbolp var)) - (macroexp--const-symbol-p var t)) - (byte-compile-warning-enabled-p 'constants) - (byte-compile-warn - "variable assignment to %s `%s'" - (if (symbolp var) "constant" "nonvariable") - (prin1-to-string var))) - (byte-compile-normal-call `(set-default ',var ,@(cdr form))))))) - (byte-defop-compiler-1 set-default) (defun byte-compile-set-default (form) (let ((varexp (car-safe (cdr-safe form)))) (if (eq (car-safe varexp) 'quote) - ;; If the varexp is constant, compile it as a setq-default - ;; so we get more warnings. - (byte-compile-setq-default `(setq-default ,(car-safe (cdr varexp)) - ,@(cddr form))) - (byte-compile-normal-call form)))) + ;; If the varexp is constant, check the var's name. + (let ((var (car-safe (cdr varexp)))) + (and (or (not (symbolp var)) + (macroexp--const-symbol-p var t)) + (byte-compile-warning-enabled-p 'constants + (and (symbolp var) var)) + (byte-compile-warn + "variable assignment to %s `%s'" + (if (symbolp var) "constant" "nonvariable") + (prin1-to-string var))))) + (byte-compile-normal-call form))) (defun byte-compile-quote (form) (byte-compile-constant (car (cdr form)))) @@ -3960,7 +4025,6 @@ discarding." (byte-defop-compiler-1 inline byte-compile-progn) (byte-defop-compiler-1 progn) (byte-defop-compiler-1 prog1) -(byte-defop-compiler-1 prog2) (byte-defop-compiler-1 if) (byte-defop-compiler-1 cond) (byte-defop-compiler-1 and) @@ -3977,11 +4041,6 @@ discarding." (byte-compile-form-do-effect (car (cdr form))) (byte-compile-body (cdr (cdr form)) t)) -(defun byte-compile-prog2 (form) - (byte-compile-form (nth 1 form) t) - (byte-compile-form-do-effect (nth 2 form)) - (byte-compile-body (cdr (cdr (cdr form))) t)) - (defmacro byte-compile-goto-if (cond discard tag) `(byte-compile-goto (if ,cond @@ -4030,7 +4089,7 @@ that suppresses all warnings during execution of BODY." ,condition '(fboundp functionp) byte-compile-unresolved-functions)) (bound-list (byte-compile-find-bound-condition - ,condition '(boundp default-boundp))) + ,condition '(boundp default-boundp local-variable-p))) ;; Maybe add to the bound list. (byte-compile-bound-variables (append bound-list byte-compile-bound-variables))) @@ -4078,170 +4137,183 @@ that suppresses all warnings during execution of BODY." (byte-compile-out-tag donetag)))) (setq byte-compile--for-effect nil)) -(defun byte-compile-cond-vars (obj1 obj2) +(defun byte-compile--cond-vars (obj1 obj2) ;; We make sure that of OBJ1 and OBJ2, one of them is a symbol, ;; and the other is a constant expression whose value can be ;; compared with `eq' (with `macroexp-const-p'). (or - (and (symbolp obj1) (macroexp-const-p obj2) (cons obj1 obj2)) - (and (symbolp obj2) (macroexp-const-p obj1) (cons obj2 obj1)))) - -(defconst byte-compile--default-val (cons nil nil) "A unique object.") - -(defun byte-compile-cond-jump-table-info (clauses) - "If CLAUSES is a `cond' form where: -The condition for each clause is of the form (TEST VAR VALUE). -VAR is a variable. -TEST and VAR are the same throughout all conditions. -VALUE satisfies `macroexp-const-p'. - -Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))" - (let ((cases '()) - (ok t) - prev-var prev-test) - (and (catch 'break - (dolist (clause (cdr clauses) ok) - (let* ((condition (car clause)) - (test (car-safe condition)) - (vars (when (consp condition) - (byte-compile-cond-vars (cadr condition) (cl-caddr condition)))) - (obj1 (car-safe vars)) - (obj2 (cdr-safe vars)) - (body (cdr-safe clause))) - (unless prev-var - (setq prev-var obj1)) - (unless prev-test - (setq prev-test test)) - (if (and obj1 (memq test '(eq eql equal)) - (consp condition) - (eq test prev-test) - (eq obj1 prev-var) - ;; discard duplicate clauses - (not (assq obj2 cases))) - (push (list (if (consp obj2) (eval obj2) obj2) body) cases) - (if (and (macroexp-const-p condition) condition) - (progn (push (list byte-compile--default-val - (or body `(,condition))) - cases) - (throw 'break t)) - (setq ok nil) - (throw 'break nil)))))) - (list (cons prev-test prev-var) (nreverse cases))))) - -(defun byte-compile-cond-jump-table (clauses) - (let* ((table-info (byte-compile-cond-jump-table-info clauses)) - (test (caar table-info)) - (var (cdar table-info)) - (cases (cadr table-info)) - jump-table test-obj body tag donetag default-tag default-case) - (when (and cases (not (= (length cases) 1))) - ;; TODO: Once :linear-search is implemented for `make-hash-table' - ;; set it to `t' for cond forms with a small number of cases. + (and (symbolp obj1) (macroexp-const-p obj2) (cons obj1 (eval obj2))) + (and (symbolp obj2) (macroexp-const-p obj1) (cons obj2 (eval obj1))))) + +(defun byte-compile--common-test (test-1 test-2) + "Most specific common test of `eq', `eql' and `equal'" + (cond ((or (eq test-1 'equal) (eq test-2 'equal)) 'equal) + ((or (eq test-1 'eql) (eq test-2 'eql)) 'eql) + (t 'eq))) + +(defun byte-compile--cond-switch-prefix (clauses) + "Find a switch corresponding to a prefix of CLAUSES, or nil if none. +Return (TAIL VAR TEST CASES), where: + TAIL is the remaining part of CLAUSES after the switch, including + any default clause, + VAR is the variable being switched on, + TEST is the equality test (`eq', `eql' or `equal'), + CASES is a list of (VALUES . BODY) where VALUES is a list of values + corresponding to BODY (always non-empty)." + (let ((cases nil) ; Reversed list of (VALUES BODY). + (keys nil) ; Switch keys seen so far. + (switch-var nil) + (switch-test 'eq)) + (while (pcase (car clauses) + (`((,fn ,expr1 ,expr2) . ,body) + (let* ((vars (byte-compile--cond-vars expr1 expr2)) + (var (car vars)) + (value (cdr vars))) + (and var (or (eq var switch-var) (not switch-var)) + (cond + ((memq fn '(eq eql equal)) + (setq switch-var var) + (setq switch-test + (byte-compile--common-test switch-test fn)) + (unless (member value keys) + (push value keys) + (push (cons (list value) (or body '(t))) cases)) + t) + ((and (memq fn '(memq memql member)) + (listp value) + ;; Require a non-empty body, since the member + ;; function value depends on the switch + ;; argument. + body) + (setq switch-var var) + (setq switch-test + (byte-compile--common-test + switch-test (cdr (assq fn '((memq . eq) + (memql . eql) + (member . equal)))))) + (let ((vals nil)) + (dolist (elem value) + (unless (funcall fn elem keys) + (push elem vals))) + (when vals + (setq keys (append vals keys)) + (push (cons (nreverse vals) body) cases))) + t)))))) + (setq clauses (cdr clauses))) + ;; Assume that a single switch is cheaper than two or more discrete + ;; compare clauses. This could be tuned, possibly taking into + ;; account the total number of values involved. + (and (> (length cases) 1) + (list clauses switch-var switch-test (nreverse cases))))) + +(defun byte-compile-cond-jump-table (switch donetag) + "Generate code for SWITCH, ending at DONETAG." + (let* ((var (car switch)) + (test (nth 1 switch)) + (cases (nth 2 switch)) + jump-table test-objects body tag default-tag) + ;; TODO: Once :linear-search is implemented for `make-hash-table' + ;; set it to `t' for cond forms with a small number of cases. + (let ((nvalues (apply #'+ (mapcar (lambda (case) (length (car case))) + cases)))) (setq jump-table (make-hash-table :test test :purecopy t - :size (if (assq byte-compile--default-val cases) - (1- (length cases)) - (length cases))) - default-tag (byte-compile-make-tag) - donetag (byte-compile-make-tag)) - ;; The structure of byte-switch code: - ;; - ;; varref var - ;; constant #s(hash-table purecopy t data (val1 (TAG1) val2 (TAG2))) - ;; switch - ;; goto DEFAULT-TAG - ;; TAG1 - ;; <clause body> - ;; goto DONETAG - ;; TAG2 - ;; <clause body> - ;; goto DONETAG - ;; DEFAULT-TAG - ;; <body for `t' clause, if any (else `constant nil')> - ;; DONETAG - - (byte-compile-variable-ref var) - (byte-compile-push-constant jump-table) - (byte-compile-out 'byte-switch) - - ;; When the opcode argument is `byte-goto', `byte-compile-goto' sets - ;; `byte-compile-depth' to `nil'. However, we need `byte-compile-depth' - ;; to be non-nil for generating tags for all cases. Since - ;; `byte-compile-depth' will increase by at most 1 after compiling - ;; all of the clause (which is further enforced by cl-assert below) - ;; it should be safe to preserve its value. - (let ((byte-compile-depth byte-compile-depth)) - (byte-compile-goto 'byte-goto default-tag)) - - (let ((default-match (assq byte-compile--default-val cases))) - (when default-match - (setq default-case (cadr default-match) - cases (butlast cases)))) - - (dolist (case cases) - (setq tag (byte-compile-make-tag) - test-obj (nth 0 case) - body (nth 1 case)) - (byte-compile-out-tag tag) - (puthash test-obj tag jump-table) - - (let ((byte-compile-depth byte-compile-depth) - (init-depth byte-compile-depth)) - ;; Since `byte-compile-body' might increase `byte-compile-depth' - ;; by 1, not preserving its value will cause it to potentially - ;; increase by one for every clause body compiled, causing - ;; depth/tag conflicts or violating asserts down the road. - ;; To make sure `byte-compile-body' itself doesn't violate this, - ;; we use `cl-assert'. - (if (null body) - (byte-compile-form t byte-compile--for-effect) - (byte-compile-body body byte-compile--for-effect)) - (cl-assert (or (= byte-compile-depth init-depth) - (= byte-compile-depth (1+ init-depth)))) - (byte-compile-goto 'byte-goto donetag) - (setcdr (cdr donetag) nil))) - - (byte-compile-out-tag default-tag) - (if default-case - (byte-compile-body-do-effect default-case) - (byte-compile-constant nil)) - (byte-compile-out-tag donetag) - (push jump-table byte-compile-jump-tables)))) + :size nvalues))) + (setq default-tag (byte-compile-make-tag)) + ;; The structure of byte-switch code: + ;; + ;; varref var + ;; constant #s(hash-table purecopy t data (val1 (TAG1) val2 (TAG2))) + ;; switch + ;; goto DEFAULT-TAG + ;; TAG1 + ;; <clause body> + ;; goto DONETAG + ;; TAG2 + ;; <clause body> + ;; goto DONETAG + ;; DEFAULT-TAG + ;; <body for remaining (non-switch) clauses> + ;; DONETAG + + (byte-compile-variable-ref var) + (byte-compile-push-constant jump-table) + (byte-compile-out 'byte-switch) + + ;; When the opcode argument is `byte-goto', `byte-compile-goto' sets + ;; `byte-compile-depth' to `nil'. However, we need `byte-compile-depth' + ;; to be non-nil for generating tags for all cases. Since + ;; `byte-compile-depth' will increase by at most 1 after compiling + ;; all of the clause (which is further enforced by cl-assert below) + ;; it should be safe to preserve its value. + (let ((byte-compile-depth byte-compile-depth)) + (byte-compile-goto 'byte-goto default-tag)) + + (dolist (case cases) + (setq tag (byte-compile-make-tag) + test-objects (car case) + body (cdr case)) + (byte-compile-out-tag tag) + (dolist (value test-objects) + (puthash value tag jump-table)) + + (let ((byte-compile-depth byte-compile-depth) + (init-depth byte-compile-depth)) + ;; Since `byte-compile-body' might increase `byte-compile-depth' + ;; by 1, not preserving its value will cause it to potentially + ;; increase by one for every clause body compiled, causing + ;; depth/tag conflicts or violating asserts down the road. + ;; To make sure `byte-compile-body' itself doesn't violate this, + ;; we use `cl-assert'. + (byte-compile-body body byte-compile--for-effect) + (cl-assert (or (= byte-compile-depth init-depth) + (= byte-compile-depth (1+ init-depth)))) + (byte-compile-goto 'byte-goto donetag) + (setcdr (cdr donetag) nil))) + + (byte-compile-out-tag default-tag) + (push jump-table byte-compile-jump-tables))) (defun byte-compile-cond (clauses) - (or (and byte-compile-cond-use-jump-table - (byte-compile-cond-jump-table clauses)) - (let ((donetag (byte-compile-make-tag)) - nexttag clause) - (while (setq clauses (cdr clauses)) - (setq clause (car clauses)) - (cond ((or (eq (car clause) t) - (and (eq (car-safe (car clause)) 'quote) - (car-safe (cdr-safe (car clause))))) - ;; Unconditional clause - (setq clause (cons t clause) - clauses nil)) - ((cdr clauses) - (byte-compile-form (car clause)) - (if (null (cdr clause)) - ;; First clause is a singleton. - (byte-compile-goto-if t byte-compile--for-effect donetag) - (setq nexttag (byte-compile-make-tag)) - (byte-compile-goto 'byte-goto-if-nil nexttag) - (byte-compile-maybe-guarded (car clause) - (byte-compile-body (cdr clause) byte-compile--for-effect)) - (byte-compile-goto 'byte-goto donetag) - (byte-compile-out-tag nexttag))))) - ;; Last clause - (let ((guard (car clause))) - (and (cdr clause) (not (eq guard t)) - (progn (byte-compile-form guard) - (byte-compile-goto-if nil byte-compile--for-effect donetag) - (setq clause (cdr clause)))) - (byte-compile-maybe-guarded guard - (byte-compile-body-do-effect clause))) - (byte-compile-out-tag donetag)))) + (let ((donetag (byte-compile-make-tag)) + nexttag clause) + (setq clauses (cdr clauses)) + (while clauses + (let ((switch-prefix (and byte-compile-cond-use-jump-table + (byte-compile--cond-switch-prefix clauses)))) + (if switch-prefix + (progn + (byte-compile-cond-jump-table (cdr switch-prefix) donetag) + (setq clauses (car switch-prefix))) + (setq clause (car clauses)) + (cond ((or (eq (car clause) t) + (and (eq (car-safe (car clause)) 'quote) + (car-safe (cdr-safe (car clause))))) + ;; Unconditional clause + (setq clause (cons t clause) + clauses nil)) + ((cdr clauses) + (byte-compile-form (car clause)) + (if (null (cdr clause)) + ;; First clause is a singleton. + (byte-compile-goto-if t byte-compile--for-effect donetag) + (setq nexttag (byte-compile-make-tag)) + (byte-compile-goto 'byte-goto-if-nil nexttag) + (byte-compile-maybe-guarded (car clause) + (byte-compile-body (cdr clause) byte-compile--for-effect)) + (byte-compile-goto 'byte-goto donetag) + (byte-compile-out-tag nexttag)))) + (setq clauses (cdr clauses))))) + ;; Last clause + (let ((guard (car clause))) + (and (cdr clause) (not (eq guard t)) + (progn (byte-compile-form guard) + (byte-compile-goto-if nil byte-compile--for-effect donetag) + (setq clause (cdr clause)))) + (byte-compile-maybe-guarded guard + (byte-compile-body-do-effect clause))) + (byte-compile-out-tag donetag))) (defun byte-compile-and (form) (let ((failtag (byte-compile-make-tag)) @@ -4599,7 +4671,7 @@ binding slots have been popped." (defun byte-compile-save-excursion (form) (if (and (eq 'set-buffer (car-safe (car-safe (cdr form)))) - (byte-compile-warning-enabled-p 'suspicious)) + (byte-compile-warning-enabled-p 'suspicious 'set-buffer)) (byte-compile-warn "Use `with-current-buffer' rather than save-excursion+set-buffer")) (byte-compile-out 'byte-save-excursion 0) @@ -4640,7 +4712,7 @@ binding slots have been popped." ;; This is not used for file-level defvar/consts. (when (and (symbolp (nth 1 form)) (not (string-match "[-*/:$]" (symbol-name (nth 1 form)))) - (byte-compile-warning-enabled-p 'lexical)) + (byte-compile-warning-enabled-p 'lexical (nth 1 form))) (byte-compile-warn "global/dynamic var `%s' lacks a prefix" (nth 1 form))) (let ((fun (nth 0 form)) @@ -4725,7 +4797,7 @@ binding slots have been popped." arg) ;; `lam' is the lambda expression in `fun' (or nil if not ;; recognized). - ((or `(,(or `quote `function) ,lam) (let lam nil)) + ((or `(,(or 'quote 'function) ,lam) (let lam nil)) fun) ;; `arglist' is the list of arguments (or t if not recognized). ;; `body' is the body of `lam' (or t if not recognized). @@ -4757,6 +4829,13 @@ binding slots have been popped." (let (byte-compile-warnings) (byte-compile-form (cons 'progn (cdr form))))) +(byte-defop-compiler-1 internal--with-suppressed-warnings + byte-compile-suppressed-warnings) +(defun byte-compile-suppressed-warnings (form) + (let ((byte-compile--suppressed-warnings + (append (cadadr form) byte-compile--suppressed-warnings))) + (byte-compile-form (macroexp-progn (cddr form))))) + ;; Warn about misuses of make-variable-buffer-local. (byte-defop-compiler-1 make-variable-buffer-local byte-compile-make-variable-buffer-local) @@ -4912,18 +4991,18 @@ invoked interactively." (setq byte-compile-call-tree (sort byte-compile-call-tree (pcase byte-compile-call-tree-sort - (`callers + ('callers (lambda (x y) (< (length (nth 1 x)) - (length (nth 1 y))))) - (`calls + (length (nth 1 y))))) + ('calls (lambda (x y) (< (length (nth 2 x)) - (length (nth 2 y))))) - (`calls+callers + (length (nth 2 y))))) + ('calls+callers (lambda (x y) (< (+ (length (nth 1 x)) - (length (nth 2 x))) - (+ (length (nth 1 y)) - (length (nth 2 y)))))) - (`name + (length (nth 2 x))) + (+ (length (nth 1 y)) + (length (nth 2 y)))))) + ('name (lambda (x y) (string< (car x) (car y)))) (_ (error "`byte-compile-call-tree-sort': `%s' - unknown sort mode" byte-compile-call-tree-sort)))))) @@ -5030,8 +5109,15 @@ it won't work in an interactive Emacs." "Run `byte-compile-file' on the files remaining on the command line. Use this from the command line, with `-batch'; it won't work in an interactive Emacs. -Each file is processed even if an error occurred previously. + +Each file is processed even if an error occurred previously. If +a file name denotes a directory, all Emacs Lisp source files in +that directory (that have previously been compiled) will be +recompiled if newer than the compiled files. In this case, +NOFORCE is ignored. + For example, invoke \"emacs -batch -f batch-byte-compile $emacs/ ~/*.el\". + If NOFORCE is non-nil, don't recompile a file that seems to be already up-to-date." ;; command-line-args-left is what is left of the command line, from |