Hello. We have had running in XEmacs for two years or more some routines I
wrote to cleanly handle byte-compilation warnings. The problem was that
many byte-compilation warnings were unavoidable when doing legitimate
things. I came up with a clean solution to this problem and it has worked
very well; all of the XEmacs core elisp code is now completely warning-free.
I propose that this be incorporated into GNU Emacs as well. If agreed, I
will sign papers and do whatever else is needed. I am the only author of
this code.
I'm attaching the doc strings. I would post the code itself but I gather
rms does not want GNU Emacs developers to see non-kosher [i.e. not
copyright-assigned] XEmacs code. If I'm wrong please let me know and I'll
post the sources.
;;; Functions to cleanly eliminate warnings about undefined functions
;;; or variables when the code knows what it's doing. These macros DO
;;; NOT rely on any byte-compiler changes, and thus can be copied into
;;; a package and used within it.
;; NOTE: As a result of the above requirement, the macros rely on
;; "tricks" to get the warnings suppressed. A cleaner way, of course,
;; would be to extend the byte compiler to provide a proper interface.
;; #### Should we require an unquoted symbol rather than a quoted one,
;; as we currently do? The quoting gets no generality, as `eval' is
;; called at compile time. But most functions and macros want quoted
;; arguments, and I find it extremely confusing to deal with cases
;; such as `throw' requiring a quoted argument but `block' an unquoted
;; one.
(put 'with-boundp 'lisp-indent-function 1)
(defmacro with-boundp (variables &rest body)
"Evaluate BODY, but do not issue bytecomp warnings about VARIABLES
undefined.
VARIABLES can be a symbol or a list of symbols and must be quoted. When
compiling this file, the warnings `reference to free variable VARIABLE' and
`assignment to free variable VARIABLE' will not occur anywhere in BODY, for
any of the listed variables. This is a clean way to avoid such warnings.
See also `if-boundp', `when-boundp', and `and-boundp' (ways to
conditionalize on a variable being bound and avoid warnings),
`declare-boundp' (issue a variable call without warnings), and
`globally-declare-boundp' (avoid warnings throughout a file about a
variable)."
(put 'if-boundp 'lisp-indent-function 2)
(defmacro if-boundp (variable then &rest else)
"Equivalent to (if (boundp VARIABLE) THEN ELSE) but handles bytecomp
warnings.
VARIABLE should be a quoted symbol. When compiling this file, the warnings
`reference to free variable VARIABLE' and `assignment to free variable
VARIABLE' will not occur anywhere in the if-statement. This is a clean way
to avoid such warnings. See also `with-boundp' and friends."
(put 'when-boundp 'lisp-indent-function 1)
(defmacro when-boundp (variable &rest body)
"Equivalent to (when (boundp VARIABLE) BODY) but handles bytecomp
warnings.
VARIABLE should be a quoted symbol. When compiling this file, the warnings
`reference to free variable VARIABLE' and `assignment to free variable
VARIABLE' will not occur anywhere in the when-statement. This is a clean
way to avoid such warnings. See also `with-boundp' and friends."
(put 'and-boundp 'lisp-indent-function 1)
(defmacro and-boundp (variable &rest args)
"Equivalent to (and (boundp VARIABLE) ARGS) but handles bytecomp warnings.
VARIABLE should be a quoted symbol. When compiling this file, the warnings
`reference to free variable VARIABLE' and `assignment to free variable
VARIABLE' will not occur anywhere in the and-statement. This is a clean
way to avoid such warnings. See also `with-boundp' and friends."
(defmacro declare-boundp (variable)
"Evaluate VARIABLE without bytecomp warnings about the symbol.
Sample usage is
(declare-boundp gpm-minor-mode)
which is equivalent to
(with-boundp 'gpm-minor-mode
gpm-minor-mode)
See also `with-boundp' and friends."
(defmacro globally-declare-boundp (variables)
"Declare that all free uses of VARIABLES in this file are valid.
VARIABLES can be a symbol or a list of symbols and must be quoted.
When compiling this file, the warnings `reference to free variable
VARIABLE' and `assignment to free variable VARIABLE' will not occur
regardless of where references to VARIABLE occur in the file.
In general, you should *NOT* use this; use `with-boundp' or its friends to
wrap individual uses, as necessary. That way, you're more likely to
remember to put in the explicit checks for the variable's existence that
are usually necessary. However, `globally-declare-boundp' is better in
some circumstances, such as when writing an ELisp package that makes
integral use of optionally-compiled-in functionality (typically, an
interface onto a system library) and checks for the existence of the
functionality at some entry point to the package. See
`globally-declare-fboundp' for more information."
(put 'with-fboundp 'lisp-indent-function 1)
(defmacro with-fboundp (functions &rest body)
"Evaluate BODY, but do not issue bytecomp warnings about FUNCTIONS
undefined.
FUNCTIONS can be a symbol or a list of symbols and must be quoted. When
compiling this file, the warning `the function FUNCTION is not known to be
defined' will not occur anywhere in BODY, for any of the listed functions.
This is a clean way to avoid such warnings.
See also `if-fboundp', `when-fboundp', and `and-fboundp' (ways to
conditionalize on a function being bound and avoid warnings),
`declare-fboundp' (issue a function call without warnings), and
`globally-declare-fboundp' (avoid warnings throughout a file about a
function)."
(put 'if-fboundp 'lisp-indent-function 2)
(defmacro if-fboundp (function then &rest else)
"Equivalent to (if (fboundp FUNCTION) THEN ELSE) but handles bytecomp
warnings.
FUNCTION should be a quoted symbol. When compiling this file, the warning
`the function FUNCTION is not known to be defined' will not occur anywhere
in the if-statement. This is a clean way to avoid such warnings. See also
`with-fboundp' and friends."
(put 'when-fboundp 'lisp-indent-function 1)
(defmacro when-fboundp (function &rest body)
"Equivalent to (when (fboundp FUNCTION) BODY) but handles bytecomp
warnings.
FUNCTION should be a quoted symbol. When compiling this file, the warning
`the function FUNCTION is not known to be defined' will not occur anywhere
in the when-statement. This is a clean way to avoid such warnings. See
also
`with-fboundp' and friends."
(put 'and-fboundp 'lisp-indent-function 1)
(defmacro and-fboundp (function &rest args)
"Equivalent to (and (fboundp FUNCTION) ARGS) but handles bytecomp
warnings.
FUNCTION should be a quoted symbol. When compiling this file, the warning
`the function FUNCTION is not known to be defined' will not occur anywhere
in the and-statement. This is a clean way to avoid such warnings. See also
`with-fboundp' and friends."
(defmacro declare-fboundp (form)
"Execute FORM (a function call) without bytecomp warnings about the call.
Sample usage is
(declare-fboundp (x-keysym-on-keyboard-sans-modifiers-p 'backspace))
which is equivalent to
(with-fboundp 'x-keysym-on-keyboard-sans-modifiers-p
(x-keysym-on-keyboard-sans-modifiers-p 'backspace))
See also `with-fboundp' and friends."
(defmacro globally-declare-fboundp (functions)
"Declare that all calls to function FUNCTIONS in this file are valid.
FUNCTIONS can be a symbol or a list of symbols and must be quoted.
When compiling this file, the warning `the function FUNCTION is not known
to be defined' will not occur regardless of where calls to FUNCTION occur
in the file.
In general, you should *NOT* use this; use `with-fboundp' or its friends to
wrap individual uses, as necessary. That way, you're more likely to
remember to put in the explicit checks for the function's existence that
are usually necessary. However, `globally-declare-fboundp' is better in
some circumstances, such as when writing an ELisp package that makes
integral use of optionally-compiled-in functionality (typically, an
interface onto a system library) and checks for the existence of the
functionality at some entry point to the package. The file `ldap.el' is a
good example: It provides a layer on top of the optional LDAP ELisp
primitives, makes calls to them throughout its code, and verifies the
presence of LDAP support at load time. Putting calls to `declare-fboundp'
throughout the code would be a major annoyance."
(defmacro with-byte-compiler-warnings-suppressed (type &rest body)
"Evaluate BODY, but do not issue bytecomp warnings TYPE.
TYPE should be one of `redefine', `callargs', `subr-callargs',
`free-vars', `unresolved', `unused-vars', `obsolete', or `pedantic',
or a list of one or more of these symbols. (See `byte-compile-warnings'.)
TYPE must be quoted.
NOTE: You should *NOT* under normal circumstances be using this!
There are better ways of avoiding most of these warnings. In particular:
-- use (declare (special ...)) if you are making use of
dynamically-scoped variables.
-- use `with-fboundp' and friends to avoid warnings about undefined
functions
when you know the function actually exists.
-- use `with-boundp' and friends to avoid warnings about undefined variables
when you know the variable actually exists.
-- use `with-obsolete-variable' or `with-obsolete-function' if you
are purposely using such a variable or function."
(put 'with-obsolete-variable 'lisp-indent-function 1)
(defmacro with-obsolete-variable (symbol &rest body)
"Evaluate BODY but do not warn about usage of obsolete variable SYMBOL.
SYMBOL must be quoted and can be a list of SYMBOLS. See also
`with-obsolete-function'."
(put 'with-obsolete-function 'lisp-indent-function 1)
(defmacro with-obsolete-function (symbol &rest body)
"Evaluate BODY but do not warn about usage of obsolete function SYMBOL.
SYMBOL must be quoted and can be a list of SYMBOLS. See also
`with-obsolete-variable'."