X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/b88a41d0064828aab6c75d7a8c6f543022fa5dd5..5dd1c041c7fdb876b52bf33f41e8aeb119282cef:/lisp/emacs-lisp/bytecomp.el diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 8e20925c70..02a88c1397 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -1,7 +1,7 @@ ;;; 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 @@ -22,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: @@ -98,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. @@ -190,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) @@ -290,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. @@ -308,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*. @@ -325,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). @@ -334,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. @@ -435,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. @@ -792,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) @@ -809,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'." @@ -848,12 +890,13 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." ;; Log something that isn't a warning. (defun byte-compile-log-1 (string) (with-current-buffer "*Compile-Log*" - (goto-char (point-max)) - (byte-compile-warning-prefix nil nil) - (cond (noninteractive - (message " %s" string)) - (t - (insert (format "%s\n" string)))))) + (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.") @@ -881,20 +924,27 @@ 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))))))) @@ -904,7 +954,8 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'." ;; 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) @@ -950,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) @@ -984,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) @@ -1008,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 @@ -1075,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 @@ -1140,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) @@ -1170,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. @@ -1181,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. @@ -1211,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) @@ -1532,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) @@ -1593,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))) @@ -1732,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. @@ -2076,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)) @@ -2095,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. @@ -2123,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))) @@ -2140,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) @@ -2206,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 @@ -2215,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"))) @@ -2254,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) @@ -2450,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 @@ -2683,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)))) @@ -2730,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) @@ -2740,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) @@ -2753,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 @@ -2862,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) @@ -2900,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) @@ -2958,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. @@ -3124,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)) @@ -3295,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)) @@ -3317,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))) @@ -3344,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)) @@ -3364,12 +3468,12 @@ 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 (let ((guard (car clause))) (and (cdr clause) (not (eq guard t)) @@ -3385,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)) @@ -3507,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)) @@ -3525,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 @@ -3578,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. @@ -3592,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. @@ -3600,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))) @@ -3609,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)))))) @@ -3627,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") @@ -3644,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 @@ -3680,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 @@ -3711,6 +3835,19 @@ being undefined will be suppressed." (defun byte-compile-no-warnings (form) (let (byte-compile-warnings) (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 @@ -3878,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...)") @@ -3895,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))) @@ -3988,7 +4128,11 @@ already up-to-date." (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) @@ -4000,27 +4144,6 @@ For example, invoke `emacs -batch -f batch-byte-recompile-directory .'." (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) @@ -4077,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