0.9.10.30
[sbcl.git] / src / code / cold-error.lisp
1 ;;;; miscellaneous error stuff that needs to be in the cold load
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!KERNEL")
13
14 (defvar *break-on-signals* nil
15   #!+sb-doc
16   "When (TYPEP condition *BREAK-ON-SIGNALS*) is true, then calls to SIGNAL will
17    enter the debugger prior to signalling that condition.")
18
19 (defun signal (datum &rest arguments)
20   #!+sb-doc
21   "Invokes the signal facility on a condition formed from DATUM and
22    ARGUMENTS. If the condition is not handled, NIL is returned. If
23    (TYPEP condition *BREAK-ON-SIGNALS*) is true, the debugger is invoked
24    before any signalling is done."
25   (let ((condition (coerce-to-condition datum
26                                         arguments
27                                         'simple-condition
28                                         'signal))
29         (*handler-clusters* *handler-clusters*)
30         (old-bos *break-on-signals*))
31     (restart-case
32         (when (typep condition *break-on-signals*)
33           (let ((*break-on-signals* nil))
34             (break "~A~%BREAK was entered because of *BREAK-ON-SIGNALS* ~
35                     (now rebound to NIL)."
36                    condition)))
37       ;; Give the user a chance to unset *BREAK-ON-SIGNALS* on the
38       ;; way out.
39       ;;
40       ;; (e.g.: Consider a long compilation. After a failed compile
41       ;; the user sets *BREAK-ON-SIGNALS* to T, and select the
42       ;; RECOMPILE restart. Once the user diagnoses and fixes the
43       ;; problem, he selects RECOMPILE again... and discovers that
44       ;; he's entered the *BREAK-ON-SIGNALS* hell with no escape,
45       ;; unless we provide this restart.)
46       (reassign (new-value)
47         :report
48         "Return from BREAK and assign a new value to *BREAK-ON-SIGNALS*."
49         :interactive
50         (lambda ()
51           (let (new-value)
52             (loop
53              (format *query-io*
54                      "Enter new value for *BREAK-ON-SIGNALS*. ~
55                       Current value is ~S.~%~
56                       > "
57                      old-bos)
58              (force-output *query-io*)
59              (let ((*break-on-signals* nil))
60                (setf new-value (eval (read *query-io*)))
61                (if (typep new-value 'type-specifier)
62                    (return)
63                    (format *query-io*
64                            "~S is not a valid value for *BREAK-ON-SIGNALS* ~
65                             (must be a type-specifier).~%"
66                            new-value))))
67             (list new-value)))
68         (setf *break-on-signals* new-value)))
69     (loop
70       (unless *handler-clusters*
71         (return))
72       (let ((cluster (pop *handler-clusters*)))
73         (dolist (handler cluster)
74           (when (typep condition (car handler))
75             (funcall (cdr handler) condition)))))
76     nil))
77
78 ;;; a shared idiom in ERROR, CERROR, and BREAK: The user probably
79 ;;; doesn't want to hear that the error "occurred in" one of these
80 ;;; functions, so we try to point the top of the stack to our caller
81 ;;; instead.
82 (eval-when (:compile-toplevel :execute)
83   (defmacro-mundanely maybe-find-stack-top-hint ()
84     `(or sb!debug:*stack-top-hint*
85          (nth-value 1 (find-caller-name-and-frame)))))
86
87 (defun error (datum &rest arguments)
88   #!+sb-doc
89   "Invoke the signal facility on a condition formed from DATUM and ARGUMENTS.
90   If the condition is not handled, the debugger is invoked."
91   (/show0 "entering ERROR, argument list=..")
92   (/hexstr arguments)
93
94   (/show0 "cold-printing ERROR arguments one by one..")
95   #!+sb-show (dolist (argument arguments)
96                (sb!impl::cold-print argument))
97   (/show0 "done cold-printing ERROR arguments")
98
99   (infinite-error-protect
100     (let ((condition (coerce-to-condition datum arguments
101                                           'simple-error 'error))
102           (sb!debug:*stack-top-hint* (maybe-find-stack-top-hint)))
103       (/show0 "done coercing DATUM to CONDITION")
104       (let ((sb!debug:*stack-top-hint* nil))
105         (/show0 "signalling CONDITION from within ERROR")
106         (signal condition))
107       (/show0 "done signalling CONDITION within ERROR")
108       (invoke-debugger condition))))
109
110 (defun cerror (continue-string datum &rest arguments)
111   (infinite-error-protect
112     (with-simple-restart
113         (continue "~A" (apply #'format nil continue-string arguments))
114       (let ((condition (coerce-to-condition datum
115                                             arguments
116                                             'simple-error
117                                             'cerror))
118             (sb!debug:*stack-top-hint* (maybe-find-stack-top-hint)))
119         (with-condition-restarts condition (list (find-restart 'continue))
120           (let ((sb!debug:*stack-top-hint* nil))
121             (signal condition))
122           (invoke-debugger condition)))))
123   nil)
124
125 ;;; like BREAK, but without rebinding *DEBUGGER-HOOK* to NIL, so that
126 ;;; we can use it in system code (e.g. in SIGINT handling) without
127 ;;; messing up --disable-debugger mode (which works by setting
128 ;;; *DEBUGGER-HOOK*); or for that matter, without messing up ordinary
129 ;;; applications which try to do similar things with *DEBUGGER-HOOK*
130 (defun %break (what &optional (datum "break") &rest arguments)
131   (infinite-error-protect
132     (with-simple-restart (continue "Return from ~S." what)
133       (let ((sb!debug:*stack-top-hint* (maybe-find-stack-top-hint)))
134         (invoke-debugger
135          (coerce-to-condition datum arguments 'simple-condition what)))))
136   nil)
137
138 (defun break (&optional (datum "break") &rest arguments)
139   #!+sb-doc
140   "Print a message and invoke the debugger without allowing any possibility
141    of condition handling occurring."
142   (let ((*debugger-hook* nil)) ; as specifically required by ANSI
143     (apply #'%break 'break datum arguments)))
144
145 (defun warn (datum &rest arguments)
146   #!+sb-doc
147   "Warn about a situation by signalling a condition formed by DATUM and
148    ARGUMENTS. While the condition is being signaled, a MUFFLE-WARNING restart
149    exists that causes WARN to immediately return NIL."
150   (/show0 "entering WARN")
151   ;; KLUDGE: The current cold load initialization logic causes several calls
152   ;; to WARN, so we need to be able to handle them without dying. (And calling
153   ;; FORMAT or even PRINC in cold load is a good way to die.) Of course, the
154   ;; ideal would be to clean up cold load so that it doesn't call WARN..
155   ;; -- WHN 19991009
156   (if (not *cold-init-complete-p*)
157       (progn
158         (/show0 "ignoring WARN in cold init, arguments=..")
159         #!+sb-show (dolist (argument arguments)
160                      (sb!impl::cold-print argument)))
161       (infinite-error-protect
162        (/show0 "doing COERCE-TO-CONDITION")
163        (let ((condition (coerce-to-condition datum arguments
164                                              'simple-warning 'warn)))
165          (/show0 "back from COERCE-TO-CONDITION, doing ENFORCE-TYPE")
166          (enforce-type condition warning)
167          (/show0 "back from ENFORCE-TYPE, doing RESTART-CASE MUFFLE-WARNING")
168          (restart-case (signal condition)
169            (muffle-warning ()
170              :report "Skip warning."
171              (return-from warn nil)))
172          (/show0 "back from RESTART-CASE MUFFLE-WARNING (i.e. normal return)")
173
174          (let ((badness (etypecase condition
175                           (style-warning 'style-warning)
176                           (warning 'warning))))
177            (/show0 "got BADNESS, calling FORMAT")
178            (format *error-output*
179                    "~&~@<~S: ~3i~:_~A~:>~%"
180                    badness
181                    condition)
182            (/show0 "back from FORMAT, voila!")))))
183   nil)