Handle run-program with :directory nil.
[sbcl.git] / src / code / defbangstruct.lisp
index 55cff76..32d2135 100644 (file)
@@ -4,7 +4,10 @@
 ;;;;     retained in such a way that we can get to it even on vanilla
 ;;;;     ANSI Common Lisp at cross-compiler build time.
 ;;;;  2. MAKE-LOAD-FORM information is stored in such a way that we can
-;;;;     get to it at bootstrap time before CLOS is built.
+;;;;     get to it at bootstrap time before CLOS is built. This is
+;;;;     important because at least as of sbcl-0.6.11.26, CLOS is built
+;;;;     (compiled) after cold init, so we need to have the compiler
+;;;;     even before CLOS runs.
 
 ;;;; This software is part of the SBCL system. See the README file for
 ;;;; more information.
 ;;; information for DEF!STRUCT-defined types
 (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
 
-  ;; FIXME: All this could be byte compiled. (Perhaps most of the rest
-  ;; of the file could be, too.)
-
   ;; (DEF!STRUCT-SUPERTYPE TYPE) is the DEF!STRUCT-defined type that
   ;; TYPE inherits from, or NIL if none.
   (defvar *def!struct-supertype* (make-hash-table))
   (defun def!struct-supertype (type)
     (multiple-value-bind (value value-p) (gethash type *def!struct-supertype*)
       (unless value-p
-       (error "~S is not a DEF!STRUCT-defined type." type))
+        (error "~S is not a DEF!STRUCT-defined type." type))
       value))
   (defun (setf def!struct-supertype) (value type)
     (when (and value #-sb-xc-host *type-system-initialized*)
-      (assert (subtypep value 'structure!object))
-      (assert (subtypep type value)))
+      (aver (subtypep value 'structure!object))
+      (aver (subtypep type value)))
     (setf (gethash type *def!struct-supertype*) value))
 
   ;; (DEF!STRUCT-TYPE-MAKE-LOAD-FORM-FUN TYPE) is the load form
   (defvar *def!struct-type-make-load-form-fun* (make-hash-table))
   (defun def!struct-type-make-load-form-fun (type)
     (do ((supertype type))
-       (nil)
+        (nil)
       (multiple-value-bind (value value-p)
-         (gethash supertype *def!struct-type-make-load-form-fun*)
-       (unless value-p
-         (error "~S (supertype of ~S) is not a DEF!STRUCT-defined type."
-                supertype
-                type))
-       (when value
-         (return value))
-       (setf supertype (def!struct-supertype supertype))
-       (unless supertype
-         (error "There is no MAKE-LOAD-FORM function for bootstrap type ~S."
-                type)))))
+          (gethash supertype *def!struct-type-make-load-form-fun*)
+        (unless value-p
+          (error "~S (supertype of ~S) is not a DEF!STRUCT-defined type."
+                 supertype
+                 type))
+        (when value
+          (return value))
+        (setf supertype (def!struct-supertype supertype))
+        (unless supertype
+          (error "There is no MAKE-LOAD-FORM function for bootstrap type ~S."
+                 type)))))
   (defun (setf def!struct-type-make-load-form-fun) (new-value type)
     (when #+sb-xc-host t #-sb-xc-host *type-system-initialized*
-      (assert (subtypep type 'structure!object))
-      (check-type new-value def!struct-type-make-load-form-fun))
+      (aver (subtypep type 'structure!object))
+      (aver (typep new-value 'def!struct-type-make-load-form-fun)))
     (setf (gethash type *def!struct-type-make-load-form-fun*) new-value)))
 
 ;;; the simplest, most vanilla MAKE-LOAD-FORM function for DEF!STRUCT
 ;;; objects
 (defun just-dump-it-normally (object &optional (env nil env-p))
   (declare (type structure!object object))
+  (declare (ignorable env env-p object))
+  ;; KLUDGE: we require essentially three different behaviours of
+  ;; JUST-DUMP-IT-NORMALLY, two of which (host compiler's
+  ;; MAKE-LOAD-FORM, cross-compiler's MAKE-LOAD-FORM) are handled by
+  ;; the #+SB-XC-HOST clause.  The #-SB-XC-HOST clause is the
+  ;; behaviour required by the target, before the CLOS-based
+  ;; MAKE-LOAD-FORM-SAVING-SLOTS is implemented.
+  #+sb-xc-host
   (if env-p
-    (make-load-form-saving-slots object :environment env)
-    (make-load-form-saving-slots object)))
+      (sb!xc:make-load-form-saving-slots object :environment env)
+      (sb!xc:make-load-form-saving-slots object))
+  #-sb-xc-host
+  :sb-just-dump-it-normally)
 
 ;;; a MAKE-LOAD-FORM function for objects which don't use the load
 ;;; form system. This is used for LAYOUT objects because the special
   ;; a description of a DEF!STRUCT call to be stored until we get
   ;; enough of the system running to finish processing it
   (defstruct delayed-def!struct
-    (args (required-argument) :type cons)
-    (package *package* :type package))
+    (args (missing-arg) :type cons)
+    (package (sane-package) :type package))
   ;; a list of DELAYED-DEF!STRUCTs stored until we get DEF!STRUCT
   ;; working fully so that we can apply it to them then. After
   ;; DEF!STRUCT is made to work fully, this list is processed, then
   ;; made unbound, and should no longer be used.
   (defvar *delayed-def!structs* nil))
-(eval-when (:compile-toplevel :load-toplevel :execute)
+(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
   ;; Parse the arguments for a DEF!STRUCT call, and return
   ;;   (VALUES NAME DEFSTRUCT-ARGS MAKE-LOAD-FORM-FUN DEF!STRUCT-SUPERTYPE),
   ;; where NAME is the name of the new type, DEFSTRUCT-ARGS is the
   ;; otherwise.
   (defun parse-def!struct-args (nameoid &rest rest)
     (multiple-value-bind (name options) ; Note: OPTIONS can change below.
-       (if (consp nameoid)
-         (values (first nameoid) (rest nameoid))
-         (values nameoid nil))
+        (if (consp nameoid)
+            (values (first nameoid) (rest nameoid))
+            (values nameoid nil))
+      (declare (type list options))
       (let* ((include-clause (find :include options :key #'first))
-            (def!struct-supertype nil) ; may change below
-            (mlff-clause (find :make-load-form-fun options :key #'first))
-            (mlff (and mlff-clause (second mlff-clause))))
-       (when (find :type options :key #'first)
-         (error "can't use :TYPE option in DEF!STRUCT"))
-       (when mlff-clause
-         (setf options (remove mlff-clause options)))
-       (when include-clause
-         (setf def!struct-supertype (second include-clause)))
-       (if (eq name 'structure!object) ; if root of hierarchy
-         (assert (not include-clause))
-         (unless include-clause
-           (setf def!struct-supertype 'structure!object)
-           (push `(:include ,def!struct-supertype) options)))
-       (values name `((,name ,@options) ,@rest) mlff def!struct-supertype)))))
+             (def!struct-supertype nil) ; may change below
+             (mlff-clause (find :make-load-form-fun options :key #'first))
+             (mlff (and mlff-clause (second mlff-clause))))
+        (when (find :type options :key #'first)
+          (error "can't use :TYPE option in DEF!STRUCT"))
+        (when mlff-clause
+          (setf options (remove mlff-clause options)))
+        (when include-clause
+          (setf def!struct-supertype (second include-clause)))
+        (if (eq name 'structure!object) ; if root of hierarchy
+            (aver (not include-clause))
+            (unless include-clause
+              (setf def!struct-supertype 'structure!object)
+              (push `(:include ,def!struct-supertype) options)))
+        (values name `((,name ,@options) ,@rest) mlff def!struct-supertype)))))
 
 ;;; Part of the raison d'etre for DEF!STRUCT is to be able to emulate
 ;;; these low-level CMU CL functions in a vanilla ANSI Common Lisp
 #+sb-xc-host
 (progn
   (defun %instance-length (instance)
-    (check-type instance structure!object)
-    (layout-length (class-layout (sb!xc:find-class (type-of instance)))))
+    (aver (typep instance 'structure!object))
+    (layout-length (classoid-layout (find-classoid (type-of instance)))))
   (defun %instance-ref (instance index)
-    (check-type instance structure!object)
-    (let* ((class (sb!xc:find-class (type-of instance)))
-          (layout (class-layout class)))
+    (aver (typep instance 'structure!object))
+    (let* ((class (find-classoid (type-of instance)))
+           (layout (classoid-layout class)))
       (if (zerop index)
-       layout
-       (let* ((dd (layout-info layout))
-              (dsd (elt (dd-slots dd) (1- index)))
-              (accessor (dsd-accessor dsd)))
-         (declare (type symbol accessor))
-         (funcall accessor instance)))))
+          layout
+          (let* ((dd (layout-info layout))
+                 (dsd (elt (dd-slots dd) (1- index)))
+                 (accessor-name (dsd-accessor-name dsd)))
+            (declare (type symbol accessor-name))
+            (funcall accessor-name instance)))))
   (defun %instance-set (instance index new-value)
-    (check-type instance structure!object)
-    (let* ((class (sb!xc:find-class (type-of instance)))
-          (layout (class-layout class)))
+    (aver (typep instance 'structure!object))
+    (let* ((class (find-classoid (type-of instance)))
+           (layout (classoid-layout class)))
       (if (zerop index)
-       (error "can't set %INSTANCE-REF FOO 0 in cross-compilation host")
-       (let* ((dd (layout-info layout))
-              (dsd (elt (dd-slots dd) (1- index)))
-              (accessor (dsd-accessor dsd)))
-         (declare (type symbol accessor))
-         (funcall (fdefinition `(setf ,accessor)) new-value instance))))))
+          (error "can't set %INSTANCE-REF FOO 0 in cross-compilation host")
+          (let* ((dd (layout-info layout))
+                 (dsd (elt (dd-slots dd) (1- index)))
+                 (accessor-name (dsd-accessor-name dsd)))
+            (declare (type symbol accessor-name))
+            (funcall (fdefinition `(setf ,accessor-name))
+                     new-value
+                     instance))))))
 
 ;;; a helper function for DEF!STRUCT in the #+SB-XC-HOST case: Return
 ;;; DEFSTRUCT-style arguments with any class names in the SB!XC
   (defun uncross-defstruct-args (defstruct-args)
     (destructuring-bind (name-and-options &rest slots-and-doc) defstruct-args
       (multiple-value-bind (name options)
-         (if (symbolp name-and-options)
-           (values name-and-options nil)
-           (values (first name-and-options)
-                   (rest name-and-options)))
-       (flet ((uncross-option (option)
-                (if (eq (first option) :include)
-                  (destructuring-bind
-                      (include-keyword included-name &rest rest)
-                      option
-                    `(,include-keyword
-                      ,(uncross included-name)
-                      ,@rest))
-                  option)))
-         `((,(uncross name)
-            ,@(mapcar #'uncross-option options))
-           ,@slots-and-doc))))))
+          (if (symbolp name-and-options)
+              (values name-and-options nil)
+              (values (first name-and-options)
+                      (rest name-and-options)))
+        (flet ((uncross-option (option)
+                 (if (eq (first option) :include)
+                     (destructuring-bind
+                         (include-keyword included-name &rest rest)
+                         option
+                       `(,include-keyword
+                         ,(uncross included-name)
+                         ,@rest))
+                   option)))
+          `((,(uncross name)
+             ,@(mapcar #'uncross-option options))
+            ,@slots-and-doc))))))
 
 ;;; DEF!STRUCT's arguments are like DEFSTRUCT's arguments, except that
 ;;; DEF!STRUCT accepts an extra optional :MAKE-LOAD-FORM-FUN clause.
   (multiple-value-bind (name defstruct-args mlff def!struct-supertype)
       (apply #'parse-def!struct-args args)
     `(progn
-       ;; (Putting the DEFSTRUCT here, outside the EVAL-WHEN, seems to
-       ;; be necessary in order to cross-compile the hash table
-       ;; implementation. -- WHN 19990809)
+       ;; There are two valid cases here: creating the
+       ;; STRUCTURE!OBJECT root of the inheritance hierarchy, or
+       ;; inheriting from STRUCTURE!OBJECT somehow.
+      ;;
+       ;; The invalid case that we want to exclude is when an :INCLUDE
+       ;; clause was used, and the included class didn't inherit frmo
+       ;; STRUCTURE!OBJECT. We want to catch that error ASAP because
+       ;; otherwise the bug might lurk until someone tried to do
+       ;; MAKE-LOAD-FORM on an instance of the class.
+       ,@(if (eq name 'structure!object)
+             (aver (null def!struct-supertype))
+             `((aver (subtypep ',def!struct-supertype 'structure!object))))
        (defstruct ,@defstruct-args)
-       ;; (Putting this SETF here, outside the EVAL-WHEN, seems to be
-       ;; necessary in order to allow us to put the DEFSTRUCT outside
-       ;; the EVAL-WHEN.)
        (setf (def!struct-type-make-load-form-fun ',name)
-            ,(if (symbolp mlff)
-               `',mlff
-               mlff)
-            (def!struct-supertype ',name)
-            ',def!struct-supertype)
-       ;; This bit of commented-out code hasn't been needed for quite
-       ;; some time, but the comments here about why not might still
-       ;; be useful to me until I finally get the system to work. When
-       ;; I do remove all this, I should be sure also to remove the
-       ;; "outside the EVAL-WHEN" comments above, since they will no
-       ;; longer make sense. -- WHN 19990803
-       ;;(eval-when (:compile-toplevel :load-toplevel :execute)
-       ;;  ;; (The DEFSTRUCT used to be in here, but that failed when trying
-       ;;  ;; to cross-compile the hash table implementation.)
-       ;;  ;;(defstruct ,@defstruct-args)
-       ;;  ;; The (SETF (DEF!STRUCT-TYPE-MAKE-LOAD-FORM-FUN ..) ..) used to
-       ;;  ;; be in here too, but that failed an assertion in the SETF
-       ;;  ;; definition once we moved the DEFSTRUCT outside.)
-       ;;  )
+             ,(if (symbolp mlff)
+                  `',mlff
+                  mlff)
+             (def!struct-supertype ',name)
+             ',def!struct-supertype)
        #+sb-xc-host ,(let ((u (uncross-defstruct-args defstruct-args)))
-                      (if (boundp '*delayed-def!structs*)
-                          `(push (make-delayed-def!struct :args ',u)
-                                 *delayed-def!structs*)
-                          `(sb!xc:defstruct ,@u)))
+                       (if (boundp '*delayed-def!structs*)
+                           `(push (make-delayed-def!struct :args ',u)
+                                  *delayed-def!structs*)
+                           `(sb!xc:defstruct ,@u)))
        ',name)))
 
 ;;; When building the cross-compiler, this function has to be called
 #+sb-xc-host
 (defun force-delayed-def!structs ()
   (if (boundp '*delayed-def!structs*)
-    (progn
-      (mapcar (lambda (x)
-               (let ((*package* (delayed-def!struct-package x)))
-                 ;; KLUDGE(?): EVAL is almost always the wrong thing.
-                 ;; However, since we have to map DEFSTRUCT over the
-                 ;; list, and since ANSI declined to specify any
-                 ;; functional primitives corresponding to the
-                 ;; DEFSTRUCT macro, it seems to me that EVAL is
-                 ;; required in there somewhere..
-                 (eval `(sb!xc:defstruct ,@(delayed-def!struct-args x)))))
-             (reverse *delayed-def!structs*))
-      ;; We shouldn't need this list any more. Making it unbound
-      ;; serves as a signal to DEF!STRUCT that it needn't delay
-      ;; DEF!STRUCTs any more. It is also generally a good thing for
-      ;; other reasons: it frees garbage, and it discourages anyone
-      ;; else from pushing anything else onto the list later.
-      (makunbound '*delayed-def!structs*))
-    ;; This condition is probably harmless if it comes up when
-    ;; interactively experimenting with the system by loading a source
-    ;; file into it more than once. But it's worth warning about it
-    ;; because it definitely shouldn't come up in an ordinary build
-    ;; process.
-    (warn "*DELAYED-DEF!STRUCTS* is already unbound.")))
+      (progn
+        (mapcar (lambda (x)
+                  (let ((*package* (delayed-def!struct-package x)))
+                    ;; KLUDGE(?): EVAL is almost always the wrong thing.
+                    ;; However, since we have to map DEFSTRUCT over the
+                    ;; list, and since ANSI declined to specify any
+                    ;; functional primitives corresponding to the
+                    ;; DEFSTRUCT macro, it seems to me that EVAL is
+                    ;; required in there somewhere..
+                    (eval `(sb!xc:defstruct ,@(delayed-def!struct-args x)))))
+                (reverse *delayed-def!structs*))
+        ;; We shouldn't need this list any more. Making it unbound
+        ;; serves as a signal to DEF!STRUCT that it needn't delay
+        ;; DEF!STRUCTs any more. It is also generally a good thing for
+        ;; other reasons: it frees garbage, and it discourages anyone
+        ;; else from pushing anything else onto the list later.
+        (makunbound '*delayed-def!structs*))
+      ;; This condition is probably harmless if it comes up when
+      ;; interactively experimenting with the system by loading a source
+      ;; file into it more than once. But it's worth warning about it
+      ;; because it definitely shouldn't come up in an ordinary build
+      ;; process.
+      (warn "*DELAYED-DEF!STRUCTS* is already unbound.")))
 
 ;;; The STRUCTURE!OBJECT abstract class is the base of the type
-;;; hierarchy for objects which use DEF!STRUCT functionality.
+;;; hierarchy for objects which have/use DEF!STRUCT functionality.
+;;; (The extra hackery in DEF!STRUCT-defined things isn't needed for
+;;; STRUCTURE-OBJECTs defined by ordinary, post-warm-init programs, so
+;;; it's only put into STRUCTURE-OBJECTs which inherit from
+;;; STRUCTURE!OBJECT.)
 (def!struct (structure!object (:constructor nil)))
 \f
 ;;;; hooking this all into the standard MAKE-LOAD-FORM system
 
+;;; MAKE-LOAD-FORM for DEF!STRUCT-defined types
 (defun structure!object-make-load-form (object &optional env)
-  #!+sb-doc
-  "MAKE-LOAD-FORM for DEF!STRUCT-defined types"
   (declare (ignore env))
   (funcall (def!struct-type-make-load-form-fun (type-of object))
-          object))
+           object))
 
 ;;; Do the right thing at cold load time.
 ;;;
 #+sb-xc-host
 (defmethod make-load-form ((obj structure!object) &optional (env nil env-p))
   (if env-p
-    (structure!object-make-load-form obj env)
-    (structure!object-make-load-form obj)))
+      (structure!object-make-load-form obj env)
+      (structure!object-make-load-form obj)))