0.8.20.6:
[sbcl.git] / src / code / defstruct.lisp
index dfd7be2..ef5559c 100644 (file)
          (t res))))
 
 ;;; Delay looking for compiler-layout until the constructor is being
-;;; compiled, since it doesn't exist until after the eval-when
-;;; (compile) is compiled.
+;;; compiled, since it doesn't exist until after the EVAL-WHEN
+;;; (COMPILE) stuff is compiled. (Or, in the oddball case when
+;;; DEFSTRUCT is executing in a non-toplevel context, the
+;;; compiler-layout still doesn't exist at compilation time, and we
+;;; delay still further.)
 (sb!xc:defmacro %delayed-get-compiler-layout (name)
-  `',(compiler-layout-or-lose name))
+  (let ((layout (info :type :compiler-layout name)))
+    (cond (layout
+          ;; ordinary case: When the DEFSTRUCT is at top level,
+          ;; then EVAL-WHEN (COMPILE) stuff will have set up the
+          ;; layout for us to use.
+          (unless (typep (layout-info layout) 'defstruct-description)
+            (error "Class is not a structure class: ~S" name))
+          `,layout)
+         (t
+          ;; KLUDGE: In the case that DEFSTRUCT is not at top-level
+          ;; the layout doesn't exist at compile time. In that case
+          ;; we laboriously look it up at run time. This code will
+          ;; run on every constructor call and will likely be quite
+          ;; slow, so if anyone cares about performance of
+          ;; non-toplevel DEFSTRUCTs, it should be rewritten to be
+          ;; cleverer. -- WHN 2002-10-23
+          (sb!c:compiler-notify
+           "implementation limitation: ~
+             Non-toplevel DEFSTRUCT constructors are slow.")
+          (with-unique-names (layout)
+            `(let ((,layout (info :type :compiler-layout ',name)))
+               (unless (typep (layout-info ,layout) 'defstruct-description)
+                 (error "Class is not a structure class: ~S" ',name))
+               ,layout))))))
 
 ;;; Get layout right away.
 (sb!xc:defmacro compile-time-find-layout (name)
             (:conc-name dd-)
             (:make-load-form-fun just-dump-it-normally)
             #-sb-xc-host (:pure t)
-            (:constructor make-defstruct-description (name)))
+            (:constructor make-defstruct-description
+                          (name &aux
+                                (conc-name (symbolicate name "-"))
+                                (copier-name (symbolicate "COPY-" name))
+                                (predicate-name (symbolicate name "-P")))))
   ;; name of the structure
-  (name (required-argument) :type symbol)
+  (name (missing-arg) :type symbol :read-only t)
   ;; documentation on the structure
   (doc nil :type (or string null))
   ;; prefix for slot names. If NIL, none.
-  (conc-name (symbolicate name "-") :type (or symbol null))
+  (conc-name nil :type (or symbol null))
   ;; the name of the primary standard keyword constructor, or NIL if none
   (default-constructor nil :type (or symbol null))
   ;; all the explicit :CONSTRUCTOR specs, with name defaulted
   (constructors () :type list)
   ;; name of copying function
-  (copier-name (symbolicate "COPY-" name) :type (or symbol null))
+  (copier-name nil :type (or symbol null))
   ;; name of type predicate
-  (predicate-name (symbolicate name "-P") :type (or symbol null))
+  (predicate-name nil :type (or symbol null))
   ;; the arguments to the :INCLUDE option, or NIL if no included
   ;; structure
   (include nil :type list)
-  ;; The arguments to the :ALTERNATE-METACLASS option (an extension
-  ;; used to define structure-like objects with an arbitrary
-  ;; superclass and that may not have STRUCTURE-CLASS as the
-  ;; metaclass.) Syntax is:
+  ;; properties used to define structure-like classes with an
+  ;; arbitrary superclass and that may not have STRUCTURE-CLASS as the
+  ;; metaclass. Syntax is:
   ;;    (superclass-name metaclass-name metaclass-constructor)
   (alternate-metaclass nil :type list)
   ;; a list of DEFSTRUCT-SLOT-DESCRIPTION objects for all slots
   ;; (including included ones)
   (slots () :type list)
+  ;; a list of (NAME . INDEX) pairs for accessors of included structures
+  (inherited-accessor-alist () :type list)
   ;; number of elements we've allocated (See also RAW-LENGTH.)
   (length 0 :type index)
   ;; General kind of implementation.
   (print-unreadable-object (x stream :type t)
     (prin1 (dd-name x) stream)))
 
-;;; Is DD a structure with a class?
-(defun dd-class-p (defstruct)
-  (member (dd-type defstruct) '(structure funcallable-structure)))
+;;; Does DD describe a structure with a class?
+(defun dd-class-p (dd)
+  (member (dd-type dd)
+         '(structure funcallable-structure)))
+
+;;; a type name which can be used when declaring things which operate
+;;; on structure instances
+(defun dd-declarable-type (dd)
+  (if (dd-class-p dd)
+      ;; Native classes are known to the type system, and we can
+      ;; declare them as types.
+      (dd-name dd)
+      ;; Structures layered on :TYPE LIST or :TYPE VECTOR aren't part
+      ;; of the type system, so all we can declare is the underlying
+      ;; LIST or VECTOR type.
+      (dd-type dd)))
 
 (defun dd-layout-or-lose (dd)
   (compiler-layout-or-lose (dd-name dd)))
             (:conc-name dsd-)
             (:copier nil)
             #-sb-xc-host (:pure t))
-  ;; string name of slot
-  %name        
+  ;; name of slot
+  name
   ;; its position in the implementation sequence
-  (index (required-argument) :type fixnum)
+  (index (missing-arg) :type fixnum)
   ;; the name of the accessor function
   ;;
   ;; (CMU CL had extra complexity here ("..or NIL if this accessor has
   (accessor-name nil)
   default                      ; default value expression
   (type t)                     ; declared type specifier
+  (safe-p t :type boolean)      ; whether the slot is known to be
+                                ; always of the specified type
   ;; If this object does not describe a raw slot, this value is T.
   ;;
   ;; If this object describes a raw slot, this value is the type of the
 (def!method print-object ((x defstruct-slot-description) stream)
   (print-unreadable-object (x stream :type t)
     (prin1 (dsd-name x) stream)))
-
-;;; Return the name of a defstruct slot as a symbol. We store it as a
-;;; string to avoid creating lots of worthless symbols at load time.
-(defun dsd-name (dsd)
-  (intern (string (dsd-%name dsd))
-         (if (dsd-accessor-name dsd)
-             (symbol-package (dsd-accessor-name dsd))
-             (sane-package))))
 \f
 ;;;; typed (non-class) structures
 
     (list 'list)
     (vector `(simple-array ,(dd-element-type defstruct) (*)))))
 \f
-;;;; checking structure types
-
-;;; Check that X is an instance of the named structure type.
-(defmacro %check-structure-type-from-name (x name)
-  `(%check-structure-type-from-layout ,x ,(compiler-layout-or-lose name)))
-
-;;; Check that X is a structure of the type described by DD.
-(defmacro %check-structure-type-from-dd (x dd)
-  (declare (type defstruct-description dd))
-  (let ((class-name (dd-name dd)))
-    (ecase (dd-type dd)
-      ((structure funcallable-instance)
-       `(%check-structure-type-from-layout
-        ,x
-        ,(compiler-layout-or-lose class-name)))
-      ((vector)
-       (let ((xx (gensym "X")))
-        `(let ((,xx ,x))
-           (declare (type vector ,xx))
-           ,@(when (dd-named dd)
-               `((unless (eql (aref ,xx 0) ',class-name)
-                   (error
-                    'simple-type-error
-                    :datum (aref ,xx 0)
-                    :expected-type `(member ,class-name)
-                    :format-control
-                    "~@<missing name in instance of ~
-                      VECTOR-typed structure ~S: ~2I~_S~:>"
-                    :format-arguments (list ',class-name ,xx)))))))
-       (values))
-      ((list)
-       (let ((xx (gensym "X")))
-        `(let ((,xx ,x))
-           (declare (type list ,xx))
-           ,@(when (dd-named dd)
-               `((unless (eql (first ,xx) ',class-name)
-                   (error
-                    'simple-type-error
-                    :datum (aref ,xx 0)
-                    :expected-type `(member ,class-name)
-                    :format-control
-                    "~@<missing name in instance of LIST-typed structure ~S: ~
-                      ~2I~_S~:>"
-                    :format-arguments (list ',class-name ,xx)))))
-           (values)))))))
-
-;;; Check that X is an instance of the structure class with layout LAYOUT.
-(defun %check-structure-type-from-layout (x layout)
-  (unless (typep-to-layout x layout)
-    (error 'simple-type-error
-          :datum x
-          :expected-type (sb!xc:class-name (layout-class layout))))
-  (values))
-\f
 ;;;; shared machinery for inline and out-of-line slot accessor functions
 
-;;; an alist mapping from raw slot type to the operator used to access
-;;; the raw slot
-;;;
-;;; FIXME: should be shared 
-(eval-when (:compile-toplevel :load-toplevel :execute)
-  (defvar *raw-type->rawref-fun-name*
-    '(;; The compiler thinks that the raw data vector is a vector of
-      ;; unsigned bytes, so if the slot we want to access actually *is*
-      ;; an unsigned byte, it'll access the slot for us even if we don't
-      ;; lie to it at all.
-      (unsigned-byte . aref)
-      ;; "A lie can travel halfway round the world while the truth is
-      ;; putting on its shoes." -- Mark Twain
-      (single-float . %raw-ref-single)
-      (double-float . %raw-ref-double)
-      #!+long-float (long-float . %raw-ref-long)
-      (complex-single-float . %raw-ref-complex-single)
-      (complex-double-float . %raw-ref-complex-double)
-      #!+long-float (complex-long-float . %raw-ref-complex-long))))
-\f
-;;;; generating out-of-line slot accessor functions
-
-;;; code generators for cases of DEFUN SLOT-ACCESSOR-FUNS
-;;;
-;;; (caution: These macros are sleazily specialized for use only in
-;;; DEFUN SLOT-ACCESSOR-FUNS, not anywhere near fully parameterized:
-;;; they grab symbols like INSTANCE and DSD-FOO automatically.
-;;; Logically they probably belong in a MACROLET inside the DEFUN, but
-;;; separating them like this makes it easier to experiment with them
-;;; in the interpreter and reduces indentation hell.)
-;;;
-;;; FIXME: Ideally, the presence of the type checks in the functions
-;;; here would be conditional on the optimization policy at the point
-;;; of expansion of DEFSTRUCT. (For now we're just doing the simpler
-;;; thing, putting in the type checks unconditionally.)
-(eval-when (:compile-toplevel)
-
-  ;; code shared between funcallable instance case and the ordinary
-  ;; STRUCTURE-OBJECT case: Handle native structures with LAYOUTs and
-  ;; (possibly) raw slots.
-  (defmacro %native-slot-accessor-funs (dd-ref-fun-name)
-    (let ((instance-type-check-form '(%check-structure-type-from-layout
-                                     instance layout)))
-      `(let ((layout (dd-layout-or-lose dd))
-            (dsd-raw-type (dsd-raw-type dsd)))
-        ;; Map over all the possible RAW-TYPEs, compiling a different
-        ;; closure-function for each one, so that once the COND over
-        ;; RAW-TYPEs happens (at the time closure is allocated) there
-        ;; are no more decisions to be made and things execute
-        ;; reasonably efficiently.
-        (cond
-         ;; nonraw slot case
-         ((eql (dsd-raw-type dsd) t)
-          (%slotplace-accessor-funs (,dd-ref-fun-name instance dsd-index)
-                                    ,instance-type-check-form))
-         ;; raw slot cases
-         ,@(mapcar (lambda (raw-type-and-rawref-fun-name)
-                     (destructuring-bind (raw-type . rawref-fun-name)
-                         raw-type-and-rawref-fun-name
-                       `((equal dsd-raw-type ',raw-type)
-                         (let ((raw-index (dd-raw-index dd)))
-                           (%slotplace-accessor-funs
-                            (,rawref-fun-name (,dd-ref-fun-name instance
-                                                                raw-index)
-                                              dsd-index)
-                            ,instance-type-check-form)))))
-                   *raw-type->rawref-fun-name*)))))
-
-  ;; code shared between DEFSTRUCT :TYPE LIST and
-  ;; DEFSTRUCT :TYPE VECTOR cases: Handle the "typed structure" case,
-  ;; with no LAYOUTs and no raw slots.
-  (defmacro %colontyped-slot-accessor-funs () (error "stub")) 
-
-  ;; the common structure of the raw-slot and not-raw-slot cases,
-  ;; defined in terms of the writable SLOTPLACE. All possible flavors
-  ;; of slot access should be able to pass through here.
-  (defmacro %slotplace-accessor-funs (slotplace instance-type-check-form)
-    (cl-user:/show slotplace instance-type-check-form)
-    `(values (lambda (instance)
-              ,instance-type-check-form
-              ,slotplace)
-            (let ((typecheckfun (typespec-typecheckfun dsd-type)))
-              (lambda (new-value instance)
-                ,instance-type-check-form
-                (funcall typecheckfun new-value)
-                (setf ,slotplace new-value))))))
-
-;;; Return (VALUES SLOT-READER-FUN SLOT-WRITER-FUN).
-(defun slot-accessor-funs (dd dsd)
-
-  (let ((dsd-index (dsd-index dsd))
-       (dsd-type (dsd-type dsd)))
-           
-      (ecase (dd-type dd)
-
-       ;; native structures
-       (structure (%native-slot-accessor-funs %instance-ref))
-       (funcallable-structure (%native-slot-accessor-funs
-                               %funcallable-instance-info))
-                                    
-       ;; structures with the :TYPE option
-
-       ;; FIXME: Worry about these later..
-       #|
-        ;; In :TYPE LIST and :TYPE VECTOR structures, ANSI specifies the
-        ;; layout completely, so that raw slots are impossible.
-        (list
-         (dd-type-slot-accessor-funs nth-but-with-sane-arg-order
-                                `(%check-structure-type-from-dd
-                                :maybe-raw-p nil))
-        (vector
-         (dd-type-slot-accessor-funs aref
-                                :maybe-raw-p nil)))
-        |#
-       )))
-\f
-;;;; REMOVEME: baby steps for the new out-of-line slot accessor functions
-
-#|
-(in-package :sb-kernel)
-
-(defstruct foo
-  ;; vanilla slots
-  a
-  (b 5 :type package :read-only t)
-  ;; raw slots
-  (x 5 :type (unsigned-byte 32))
-  (y 5.0 :type single-float :read-only t))
-
-(load "/usr/stuff/sbcl/src/cold/chill")
-(cl-user:fasl "/usr/stuff/sbcl/src/code/typecheckfuns")
-(cl-user:fasl "/usr/stuff/outsacc")
-
-(let* ((foo-layout (compiler-layout-or-lose 'foo))
-       (foo-dd (layout-info foo-layout))
-       (foo-dsds (dd-slots foo-dd))
-       (foo-a-dsd (find "A" foo-dsds :test #'string= :key #'dsd-%name))
-       (foo-b-dsd (find "B" foo-dsds :test #'string= :key #'dsd-%name))
-       (foo-x-dsd (find "X" foo-dsds :test #'string= :key #'dsd-%name))
-       (foo-y-dsd (find "X" foo-dsds :test #'string= :key #'dsd-%name))
-       (foo (make-foo :a 'avalue
-                     :b (find-package :cl)
-                     :x 50)))
-  (declare (type layout foo-layout))
-  (declare (type defstruct-description foo-dd))
-  (declare (type defstruct-slot-description foo-a-dsd))
-
-  (cl-user:/show foo)
-
-  (multiple-value-bind (foo-a-reader foo-a-writer)
-      (slot-accessor-funs foo-dd foo-a-dsd)
-
-    ;; basic functionality
-    (cl-user:/show foo-a-reader)
-    (cl-user:/show (funcall foo-a-reader foo))
-    (aver (eql (funcall foo-a-reader foo) 'avalue))
-    (cl-user:/show foo-a-writer)
-    (cl-user:/show (funcall foo-a-writer 'replacedavalue foo))
-    (cl-user:/show "new" (funcall foo-a-reader foo))
-    (aver (eql (funcall foo-a-reader foo) 'replacedavalue))
-
-    ;; type checks on FOO-ness of instance argument
-    (cl-user:/show (nth-value 1 (ignore-errors (funcall foo-a-reader 3))))
-    (aver (typep (nth-value 1 (ignore-errors (funcall foo-a-reader 3)))
-                'type-error))
-    (aver (typep (nth-value 1 (ignore-errors (funcall foo-a-writer 3 4)))
-                'type-error)))
-
-  ;; type checks on written slot value
-  (multiple-value-bind (foo-b-reader foo-b-writer)
-      (slot-accessor-funs foo-dd foo-b-dsd)
-    (cl-user:/show "old" (funcall foo-b-reader foo))
-    (aver (not (eql (funcall foo-b-reader foo) (find-package :cl-user))))
-    (funcall foo-b-writer (find-package :cl-user) foo)    
-    (cl-user:/show "new" (funcall foo-b-reader foo))
-    (aver (eql (funcall foo-b-reader foo) (find-package :cl-user)))
-    (aver (typep (nth-value 1 (ignore-errors (funcall foo-b-writer 5 foo)))
-                'type-error))
-    (aver (eql (funcall foo-b-reader foo) (find-package :cl-user))))
-
-  ;; raw slots
-  (cl-user:/describe foo-x-dsd)
-  (cl-user:/describe foo-y-dsd)
-  (multiple-value-bind (foo-x-reader foo-x-writer)
-      (slot-accessor-funs foo-dd foo-x-dsd)
-    (multiple-value-bind (foo-y-reader foo-y-writer)
-       (slot-accessor-funs foo-dd foo-y-dsd)
-
-      ;; basic functionality for (UNSIGNED-BYTE 32) slot
-      (cl-user:/show foo-x-reader)
-      (cl-user:/show (funcall foo-x-reader foo))
-      (aver (eql (funcall foo-x-reader foo) 50))
-      (cl-user:/show foo-x-writer)
-      (cl-user:/show (funcall foo-x-writer 14 foo))
-      (cl-user:/show "new" (funcall foo-x-reader foo))
-      (aver (eql (funcall foo-x-reader foo) 14)))
-
-      ;; type check for (UNSIGNED-BYTE 32) slot
-      (/show "to do: type check X")
-
-      ;; SINGLE-FLOAT slot
-      (/show "to do: Y")))
-|#
+(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
+
+  ;; information about how a slot of a given DSD-RAW-TYPE is to be accessed
+  (defstruct raw-slot-data
+    ;; the raw slot type, or T for a non-raw slot
+    ;;
+    ;; (Raw slots are allocated in the raw slots array in a vector which
+    ;; the GC doesn't need to scavenge. Non-raw slots are in the
+    ;; ordinary place you'd expect, directly indexed off the instance
+    ;; pointer.)
+    (raw-type (missing-arg) :type (or symbol cons) :read-only t)
+    ;; What operator is used (on the raw data vector) to access a slot
+    ;; of this type?
+    (accessor-name (missing-arg) :type symbol :read-only t)
+    ;; How many words are each value of this type? (This is used to
+    ;; rescale the offset into the raw data vector.)
+    (n-words (missing-arg) :type (and index (integer 1)) :read-only t))
+
+  (defvar *raw-slot-data-list*
+    (list
+     ;; The compiler thinks that the raw data vector is a vector of
+     ;; word-sized unsigned bytes, so if the slot we want to access
+     ;; actually *is* an unsigned byte, it'll access the slot for us
+     ;; even if we don't lie to it at all, just let it use normal AREF.
+     (make-raw-slot-data :raw-type 'unsigned-byte
+                        :accessor-name 'aref
+                        :n-words 1)
+     ;; In the other cases, we lie to the compiler, making it use
+     ;; some low-level AREFish access in order to pun the hapless
+     ;; bits into some other-than-unsigned-byte meaning.
+     ;;
+     ;; "A lie can travel halfway round the world while the truth is
+     ;; putting on its shoes." -- Mark Twain
+     (make-raw-slot-data :raw-type 'single-float
+                        :accessor-name '%raw-ref-single
+                        :n-words 1)
+     (make-raw-slot-data :raw-type 'double-float
+                        :accessor-name '%raw-ref-double
+                        :n-words 2)
+     (make-raw-slot-data :raw-type 'complex-single-float
+                        :accessor-name '%raw-ref-complex-single
+                        :n-words 2)
+     (make-raw-slot-data :raw-type 'complex-double-float
+                        :accessor-name '%raw-ref-complex-double
+                        :n-words 4)
+     #!+long-float
+     (make-raw-slot-data :raw-type long-float
+                        :accessor-name '%raw-ref-long
+                        :n-words #!+x86 3 #!+sparc 4)
+     #!+long-float
+     (make-raw-slot-data :raw-type complex-long-float
+                        :accessor-name '%raw-ref-complex-long
+                        :n-words #!+x86 6 #!+sparc 8))))
 \f
 ;;;; the legendary DEFSTRUCT macro itself (both CL:DEFSTRUCT and its
 ;;;; close personal friend SB!XC:DEFSTRUCT)
        ;; class names which creates fast but non-cold-loadable,
        ;; non-compact code. In this context, we'd rather have
        ;; compact, cold-loadable code. -- WHN 19990928
-       (declare (notinline sb!xc:find-class))
+       (declare (notinline find-classoid))
        ,@(let ((pf (dd-print-function defstruct))
                (po (dd-print-object defstruct))
                (x (gensym))
                       fun-name)))
              (cond ((not (eql pf 0))
                     `((def!method print-object ((,x ,name) ,s)
-                        (funcall #',(farg pf) ,x ,s *current-level*))))
+                        (funcall #',(farg pf)
+                                 ,x
+                                 ,s
+                                 *current-level-in-print*))))
                    ((not (eql po 0))
                     `((def!method print-object ((,x ,name) ,s)
                         (funcall #',(farg po) ,x ,s))))
                    (t nil))))
        ,@(let ((pure (dd-pure defstruct)))
            (cond ((eq pure t)
-                  `((setf (layout-pure (class-layout
-                                        (sb!xc:find-class ',name)))
+                  `((setf (layout-pure (classoid-layout
+                                        (find-classoid ',name)))
                           t)))
                  ((eq pure :substructure)
-                  `((setf (layout-pure (class-layout
-                                        (sb!xc:find-class ',name)))
+                  `((setf (layout-pure (classoid-layout
+                                        (find-classoid ',name)))
                           0)))))
        ,@(let ((def-con (dd-default-constructor defstruct)))
            (when (and def-con (not (dd-alternate-metaclass defstruct)))
-             `((setf (structure-class-constructor (sb!xc:find-class ',name))
+             `((setf (structure-classoid-constructor (find-classoid ',name))
                      #',def-con))))))))
-;;; FIXME: I really would like to make structure accessors less
-;;; special, just ordinary inline functions. (Or perhaps inline
-;;; functions with special compact implementations of their
-;;; expansions, to avoid bloating the system.)
 
 ;;; shared logic for CL:DEFSTRUCT and SB!XC:DEFSTRUCT
 (defmacro !expander-for-defstruct (name-and-options
        (if (dd-class-p dd)
           (let ((inherits (inherits-for-structure dd)))
             `(progn
+               ;; Note we intentionally enforce package locks and
+               ;; call %DEFSTRUCT first, and especially before
+               ;; %COMPILER-DEFSTRUCT. %DEFSTRUCT has the tests (and
+               ;; resulting CERROR) for collisions with LAYOUTs which
+               ;; already exist in the runtime. If there are any
+               ;; collisions, we want the user's response to CERROR
+               ;; to control what happens. Especially, if the user
+               ;; responds to the collision with ABORT, we don't want
+               ;; %COMPILER-DEFSTRUCT to modify the definition of the
+               ;; class.
+               (with-single-package-locked-error
+                   (:symbol ',name "defining ~A as a structure"))
+               (%defstruct ',dd ',inherits)
                (eval-when (:compile-toplevel :load-toplevel :execute)
                  (%compiler-defstruct ',dd ',inherits))
-               (%defstruct ',dd ',inherits)
                ,@(unless expanding-into-code-for-xc-host-p
-                   (append (raw-accessor-definitions dd)
-                           (predicate-definitions dd)
-                           ;; FIXME: We've inherited from CMU CL nonparallel
+                   (append ;; FIXME: We've inherited from CMU CL nonparallel
                            ;; code for creating copiers for typed and untyped
                            ;; structures. This should be fixed.
-                                       ;(copier-definition dd)
+                           ;(copier-definition dd)
                            (constructor-definitions dd)
                            (class-method-definitions dd)))
                ',name))
           `(progn
+             (with-single-package-locked-error
+                 (:symbol ',name "defining ~A as a structure"))
              (eval-when (:compile-toplevel :load-toplevel :execute)
                (setf (info :typed-structure :info ',name) ',dd))
              ,@(unless expanding-into-code-for-xc-host-p
 \f
 ;;;; functions to generate code for various parts of DEFSTRUCT definitions
 
-;;; Catch requests to mess up definitions in COMMON-LISP.
-#-sb-xc-host
-(eval-when (:compile-toplevel :load-toplevel :execute)
-  (defun protect-cl (symbol)
-    (when (and *cold-init-complete-p*
-              (eq (symbol-package symbol) *cl-package*))
-      (cerror "Go ahead and patch the system."
-             "attempting to modify a symbol in the COMMON-LISP package: ~S"
-             symbol))))
-
-;;; Return forms to define readers and writers for raw slots as inline
-;;; functions.
-(defun raw-accessor-definitions (dd)
-  (let* ((name (dd-name dd)))
-    (collect ((res))
-      (dolist (slot (dd-slots dd))
-       (let ((slot-type (dsd-type slot))
-             (accessor-name (dsd-accessor-name slot))
-             (argname (gensym "ARG"))
-             (nvname (gensym "NEW-VALUE-")))
-         (multiple-value-bind (accessor offset data)
-             (slot-accessor-form dd slot argname)
-           ;; When accessor exists and is raw
-           (when (and accessor-name
-                      (not (eq accessor-name '%instance-ref)))
-             (res `(declaim (inline ,accessor-name)))
-             (res `(declaim (ftype (function (,name) ,slot-type)
-                                   ,accessor-name)))
-             (res `(defun ,accessor-name (,argname)
-                     ;; Note: The DECLARE here might seem redundant
-                     ;; with the DECLAIM FTYPE above, but it's not:
-                     ;; If we're not at toplevel, the PROCLAIM inside
-                     ;; the DECLAIM doesn't get executed until after
-                     ;; this function is compiled.
-                     (declare (type ,name ,argname))
-                     (truly-the ,slot-type (,accessor ,data ,offset))))
-             (unless (dsd-read-only slot)
-               (res `(declaim (inline (setf ,accessor-name))))
-               (res `(declaim (ftype (function (,slot-type ,name) ,slot-type)
-                                     (setf ,accessor-name))))
-               ;; FIXME: I rewrote this somewhat from the CMU CL definition.
-               ;; Do some basic tests to make sure that reading and writing
-               ;; raw slots still works correctly.
-               (res `(defun (setf ,accessor-name) (,nvname ,argname)
-                       (declare (type ,name ,argname))
-                       (setf (,accessor ,data ,offset) ,nvname)
-                       ,nvname)))))))
-      (res))))
+;;; First, a helper to determine whether a name names an inherited
+;;; accessor.
+(defun accessor-inherited-data (name defstruct)
+  (assoc name (dd-inherited-accessor-alist defstruct) :test #'eq))
 
-;;; Return a list of forms which create a predicate for an untyped DEFSTRUCT.
-(defun predicate-definitions (dd)
-  (let ((pred (dd-predicate-name dd))
-       (argname (gensym)))
-    (when pred
-      (if (eq (dd-type dd) 'funcallable-structure)
-         ;; FIXME: Why does this need to be special-cased for
-         ;; FUNCALLABLE-STRUCTURE? CMU CL did it, but without explanation.
-         ;; Could we do without it? What breaks if we do? Or could we
-         ;; perhaps get by with no predicates for funcallable structures?
-         `((declaim (inline ,pred))
-           (defun ,pred (,argname) (typep ,argname ',(dd-name dd))))
-         `((protect-cl ',pred)
-           (declaim (inline ,pred))
-           (defun ,pred (,argname)
-             (declare (optimize (speed 3) (safety 0)))
-             (typep-to-layout ,argname
-                              (compile-time-find-layout ,(dd-name dd)))))))))
-
-;;; Return a list of forms which create a predicate function for a typed
-;;; DEFSTRUCT.
+;;; Return a list of forms which create a predicate function for a
+;;; typed DEFSTRUCT.
 (defun typed-predicate-definitions (defstruct)
   (let ((name (dd-name defstruct))
        (predicate-name (dd-predicate-name defstruct))
        (argname (gensym)))
     (when (and predicate-name (dd-named defstruct))
-      (let ((ltype (dd-lisp-type defstruct)))
+      (let ((ltype (dd-lisp-type defstruct))
+           (name-index (cdr (car (last (find-name-indices defstruct))))))
        `((defun ,predicate-name (,argname)
            (and (typep ,argname ',ltype)
-                (eq (elt (the ,ltype ,argname)
-                         ,(cdr (car (last (find-name-indices defstruct)))))
-                    ',name))))))))
-
-;;; FIXME: We've inherited from CMU CL code to do typed structure copiers
-;;; in a completely different way than untyped structure copiers. Fix this.
-;;; (This function was my first attempt to fix this, but I stopped before
-;;; figuring out how to install it completely and remove the parallel
-;;; code which simply SETF's the FDEFINITION of the DD-COPIER name.
-#|
-;;; Return the copier definition for an untyped DEFSTRUCT.
-(defun copier-definition (dd)
-  (when (and (dd-copier dd)
-            ;; FUNCALLABLE-STRUCTUREs don't need copiers, and this
-            ;; implementation wouldn't work for them anyway, since
-            ;; COPY-STRUCTURE returns a STRUCTURE-OBJECT and they're not.
-            (not (eq (dd-type info) 'funcallable-structure)))
-    (let ((argname (gensym)))
-      `(progn
-        (protect-cl ',(dd-copier dd))
-        (defun ,(dd-copier dd) (,argname)
-          (declare (type ,(dd-name dd) ,argname))
-          (copy-structure ,argname))))))
-|#
+                ,(cond
+                  ((subtypep ltype 'list)
+                     `(do ((head (the ,ltype ,argname) (cdr head))
+                          (i 0 (1+ i)))
+                         ((or (not (consp head)) (= i ,name-index))
+                          (and (consp head) (eq ',name (car head))))))
+                  ((subtypep ltype 'vector)
+                   `(and (= (length (the ,ltype ,argname))
+                          ,(dd-length defstruct))
+                         (eq ',name (aref (the ,ltype ,argname) ,name-index))))
+                  (t (bug "Uncatered-for lisp type in typed DEFSTRUCT: ~S."
+                          ltype))))))))))
 
 ;;; Return a list of forms to create a copier function of a typed DEFSTRUCT.
 (defun typed-copier-definitions (defstruct)
     `((setf (fdefinition ',(dd-copier-name defstruct)) #'copy-seq)
       (declaim (ftype function ,(dd-copier-name defstruct))))))
 
-;;; Return a list of function definitions for accessing and setting the
-;;; slots of a typed DEFSTRUCT. The functions are proclaimed to be inline,
-;;; and the types of their arguments and results are declared as well. We
-;;; count on the compiler to do clever things with ELT.
+;;; Return a list of function definitions for accessing and setting
+;;; the slots of a typed DEFSTRUCT. The functions are proclaimed to be
+;;; inline, and the types of their arguments and results are declared
+;;; as well. We count on the compiler to do clever things with ELT.
 (defun typed-accessor-definitions (defstruct)
   (collect ((stuff))
     (let ((ltype (dd-lisp-type defstruct)))
              (index (dsd-index slot))
              (slot-type `(and ,(dsd-type slot)
                               ,(dd-element-type defstruct))))
-         (stuff `(proclaim '(inline ,name (setf ,name))))
-         ;; FIXME: The arguments in the next two DEFUNs should be
-         ;; gensyms. (Otherwise e.g. if NEW-VALUE happened to be the
-         ;; name of a special variable, things could get weird.)
-         (stuff `(defun ,name (structure)
-                   (declare (type ,ltype structure))
-                   (the ,slot-type (elt structure ,index))))
-         (unless (dsd-read-only slot)
-           (stuff
-            `(defun (setf ,name) (new-value structure)
-               (declare (type ,ltype structure) (type ,slot-type new-value))
-               (setf (elt structure ,index) new-value)))))))
+         (let ((inherited (accessor-inherited-data name defstruct)))
+           (cond
+             ((not inherited)
+              (stuff `(declaim (inline ,name (setf ,name))))
+              ;; FIXME: The arguments in the next two DEFUNs should
+              ;; be gensyms. (Otherwise e.g. if NEW-VALUE happened to
+              ;; be the name of a special variable, things could get
+              ;; weird.)
+              (stuff `(defun ,name (structure)
+                       (declare (type ,ltype structure))
+                       (the ,slot-type (elt structure ,index))))
+              (unless (dsd-read-only slot)
+                (stuff
+                 `(defun (setf ,name) (new-value structure)
+                   (declare (type ,ltype structure) (type ,slot-type new-value))
+                   (setf (elt structure ,index) new-value)))))
+             ((not (= (cdr inherited) index))
+              (style-warn "~@<Non-overwritten accessor ~S does not access ~
+                            slot with name ~S (accessing an inherited slot ~
+                            instead).~:@>" name (dsd-name slot))))))))
     (stuff)))
 \f
 ;;;; parsing
        (name (dd-name dd)))
     (case (first option)
       (:conc-name
-       (destructuring-bind (conc-name) args
+       (destructuring-bind (&optional conc-name) args
         (setf (dd-conc-name dd)
               (if (symbolp conc-name)
                   conc-name
        (when (dd-include dd)
         (error "more than one :INCLUDE option"))
        (setf (dd-include dd) args))
-      (:alternate-metaclass
-       (setf (dd-alternate-metaclass dd) args))
       (:print-function
        (require-no-print-options-so-far dd)
        (setf (dd-print-function dd)
             (the (or symbol cons) args)))
       (:type
        (destructuring-bind (type) args
-        (cond ((eq type 'funcallable-structure)
-               (setf (dd-type dd) type))
-              ((member type '(list vector))
+        (cond ((member type '(list vector))
                (setf (dd-element-type dd) t)
                (setf (dd-type dd) type))
               ((and (consp type) (eq (first type) 'vector))
       (t (error "unknown DEFSTRUCT option:~%  ~S" option)))))
 
 ;;; Given name and options, return a DD holding that info.
-(eval-when (:compile-toplevel :load-toplevel :execute)
 (defun parse-defstruct-name-and-options (name-and-options)
   (destructuring-bind (name &rest options) name-and-options
     (aver name) ; A null name doesn't seem to make sense here.
     (let ((dd (make-defstruct-description name)))
       (dolist (option options)
-       (cond ((consp option)
-              (parse-1-dd-option option dd))
-             ((eq option :named)
+       (cond ((eq option :named)
               (setf (dd-named dd) t))
-             ((member option '(:constructor :copier :predicate :named))
+             ((consp option)
+              (parse-1-dd-option option dd))
+             ((member option '(:conc-name :constructor :copier :predicate))
               (parse-1-dd-option (list option) dd))
              (t
               (error "unrecognized DEFSTRUCT option: ~S" option))))
         (when (dd-offset dd)
           (error ":OFFSET can't be specified unless :TYPE is specified."))
         (unless (dd-include dd)
+          ;; FIXME: It'd be cleaner to treat no-:INCLUDE as defaulting
+          ;; to :INCLUDE STRUCTURE-OBJECT, and then let the general-case
+          ;; (INCF (DD-LENGTH DD) (DD-LENGTH included-DD)) logic take
+          ;; care of this. (Except that the :TYPE VECTOR and :TYPE
+          ;; LIST cases, with their :NAMED and un-:NAMED flavors,
+          ;; make that messy, alas.)
           (incf (dd-length dd))))
-       (funcallable-structure)
        (t
         (require-no-print-options-so-far dd)
         (when (dd-named dd)
           (when offset (incf (dd-length dd) offset)))))
 
       (when (dd-include dd)
-       (do-dd-inclusion-stuff dd))
+       (frob-dd-inclusion-stuff dd))
 
       dd)))
 
     (dolist (slot-description slot-descriptions)
       (allocate-1-slot result (parse-1-dsd result slot-description)))
     result))
-
-) ; EVAL-WHEN
 \f
 ;;;; stuff to parse slot descriptions
 
 ;;; that we modify to get the new slot. This is supplied when handling
 ;;; included slots.
 (defun parse-1-dsd (defstruct spec &optional
-                   (slot (make-defstruct-slot-description :%name ""
+                   (slot (make-defstruct-slot-description :name ""
                                                           :index 0
                                                           :type t)))
   (multiple-value-bind (name default default-p type type-p read-only ro-p)
-      (cond
-       ((listp spec)
-       (destructuring-bind
-           (name
-            &optional (default nil default-p)
-            &key (type nil type-p) (read-only nil ro-p))
-           spec
-         (values name
-                 default default-p
-                 (uncross type) type-p
-                 read-only ro-p)))
-       (t
-       (when (keywordp spec)
-         (style-warn "Keyword slot name indicates probable syntax ~
-                      error in DEFSTRUCT: ~S."
-                     spec))
-       spec))
-
-    (when (find name (dd-slots defstruct) :test #'string= :key #'dsd-%name)
+      (typecase spec
+       (symbol
+        (when (keywordp spec)
+          (style-warn "Keyword slot name indicates probable syntax ~
+                        error in DEFSTRUCT: ~S."
+                      spec))
+        spec)
+       (cons
+        (destructuring-bind
+              (name
+               &optional (default nil default-p)
+               &key (type nil type-p) (read-only nil ro-p))
+            spec
+          (values name
+                  default default-p
+                  (uncross type) type-p
+                  read-only ro-p)))
+       (t (error 'simple-program-error
+                 :format-control "in DEFSTRUCT, ~S is not a legal slot ~
+                                   description."
+                 :format-arguments (list spec))))
+
+    (when (find name (dd-slots defstruct)
+               :test #'string=
+               :key (lambda (x) (symbol-name (dsd-name x))))
       (error 'simple-program-error
             :format-control "duplicate slot name ~S"
             :format-arguments (list name)))
-    (setf (dsd-%name slot) (string name))
+    (setf (dsd-name slot) name)
     (setf (dd-slots defstruct) (nconc (dd-slots defstruct) (list slot)))
 
-    (let ((accessor-name (symbolicate (or (dd-conc-name defstruct) "") name))
+    (let ((accessor-name (if (dd-conc-name defstruct)
+                            (symbolicate (dd-conc-name defstruct) name)
+                            name))
          (predicate-name (dd-predicate-name defstruct)))
       (setf (dsd-accessor-name slot) accessor-name)
       (when (eql accessor-name predicate-name)
        (style-warn
         "~@<The structure accessor name ~S is the same as the name of the ~
           structure type predicate. ANSI doesn't specify what to do in ~
-          this case; this implementation chooses to overwrite the type ~
-          predicate with the slot accessor.~@:>"
+          this case. We'll overwrite the type predicate with the slot ~
+          accessor, but you can't rely on this behavior, so it'd be wise to ~
+          remove the ambiguity in your code.~@:>"
         accessor-name)
-       (setf (dd-predicate-name defstruct) nil)))
-
+       (setf (dd-predicate-name defstruct) nil))
+      ;; FIXME: It would be good to check for name collisions here, but
+      ;; the easy check,
+      ;;x#-sb-xc-host
+      ;;x(when (and (fboundp accessor-name)
+      ;;x           (not (accessor-inherited-data accessor-name defstruct)))
+      ;;x  (style-warn "redefining ~S in DEFSTRUCT" accessor-name)))
+      ;; which was done until sbcl-0.8.11.18 or so, is wrong: it causes
+      ;; a warning at MACROEXPAND time, when instead the warning should
+      ;; occur not just because the code was constructed, but because it
+      ;; is actually compiled or loaded.
+      )
+    
     (when default-p
       (setf (dsd-default slot) default))
     (when type-p
       (if read-only
          (setf (dsd-read-only slot) t)
          (when (dsd-read-only slot)
-           (error "Slot ~S is :READ-ONLY in parent and must be :READ-ONLY in subtype ~S."
-                  name
+           (error "~@<The slot ~S is :READ-ONLY in superclass, and so must ~
+                       be :READ-ONLY in subclass.~:@>"
                   (dsd-name slot)))))
     slot))
 
 ;;;   RAW? is true if TYPE should be stored in a raw slot.
 ;;;   RAW-TYPE is the raw slot type, or NIL if no raw slot.
 ;;;   WORDS is the number of words in the raw slot, or NIL if no raw slot.
+;;;
+;;; FIXME: This should use the data in *RAW-SLOT-DATA-LIST*.
 (defun structure-raw-slot-type-and-size (type)
-  (/noshow "in STRUCTURE-RAW-SLOT-TYPE-AND-SIZE" type (sb!xc:subtypep type 'fixnum))
-  (cond #+nil
-       (;; FIXME: For now we suppress raw slots, since there are various
-        ;; issues about the way that the cross-compiler handles them.
-        (not (boundp '*dummy-placeholder-to-stop-compiler-warnings*))
-        (values nil nil nil))
-       ((and (sb!xc:subtypep type '(unsigned-byte 32))
+  (cond ((and (sb!xc:subtypep type 'sb!vm:word)
              (multiple-value-bind (fixnum? fixnum-certain?)
                  (sb!xc:subtypep type 'fixnum)
-               (/noshow fixnum? fixnum-certain?)
                ;; (The extra test for FIXNUM-CERTAIN? here is
                ;; intended for bootstrapping the system. In
                ;; particular, in sbcl-0.6.2, we set up LAYOUT before
       (if (eq (dd-type dd) 'structure)
          (structure-raw-slot-type-and-size (dsd-type dsd))
          (values nil nil nil))
-    (/noshow "ALLOCATE-1-SLOT" dsd raw? raw-type words)
     (cond ((not raw?)
           (setf (dsd-index dsd) (dd-length dd))
           (incf (dd-length dd)))
 
 ;;; Process any included slots pretty much like they were specified.
 ;;; Also inherit various other attributes.
-(defun do-dd-inclusion-stuff (dd)
+(defun frob-dd-inclusion-stuff (dd)
   (destructuring-bind (included-name &rest modified-slots) (dd-include dd)
     (let* ((type (dd-type dd))
           (included-structure
            (if (dd-class-p dd)
                (layout-info (compiler-layout-or-lose included-name))
                (typed-structure-info-or-lose included-name))))
+
+      ;; checks on legality
       (unless (and (eq type (dd-type included-structure))
                   (type= (specifier-type (dd-element-type included-structure))
                          (specifier-type (dd-element-type dd))))
        (error ":TYPE option mismatch between structures ~S and ~S"
               (dd-name dd) included-name))
+      (let ((included-classoid (find-classoid included-name nil)))
+       (when included-classoid
+         ;; It's not particularly well-defined to :INCLUDE any of the
+         ;; CMU CL INSTANCE weirdosities like CONDITION or
+         ;; GENERIC-FUNCTION, and it's certainly not ANSI-compliant.
+         (let* ((included-layout (classoid-layout included-classoid))
+                (included-dd (layout-info included-layout)))
+           (when (and (dd-alternate-metaclass included-dd)
+                      ;; As of sbcl-0.pre7.73, anyway, STRUCTURE-OBJECT
+                      ;; is represented with an ALTERNATE-METACLASS. But
+                      ;; it's specifically OK to :INCLUDE (and PCL does)
+                      ;; so in this one case, it's OK to include
+                      ;; something with :ALTERNATE-METACLASS after all.
+                      (not (eql included-name 'structure-object)))
+             (error "can't :INCLUDE class ~S (has alternate metaclass)"
+                    included-name)))))
 
       (incf (dd-length dd) (dd-length included-structure))
       (when (dd-class-p dd)
        (setf (dd-raw-index dd) (dd-raw-index included-structure))
        (setf (dd-raw-length dd) (dd-raw-length included-structure)))
 
+      (setf (dd-inherited-accessor-alist dd)
+           (dd-inherited-accessor-alist included-structure))
       (dolist (included-slot (dd-slots included-structure))
        (let* ((included-name (dsd-name included-slot))
               (modified (or (find included-name modified-slots
-                                  :key #'(lambda (x) (if (atom x) x (car x)))
+                                  :key (lambda (x) (if (atom x) x (car x)))
                                   :test #'string=)
                             `(,included-name))))
-         (parse-1-dsd dd
-                      modified
-                      (copy-structure included-slot)))))))
+         ;; We stash away an alist of accessors to parents' slots
+         ;; that have already been created to avoid conflicts later
+         ;; so that structures with :INCLUDE and :CONC-NAME (and
+         ;; other edge cases) can work as specified.
+         (when (dsd-accessor-name included-slot)
+           ;; the "oldest" (i.e. highest up the tree of inheritance)
+           ;; will prevail, so don't push new ones on if they
+           ;; conflict.
+           (pushnew (cons (dsd-accessor-name included-slot)
+                          (dsd-index included-slot))
+                    (dd-inherited-accessor-alist dd)
+                    :test #'eq :key #'car))
+         (let ((new-slot (parse-1-dsd dd
+                                       modified
+                                       (copy-structure included-slot))))
+            (when (and (neq (dsd-type new-slot) (dsd-type included-slot))
+                       (not (subtypep (dsd-type included-slot)
+                                      (dsd-type new-slot)))
+                       (dsd-safe-p included-slot))
+              (setf (dsd-safe-p new-slot) nil)
+              ;; XXX: notify?
+              )))))))
 \f
 ;;;; various helper functions for setting up DEFSTRUCTs
 
         (super
          (if include
              (compiler-layout-or-lose (first include))
-             (class-layout (sb!xc:find-class
-                            (or (first superclass-opt)
-                                'structure-object))))))
-    (if (eq (dd-name info) 'lisp-stream)
-       ;; a hack to added the stream class as a mixin for LISP-STREAMs
-       (concatenate 'simple-vector
-                    (layout-inherits super)
-                    (vector super
-                            (class-layout (sb!xc:find-class 'stream))))
-       (concatenate 'simple-vector
-                    (layout-inherits super)
-                    (vector super)))))
+             (classoid-layout (find-classoid
+                               (or (first superclass-opt)
+                                   'structure-object))))))
+    (case (dd-name info)
+      ((ansi-stream)
+       (concatenate 'simple-vector
+                   (layout-inherits super)
+                   (vector super (classoid-layout (find-classoid 'stream)))))
+      ((fd-stream)
+       (concatenate 'simple-vector
+                   (layout-inherits super)
+                   (vector super 
+                           (classoid-layout (find-classoid 'file-stream)))))
+      ((sb!impl::string-input-stream 
+       sb!impl::string-output-stream
+       sb!impl::fill-pointer-output-stream)
+       (concatenate 'simple-vector
+                   (layout-inherits super)
+                   (vector super
+                           (classoid-layout (find-classoid 'string-stream)))))
+      (t (concatenate 'simple-vector 
+                     (layout-inherits super)
+                     (vector super))))))
 
 ;;; Do miscellaneous (LOAD EVAL) time actions for the structure
-;;; described by DD. Create the class & LAYOUT, checking for
-;;; incompatible redefinition. Define setters, accessors, copier,
-;;; predicate, documentation, instantiate definition in load-time
-;;; environment.
+;;; described by DD. Create the class and LAYOUT, checking for
+;;; incompatible redefinition. Define those functions which are
+;;; sufficiently stereotyped that we can implement them as standard
+;;; closures.
 (defun %defstruct (dd inherits)
   (declare (type defstruct-description dd))
-  (remhash (dd-name dd) *typecheckfuns*)
-  (multiple-value-bind (class layout old-layout)
+
+  ;; We set up LAYOUTs even in the cross-compilation host.
+  (multiple-value-bind (classoid layout old-layout)
       (ensure-structure-class dd inherits "current" "new")
     (cond ((not old-layout)
-          (unless (eq (class-layout class) layout)
+          (unless (eq (classoid-layout classoid) layout)
             (register-layout layout)))
          (t
-          (let ((old-dd (layout-dd old-layout)))
+          (let ((old-dd (layout-info old-layout)))
             (when (defstruct-description-p old-dd)
               (dolist (slot (dd-slots old-dd))
                 (fmakunbound (dsd-accessor-name slot))
                 (unless (dsd-read-only slot)
                   (fmakunbound `(setf ,(dsd-accessor-name slot)))))))
-          (%redefine-defstruct class old-layout layout)
-          (setq layout (class-layout class))))
+          (%redefine-defstruct classoid old-layout layout)
+          (setq layout (classoid-layout classoid))))
+    (setf (find-classoid (dd-name dd)) classoid)
 
-    (setf (sb!xc:find-class (dd-name dd)) class)
-
-    ;; Set FDEFINITIONs for structure accessors, setters, predicates,
-    ;; and copiers.
+    ;; Various other operations only make sense on the target SBCL.
     #-sb-xc-host
-    (unless (eq (dd-type dd) 'funcallable-structure)
-
-      (dolist (slot (dd-slots dd))
-       (let ((dsd slot))
-         (when (and (dsd-accessor-name slot)
-                    (eq (dsd-raw-type slot) t))
-           (protect-cl (dsd-accessor-name slot))
-           (setf (symbol-function (dsd-accessor-name slot))
-                 (structure-slot-getter layout dsd))
-           (unless (dsd-read-only slot)
-             (setf (fdefinition `(setf ,(dsd-accessor-name slot)))
-                   (structure-slot-setter layout dsd))))))
-
-      ;; FIXME: Someday it'd probably be good to go back to using
-      ;; closures for the out-of-line forms of structure accessors.
-      #|
-      (when (dd-predicate dd)
-       (protect-cl (dd-predicate dd))
-       (setf (symbol-function (dd-predicate dd))
-             #'(lambda (object)
-                 (declare (optimize (speed 3) (safety 0)))
-                 (typep-to-layout object layout))))
-      |#
-
-      (when (dd-copier-name dd)
-       (protect-cl (dd-copier-name dd))
-       (setf (symbol-function (dd-copier-name dd))
-             #'(lambda (structure)
-                 (declare (optimize (speed 3) (safety 0)))
-                 (flet ((layout-test (structure)
-                          (typep-to-layout structure layout)))
-                   (unless (layout-test structure)
-                     (error 'simple-type-error
-                            :datum structure
-                            :expected-type '(satisfies layout-test)
-                            :format-control
-                            "Structure for copier is not a ~S:~% ~S"
-                            :format-arguments
-                            (list (sb!xc:class-name (layout-class layout))
-                                  structure))))
-                 (copy-structure structure))))))
-
-  (when (dd-doc dd)
-    (setf (fdocumentation (dd-name dd) 'type)
-         (dd-doc dd)))
+    (%target-defstruct dd layout))
 
   (values))
-
+\f
 ;;; Return a form describing the writable place used for this slot
 ;;; in the instance named INSTANCE-NAME.
 (defun %accessor-place-form (dd dsd instance-name)
        ;; the case of a raw slot, to read the vector of raw slots
        (ref (ecase (dd-type dd)
               (structure '%instance-ref)
-              (funcallable-structure '%funcallable-instance-info)
               (list 'nth-but-with-sane-arg-order)
               (vector 'aref)))
        (raw-type (dsd-raw-type dsd)))
     (if (eq raw-type t) ; if not raw slot
        `(,ref ,instance-name ,(dsd-index dsd))
-       (let (;; the operator that we'll use to access one value in
-             ;; the raw data vector
-             (rawref (ecase raw-type
-                       ;; The compiler thinks that the raw data
-                       ;; vector is a vector of unsigned bytes, so if
-                       ;; the slot we want to access actually *is* an
-                       ;; unsigned byte, it'll access the slot for
-                       ;; us even if we don't lie to it at all.
-                       (unsigned-byte 'aref)
-                       ;; "A lie can travel halfway round the world while
-                       ;; the truth is putting on its shoes." -- Mark Twain
-                       (single-float '%raw-ref-single)
-                       (double-float '%raw-ref-double)
-                       #!+long-float (long-float '%raw-ref-long)
-                       (complex-single-float '%raw-ref-complex-single)
-                       (complex-double-float '%raw-ref-complex-double)
-                       #!+long-float (complex-long-float
-                                      '%raw-ref-complex-long))))
-         `(,rawref (,ref ,instance-name ,(dd-raw-index dd))
-                   ,(dsd-index dsd))))))
-
-;;; Return inline expansion designators (i.e. values suitable for
-;;; (INFO :FUNCTION :INLINE-EXPANSSION-DESIGNATOR ..)) for the reader
-;;; and writer functions of the slot described by DSD.
-(defun accessor-inline-expansion-designators (dd dsd)
-  (values (lambda ()
-           `(lambda (instance)
-              (declare (type ,(dd-name dd) instance))
-              (truly-the ,(dsd-type dsd)
-                         ,(%accessor-place-form dd dsd 'instance))))
-         (lambda ()
-           `(lambda (new-value instance)
-              (declare (type ,(dsd-type dsd) new-value))
-              (declare (type ,(dd-name dd) structure-object))
-              (setf ,(%accessor-place-form dd dsd 'instance) new-value)))))
-
-;;; Do (COMPILE LOAD EVAL)-time actions for the defstruct described by DD.
-(defun %compiler-defstruct (dd inherits)
-  (declare (type defstruct-description dd))
-  (multiple-value-bind (class layout old-layout)
+       (let* ((raw-slot-data (find raw-type *raw-slot-data-list*
+                                   :key #'raw-slot-data-raw-type
+                                   :test #'equal))
+              (raw-slot-accessor (raw-slot-data-accessor-name raw-slot-data))
+              (raw-n-words (raw-slot-data-n-words raw-slot-data)))
+         (multiple-value-bind (scaled-dsd-index misalignment)
+             (floor (dsd-index dsd) raw-n-words)
+           (aver (zerop misalignment))
+           (let* ((raw-vector-bare-form
+                   `(,ref ,instance-name ,(dd-raw-index dd)))
+                  (raw-vector-form
+                   (if (eq raw-type 'unsigned-byte)
+                       (progn
+                         (aver (= raw-n-words 1))
+                         (aver (eq raw-slot-accessor 'aref))
+                         ;; FIXME: when the 64-bit world rolls
+                         ;; around, this will need to be reviewed,
+                         ;; along with the whole RAW-SLOT thing.
+                         `(truly-the
+                           (simple-array sb!vm:word (*))
+                           ,raw-vector-bare-form))
+                       raw-vector-bare-form)))
+             `(,raw-slot-accessor ,raw-vector-form ,scaled-dsd-index)))))))
+
+;;; Return source transforms for the reader and writer functions of
+;;; the slot described by DSD. They should be inline expanded, but
+;;; source transforms work faster.
+(defun slot-accessor-transforms (dd dsd)
+  (let ((accessor-place-form (%accessor-place-form dd dsd
+                                                   `(the ,(dd-name dd) instance)))
+        (dsd-type (dsd-type dsd))
+        (value-the (if (dsd-safe-p dsd) 'truly-the 'the)))
+    (values (sb!c:source-transform-lambda (instance)
+              `(,value-the ,dsd-type ,(subst instance 'instance
+                                             accessor-place-form)))
+            (sb!c:source-transform-lambda (new-value instance)
+              (destructuring-bind (accessor-name &rest accessor-args)
+                  accessor-place-form
+                (once-only ((new-value new-value)
+                            (instance instance))
+                  `(,(info :setf :inverse accessor-name)
+                     ,@(subst instance 'instance accessor-args)
+                     (the ,dsd-type ,new-value))))))))
+
+;;; Return a LAMBDA form which can be used to set a slot.
+(defun slot-setter-lambda-form (dd dsd)
+  `(lambda (new-value instance)
+     ,(funcall (nth-value 1 (slot-accessor-transforms dd dsd))
+               '(dummy new-value instance))))
+
+;;; core compile-time setup of any class with a LAYOUT, used even by
+;;; !DEFSTRUCT-WITH-ALTERNATE-METACLASS weirdosities
+(defun %compiler-set-up-layout (dd
+                               &optional
+                               ;; Several special cases (STRUCTURE-OBJECT
+                               ;; itself, and structures with alternate
+                               ;; metaclasses) call this function directly,
+                               ;; and they're all at the base of the
+                               ;; instance class structure, so this is
+                               ;; a handy default.
+                               (inherits (vector (find-layout t)
+                                                 (find-layout 'instance))))
+
+  (multiple-value-bind (classoid layout old-layout)
       (multiple-value-bind (clayout clayout-p)
          (info :type :compiler-layout (dd-name dd))
        (ensure-structure-class dd
                                "compiled"
                                :compiler-layout clayout))
     (cond (old-layout
-          (undefine-structure (layout-class old-layout))
-          (when (and (class-subclasses class)
+          (undefine-structure (layout-classoid old-layout))
+          (when (and (classoid-subclasses classoid)
                      (not (eq layout old-layout)))
             (collect ((subs))
-                     (dohash (class layout (class-subclasses class))
+                     (dohash (classoid layout (classoid-subclasses classoid))
                        (declare (ignore layout))
-                       (undefine-structure class)
-                       (subs (class-proper-name class)))
+                       (undefine-structure classoid)
+                       (subs (classoid-proper-name classoid)))
                      (when (subs)
                        (warn "removing old subclasses of ~S:~%  ~S"
-                             (sb!xc:class-name class)
+                             (classoid-name classoid)
                              (subs))))))
          (t
-          (unless (eq (class-layout class) layout)
+          (unless (eq (classoid-layout classoid) layout)
             (register-layout layout :invalidate nil))
-          (setf (sb!xc:find-class (dd-name dd)) class)))
+          (setf (find-classoid (dd-name dd)) classoid)))
+
+    ;; At this point the class should be set up in the INFO database.
+    ;; But the logic that enforces this is a little tangled and
+    ;; scattered, so it's not obvious, so let's check.
+    (aver (find-classoid (dd-name dd) nil))
 
     (setf (info :type :compiler-layout (dd-name dd)) layout))
 
-  (let* ((dd-name (dd-name dd))
-        (class (sb!xc:find-class dd-name)))
+  (values))
+
+;;; Do (COMPILE LOAD EVAL)-time actions for the normal (not
+;;; ALTERNATE-LAYOUT) DEFSTRUCT described by DD.
+(defun %compiler-defstruct (dd inherits)
+  (declare (type defstruct-description dd))
+
+  (%compiler-set-up-layout dd inherits)
+
+  (let* ((dtype (dd-declarable-type dd)))
 
     (let ((copier-name (dd-copier-name dd)))
       (when copier-name
-       (sb!xc:proclaim `(ftype (function (,dd-name) ,dd-name) ,copier-name))))
+       (sb!xc:proclaim `(ftype (sfunction (,dtype) ,dtype) ,copier-name))))
 
     (let ((predicate-name (dd-predicate-name dd)))
       (when predicate-name
-       (sb!xc:proclaim `(ftype (function (t) t) ,predicate-name))))
+       (sb!xc:proclaim `(ftype (sfunction (t) boolean) ,predicate-name))
+       ;; Provide inline expansion (or not).
+       (ecase (dd-type dd)
+         ((structure funcallable-structure)
+          ;; Let the predicate be inlined.
+          (setf (info :function :inline-expansion-designator predicate-name)
+                (lambda ()
+                  `(lambda (x)
+                     ;; This dead simple definition works because the
+                     ;; type system knows how to generate inline type
+                     ;; tests for instances.
+                     (typep x ',(dd-name dd))))
+                (info :function :inlinep predicate-name)
+                :inline))
+         ((list vector)
+          ;; Just punt. We could provide inline expansions for :TYPE
+          ;; LIST and :TYPE VECTOR predicates too, but it'd be a
+          ;; little messier and we don't bother. (Does anyway use
+          ;; typed DEFSTRUCTs at all, let alone for high
+          ;; performance?)
+          ))))
 
     (dolist (dsd (dd-slots dd))
       (let* ((accessor-name (dsd-accessor-name dsd))
             (dsd-type (dsd-type dsd)))
        (when accessor-name
-         (multiple-value-bind (reader-designator writer-designator)
-             (accessor-inline-expansion-designators dd dsd)
-           (sb!xc:proclaim `(ftype (function (,dd-name) ,dsd-type)
-                                   ,accessor-name))
-           (setf (info :function
-                       :inline-expansion-designator
-                       accessor-name)
-                 reader-designator
-                 (info :function :inlinep accessor-name)
-                 :inline)
-           (unless (dsd-read-only dsd)
-             (let ((setf-accessor-name `(setf ,accessor-name)))
-               (sb!xc:proclaim
-                `(ftype (function (,dsd-type ,dd-name) ,dsd-type)
-                        ,setf-accessor-name))
-               (setf (info :function
-                           :inline-expansion-designator
-                           setf-accessor-name)
-                     writer-designator
-                     (info :function :inlinep setf-accessor-name)
-                     :inline))))))))
-
+         (let ((inherited (accessor-inherited-data accessor-name dd)))
+           (cond
+             ((not inherited)
+              (multiple-value-bind (reader-designator writer-designator)
+                  (slot-accessor-transforms dd dsd)
+                (sb!xc:proclaim `(ftype (sfunction (,dtype) ,dsd-type)
+                                  ,accessor-name))
+                (setf (info :function :source-transform accessor-name)
+                      reader-designator)
+                (unless (dsd-read-only dsd)
+                  (let ((setf-accessor-name `(setf ,accessor-name)))
+                    (sb!xc:proclaim
+                     `(ftype (sfunction (,dsd-type ,dtype) ,dsd-type)
+                       ,setf-accessor-name))
+                    (setf (info :function :source-transform setf-accessor-name)
+                          writer-designator)))))
+             ((not (= (cdr inherited) (dsd-index dsd)))
+              (style-warn "~@<Non-overwritten accessor ~S does not access ~
+                            slot with name ~S (accessing an inherited slot ~
+                            instead).~:@>"
+                          accessor-name
+                          (dsd-name dsd)))))))))
   (values))
 \f
 ;;;; redefinition stuff
     (collect ((moved)
              (retyped))
       (dolist (name (intersection onames nnames))
-       (let ((os (find name oslots :key #'dsd-name))
-             (ns (find name nslots :key #'dsd-name)))
-         (unless (subtypep (dsd-type ns) (dsd-type os))
-           (/noshow "found retyped slots" ns os (dsd-type ns) (dsd-type os))
+       (let ((os (find name oslots :key #'dsd-name :test #'string=))
+             (ns (find name nslots :key #'dsd-name :test #'string=)))
+         (unless (sb!xc:subtypep (dsd-type ns) (dsd-type os))
            (retyped name))
          (unless (and (= (dsd-index os) (dsd-index ns))
                       (eq (dsd-raw-type os) (dsd-raw-type ns)))
            (moved name))))
       (values (moved)
              (retyped)
-             (set-difference onames nnames)))))
+             (set-difference onames nnames :test #'string=)))))
 
 ;;; If we are redefining a structure with different slots than in the
 ;;; currently loaded version, give a warning and return true.
-(defun redefine-structure-warning (class old new)
+(defun redefine-structure-warning (classoid old new)
   (declare (type defstruct-description old new)
-          (type sb!xc:class class)
-          (ignore class))
+          (type classoid classoid)
+          (ignore classoid))
   (let ((name (dd-name new)))
     (multiple-value-bind (moved retyped deleted) (compare-slots old new)
       (when (or moved retyped deleted)
        (warn
         "incompatibly redefining slots of structure class ~S~@
-         Make sure any uses of affected accessors are recompiled:~@
-         ~@[  These slots were moved to new positions:~%    ~S~%~]~
-         ~@[  These slots have new incompatible types:~%    ~S~%~]~
-         ~@[  These slots were deleted:~%    ~S~%~]"
+          Make sure any uses of affected accessors are recompiled:~@
+          ~@[  These slots were moved to new positions:~%    ~S~%~]~
+          ~@[  These slots have new incompatible types:~%    ~S~%~]~
+          ~@[  These slots were deleted:~%    ~S~%~]"
         name moved retyped deleted)
        t))))
 
 ;;; structure CLASS to have the specified NEW-LAYOUT. We signal an
 ;;; error with some proceed options and return the layout that should
 ;;; be used.
-(defun %redefine-defstruct (class old-layout new-layout)
-  (declare (type sb!xc:class class) (type layout old-layout new-layout))
-  (let ((name (class-proper-name class)))
+(defun %redefine-defstruct (classoid old-layout new-layout)
+  (declare (type classoid classoid)
+          (type layout old-layout new-layout))
+  (let ((name (classoid-proper-name classoid)))
     (restart-case
-       (error "redefining class ~S incompatibly with the current definition"
+       (error "~@<attempt to redefine the ~S class ~S incompatibly with the current definition~:@>"
+              'structure-object
               name)
       (continue ()
-       :report "Invalidate current definition."
-       (warn "Previously loaded ~S accessors will no longer work." name)
-       (register-layout new-layout))
+       :report (lambda (s)
+                (format s
+                        "~@<Use the new definition of ~S, invalidating ~
+                          already-loaded code and instances.~@:>"
+                        name))
+       (register-layout new-layout))
+      (recklessly-continue ()
+       :report (lambda (s)
+                (format s
+                        "~@<Use the new definition of ~S as if it were ~
+                          compatible, allowing old accessors to use new ~
+                          instances and allowing new accessors to use old ~
+                          instances.~@:>"
+                        name))
+       ;; classic CMU CL warning: "Any old ~S instances will be in a bad way. 
+       ;; I hope you know what you're doing..."
+       (register-layout new-layout
+                       :invalidate nil
+                       :destruct-layout old-layout))
       (clobber-it ()
-       :report "Smash current layout, preserving old code."
-       (warn "Any old ~S instances will be in a bad way.~@
-              I hope you know what you're doing..."
-             name)
-       (register-layout new-layout :invalidate nil
-                        :destruct-layout old-layout))))
+       ;; FIXME: deprecated 2002-10-16, and since it's only interactive
+       ;; hackery instead of a supported feature, can probably be deleted
+       ;; in early 2003
+       :report "(deprecated synonym for RECKLESSLY-CONTINUE)"
+       (register-layout new-layout
+                       :invalidate nil
+                       :destruct-layout old-layout))))
   (values))
 
 ;;; This is called when we are about to define a structure class. It
       (destructuring-bind
          (&optional
           name
-          (class 'sb!xc:structure-class)
-          (constructor 'make-structure-class))
+          (class 'structure-classoid)
+          (constructor 'make-structure-classoid))
          (dd-alternate-metaclass info)
        (declare (ignore name))
-       (insured-find-class (dd-name info)
-                           (if (eq class 'sb!xc:structure-class)
-                             (lambda (x)
-                               (typep x 'sb!xc:structure-class))
-                             (lambda (x)
-                               (sb!xc:typep x (sb!xc:find-class class))))
-                           (fdefinition constructor)))
-    (setf (class-direct-superclasses class)
-         (if (eq (dd-name info) 'lisp-stream)
-             ;; a hack to add STREAM as a superclass mixin to LISP-STREAMs
-             (list (layout-class (svref inherits (1- (length inherits))))
-                   (layout-class (svref inherits (- (length inherits) 2))))
-             (list (layout-class (svref inherits (1- (length inherits)))))))
-    (let ((new-layout (make-layout :class class
+       (insured-find-classoid (dd-name info)
+                              (if (eq class 'structure-classoid)
+                                  (lambda (x)
+                                    (sb!xc:typep x 'structure-classoid))
+                                  (lambda (x)
+                                    (sb!xc:typep x (find-classoid class))))
+                              (fdefinition constructor)))
+    (setf (classoid-direct-superclasses class)
+         (case (dd-name info)
+           ((ansi-stream 
+             fd-stream 
+             sb!impl::string-input-stream sb!impl::string-output-stream
+             sb!impl::fill-pointer-output-stream)
+            (list (layout-classoid (svref inherits (1- (length inherits))))
+                  (layout-classoid (svref inherits (- (length inherits) 2)))))
+           (t
+            (list (layout-classoid
+                   (svref inherits (1- (length inherits))))))))
+    (let ((new-layout (make-layout :classoid class
                                   :inherits inherits
                                   :depthoid (length inherits)
                                   :length (dd-length info)
        (;; This clause corresponds to an assertion in REDEFINE-LAYOUT-WARNING
        ;; of classic CMU CL. I moved it out to here because it was only
        ;; exercised in this code path anyway. -- WHN 19990510
-       (not (eq (layout-class new-layout) (layout-class old-layout)))
+       (not (eq (layout-classoid new-layout) (layout-classoid old-layout)))
        (error "shouldn't happen: weird state of OLD-LAYOUT?"))
        ((not *type-system-initialized*)
        (setf (layout-info old-layout) info)
 ;;; over this type, clearing the compiler structure type info, and
 ;;; undefining all the associated functions.
 (defun undefine-structure (class)
-  (let ((info (layout-info (class-layout class))))
+  (let ((info (layout-info (classoid-layout class))))
     (when (defstruct-description-p info)
       (let ((type (dd-name info)))
+       (remhash type *typecheckfuns*)
        (setf (info :type :compiler-layout type) nil)
        (undefine-fun-name (dd-copier-name info))
        (undefine-fun-name (dd-predicate-name info))
        (dolist (slot (dd-slots info))
          (let ((fun (dsd-accessor-name slot)))
-           (undefine-fun-name fun)
-           (unless (dsd-read-only slot)
-             (undefine-fun-name `(setf ,fun))))))
+           (unless (accessor-inherited-data fun info)
+             (undefine-fun-name fun)
+             (unless (dsd-read-only slot)
+               (undefine-fun-name `(setf ,fun)))))))
       ;; Clear out the SPECIFIER-TYPE cache so that subsequent
       ;; references are unknown types.
       (values-specifier-type-cache-clear)))
 
     (res)))
 \f
-;;;; slot accessors for raw slots
-
-;;; Return info about how to read/write a slot in the value stored in
-;;; OBJECT. This is also used by constructors (since we can't safely
-;;; use the accessor function, since some slots are read-only). If
-;;; supplied, DATA is a variable holding the raw-data vector.
-;;;
-;;; returned values:
-;;; 1. accessor function name (SETFable)
-;;; 2. index to pass to accessor.
-;;; 3. object form to pass to accessor
-(defun slot-accessor-form (defstruct slot object &optional data)
-  (let ((rtype (dsd-raw-type slot)))
-    (values
-     (ecase rtype
-       (single-float '%raw-ref-single)
-       (double-float '%raw-ref-double)
-       #!+long-float
-       (long-float '%raw-ref-long)
-       (complex-single-float '%raw-ref-complex-single)
-       (complex-double-float '%raw-ref-complex-double)
-       #!+long-float
-       (complex-long-float '%raw-ref-complex-long)
-       (unsigned-byte 'aref)
-       ((t)
-       (if (eq (dd-type defstruct) 'funcallable-structure)
-           '%funcallable-instance-info
-           '%instance-ref)))
-     (case rtype
-       #!+long-float
-       (complex-long-float
-       (truncate (dsd-index slot) #!+x86 6 #!+sparc 8))
-       #!+long-float
-       (long-float
-       (truncate (dsd-index slot) #!+x86 3 #!+sparc 4))
-       (double-float
-       (ash (dsd-index slot) -1))
-       (complex-double-float
-       (ash (dsd-index slot) -2))
-       (complex-single-float
-       (ash (dsd-index slot) -1))
-       (t
-       (dsd-index slot)))
-     (cond
-      ((eq rtype t) object)
-      (data)
-      (t
-       `(truly-the (simple-array (unsigned-byte 32) (*))
-                  (%instance-ref ,object ,(dd-raw-index defstruct))))))))
-\f
 ;;; These functions are called to actually make a constructor after we
 ;;; have processed the arglist. The correct variant (according to the
 ;;; DD-TYPE) should be called. The function is defined with the
-;;; specified name and arglist. Vars and Types are used for argument
-;;; type declarations. Values are the values for the slots (in order.)
+;;; specified name and arglist. VARS and TYPES are used for argument
+;;; type declarations. VALUES are the values for the slots (in order.)
 ;;;
-;;; This is split four ways because:
-;;; 1] list & vector structures need "name" symbols stuck in at
-;;;    various weird places, whereas STRUCTURE structures have
-;;;    a LAYOUT slot.
-;;; 2] We really want to use LIST to make list structures, instead of
-;;;    MAKE-LIST/(SETF ELT).
-;;; 3] STRUCTURE structures can have raw slots that must also be
-;;;    allocated and indirectly referenced. We use SLOT-ACCESSOR-FORM
-;;;    to compute how to set the slots, which deals with raw slots.
-;;; 4] Funcallable structures are weird.
-(defun create-vector-constructor
-       (defstruct cons-name arglist vars types values)
+;;; This is split three ways because:
+;;;   * LIST & VECTOR structures need "name" symbols stuck in at
+;;;     various weird places, whereas STRUCTURE structures have
+;;;     a LAYOUT slot.
+;;;   * We really want to use LIST to make list structures, instead of
+;;;     MAKE-LIST/(SETF ELT). (We can't in general use VECTOR in an
+;;;     analogous way, since VECTOR makes a SIMPLE-VECTOR and vector-typed
+;;;     structures can have arbitrary subtypes of VECTOR, not necessarily
+;;;     SIMPLE-VECTOR.)
+;;;   * STRUCTURE structures can have raw slots that must also be
+;;;     allocated and indirectly referenced.
+(defun create-vector-constructor (dd cons-name arglist vars types values)
   (let ((temp (gensym))
-       (etype (dd-element-type defstruct)))
+       (etype (dd-element-type dd)))
     `(defun ,cons-name ,arglist
-       (declare ,@(mapcar #'(lambda (var type) `(type (and ,type ,etype) ,var))
+       (declare ,@(mapcar (lambda (var type) `(type (and ,type ,etype) ,var))
                          vars types))
-       (let ((,temp (make-array ,(dd-length defstruct)
-                               :element-type ',(dd-element-type defstruct))))
-        ,@(mapcar #'(lambda (x)
-                      `(setf (aref ,temp ,(cdr x))  ',(car x)))
-                  (find-name-indices defstruct))
-        ,@(mapcar #'(lambda (dsd value)
-                      `(setf (aref ,temp ,(dsd-index dsd)) ,value))
-                  (dd-slots defstruct) values)
+       (let ((,temp (make-array ,(dd-length dd)
+                               :element-type ',(dd-element-type dd))))
+        ,@(mapcar (lambda (x)
+                    `(setf (aref ,temp ,(cdr x))  ',(car x)))
+                  (find-name-indices dd))
+        ,@(mapcar (lambda (dsd value)
+                    (unless (eq value '.do-not-initialize-slot.)
+                         `(setf (aref ,temp ,(dsd-index dsd)) ,value)))
+                  (dd-slots dd) values)
         ,temp))))
-(defun create-list-constructor
-       (defstruct cons-name arglist vars types values)
-  (let ((vals (make-list (dd-length defstruct) :initial-element nil)))
-    (dolist (x (find-name-indices defstruct))
+(defun create-list-constructor (dd cons-name arglist vars types values)
+  (let ((vals (make-list (dd-length dd) :initial-element nil)))
+    (dolist (x (find-name-indices dd))
       (setf (elt vals (cdr x)) `',(car x)))
-    (loop for dsd in (dd-slots defstruct) and val in values do
-      (setf (elt vals (dsd-index dsd)) val))
+    (loop for dsd in (dd-slots dd) and val in values do
+      (setf (elt vals (dsd-index dsd))
+            (if (eq val '.do-not-initialize-slot.) 0 val)))
 
     `(defun ,cons-name ,arglist
-       (declare ,@(mapcar #'(lambda (var type) `(type ,type ,var))
-                         vars types))
+       (declare ,@(mapcar (lambda (var type) `(type ,type ,var)) vars types))
        (list ,@vals))))
-(defun create-structure-constructor
-       (defstruct cons-name arglist vars types values)
-  (let* ((temp (gensym))
-        (raw-index (dd-raw-index defstruct))
-        (n-raw-data (when raw-index (gensym))))
+(defun create-structure-constructor (dd cons-name arglist vars types values)
+  (let* ((instance (gensym "INSTANCE"))
+        (raw-index (dd-raw-index dd)))
     `(defun ,cons-name ,arglist
-       (declare ,@(mapcar #'(lambda (var type) `(type ,type ,var))
+       (declare ,@(mapcar (lambda (var type) `(type ,type ,var))
                          vars types))
-       (let ((,temp (truly-the ,(dd-name defstruct)
-                              (%make-instance ,(dd-length defstruct))))
-            ,@(when n-raw-data
-                `((,n-raw-data
-                   (make-array ,(dd-raw-length defstruct)
-                               :element-type '(unsigned-byte 32))))))
-        (setf (%instance-layout ,temp)
-              (%delayed-get-compiler-layout ,(dd-name defstruct)))
-        ,@(when n-raw-data
-            `((setf (%instance-ref ,temp ,raw-index) ,n-raw-data)))
+       (let ((,instance (truly-the ,(dd-name dd)
+                         (%make-instance-with-layout
+                          (%delayed-get-compiler-layout ,(dd-name dd))))))
+        ,@(when raw-index
+            `((setf (%instance-ref ,instance ,raw-index)
+                    (make-array ,(dd-raw-length dd)
+                                :element-type 'sb!vm:word))))
         ,@(mapcar (lambda (dsd value)
-                    (multiple-value-bind (accessor index data)
-                        (slot-accessor-form defstruct dsd temp n-raw-data)
-                      `(setf (,accessor ,data ,index) ,value)))
-                  (dd-slots defstruct)
+                    ;; (Note that we can't in general use the
+                    ;; ordinary named slot setter function here
+                    ;; because the slot might be :READ-ONLY, so we
+                    ;; whip up new LAMBDA representations of slot
+                    ;; setters for the occasion.)
+                     (unless (eq value '.do-not-initialize-slot.)
+                       `(,(slot-setter-lambda-form dd dsd) ,value ,instance)))
+                  (dd-slots dd)
                   values)
-        ,temp))))
-(defun create-fin-constructor
-       (defstruct cons-name arglist vars types values)
-  (let ((temp (gensym)))
-    `(defun ,cons-name ,arglist
-       (declare ,@(mapcar #'(lambda (var type) `(type ,type ,var))
-                         vars types))
-       (let ((,temp (truly-the
-                    ,(dd-name defstruct)
-                    (%make-funcallable-instance
-                     ,(dd-length defstruct)
-                     (%delayed-get-compiler-layout ,(dd-name defstruct))))))
-        ,@(mapcar #'(lambda (dsd value)
-                      `(setf (%funcallable-instance-info
-                              ,temp ,(dsd-index dsd))
-                             ,value))
-                  (dd-slots defstruct) values)
-        ,temp))))
+        ,instance))))
 
 ;;; Create a default (non-BOA) keyword constructor.
 (defun create-keyword-constructor (defstruct creator)
+  (declare (type function creator))
   (collect ((arglist (list '&key))
            (types)
            (vals))
 ;;; Given a structure and a BOA constructor spec, call CREATOR with
 ;;; the appropriate args to make a constructor.
 (defun create-boa-constructor (defstruct boa creator)
-  (multiple-value-bind (req opt restp rest keyp keys allowp aux)
-      (sb!kernel:parse-lambda-list (second boa))
+  (declare (type function creator))
+  (multiple-value-bind (req opt restp rest keyp keys allowp auxp aux)
+      (parse-lambda-list (second boa))
     (collect ((arglist)
              (vars)
-             (types))
+             (types)
+              (skipped-vars))
       (labels ((get-slot (name)
                 (let ((res (find name (dd-slots defstruct)
                                  :test #'string=
          (arglist arg)
          (vars arg)
          (types (get-slot arg)))
-       
+
        (when opt
          (arglist '&optional)
          (dolist (arg opt)
            (cond ((consp arg)
                   (destructuring-bind
-                      (name &optional (def (nth-value 1 (get-slot name))))
+                        ;; FIXME: this shares some logic (though not
+                        ;; code) with the &key case below (and it
+                        ;; looks confusing) -- factor out the logic
+                        ;; if possible. - CSR, 2002-04-19
+                        (name
+                         &optional
+                         (def (nth-value 1 (get-slot name)))
+                         (supplied-test nil supplied-test-p))
                       arg
-                    (arglist `(,name ,def))
+                    (arglist `(,name ,def ,@(if supplied-test-p `(,supplied-test) nil)))
                     (vars name)
                     (types (get-slot name))))
                  (t
          (arglist '&key)
          (dolist (key keys)
            (if (consp key)
-               (destructuring-bind (wot &optional (def nil def-p)) key
+               (destructuring-bind (wot
+                                     &optional
+                                     (def nil def-p)
+                                     (supplied-test nil supplied-test-p))
+                    key
                  (let ((name (if (consp wot)
                                  (destructuring-bind (key var) wot
                                    (declare (ignore key))
                                    var)
                                  wot)))
-                   (multiple-value-bind (type slot-def) (get-slot name)
-                     (arglist `(,wot ,(if def-p def slot-def)))
+                   (multiple-value-bind (type slot-def)
+                        (get-slot name)
+                     (arglist `(,wot ,(if def-p def slot-def)
+                                 ,@(if supplied-test-p `(,supplied-test) nil)))
                      (vars name)
                      (types type))))
                (do-default key))))
 
        (when allowp (arglist '&allow-other-keys))
 
-       (when aux
+       (when auxp
          (arglist '&aux)
          (dolist (arg aux)
-           (let* ((arg (if (consp arg) arg (list arg)))
-                  (var (first arg)))
-             (arglist arg)
-             (vars var)
-             (types (get-slot var))))))
+            (arglist arg)
+            (if (proper-list-of-length-p arg 2)
+              (let ((var (first arg)))
+                (vars var)
+                (types (get-slot var)))
+              (skipped-vars (if (consp arg) (first arg) arg))))))
 
       (funcall creator defstruct (first boa)
               (arglist) (vars) (types)
-              (mapcar #'(lambda (slot)
-                          (or (find (dsd-name slot) (vars) :test #'string=)
-                              (dsd-default slot)))
-                      (dd-slots defstruct))))))
+               (loop for slot in (dd-slots defstruct)
+                     for name = (dsd-name slot)
+                     collect (cond ((find name (skipped-vars) :test #'string=)
+                                    (setf (dsd-safe-p slot) nil)
+                                    '.do-not-initialize-slot.)
+                                   ((or (find (dsd-name slot) (vars) :test #'string=)
+                                        (dsd-default slot)))))))))
 
 ;;; Grovel the constructor options, and decide what constructors (if
 ;;; any) to create.
        (defaults ())
        (creator (ecase (dd-type defstruct)
                   (structure #'create-structure-constructor)
-                  (funcallable-structure #'create-fin-constructor)
                   (vector #'create-vector-constructor)
                   (list #'create-list-constructor))))
     (dolist (constructor (dd-constructors defstruct))
     (unless (or defaults boas)
       (push (symbolicate "MAKE-" (dd-name defstruct)) defaults))
 
-    (collect ((res))
+    (collect ((res) (names))
       (when defaults
-       (let ((cname (first defaults)))
-         (setf (dd-default-constructor defstruct) cname)
-         (res (create-keyword-constructor defstruct creator))
-         (dolist (other-name (rest defaults))
-           (res `(setf (fdefinition ',other-name) (fdefinition ',cname)))
-           (res `(declaim (ftype function ',other-name))))))
+        (let ((cname (first defaults)))
+          (setf (dd-default-constructor defstruct) cname)
+          (res (create-keyword-constructor defstruct creator))
+          (names cname)
+          (dolist (other-name (rest defaults))
+            (res `(setf (fdefinition ',other-name) (fdefinition ',cname)))
+            (names other-name))))
 
       (dolist (boa boas)
-       (res (create-boa-constructor defstruct boa creator)))
+        (res (create-boa-constructor defstruct boa creator))
+        (names (first boa)))
+
+      (res `(declaim (ftype
+                      (sfunction *
+                                 ,(if (eq (dd-type defstruct) 'structure)
+                                      (dd-name defstruct)
+                                      '*))
+                      ,@(names))))
 
       (res))))
 \f
+;;;; instances with ALTERNATE-METACLASS
+;;;;
+;;;; The CMU CL support for structures with ALTERNATE-METACLASS was a
+;;;; fairly general extension embedded in the main DEFSTRUCT code, and
+;;;; the result was an fairly impressive mess as ALTERNATE-METACLASS
+;;;; extension mixed with ANSI CL generality (e.g. :TYPE and :INCLUDE)
+;;;; and CMU CL implementation hairiness (esp. raw slots). This SBCL
+;;;; version is much less ambitious, noticing that ALTERNATE-METACLASS
+;;;; is only used to implement CONDITION, STANDARD-INSTANCE, and
+;;;; GENERIC-FUNCTION, and defining a simple specialized
+;;;; separate-from-DEFSTRUCT macro to provide only enough
+;;;; functionality to support those.
+;;;;
+;;;; KLUDGE: The defining macro here is so specialized that it's ugly
+;;;; in its own way. It also violates once-and-only-once by knowing
+;;;; much about structures and layouts that is already known by the
+;;;; main DEFSTRUCT macro. Hopefully it will go away presently
+;;;; (perhaps when CL:CLASS and SB-PCL:CLASS meet) as per FIXME below.
+;;;; -- WHN 2001-10-28
+;;;;
+;;;; FIXME: There seems to be no good reason to shoehorn CONDITION,
+;;;; STANDARD-INSTANCE, and GENERIC-FUNCTION into mutated structures
+;;;; instead of just implementing them as primitive objects. (This
+;;;; reduced-functionality macro seems pretty close to the
+;;;; functionality of DEFINE-PRIMITIVE-OBJECT..)
+
+(defun make-dd-with-alternate-metaclass (&key (class-name (missing-arg))
+                                             (superclass-name (missing-arg))
+                                             (metaclass-name (missing-arg))
+                                             (dd-type (missing-arg))
+                                             metaclass-constructor
+                                             slot-names)
+  (let* ((dd (make-defstruct-description class-name))
+        (conc-name (concatenate 'string (symbol-name class-name) "-"))
+        (dd-slots (let ((reversed-result nil)
+                        ;; The index starts at 1 for ordinary
+                        ;; named slots because slot 0 is
+                        ;; magical, used for LAYOUT in
+                        ;; CONDITIONs or for something (?) in
+                        ;; funcallable instances.
+                        (index 1))
+                    (dolist (slot-name slot-names)
+                      (push (make-defstruct-slot-description
+                             :name slot-name
+                             :index index
+                             :accessor-name (symbolicate conc-name slot-name))
+                            reversed-result)
+                      (incf index))
+                    (nreverse reversed-result))))
+    (setf (dd-alternate-metaclass dd) (list superclass-name
+                                           metaclass-name
+                                           metaclass-constructor)
+         (dd-slots dd) dd-slots
+         (dd-length dd) (1+ (length slot-names))
+         (dd-type dd) dd-type)
+    dd))
+
+(sb!xc:defmacro !defstruct-with-alternate-metaclass
+    (class-name &key
+               (slot-names (missing-arg))
+               (boa-constructor (missing-arg))
+               (superclass-name (missing-arg))
+               (metaclass-name (missing-arg))
+               (metaclass-constructor (missing-arg))
+               (dd-type (missing-arg))
+               predicate
+               (runtime-type-checks-p t))
+
+  (declare (type (and list (not null)) slot-names))
+  (declare (type (and symbol (not null))
+                boa-constructor
+                superclass-name
+                metaclass-name
+                metaclass-constructor))
+  (declare (type symbol predicate))
+  (declare (type (member structure funcallable-structure) dd-type))
+
+  (let* ((dd (make-dd-with-alternate-metaclass
+             :class-name class-name
+             :slot-names slot-names
+             :superclass-name superclass-name
+             :metaclass-name metaclass-name
+             :metaclass-constructor metaclass-constructor
+             :dd-type dd-type))
+        (dd-slots (dd-slots dd))
+        (dd-length (1+ (length slot-names)))
+        (object-gensym (gensym "OBJECT"))
+        (new-value-gensym (gensym "NEW-VALUE-"))
+        (delayed-layout-form `(%delayed-get-compiler-layout ,class-name)))
+    (multiple-value-bind (raw-maker-form raw-reffer-operator)
+       (ecase dd-type
+         (structure
+          (values `(let ((,object-gensym (%make-instance ,dd-length)))
+                     (setf (%instance-layout ,object-gensym)
+                           ,delayed-layout-form)
+                     ,object-gensym)
+                  '%instance-ref))
+         (funcallable-structure
+          (values `(%make-funcallable-instance ,dd-length
+                                               ,delayed-layout-form)
+                  '%funcallable-instance-info)))
+      `(progn
+
+        (eval-when (:compile-toplevel :load-toplevel :execute)
+          (%compiler-set-up-layout ',dd))
+
+        ;; slot readers and writers
+        (declaim (inline ,@(mapcar #'dsd-accessor-name dd-slots)))
+        ,@(mapcar (lambda (dsd)
+                    `(defun ,(dsd-accessor-name dsd) (,object-gensym)
+                       ,@(when runtime-type-checks-p
+                           `((declare (type ,class-name ,object-gensym))))
+                       (,raw-reffer-operator ,object-gensym
+                                             ,(dsd-index dsd))))
+                  dd-slots)
+        (declaim (inline ,@(mapcar (lambda (dsd)
+                                     `(setf ,(dsd-accessor-name dsd)))
+                                   dd-slots)))
+        ,@(mapcar (lambda (dsd)
+                    `(defun (setf ,(dsd-accessor-name dsd)) (,new-value-gensym
+                                                             ,object-gensym)
+                       ,@(when runtime-type-checks-p
+                           `((declare (type ,class-name ,object-gensym))))
+                       (setf (,raw-reffer-operator ,object-gensym
+                                                   ,(dsd-index dsd))
+                             ,new-value-gensym)))
+                  dd-slots)
+
+        ;; constructor
+        (defun ,boa-constructor ,slot-names
+          (let ((,object-gensym ,raw-maker-form))
+            ,@(mapcar (lambda (slot-name)
+                        (let ((dsd (find (symbol-name slot-name) dd-slots
+                                         :key (lambda (x)
+                                                (symbol-name (dsd-name x)))
+                                         :test #'string=)))
+                          ;; KLUDGE: bug 117 bogowarning.  Neither
+                          ;; DECLAREing the type nor TRULY-THE cut
+                          ;; the mustard -- it still gives warnings.
+                          (enforce-type dsd defstruct-slot-description)
+                          `(setf (,(dsd-accessor-name dsd) ,object-gensym)
+                                 ,slot-name)))
+                      slot-names)
+            ,object-gensym))
+
+        ;; predicate
+        ,@(when predicate
+            ;; Just delegate to the compiler's type optimization
+            ;; code, which knows how to generate inline type tests
+            ;; for the whole CMU CL INSTANCE menagerie.
+            `(defun ,predicate (,object-gensym)
+               (typep ,object-gensym ',class-name)))))))
+\f
 ;;;; finalizing bootstrapping
 
-;;; early structure placeholder definitions: Set up layout and class
-;;; data for structures which are needed early.
+;;; Set up DD and LAYOUT for STRUCTURE-OBJECT class itself.
+;;;
+;;; Ordinary structure classes effectively :INCLUDE STRUCTURE-OBJECT
+;;; when they have no explicit :INCLUDEs, so (1) it needs to be set up
+;;; before we can define ordinary structure classes, and (2) it's
+;;; special enough (and simple enough) that we just build it by hand
+;;; instead of trying to generalize the ordinary DEFSTRUCT code.
+(defun !set-up-structure-object-class ()
+  (let ((dd (make-defstruct-description 'structure-object)))
+    (setf
+     ;; Note: This has an ALTERNATE-METACLASS only because of blind
+     ;; clueless imitation of the CMU CL code -- dunno if or why it's
+     ;; needed. -- WHN 
+     (dd-alternate-metaclass dd) '(instance)
+     (dd-slots dd) nil
+     (dd-length dd) 1
+     (dd-type dd) 'structure)
+    (%compiler-set-up-layout dd)))
+(!set-up-structure-object-class)
+
+;;; early structure predeclarations: Set up DD and LAYOUT for ordinary
+;;; (non-ALTERNATE-METACLASS) structures which are needed early.
 (dolist (args
         '#.(sb-cold:read-from-file
             "src/code/early-defstruct-args.lisp-expr"))