X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/b122f3fb5ac825f2a429442b2485cd77bb0ecf94..5dd1c041c7fdb876b52bf33f41e8aeb119282cef:/lisp/emacs-lisp/bytecomp.el diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index e2a228c0d7..02a88c1397 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -1,17 +1,13 @@ ;;; bytecomp.el --- compilation of Lisp code into byte code -;; Copyright (C) 1985,86,87,92,94,1998,2000,01,02,03,2004 -;; Free Software Foundation, Inc. +;; Copyright (C) 1985, 1986, 1987, 1992, 1994, 1998, 2000, 2001, 2002, +;; 2003, 2004, 2005, 2006 Free Software Foundation, Inc. ;; Author: Jamie Zawinski ;; Hallvard Furuseth ;; Maintainer: FSF ;; Keywords: lisp -;;; This version incorporates changes up to version 2.10 of the -;;; Zawinski-Furuseth compiler. -(defconst byte-compile-version "$Revision: 2.143 $") - ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify @@ -26,8 +22,8 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Commentary: @@ -102,6 +98,9 @@ ;; `obsolete' (obsolete variables and functions) ;; `noruntime' (calls to functions only defined ;; within `eval-when-compile') +;; `cl-warnings' (calls to CL functions) +;; `interactive-only' (calls to commands that are +;; not good to call from Lisp) ;; byte-compile-compatibility Whether the compiler should ;; generate .elc files which can be loaded into ;; generic emacs 18. @@ -194,7 +193,7 @@ (defgroup bytecomp nil - "Emacs Lisp byte-compiler" + "Emacs Lisp byte-compiler." :group 'lisp) (defcustom emacs-lisp-file-regexp (if (eq system-type 'vax-vms) @@ -294,6 +293,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.") +;;;###autoload(put 'byte-compile-dynamic 'safe-local-variable 'booleanp) (defcustom byte-compile-dynamic-docstrings t "*If non-nil, compile doc strings for lazy access. @@ -312,6 +312,7 @@ 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) (defcustom byte-optimize-log nil "*If true, the byte-compiler will log its optimizations into *Compile-Log*. @@ -329,7 +330,8 @@ If it is 'byte, then only byte-level optimizations will be logged." :type 'boolean) (defconst byte-compile-warning-types - '(redefine callargs free-vars unresolved obsolete noruntime cl-functions) + '(redefine callargs free-vars unresolved + obsolete noruntime cl-functions interactive-only) "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). @@ -338,27 +340,49 @@ Elements of the list may be be: free-vars references to variables not in the current lexical scope. unresolved calls to unknown functions. - callargs lambda calls with args that don't match the definition. - redefine function cell redefined from a macro to a lambda or vice + callargs function calls with args that don't match the definition. + redefine function name redefined from a macro to ordinary function or vice versa, or redefined to take a different number of arguments. obsolete obsolete variables and functions. noruntime functions that may not be defined at runtime (typically defined only under `eval-when-compile'). cl-functions calls to runtime functions from the CL package (as - distinguished from macros and aliases)." + distinguished from macros and aliases). + interactive-only + commands that normally shouldn't be called from Lisp code." :group 'bytecomp :type `(choice (const :tag "All" t) (set :menu-tag "Some" (const free-vars) (const unresolved) (const callargs) (const redefine) - (const obsolete) (const noruntime) (const cl-functions)))) + (const obsolete) (const noruntime) + (const cl-functions) (const interactive-only)))) +(put 'byte-compile-warnings 'safe-local-variable 'byte-compile-warnings-safe-p) +;;;###autoload +(defun byte-compile-warnings-safe-p (x) + (or (booleanp x) + (and (listp x) + (equal (mapcar + (lambda (e) + (when (memq e '(free-vars unresolved + callargs redefine + obsolete noruntime + cl-functions interactive-only)) + e)) + x) + x)))) + +(defvar byte-compile-interactive-only-functions + '(beginning-of-buffer end-of-buffer replace-string replace-regexp + insert-file insert-buffer insert-file-literally) + "List of commands that are not meant to be called from Lisp.") (defvar byte-compile-not-obsolete-var nil "If non-nil, this is a variable that shouldn't be reported as obsolete.") (defcustom byte-compile-generate-call-tree nil "*Non-nil means collect call-graph information when compiling. -This records functions were called and from where. +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. @@ -439,7 +463,9 @@ Each element looks like (MACRONAME . DEFINITION). It is "Alist of functions defined in the file being compiled. This is so we can inline them when necessary. Each element looks like (FUNCTIONNAME . DEFINITION). It is -\(FUNCTIONNAME . nil) when a function is redefined as a macro.") +\(FUNCTIONNAME . nil) when a function is redefined as a macro. +It is \(FUNCTIONNAME . t) when all we know is that it was defined, +and we don't know the definition.") (defvar byte-compile-unresolved-functions nil "Alist of undefined functions to which calls have been compiled. @@ -796,7 +822,8 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (let ((xs (pop hist-new)) old-autoloads) ;; Make sure the file was not already loaded before. - (unless (assoc (car xs) hist-orig) + (unless (or (assoc (car xs) hist-orig) + (equal (car xs) "cl")) (dolist (s xs) (cond ((symbolp s) @@ -813,7 +840,18 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (when (and (symbolp s) (not (memq s old-autoloads))) (push s byte-compile-noruntime-functions)) (when (and (consp s) (eq t (car s))) - (push (cdr s) old-autoloads)))))))))) + (push (cdr s) old-autoloads))))))) + (when (memq 'cl-functions byte-compile-warnings) + (let ((hist-new load-history) + (hist-nil-new current-load-list)) + ;; Go through load-history, look for newly loaded files + ;; and mark all the functions defined therein. + (while (and hist-new (not (eq hist-new hist-orig))) + (let ((xs (pop hist-new)) + old-autoloads) + ;; Make sure the file was not already loaded before. + (when (and (equal (car xs) "cl") (not (assoc (car xs) hist-orig))) + (byte-compile-find-cl-functions))))))))) (defun byte-compile-eval-before-compile (form) "Evaluate FORM for `eval-and-compile'." @@ -836,30 +874,29 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." ;; Log something that isn't a warning. (defmacro byte-compile-log (format-string &rest args) - (list 'and - 'byte-optimize - '(memq byte-optimize-log '(t source)) - (list 'let '((print-escape-newlines t) - (print-level 4) - (print-length 4)) - (list 'byte-compile-log-1 - (cons 'format - (cons format-string - (mapcar - (lambda (x) - (if (symbolp x) (list 'prin1-to-string x) x)) - args))))))) + `(and + byte-optimize + (memq byte-optimize-log '(t source)) + (let ((print-escape-newlines t) + (print-level 4) + (print-length 4)) + (byte-compile-log-1 + (format + ,format-string + ,@(mapcar + (lambda (x) (if (symbolp x) (list 'prin1-to-string x) x)) + args)))))) ;; Log something that isn't a warning. (defun byte-compile-log-1 (string) - (save-excursion - (byte-goto-log-buffer) - (goto-char (point-max)) - (byte-compile-warning-prefix nil nil) - (cond (noninteractive - (message " %s" string)) - (t - (insert (format "%s\n" string)))))) + (with-current-buffer "*Compile-Log*" + (let ((inhibit-read-only t)) + (goto-char (point-max)) + (byte-compile-warning-prefix nil nil) + (cond (noninteractive + (message " %s" string)) + (t + (insert (format "%s\n" string))))))) (defvar byte-compile-read-position nil "Character position we began the last `read' from.") @@ -887,35 +924,38 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." ;; list. If our current position is after the symbol's position, we ;; assume we've already passed that point, and look for the next ;; occurrence of the symbol. +;; +;; This function should not be called twice for the same occurrence of +;; a symbol, and it should not be called for symbols generated by the +;; byte compiler itself; because rather than just fail looking up the +;; symbol, we may find an occurrence of the symbol further ahead, and +;; then `byte-compile-last-position' as advanced too far. +;; ;; So your're probably asking yourself: Isn't this function a ;; gross hack? And the answer, of course, would be yes. (defun byte-compile-set-symbol-position (sym &optional allow-previous) (when byte-compile-read-position (let (last entry) (while (progn - (setq last byte-compile-last-position - entry (assq sym read-symbol-positions-list)) - (when entry - (setq byte-compile-last-position - (+ byte-compile-read-position (cdr entry)) - read-symbol-positions-list - (byte-compile-delete-first - entry read-symbol-positions-list))) + (setq last byte-compile-last-position + entry (assq sym read-symbol-positions-list)) + (when entry + (setq byte-compile-last-position + (+ byte-compile-read-position (cdr entry)) + read-symbol-positions-list + (byte-compile-delete-first + entry read-symbol-positions-list))) (or (and allow-previous (not (= last byte-compile-last-position))) (> last byte-compile-last-position))))))) (defvar byte-compile-last-warned-form nil) (defvar byte-compile-last-logged-file nil) -(defun byte-goto-log-buffer () - (set-buffer (get-buffer-create "*Compile-Log*")) - (unless (eq major-mode 'compilation-mode) - (compilation-mode))) - ;; This is used as warning-prefix for the compiler. ;; It is always called with the warnings buffer current. (defun byte-compile-warning-prefix (level entry) - (let* ((dir default-directory) + (let* ((inhibit-read-only t) + (dir default-directory) (file (cond ((stringp byte-compile-current-file) (format "%s:" (file-relative-name byte-compile-current-file dir))) ((bufferp byte-compile-current-file) @@ -961,7 +1001,8 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (save-excursion (set-buffer (get-buffer-create "*Compile-Log*")) (goto-char (point-max)) - (let* ((dir (and byte-compile-current-file + (let* ((inhibit-read-only t) + (dir (and byte-compile-current-file (file-name-directory byte-compile-current-file))) (was-same (equal default-directory dir)) pt) @@ -987,6 +1028,7 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." ;; Do this after setting default-directory. (unless (eq major-mode 'compilation-mode) (compilation-mode)) + (compilation-forget-errors) pt)))) ;; Log a message STRING in *Compile-Log*. @@ -994,7 +1036,8 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (defun byte-compile-log-warning (string &optional fill level) (let ((warning-prefix-function 'byte-compile-warning-prefix) (warning-type-format "") - (warning-fill-prefix (if fill " "))) + (warning-fill-prefix (if fill " ")) + (inhibit-read-only t)) (display-warning 'bytecomp string level "*Compile-Log*"))) (defun byte-compile-warn (format &rest args) @@ -1018,11 +1061,11 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (when (nth 2 new))) (byte-compile-set-symbol-position (car form)) (if (memq 'obsolete byte-compile-warnings) - (byte-compile-warn "%s is an obsolete function%s; %s" (car form) - (if when (concat " since " when) "") + (byte-compile-warn "`%s' is an obsolete function%s; %s" (car form) + (if when (concat " (as of Emacs " when ")") "") (if (stringp (car new)) (car new) - (format "use %s instead." (car new))))) + (format "use `%s' instead." (car new))))) (funcall (or handler 'byte-compile-normal-call) form))) ;; Compiler options @@ -1085,6 +1128,10 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." ;;; sanity-checking arglists +;; If a function has an entry saying (FUNCTION . t). +;; that means we know it is defined but we don't know how. +;; If a function has an entry saying (FUNCTION . nil), +;; that means treat it as not defined. (defun byte-compile-fdefinition (name macro-p) (let* ((list (if macro-p byte-compile-macro-environment @@ -1150,7 +1197,7 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (defun byte-compile-callargs-warn (form) (let* ((def (or (byte-compile-fdefinition (car form) nil) (byte-compile-fdefinition (car form) t))) - (sig (if def + (sig (if (and def (not (eq def t))) (byte-compile-arglist-signature (if (eq 'lambda (car-safe def)) (nth 1 def) @@ -1180,7 +1227,7 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (byte-compile-format-warn form) ;; Check to see if the function will be available at runtime ;; and/or remember its arity if it's unknown. - (or (and (or sig (fboundp (car form))) ; might be a subr or autoload. + (or (and (or def (fboundp (car form))) ; might be a subr or autoload. (not (memq (car form) byte-compile-noruntime-functions))) (eq (car form) byte-compile-current-form) ; ## this doesn't work ; with recursion. @@ -1191,9 +1238,8 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." (if cons (or (memq n (cdr cons)) (setcdr cons (cons n (cdr cons)))) - (setq byte-compile-unresolved-functions - (cons (list (car form) n) - byte-compile-unresolved-functions))))))) + (push (list (car form) n) + byte-compile-unresolved-functions)))))) (defun byte-compile-format-warn (form) "Warn if FORM is `format'-like with inconsistent args. @@ -1221,11 +1267,28 @@ extra args." (dolist (elt '(format message error)) (put elt 'byte-compile-format-like t)) +;; Warn if a custom definition fails to specify :group. +(defun byte-compile-nogroup-warn (form) + (let ((keyword-args (cdr (cdr (cdr (cdr form))))) + (name (cadr form))) + (or (not (eq (car-safe name) 'quote)) + (and (eq (car form) 'custom-declare-group) + (equal name ''emacs)) + (plist-get keyword-args :group) + (not (and (consp name) (eq (car name) 'quote))) + (byte-compile-warn + "%s for `%s' fails to specify containing group" + (cdr (assq (car form) + '((custom-declare-group . defgroup) + (custom-declare-face . defface) + (custom-declare-variable . defcustom)))) + (cadr name))))) + ;; Warn if the function or macro is being redefined with a different ;; number of arguments. (defun byte-compile-arglist-warn (form macrop) (let ((old (byte-compile-fdefinition (nth 1 form) macrop))) - (if old + (if (and old (not (eq old t))) (let ((sig1 (byte-compile-arglist-signature (if (eq 'lambda (car-safe old)) (nth 1 old) @@ -1542,6 +1605,7 @@ recompile every `.el' file that already has a `.elc' file." This is normally set in local file variables at the end of the elisp file: ;; Local Variables:\n;; no-byte-compile: t\n;; End: ") +;;;###autoload(put 'no-byte-compile 'safe-local-variable 'booleanp) ;;;###autoload (defun byte-compile-file (filename &optional load) @@ -1603,8 +1667,12 @@ The value is non-nil if there were no errors, nil if errors." ;; If they change the file name, then change it for the output also. (let ((buffer-file-name filename) (default-major-mode 'emacs-lisp-mode) + ;; Ignore unsafe local variables. + ;; We only care about a few of them for our purposes. + (enable-local-variables :safe) (enable-local-eval nil)) - (normal-mode) + ;; Arg of t means don't alter enable-local-variables. + (normal-mode t) (setq filename buffer-file-name)) ;; Set the default directory, in case an eval-when-compile uses it. (setq default-directory (file-name-directory filename))) @@ -1742,7 +1810,7 @@ With argument, insert value in current buffer after the form." (byte-compile-maxdepth 0) (byte-compile-output nil) ;; This allows us to get the positions of symbols read; it's - ;; new in Emacs 21.4. + ;; new in Emacs 22.1. (read-with-symbol-positions inbuffer) (read-symbol-positions-list nil) ;; #### This is bound in b-c-close-variables. @@ -1860,10 +1928,7 @@ With argument, insert value in current buffer after the form." " on " (current-time-string) "\n;;; from file " filename "\n") (insert ";;; in Emacs version " emacs-version "\n") - (insert ";;; with bytecomp version " - (progn (string-match "[0-9.]+" byte-compile-version) - (match-string 0 byte-compile-version)) - "\n;;; " + (insert ";;; " (cond ((eq byte-optimize 'source) "with source-level optimization only") ((eq byte-optimize 'byte) "with byte-level optimization only") @@ -2089,7 +2154,7 @@ list that represents a doc string reference. (defun byte-compile-file-form-defsubst (form) (when (assq (nth 1 form) byte-compile-unresolved-functions) (setq byte-compile-current-form (nth 1 form)) - (byte-compile-warn "defsubst %s was used before it was defined" + (byte-compile-warn "defsubst `%s' was used before it was defined" (nth 1 form))) (byte-compile-file-form (macroexpand form byte-compile-macro-environment)) @@ -2108,9 +2173,9 @@ list that represents a doc string reference. (eq (car (nth 1 form)) 'quote) (consp (cdr (nth 1 form))) (symbolp (nth 1 (nth 1 form)))) - (add-to-list 'byte-compile-function-environment - (cons (nth 1 (nth 1 form)) - (cons 'autoload (cdr (cdr form)))))) + (push (cons (nth 1 (nth 1 form)) + (cons 'autoload (cdr (cdr form)))) + byte-compile-function-environment)) (if (stringp (nth 3 form)) form ;; No doc string, so we can compile this as a normal form. @@ -2136,6 +2201,8 @@ list that represents a doc string reference. (put 'custom-declare-variable 'byte-hunk-handler 'byte-compile-file-form-custom-declare-variable) (defun byte-compile-file-form-custom-declare-variable (form) + (when (memq 'callargs byte-compile-warnings) + (byte-compile-nogroup-warn form)) (when (memq 'free-vars byte-compile-warnings) (push (nth 1 (nth 1 form)) byte-compile-bound-variables)) (let ((tail (nthcdr 4 form))) @@ -2153,17 +2220,15 @@ list that represents a doc string reference. (setq tail (cdr tail)))) form) -(put 'require 'byte-hunk-handler 'byte-compile-file-form-eval-boundary) -(defun byte-compile-file-form-eval-boundary (form) - (let ((old-load-list current-load-list)) - (eval form) - ;; (require 'cl) turns off warnings for cl functions. - (let ((tem current-load-list)) - (while (not (eq tem old-load-list)) - (when (equal (car tem) '(require . cl)) - (setq byte-compile-warnings - (remq 'cl-functions byte-compile-warnings))) - (setq tem (cdr tem))))) +(put 'require 'byte-hunk-handler 'byte-compile-file-form-require) +(defun byte-compile-file-form-require (form) + (let ((old-load-list current-load-list) + (args (mapcar 'eval (cdr form)))) + (apply 'require args) + ;; Detect (require 'cl) in a way that works even if cl is already loaded. + (if (member (car args) '("cl" cl)) + (setq byte-compile-warnings + (remq 'cl-functions byte-compile-warnings)))) (byte-compile-keep-pending form 'byte-compile-normal-call)) (put 'progn 'byte-hunk-handler 'byte-compile-file-form-progn) @@ -2219,7 +2284,7 @@ list that represents a doc string reference. (not (assq (nth 1 form) byte-compile-initial-macro-environment))) (byte-compile-warn - "%s defined multiple times, as both function and macro" + "`%s' defined multiple times, as both function and macro" (nth 1 form))) (setcdr that-one nil)) (this-one @@ -2228,14 +2293,14 @@ list that represents a doc string reference. ;; byte-compiler macros in byte-run.el... (not (assq (nth 1 form) byte-compile-initial-macro-environment))) - (byte-compile-warn "%s %s defined multiple times in this file" + (byte-compile-warn "%s `%s' defined multiple times in this file" (if macrop "macro" "function") (nth 1 form)))) ((and (fboundp name) (eq (car-safe (symbol-function name)) (if macrop 'lambda 'macro))) (when (memq 'redefine byte-compile-warnings) - (byte-compile-warn "%s %s being redefined as a %s" + (byte-compile-warn "%s `%s' being redefined as a %s" (if macrop "function" "macro") (nth 1 form) (if macrop "macro" "function"))) @@ -2267,7 +2332,7 @@ list that represents a doc string reference. ',name ',declaration)) outbuffer))))) - (let* ((new-one (byte-compile-lambda (cons 'lambda (nthcdr 2 form)))) + (let* ((new-one (byte-compile-lambda (nthcdr 2 form) t)) (code (byte-compile-byte-code-maker new-one))) (if this-one (setcdr this-one new-one) @@ -2463,10 +2528,16 @@ If FORM is a lambda or a macro, byte-compile it as a function." ;; Byte-compile a lambda-expression and return a valid function. ;; The value is usually a compiled function but may be the original ;; lambda-expression. -(defun byte-compile-lambda (fun) - (unless (eq 'lambda (car-safe fun)) - (error "Not a lambda list: %S" fun)) - (byte-compile-set-symbol-position 'lambda) +;; When ADD-LAMBDA is non-nil, the symbol `lambda' is added as head +;; of the list FUN and `byte-compile-set-symbol-position' is not called. +;; Use this feature to avoid calling `byte-compile-set-symbol-position' +;; for symbols generated by the byte compiler itself. +(defun byte-compile-lambda (fun &optional add-lambda) + (if add-lambda + (setq fun (cons 'lambda fun)) + (unless (eq 'lambda (car-safe fun)) + (error "Not a lambda list: %S" fun)) + (byte-compile-set-symbol-position 'lambda)) (byte-compile-check-lambda-list (nth 1 fun)) (let* ((arglist (nth 1 fun)) (byte-compile-bound-variables @@ -2696,26 +2767,39 @@ If FORM is a lambda or a macro, byte-compile it as a function." (defun byte-compile-form (form &optional for-effect) (setq form (macroexpand form byte-compile-macro-environment)) (cond ((not (consp form)) - (when (symbolp form) - (byte-compile-set-symbol-position form)) (cond ((or (not (symbolp form)) (byte-compile-const-symbol-p form)) + (when (symbolp form) + (byte-compile-set-symbol-position form)) (byte-compile-constant form)) ((and for-effect byte-compile-delete-errors) + (when (symbolp form) + (byte-compile-set-symbol-position form)) (setq for-effect nil)) (t (byte-compile-variable-ref 'byte-varref form)))) ((symbolp (car form)) (let* ((fn (car form)) (handler (get fn 'byte-compile))) - (byte-compile-set-symbol-position fn) (when (byte-compile-const-symbol-p fn) - (byte-compile-warn "%s called as a function" fn)) + (byte-compile-warn "`%s' called as a function" fn)) + (and (memq 'interactive-only byte-compile-warnings) + (memq fn byte-compile-interactive-only-functions) + (byte-compile-warn "`%s' used from Lisp code\n\ +That command is designed for interactive use only" fn)) (if (and handler - (or (not (byte-compile-version-cond - byte-compile-compatibility)) - (not (get (get fn 'byte-opcode) 'emacs19-opcode)))) - (funcall handler form) - (if (memq 'callargs byte-compile-warnings) - (byte-compile-callargs-warn form)) + ;; Make sure that function exists. This is important + ;; for CL compiler macros since the symbol may be + ;; `cl-byte-compile-compiler-macro' but if CL isn't + ;; loaded, this function doesn't exist. + (or (not (memq handler '(cl-byte-compile-compiler-macro))) + (functionp handler)) + (not (and (byte-compile-version-cond + byte-compile-compatibility) + (get (get fn 'byte-opcode) 'emacs19-opcode)))) + (funcall handler form) + (when (memq 'callargs byte-compile-warnings) + (if (memq fn '(custom-declare-group custom-declare-variable custom-declare-face)) + (byte-compile-nogroup-warn form)) + (byte-compile-callargs-warn form)) (byte-compile-normal-call form)) (if (memq 'cl-functions byte-compile-warnings) (byte-compile-cl-warn form)))) @@ -2743,9 +2827,9 @@ If FORM is a lambda or a macro, byte-compile it as a function." (if (or (not (symbolp var)) (byte-compile-const-symbol-p var (not (eq base-op 'byte-varref)))) (byte-compile-warn - (cond ((eq base-op 'byte-varbind) "attempt to let-bind %s %s") - ((eq base-op 'byte-varset) "variable assignment to %s %s") - (t "variable reference to %s %s")) + (cond ((eq base-op 'byte-varbind) "attempt to let-bind %s `%s'") + ((eq base-op 'byte-varset) "variable assignment to %s `%s'") + (t "variable reference to %s `%s'")) (if (symbolp var) "constant" "nonvariable") (prin1-to-string var)) (if (and (get var 'byte-obsolete-variable) @@ -2753,11 +2837,11 @@ If FORM is a lambda or a macro, byte-compile it as a function." (not (eq var byte-compile-not-obsolete-var))) (let* ((ob (get var 'byte-obsolete-variable)) (when (cdr ob))) - (byte-compile-warn "%s is an obsolete variable%s; %s" var - (if when (concat " since " when) "") + (byte-compile-warn "`%s' is an obsolete variable%s; %s" var + (if when (concat " (as of Emacs " when ")") "") (if (stringp (car ob)) (car ob) - (format "use %s instead." (car ob)))))) + (format "use `%s' instead." (car ob)))))) (if (memq 'free-vars byte-compile-warnings) (if (eq base-op 'byte-varbind) (push var byte-compile-bound-variables) @@ -2766,11 +2850,11 @@ If FORM is a lambda or a macro, byte-compile it as a function." (if (eq base-op 'byte-varset) (or (memq var byte-compile-free-assignments) (progn - (byte-compile-warn "assignment to free variable %s" var) + (byte-compile-warn "assignment to free variable `%s'" var) (push var byte-compile-free-assignments))) (or (memq var byte-compile-free-references) (progn - (byte-compile-warn "reference to free variable %s" var) + (byte-compile-warn "reference to free variable `%s'" var) (push var byte-compile-free-references)))))))) (let ((tmp (assq var byte-compile-variables))) (unless tmp @@ -2875,9 +2959,6 @@ If FORM is a lambda or a macro, byte-compile it as a function." (put 'byte-concatN 'byte-opcode-invert 'concat) (put 'byte-insertN 'byte-opcode-invert 'insert) -(byte-defop-compiler (dot byte-point) 0) -(byte-defop-compiler (dot-max byte-point-max) 0) -(byte-defop-compiler (dot-min byte-point-min) 0) (byte-defop-compiler point 0) ;;(byte-defop-compiler mark 0) ;; obsolete (byte-defop-compiler point-max 0) @@ -2913,7 +2994,7 @@ If FORM is a lambda or a macro, byte-compile it as a function." (byte-defop-compiler char-after 0-1) (byte-defop-compiler set-buffer 1) ;;(byte-defop-compiler set-mark 1) ;; obsolete -(byte-defop-compiler19 forward-word 1) +(byte-defop-compiler19 forward-word 0-1) (byte-defop-compiler19 char-syntax 1) (byte-defop-compiler19 nreverse 1) (byte-defop-compiler19 car-safe 1) @@ -2971,7 +3052,7 @@ If FORM is a lambda or a macro, byte-compile it as a function." (defun byte-compile-subr-wrong-args (form n) (byte-compile-set-symbol-position (car form)) - (byte-compile-warn "%s called with %d arg%s, but requires %s" + (byte-compile-warn "`%s' called with %d arg%s, but requires %s" (car form) (length (cdr form)) (if (= 1 (length (cdr form))) "" "s") n) ;; get run-time wrong-number-of-args error. @@ -3137,7 +3218,7 @@ If FORM is a lambda or a macro, byte-compile it as a function." (if (and (consp (car body)) (not (eq 'byte-code (car (car body))))) (byte-compile-warn - "A quoted lambda form is the second argument of fset. This is probably + "A quoted lambda form is the second argument of `fset'. This is probably not what you want, as that lambda cannot be compiled. Consider using the syntax (function (lambda (...) ...)) instead."))))) (byte-compile-two-args form)) @@ -3308,11 +3389,14 @@ If FORM is a lambda or a macro, byte-compile it as a function." (defmacro byte-compile-maybe-guarded (condition &rest body) "Execute forms in BODY, potentially guarded by CONDITION. -CONDITION is the test in an `if' form or in a `cond' clause. -BODY is to compile the first arm of the if or the body of the -cond clause. If CONDITION is of the form `(foundp 'foo)' -or `(boundp 'foo)', the relevant warnings from BODY about foo -being undefined will be suppressed." +CONDITION is a variable whose value is a test in an `if' or `cond'. +BODY is the code to compile first arm of the if or the body of the +cond clause. If CONDITION's value is of the form (fboundp 'foo) +or (boundp 'foo), the relevant warnings from BODY about foo's +being undefined will be suppressed. + +If CONDITION's value is (not (featurep 'emacs)) or (featurep 'xemacs), +that suppresses all warnings during execution of BODY." (declare (indent 1) (debug t)) `(let* ((fbound (if (eq 'fboundp (car-safe ,condition)) @@ -3330,13 +3414,19 @@ being undefined will be suppressed." (byte-compile-bound-variables (if bound (cons bound byte-compile-bound-variables) - byte-compile-bound-variables))) - (progn ,@body) - ;; Maybe remove the function symbol from the unresolved list. - (if fbound - (setq byte-compile-unresolved-functions - (delq (assq fbound byte-compile-unresolved-functions) - byte-compile-unresolved-functions))))) + byte-compile-bound-variables)) + ;; Suppress all warnings, for code not used in Emacs. + (byte-compile-warnings + (if (member ,condition '((featurep 'xemacs) + (not (featurep 'emacs)))) + nil byte-compile-warnings))) + (unwind-protect + (progn ,@body) + ;; Maybe remove the function symbol from the unresolved list. + (if fbound + (setq byte-compile-unresolved-functions + (delq (assq fbound byte-compile-unresolved-functions) + byte-compile-unresolved-functions)))))) (defun byte-compile-if (form) (byte-compile-form (car (cdr form))) @@ -3357,7 +3447,8 @@ being undefined will be suppressed." (byte-compile-form (nth 2 form) for-effect)) (byte-compile-goto 'byte-goto donetag) (byte-compile-out-tag elsetag) - (byte-compile-body (cdr (cdr (cdr form))) for-effect) + (byte-compile-maybe-guarded (list 'not clause) + (byte-compile-body (cdr (cdr (cdr form))) for-effect)) (byte-compile-out-tag donetag)))) (setq for-effect nil)) @@ -3377,19 +3468,20 @@ being undefined will be suppressed." (if (null (cdr clause)) ;; First clause is a singleton. (byte-compile-goto-if t 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) for-effect)) - (byte-compile-goto 'byte-goto donetag) - (byte-compile-out-tag nexttag))))) + (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) for-effect)) + (byte-compile-goto 'byte-goto donetag) + (byte-compile-out-tag nexttag))))) ;; Last clause - (and (cdr clause) (not (eq (car clause) t)) - (progn (byte-compile-maybe-guarded (car clause) - (byte-compile-form (car clause))) - (byte-compile-goto-if nil for-effect donetag) - (setq clause (cdr clause)))) - (byte-compile-body-do-effect clause) + (let ((guard (car clause))) + (and (cdr clause) (not (eq guard t)) + (progn (byte-compile-form guard) + (byte-compile-goto-if nil 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) @@ -3397,24 +3489,38 @@ being undefined will be suppressed." (args (cdr form))) (if (null args) (byte-compile-form-do-effect t) - (while (cdr args) - (byte-compile-form (car args)) + (byte-compile-and-recursion args failtag)))) + +;; Handle compilation of a nontrivial `and' call. +;; We use tail recursion so we can use byte-compile-maybe-guarded. +(defun byte-compile-and-recursion (rest failtag) + (if (cdr rest) + (progn + (byte-compile-form (car rest)) (byte-compile-goto-if nil for-effect failtag) - (setq args (cdr args))) - (byte-compile-form-do-effect (car args)) - (byte-compile-out-tag failtag)))) + (byte-compile-maybe-guarded (car rest) + (byte-compile-and-recursion (cdr rest) failtag))) + (byte-compile-form-do-effect (car rest)) + (byte-compile-out-tag failtag))) (defun byte-compile-or (form) (let ((wintag (byte-compile-make-tag)) (args (cdr form))) (if (null args) (byte-compile-form-do-effect nil) - (while (cdr args) - (byte-compile-form (car args)) + (byte-compile-or-recursion args wintag)))) + +;; Handle compilation of a nontrivial `or' call. +;; We use tail recursion so we can use byte-compile-maybe-guarded. +(defun byte-compile-or-recursion (rest wintag) + (if (cdr rest) + (progn + (byte-compile-form (car rest)) (byte-compile-goto-if t for-effect wintag) - (setq args (cdr args))) - (byte-compile-form-do-effect (car args)) - (byte-compile-out-tag wintag)))) + (byte-compile-maybe-guarded (list 'not (car rest)) + (byte-compile-or-recursion (cdr rest) wintag))) + (byte-compile-form-do-effect (car rest)) + (byte-compile-out-tag wintag))) (defun byte-compile-while (form) (let ((endtag (byte-compile-make-tag)) @@ -3519,7 +3625,7 @@ being undefined will be suppressed." (byte-compile-set-symbol-position 'condition-case) (unless (symbolp var) (byte-compile-warn - "%s is not a variable-name or nil (in condition-case)" var)) + "`%s' is not a variable-name or nil (in condition-case)" var)) (byte-compile-push-constant var) (byte-compile-push-constant (byte-compile-top-level (nth 2 form) for-effect)) @@ -3537,13 +3643,13 @@ being undefined will be suppressed." (setq syms (cdr syms))) ok)))) (byte-compile-warn - "%s is not a condition name or list of such (in condition-case)" + "`%s' is not a condition name or list of such (in condition-case)" (prin1-to-string condition))) ;; ((not (or (eq condition 't) ;; (and (stringp (get condition 'error-message)) ;; (consp (get condition 'error-conditions))))) ;; (byte-compile-warn -;; "%s is not a known condition name (in condition-case)" +;; "`%s' is not a known condition name (in condition-case)" ;; condition)) ) (setq compiled-clauses @@ -3590,7 +3696,6 @@ being undefined will be suppressed." (byte-defop-compiler-1 defconst byte-compile-defvar) (byte-defop-compiler-1 autoload) (byte-defop-compiler-1 lambda byte-compile-lambda-form) -(byte-defop-compiler-1 defalias) (defun byte-compile-defun (form) ;; This is not used for file-level defuns with doc strings. @@ -3604,7 +3709,7 @@ being undefined will be suppressed." (list 'fset (list 'quote (nth 1 form)) (byte-compile-byte-code-maker - (byte-compile-lambda (cons 'lambda (cdr (cdr form))))))) + (byte-compile-lambda (cdr (cdr form)) t)))) (byte-compile-discard)) ;; We prefer to generate a defalias form so it will record the function ;; definition just like interpreting a defun. @@ -3612,7 +3717,7 @@ being undefined will be suppressed." (list 'defalias (list 'quote (nth 1 form)) (byte-compile-byte-code-maker - (byte-compile-lambda (cons 'lambda (cdr (cdr form)))))) + (byte-compile-lambda (cdr (cdr form)) t))) t)) (byte-compile-constant (nth 1 form))) @@ -3621,8 +3726,7 @@ being undefined will be suppressed." (byte-compile-body-do-effect (list (list 'fset (list 'quote (nth 1 form)) (let ((code (byte-compile-byte-code-maker - (byte-compile-lambda - (cons 'lambda (cdr (cdr form))))))) + (byte-compile-lambda (cdr (cdr form)) t)))) (if (eq (car-safe code) 'make-byte-code) (list 'cons ''macro code) (list 'quote (cons 'macro (eval code)))))) @@ -3639,7 +3743,7 @@ being undefined will be suppressed." (and (eq fun 'defconst) (null (cddr form)))) (let ((ncall (length (cdr form)))) (byte-compile-warn - "%s called with %d argument%s, but %s %s" + "`%s' called with %d argument%s, but %s %s" fun ncall (if (= 1 ncall) "" "s") (if (< ncall 2) "requires" "accepts only") @@ -3656,7 +3760,7 @@ being undefined will be suppressed." `(push ',var current-load-list)) (when (> (length form) 3) (when (and string (not (stringp string))) - (byte-compile-warn "third arg to %s %s is not a string: %s" + (byte-compile-warn "third arg to `%s %s' is not a string: %s" fun var string)) `(put ',var 'variable-documentation ,string)) (if (cddr form) ; `value' provided @@ -3692,23 +3796,31 @@ being undefined will be suppressed." (error "`lambda' used as function name is invalid")) ;; Compile normally, but deal with warnings for the function being defined. -(defun byte-compile-defalias (form) +(put 'defalias 'byte-hunk-handler 'byte-compile-file-form-defalias) +(defun byte-compile-file-form-defalias (form) (if (and (consp (cdr form)) (consp (nth 1 form)) (eq (car (nth 1 form)) 'quote) (consp (cdr (nth 1 form))) - (symbolp (nth 1 (nth 1 form))) - (consp (nthcdr 2 form)) - (consp (nth 2 form)) - (eq (car (nth 2 form)) 'quote) - (consp (cdr (nth 2 form))) - (symbolp (nth 1 (nth 2 form)))) - (progn + (symbolp (nth 1 (nth 1 form)))) + (let ((constant + (and (consp (nthcdr 2 form)) + (consp (nth 2 form)) + (eq (car (nth 2 form)) 'quote) + (consp (cdr (nth 2 form))) + (symbolp (nth 1 (nth 2 form)))))) (byte-compile-defalias-warn (nth 1 (nth 1 form))) - (setq byte-compile-function-environment - (cons (cons (nth 1 (nth 1 form)) - (nth 1 (nth 2 form))) - byte-compile-function-environment)))) - (byte-compile-normal-call form)) + (push (cons (nth 1 (nth 1 form)) + (if constant (nth 1 (nth 2 form)) t)) + byte-compile-function-environment))) + ;; We used to jus do: (byte-compile-normal-call form) + ;; But it turns out that this fails to optimize the code. + ;; So instead we now do the same as what other byte-hunk-handlers do, + ;; which is to call back byte-compile-file-form and then return nil. + ;; Except that we can't just call byte-compile-file-form since it would + ;; call us right back. + (byte-compile-keep-pending form) + ;; Return nil so the form is not output twice. + nil) ;; Turn off warnings about prior calls to the function being defalias'd. ;; This could be smarter and compare those calls with @@ -3722,7 +3834,20 @@ being undefined will be suppressed." (byte-defop-compiler-1 with-no-warnings byte-compile-no-warnings) (defun byte-compile-no-warnings (form) (let (byte-compile-warnings) - (byte-compile-form (cadr form)))) + (byte-compile-form (cons 'progn (cdr form))))) + +;; Warn about misuses of make-variable-buffer-local. +(byte-defop-compiler-1 make-variable-buffer-local byte-compile-make-variable-buffer-local) +(defun byte-compile-make-variable-buffer-local (form) + (if (eq (car-safe (car-safe (cdr-safe form))) 'quote) + (byte-compile-warn + "`make-variable-buffer-local' should be called at toplevel")) + (byte-compile-normal-call form)) +(put 'make-variable-buffer-local + 'byte-hunk-handler 'byte-compile-form-make-variable-buffer-local) +(defun byte-compile-form-make-variable-buffer-local (form) + (byte-compile-keep-pending form 'byte-compile-normal-call)) + ;;; tags @@ -3890,15 +4015,18 @@ invoked interactively." (mapconcat 'symbol-name callers ", ") "")) (let ((fill-prefix " ")) - (fill-region-as-paragraph p (point))))) + (fill-region-as-paragraph p (point))) + (unless (= 0 (current-column)) + (insert "\n")))) (if calls (progn (insert " calls:\n") (setq p (point)) (insert " " (mapconcat 'symbol-name calls ", ")) (let ((fill-prefix " ")) - (fill-region-as-paragraph p (point))))) - (insert "\n") + (fill-region-as-paragraph p (point))) + (unless (= 0 (current-column)) + (insert "\n")))) (setq rest (cdr rest))) (message "Generating call tree...(finding uncalled functions...)") @@ -3907,7 +4035,7 @@ invoked interactively." (while rest (or (nth 1 (car rest)) (null (setq f (car (car rest)))) - (byte-compile-fdefinition f t) + (functionp (byte-compile-fdefinition f t)) (commandp (byte-compile-fdefinition f nil)) (setq uncalled (cons f uncalled))) (setq rest (cdr rest))) @@ -3972,33 +4100,39 @@ already up-to-date." (kill-emacs (if error 1 0)))) (defun batch-byte-compile-file (file) - (condition-case err + (if debug-on-error (byte-compile-file file) - (file-error - (message (if (cdr err) - ">>Error occurred processing %s: %s (%s)" + (condition-case err + (byte-compile-file file) + (file-error + (message (if (cdr err) + ">>Error occurred processing %s: %s (%s)" ">>Error occurred processing %s: %s") - file - (get (car err) 'error-message) - (prin1-to-string (cdr err))) - (let ((destfile (byte-compile-dest-file file))) - (if (file-exists-p destfile) - (delete-file destfile))) - nil) - (error - (message (if (cdr err) - ">>Error occurred processing %s: %s (%s)" + file + (get (car err) 'error-message) + (prin1-to-string (cdr err))) + (let ((destfile (byte-compile-dest-file file))) + (if (file-exists-p destfile) + (delete-file destfile))) + nil) + (error + (message (if (cdr err) + ">>Error occurred processing %s: %s (%s)" ">>Error occurred processing %s: %s") - file - (get (car err) 'error-message) - (prin1-to-string (cdr err))) - nil))) + file + (get (car err) 'error-message) + (prin1-to-string (cdr err))) + nil)))) ;;;###autoload -(defun batch-byte-recompile-directory () +(defun batch-byte-recompile-directory (&optional arg) "Run `byte-recompile-directory' on the dirs remaining on the command line. Must be used only with `-batch', and kills Emacs on completion. -For example, invoke `emacs -batch -f batch-byte-recompile-directory .'." +For example, invoke `emacs -batch -f batch-byte-recompile-directory .'. + +Optional argument ARG is passed as second argument ARG to +`batch-recompile-directory'; see there for its possible values +and corresponding effects." ;; command-line-args-left is what is left of the command line (startup.el) (defvar command-line-args-left) ;Avoid 'free variable' warning (if (not noninteractive) @@ -4006,31 +4140,10 @@ For example, invoke `emacs -batch -f batch-byte-recompile-directory .'." (or command-line-args-left (setq command-line-args-left '("."))) (while command-line-args-left - (byte-recompile-directory (car command-line-args-left)) + (byte-recompile-directory (car command-line-args-left) arg) (setq command-line-args-left (cdr command-line-args-left))) (kill-emacs 0)) - -(make-obsolete-variable 'auto-fill-hook 'auto-fill-function "before 19.15") -(make-obsolete-variable 'blink-paren-hook 'blink-paren-function "before 19.15") -(make-obsolete-variable 'lisp-indent-hook 'lisp-indent-function "before 19.15") -(make-obsolete-variable 'inhibit-local-variables - "use enable-local-variables (with the reversed sense)." - "before 19.15") -(make-obsolete-variable 'unread-command-event - "use unread-command-events; which is a list of events rather than a single event." - "before 19.15") -(make-obsolete-variable 'suspend-hooks 'suspend-hook "before 19.15") -(make-obsolete-variable 'comment-indent-hook 'comment-indent-function "before 19.15") -(make-obsolete-variable 'meta-flag "use the set-input-mode function instead." "before 19.34") -(make-obsolete-variable 'before-change-function - "use before-change-functions; which is a list of functions rather than a single function." - "before 19.34") -(make-obsolete-variable 'after-change-function - "use after-change-functions; which is a list of functions rather than a single function." - "before 19.34") -(make-obsolete-variable 'font-lock-doc-string-face 'font-lock-string-face "before 19.34") - (provide 'byte-compile) (provide 'bytecomp) @@ -4087,5 +4200,5 @@ For example, invoke `emacs -batch -f batch-byte-recompile-directory .'." (run-hooks 'bytecomp-load-hook) -;;; arch-tag: 9c97b0f0-8745-4571-bfc3-8dceb677292a +;; arch-tag: 9c97b0f0-8745-4571-bfc3-8dceb677292a ;;; bytecomp.el ends here