X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fcompiler-error.lisp;h=7a62e250ac993f364757d3541e25af4b27b7387a;hb=77c80b85dc9ae9bde0692d4193187bfca507b936;hp=ac85e40a0bbf34d7ea93477f3e4568377448b27e;hpb=1bfc464c657a8f4ad24ef612f76a38d8f6f1bbad;p=sbcl.git diff --git a/src/compiler/compiler-error.lisp b/src/compiler/compiler-error.lisp index ac85e40..7a62e25 100644 --- a/src/compiler/compiler-error.lisp +++ b/src/compiler/compiler-error.lisp @@ -22,18 +22,73 @@ ;;; a function that is called to unwind out of COMPILER-ERROR (declaim (type (function () nil) *compiler-error-bailout*)) -(defvar *compiler-error-bailout* - (lambda () (error "COMPILER-ERROR with no bailout"))) +(defvar *compiler-error-bailout*) -;;; We have a separate COMPILER-ERROR condition to allow us to -;;; distinguish internal compiler errors from user errors. -;;; Non-compiler errors put us in the debugger. -(define-condition compiler-error (simple-error) ()) +;;; an application programmer's error caught by the compiler +;;; +;;; We want a separate condition for application programmer errors so +;;; that we can distinguish them from system programming errors (bugs +;;; in SBCL itself). Application programmer errors should be caught +;;; and turned into diagnostic output and a FAILURE-P return value +;;; from COMPILE or COMPILE-FILE. Bugs in SBCL itself throw us into +;;; the debugger. +;;; +;;; A further word or two of explanation might be warranted here, +;;; since I (CSR) have spent the last day or so wandering in a +;;; confused daze trying to get this to behave nicely before finally +;;; hitting on the right solution. +;;; +;;; These objects obey a slightly involved protocol in order to +;;; achieve the right dynamic behaviour. If we signal a +;;; COMPILER-ERROR from within the compiler, we want that the +;;; outermost call to COMPILE/COMPILE-FILE cease attempting to compile +;;; the code in question and instead compile a call to signal a +;;; PROGRAM-ERROR. This is achieved by resignalling the condition +;;; from within the handler, so that the condition travels up the +;;; handler stack until it finds the outermost handler. Why the +;;; outermost? Well, COMPILE-FILE could call EVAL from an EVAL-WHEN, +;;; which could recursively call COMPILE, which could then signal an +;;; error; we want the inner EVAL not to fail so that we can go on +;;; compiling, so it's the outer COMPILE-FILE that needs to replace +;;; the erroneous call with a call to ERROR. +;;; +;;; This resignalling up the stack means that COMPILER-ERROR should +;;; not be a generalized instance of ERROR, as otherwise code such as +;;; (IGNORE-ERRORS (DEFGENERIC IF (X))) will catch and claim to handle +;;; the COMPILER-ERROR. So we make COMPILER-ERROR inherit from +;;; SIMPLE-CONDITION instead, as of sbcl-0.8alpha.0.2x, so that unless +;;; the user claims to be able to handle general CONDITIONs (and if he +;;; does, he deserves what's going to happen :-) [ Note: we don't make +;;; COMPILER-ERROR inherit from SERIOUS-CONDITION, because +;;; conventionally SERIOUS-CONDITIONs, if unhandled, end up in the +;;; debugger; although the COMPILER-ERROR might well trigger an entry +;;; into the debugger, it won't be the COMPILER-ERROR itself that is +;;; the direct cause. ] +;;; +;;; So, what if we're not inside the compiler, then? Well, in that +;;; case we're in the evaluator, so we want to convert the +;;; COMPILER-ERROR into a PROGRAM-ERROR and signal it immediately. We +;;; have to signal the PROGRAM-ERROR from the dynamic environment of +;;; attempting to evaluate the erroneous code, and not from any +;;; exterior handler, so that user handlers for PROGRAM-ERROR and +;;; ERROR stand a chance of running, in e.g. (IGNORE-ERRORS +;;; (DEFGENERIC IF (X))). So this is where the SIGNAL-PROGRAM-ERROR +;;; restart comes in; the handler in EVAL-IN-LEXENV chooses this +;;; restart if it believes that the compiler is not present (which it +;;; tests using the BOUNDPness of *COMPILER-ERROR-BAILOUT*). The +;;; restart executes in the dynamic environment of the original +;;; COMPILER-ERROR call, and all is well. +;;; +;;; CSR, 2003-05-13 +(define-condition compiler-error (simple-condition) ()) ;;; Signal the appropriate condition. COMPILER-ERROR calls the bailout ;;; function so that it never returns (but compilation continues). ;;; COMPILER-ABORT falls through to the default error handling, so -;;; compilation terminates. +;;; compilation terminates. +;;; +;;; FIXME: what is COMPILER-ABORT for? It isn't currently +;;; (2003-05-27) used in SBCL at all. (declaim (ftype (function (string &rest t) nil) compiler-error compiler-abort)) (declaim (ftype (function (string &rest t) (values)) compiler-warning compiler-style-warning)) @@ -42,18 +97,22 @@ :format-control format-string :format-arguments format-args)) (defun compiler-error (format-string &rest format-args) - (cerror "Replace form with call to ERROR." - 'compiler-error - :format-control format-string - :format-arguments format-args) - (funcall *compiler-error-bailout*) - ;; FIXME: It might be nice to define a BUG or OOPS function for "shouldn't - ;; happen" cases like this. - (error "internal error, control returned from *COMPILER-ERROR-BAILOUT*")) -(defun compiler-warning (format-string &rest format-args) + (restart-case + (progn + (cerror "Replace form with call to ERROR." + 'compiler-error + :format-control format-string + :format-arguments format-args) + (funcall *compiler-error-bailout*) + (bug "Control returned from *COMPILER-ERROR-BAILOUT*.")) + (signal-program-error () + (error 'simple-program-error + :format-control format-string + :format-arguments format-args)))) +(defun compiler-warn (format-string &rest format-args) (apply #'warn format-string format-args) (values)) -(defun compiler-style-warning (format-string &rest format-args) +(defun compiler-style-warn (format-string &rest format-args) (apply #'style-warn format-string format-args) (values))