1 ;;;; the bare essentials of compiler error handling
3 ;;;; (Logically, this might belong in early-c.lisp, since it's stuff
4 ;;;; which might as well be visible to all compiler code. However,
5 ;;;; physically its DEFINE-CONDITION forms depend on the condition
6 ;;;; system being set up before it can be cold loaded, so we keep it
7 ;;;; in this separate, loaded-later file instead of in early-c.lisp.)
9 ;;;; This software is part of the SBCL system. See the README file for
10 ;;;; more information.
12 ;;;; This software is derived from the CMU CL system, which was
13 ;;;; written at Carnegie Mellon University and released into the
14 ;;;; public domain. The software is in the public domain and is
15 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
16 ;;;; files for more information.
20 ;;;; error-handling definitions which are easy to define early and
21 ;;;; which are nice to have visible everywhere
23 ;;; a function that is called to unwind out of COMPILER-ERROR
24 (declaim (type (function () nil) *compiler-error-bailout*))
25 (defvar *compiler-error-bailout*)
27 ;;; an application programmer's error caught by the compiler
29 ;;; We want a separate condition for application programmer errors so
30 ;;; that we can distinguish them from system programming errors (bugs
31 ;;; in SBCL itself). Application programmer errors should be caught
32 ;;; and turned into diagnostic output and a FAILURE-P return value
33 ;;; from COMPILE or COMPILE-FILE. Bugs in SBCL itself throw us into
36 ;;; A further word or two of explanation might be warranted here,
37 ;;; since I (CSR) have spent the last day or so wandering in a
38 ;;; confused daze trying to get this to behave nicely before finally
39 ;;; hitting on the right solution.
41 ;;; These objects obey a slightly involved protocol in order to
42 ;;; achieve the right dynamic behaviour. If we signal a
43 ;;; COMPILER-ERROR from within the compiler, we want that the
44 ;;; outermost call to COMPILE/COMPILE-FILE cease attempting to compile
45 ;;; the code in question and instead compile a call to signal a
46 ;;; PROGRAM-ERROR. This is achieved by resignalling the condition
47 ;;; from within the handler, so that the condition travels up the
48 ;;; handler stack until it finds the outermost handler. Why the
49 ;;; outermost? Well, COMPILE-FILE could call EVAL from an EVAL-WHEN,
50 ;;; which could recursively call COMPILE, which could then signal an
51 ;;; error; we want the inner EVAL not to fail so that we can go on
52 ;;; compiling, so it's the outer COMPILE-FILE that needs to replace
53 ;;; the erroneous call with a call to ERROR.
55 ;;; This resignalling up the stack means that COMPILER-ERROR should
56 ;;; not be a generalized instance of ERROR, as otherwise code such as
57 ;;; (IGNORE-ERRORS (DEFGENERIC IF (X))) will catch and claim to handle
58 ;;; the COMPILER-ERROR. So we make COMPILER-ERROR inherit from
59 ;;; SIMPLE-CONDITION and SERIOUS-CONDITION instead, as of
60 ;;; sbcl-0.8alpha.0.2x, so that unless the user claims to be able to
61 ;;; handle SERIOUS-CONDITION (and if he does, he deserves what's going
64 ;;; So, what if we're not inside the compiler, then? Well, in that
65 ;;; case we're in the evaluator, so we want to convert the
66 ;;; COMPILER-ERROR into a PROGRAM-ERROR and signal it immediately. We
67 ;;; have to signal the PROGRAM-ERROR from the dynamic environment of
68 ;;; attempting to evaluate the erroneous code, and not from any
69 ;;; exterior handler, so that user handlers for PROGRAM-ERROR and
70 ;;; ERROR stand a chance of running, in e.g. (IGNORE-ERRORS
71 ;;; (DEFGENERIC IF (X))). So this is where the SIGNAL-PROGRAM-ERROR
72 ;;; restart comes in; the handler in EVAL-IN-LEXENV chooses this
73 ;;; restart if it believes that the compiler is not present (which it
74 ;;; tests using the BOUNDPness of *COMPILER-ERROR-BAILOUT*). The
75 ;;; restart executes in the dynamic environment of the original
76 ;;; COMPILER-ERROR call, and all is well.
79 (define-condition compiler-error (simple-condition serious-condition) ())
81 ;;; Signal the appropriate condition. COMPILER-ERROR calls the bailout
82 ;;; function so that it never returns (but compilation continues).
83 ;;; COMPILER-ABORT falls through to the default error handling, so
84 ;;; compilation terminates.
85 (declaim (ftype (function (string &rest t) nil) compiler-error compiler-abort))
86 (declaim (ftype (function (string &rest t) (values))
87 compiler-warning compiler-style-warning))
88 (defun compiler-abort (format-string &rest format-args)
89 (error 'compiler-error
90 :format-control format-string
91 :format-arguments format-args))
92 (defun compiler-error (format-string &rest format-args)
95 (cerror "Replace form with call to ERROR."
97 :format-control format-string
98 :format-arguments format-args)
99 (funcall *compiler-error-bailout*)
100 (bug "Control returned from *COMPILER-ERROR-BAILOUT*."))
101 (signal-program-error ()
102 (error 'simple-program-error
103 :format-control format-string
104 :format-arguments format-args))))
105 (defun compiler-warn (format-string &rest format-args)
106 (apply #'warn format-string format-args)
108 (defun compiler-style-warn (format-string &rest format-args)
109 (apply #'style-warn format-string format-args)
112 ;;; the condition of COMPILE-FILE being unable to READ from the
115 ;;; This is not a COMPILER-ERROR, since we don't try to recover from
116 ;;; it and keep chugging along, but instead immediately bail out of
117 ;;; the entire COMPILE-FILE.
119 ;;; (The old CMU CL code did try to recover from this condition, but
120 ;;; the code for doing that was messy and didn't always work right.
121 ;;; Since in Common Lisp the simple act of reading and compiling code
122 ;;; (even without ever loading the compiled result) can have side
123 ;;; effects, it's a little scary to go on reading code when you're
124 ;;; deeply confused, so we violate what'd otherwise be good compiler
125 ;;; practice by not trying to recover from this error and bailing out
127 (define-condition input-error-in-compile-file (error)
128 (;; the original error which was trapped to produce this condition
129 (error :reader input-error-in-compile-file-error
131 ;; the position where the bad READ began, or NIL if unavailable,
132 ;; redundant, or irrelevant
133 (position :reader input-error-in-compile-file-position
137 (lambda (condition stream)
139 "~@<~S failure in ~S~@[ at character ~W~]: ~2I~_~A~:>"
142 (input-error-in-compile-file-position condition)
143 (input-error-in-compile-file-error condition)))))