Record XREFs for symbols that name functions.
[sbcl.git] / src / code / error.lisp
blob3f487d33ebd4055ff28ad88547f822bb14558c6e
1 ;;;; SBCL-specific parts of the condition system, i.e. parts which
2 ;;;; don't duplicate/clobber functionality already provided by the
3 ;;;; cross-compilation host Common Lisp
5 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; more information.
7 ;;;;
8 ;;;; This software is derived from the CMU CL system, which was
9 ;;;; written at Carnegie Mellon University and released into the
10 ;;;; public domain. The software is in the public domain and is
11 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
12 ;;;; files for more information.
14 (in-package "SB-KERNEL")
16 ;;; a utility for SIGNAL, ERROR, CERROR, WARN, COMPILER-NOTIFY and
17 ;;; INVOKE-DEBUGGER: Parse the hairy argument conventions into a
18 ;;; single argument that's directly usable by all the other routines.
19 (defun coerce-to-condition (datum default-type fun-name &rest arguments)
20 (declare (explicit-check)
21 (dynamic-extent arguments))
22 (cond ((and (%instancep datum)
23 (let ((layout (%instance-layout datum)))
24 (and (logtest (layout-flags layout) +condition-layout-flag+)
25 ;; An invalid layout will drop into the (MAKE-CONDITION) branch
26 ;; which rightly fails because ALLOCATE-CONDITION asserts that
27 ;; the first argument is a condition-designator, which it won't be.
28 (not (layout-invalid layout)))))
29 (when (and arguments (not (eq fun-name 'cerror)))
30 (cerror "Ignore the additional arguments."
31 'simple-type-error
32 :datum (copy-list arguments)
33 :expected-type 'null
34 :format-control "You may not supply additional arguments ~
35 when giving ~S to ~S."
36 :format-arguments (list datum fun-name)))
37 datum)
38 ((or (stringp datum) (functionp datum))
39 (make-condition default-type
40 :format-control datum
41 :format-arguments (copy-list arguments)))
43 (apply #'make-condition datum arguments))))
45 ;;; This condition inherits from the hosts's classes when compiling
46 ;;; the cross-compiler and the target's when cross-compiling.
47 (define-condition simple-program-error (simple-condition program-error) ())
48 (defun %program-error (&optional datum &rest arguments)
49 (error (apply #'coerce-to-condition datum
50 'simple-program-error '%program-error arguments)))
53 ;;;; HANDLER-BIND
55 (sb-xc:defmacro %handler-bind (bindings form &environment env)
56 (unless bindings
57 (return-from %handler-bind form))
58 ;; Type specifiers in BINDINGS which name classoids are parsed
59 ;; into the classoid, otherwise are translated local TYPEP wrappers.
61 ;; As a further optimization, it is possible to eliminate some runtime
62 ;; consing (which is a speed win if not a space win, since it's dx already)
63 ;; in special cases such as (HANDLER-BIND ((WARNING #'MUFFLE-WARNING)) ...).
64 ;; If all bindings are optimizable, then the runtime cost of making them
65 ;; is one dx cons cell for the whole cluster.
66 ;; Otherwise it takes 1+2N cons cells where N is the number of bindings.
68 (collect ((cluster-entries) (dummy-forms))
69 (flet ((const-cons (test handler)
70 ;; If possible, render HANDLER as a load-time constant so that
71 ;; consing the test and handler is also load-time constant.
72 (if (and (listp handler)
73 (memq (car handler) '(quote function))
74 (not (sb-c::fun-locally-defined-p (cadr handler) env))
75 (legal-fun-name-p (cadr handler)))
76 ;; The CLHS writeup of HANDLER-BIND says "Exceptional Situations: None."
77 ;; which might suggest that it's not an error if #'HANDLER is un-fboundp
78 ;; on entering the body, but we should check in safe code.
79 (let ((name (cadr handler)))
80 (cond ((info :function :info name) ; known
81 ;; This takes care of CONTINUE,ABORT,MUFFLE-WARNING.
82 ;; #' will be evaluated in the null environment.
83 `(load-time-value (cons ,test (the (function (condition)) #',name))
84 t))
86 (when (eq (car handler) 'function)
87 ;; Referencing #'F is enough to get a compile-time warning about unknown
88 ;; functions, but the use itself is flushable, so employ SAFE-FDEFN-FUN.
89 (dummy-forms `#',name)
90 (when (sb-c:policy env (= safety 3))
91 (dummy-forms `(sb-c:safe-fdefn-fun
92 (load-time-value
93 (find-or-create-fdefn ',name) t)))))
94 `(load-time-value
95 (cons ,test (the (function-designator (condition)) ',name))
96 t))))
97 `(cons ,(case (car test)
98 ((named-lambda function) test)
99 (t `(load-time-value ,test t)))
100 (the (function-designator (condition)) ,handler))))
101 (const-list (items)
102 ;; If the resultant list is (LIST (L-T-V ...) (L-T-V ...) ...)
103 ;; then pull the L-T-V outside.
104 (if (every (lambda (x) (typep x '(cons (eql load-time-value))))
105 items)
106 `(load-time-value (list ,@(mapcar #'second items)) t)
107 `(list ,@items))))
109 (with-current-source-form (bindings)
110 (dolist (binding bindings)
111 (with-current-source-form (binding)
112 (unless (proper-list-of-length-p binding 2)
113 (error "ill-formed handler binding: ~S" binding))
114 (destructuring-bind (type handler) binding
115 (setq type (typexpand type env))
116 ;; Simplify a singleton AND or OR.
117 (when (typep type '(cons (member and or) (cons t null)))
118 (setf type (second type)))
119 (cluster-entries
120 (const-cons
121 ;; Compute the test expression
122 (cond ((member type '(t condition))
123 ;; Every signal is necesarily a CONDITION, so
124 ;; whether you wrote T or CONDITION, this is
125 ;; always an eligible handler.
126 '#'constantly-t)
127 ((typep type '(cons (eql satisfies) (cons symbol null)))
128 ;; (SATISFIES F) => #'F but never a local definition of F.
129 ;; The predicate is used only if needed - it's not an error if not
130 ;; fboundp (though dangerously stupid) - so reference #'F for the
131 ;; compiler to see the use of the name. But (KLUDGE): since the
132 ;; ref is to force a compile-time effect, the interpreter should not
133 ;; see that form, because there is no way for it to perform an
134 ;; unsafe ref, and it wouldn't signal a style-warning anyway.
135 (let ((name (second type)))
136 ;; FIXME: if you've locally flet NAME (why would you do that?)
137 ;; then this does not notice the use of the global function.
138 (when (typep env 'lexenv) (dummy-forms `#',name))
139 `',name))
140 ((and (symbolp type)
141 (condition-classoid-p (find-classoid type nil)))
142 ;; It's debatable whether we need to go through
143 ;; a classoid-cell instead of just using
144 ;; load-time-value on FIND-CLASS, but the extra
145 ;; indirection is safer, and no slower than
146 ;; what TYPEP does.
147 `(find-classoid-cell ',type :create t))
148 (t ; No runtime consing here- not a closure.
149 `(named-lambda (%handler-bind ,type) (c)
150 (declare (optimize (sb-c:verify-arg-count 0)))
151 (typep c ',type))))
152 ;; If the supplied handler is spelled (LAMBDA ...) or
153 ;; #'(LAMBDA ...), then insert a declaration to elide
154 ;; arg checking.
156 ;; KLUDGE: This should really be done in a cleaner way.
157 (let ((lambda-expression
158 (typecase handler
159 ((cons (eql function) (cons (cons (eql lambda)) null))
160 (cadr handler))
161 ((cons (eql lambda))
162 handler))))
163 (if lambda-expression
164 `(lambda ,(cadr lambda-expression)
165 (declare (sb-c::source-form ,binding))
166 ,@(when (typep (cadr lambda-expression) '(cons t null))
167 '((declare (sb-c::local-optimize (sb-c::verify-arg-count 0)))))
168 ,@(cddr lambda-expression))
169 handler))))))))
170 `(let ((*handler-clusters*
171 (cons ,(const-list (cluster-entries))
172 *handler-clusters*)))
173 (declare (dynamic-extent *handler-clusters*))
174 ,@(dummy-forms)
175 ,form))))
177 (sb-xc:defmacro handler-bind (bindings &body forms)
178 "(HANDLER-BIND ( {(type handler)}* ) body)
180 Executes body in a dynamic context where the given handler bindings are in
181 effect. Each handler must take the condition being signalled as an argument.
182 The bindings are searched first to last in the event of a signalled
183 condition."
184 ;; Bindings which meet specific criteria can be established with
185 ;; slightly less runtime overhead than in general.
186 ;; To allow the optimization, TYPE must be either be (SATISFIES P)
187 ;; or a symbol naming a condition class at compile time,
188 ;; and HANDLER must be a global function specified as either 'F or #'F.
189 `(%handler-bind ,bindings
190 #-x86 (progn ,@forms)
191 ;; Need to catch FP errors here!
192 #+x86 (multiple-value-prog1 (progn ,@forms) (float-wait))))
194 ;;;; HANDLER-CASE and IGNORE-ERRORS.
195 (sb-xc:defmacro handler-case (form &rest cases)
196 "(HANDLER-CASE form { (type ([var]) body) }* )
198 Execute FORM in a context with handlers established for the condition types. A
199 peculiar property allows type to be :NO-ERROR. If such a clause occurs, and
200 form returns normally, all its values are passed to this clause as if by
201 MULTIPLE-VALUE-CALL. The :NO-ERROR clause accepts more than one var
202 specification."
203 (let ((no-error-clause (assoc ':no-error cases)))
204 (if no-error-clause
205 (let ((normal-return (make-symbol "normal-return"))
206 (error-return (make-symbol "error-return")))
207 `(block ,error-return
208 (multiple-value-call (lambda ,@(cdr no-error-clause))
209 (block ,normal-return
210 (return-from ,error-return
211 (handler-case (return-from ,normal-return ,form)
212 ,@(remove no-error-clause cases)))))))
213 (let* ((local-funs nil)
214 (annotated-cases
215 (mapcar (lambda (case)
216 (with-current-source-form (case)
217 (with-unique-names (block fun)
218 (destructuring-bind (type ll &body body) case
219 (unless (and (listp ll)
220 (symbolp (car ll))
221 (null (cdr ll)))
222 (error "Malformed HANDLER-CASE lambda-list. Should be either () or (symbol), not ~s."
223 ll))
224 (multiple-value-bind (body declarations)
225 (parse-body body nil)
226 (push `(,fun ,ll
227 (declare (sb-c::source-form ,case))
228 ,@declarations
229 (progn ,@body))
230 local-funs))
231 (list block type ll fun)))))
232 cases)))
233 (with-unique-names (block form-fun)
234 (let ((body `(%handler-bind
235 ,(mapcar (lambda (annotated-case)
236 (destructuring-bind (block type ll fun-name) annotated-case
237 (declare (ignore fun-name))
238 (list type
239 `(lambda (temp)
240 ,@(unless ll
241 `((declare (ignore temp))))
242 (return-from ,block
243 ,@(and ll '(temp)))))))
244 annotated-cases)
245 (return-from ,block (,form-fun)))))
246 (labels ((wrap (cases)
247 (if cases
248 (destructuring-bind (fun-block type ll fun-name) (car cases)
249 (declare (ignore type))
250 `(return-from ,block
251 ,(if ll
252 `(,fun-name (block ,fun-block
253 ,(wrap (cdr cases))))
254 `(progn (block ,fun-block
255 ,(wrap (cdr cases)))
256 (,fun-name)))))
257 body)))
258 `(dx-flet ((,form-fun ()
259 #-x86 (progn ,form) ;; no declarations are accepted
260 ;; Need to catch FP errors here!
261 #+x86 (multiple-value-prog1 ,form (float-wait)))
262 ,@(reverse local-funs))
263 (declare (inline ,form-fun
264 ,@(mapcar #'car local-funs)))
265 (block ,block
266 ,(wrap annotated-cases))))))))))
268 (sb-xc:defmacro ignore-errors (&rest forms)
269 "Execute FORMS handling ERROR conditions, returning the result of the last
270 form, or (VALUES NIL the-ERROR-that-was-caught) if an ERROR was handled."
271 `(handler-case (progn ,@forms)
272 (error (condition) (values nil condition))))
274 ;;; Condition slot access - needs DYNAMIC-SPACE-OBJ-P which needs misc-aliens
275 ;;; which isn't available in target-error.
276 #-sb-xc-host
277 (labels
278 ((atomic-acons (condition key val alist)
279 ;; Force new conses to the heap if instance is arena-allocated
280 (cas (condition-assigned-slots condition)
281 alist
282 (if (dynamic-space-obj-p condition)
283 (locally (declare (sb-c::tlab :system)) (acons key val alist))
284 (acons key val alist))))
285 (initval (instance slot classoid operation)
286 (let ((instance-length (%instance-length instance)))
287 (do ((i (+ sb-vm:instance-data-start 1) (+ i 2)))
288 ((>= i instance-length)
289 (find-slot-default instance classoid slot
290 (eq operation 'slot-boundp)))
291 (when (memq (%instance-ref instance i) (condition-slot-initargs slot))
292 (return (%instance-ref instance (1+ i)))))))
293 (%get (condition name operation)
294 ;; Shared code for CONDITION-SLOT-VALUE and CONDITION-SLOT-BOUNDP.
295 ;; First look for a slot with :CLASS allocation
296 (let ((classoid (layout-classoid (%instance-layout condition))))
297 (dolist (cslot (condition-classoid-class-slots classoid))
298 (when (eq (condition-slot-name cslot) name)
299 (return-from %get (car (condition-slot-cell cslot)))))
300 (let* ((alist (condition-assigned-slots condition))
301 (cell (assq name alist)))
302 (when cell (return-from %get (cdr cell)))
303 ;; find the slot definition or else signal an error
304 (let* ((slot (or (find-condition-class-slot classoid name)
305 (return-from %get
306 (values (slot-missing (classoid-pcl-class classoid)
307 condition name 'slot-value)))))
308 (val (initval condition slot classoid operation)))
309 (loop
310 (let ((old (atomic-acons condition name val alist)))
311 (when (eq old alist) (return val))
312 (setq alist old cell (assq name alist))
313 (when cell (return (cdr cell))))))))))
315 ;; This is a stupid argument order. Shouldn't NEW-VALUE be first ?
316 (defun set-condition-slot-value (condition new-value name)
317 (dolist (cslot (condition-classoid-class-slots
318 (layout-classoid (%instance-layout condition))))
319 (when (eq (condition-slot-name cslot) name)
320 (return-from set-condition-slot-value
321 (setf (car (condition-slot-cell cslot)) new-value))))
322 ;; Apparently this does not care that there might not exist a slot named NAME
323 ;; in the class, at least in this function. It seems to be handled
324 ;; at a higher level of the slot access protocol.
325 (let ((alist (condition-assigned-slots condition)))
326 (loop
327 (let ((cell (assq name alist)))
328 (when cell
329 (return (setf (cdr cell) new-value))))
330 (let ((old (atomic-acons condition name new-value alist)))
331 (if (eq old alist) (return new-value) (setq alist old))))))
333 (defun condition-slot-value (condition name)
334 (let ((value (%get condition name 'slot-value)))
335 (if (unbound-marker-p value)
336 (let ((class (classoid-pcl-class (layout-classoid (%instance-layout condition)))))
337 (values (slot-unbound class condition name)))
338 value)))
340 (defun condition-slot-boundp (condition name)
341 (not (unbound-marker-p (%get condition name 'slot-boundp))))
343 (defun condition-slot-makunbound (condition name)
344 (set-condition-slot-value condition sb-pcl:+slot-unbound+ name)))