x86-64: put vector widetag and maybe length w/byte-sized store
[sbcl.git] / tests / package-locks.impure.lisp
blob6daebe58b84d4a7dd18462022eec0e2149b83091
1 ;;;; package lock tests with side effects
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; While most of SBCL is derived from the CMU CL system, the test
7 ;;;; files (like this one) were written from scratch after the fork
8 ;;;; from CMU CL.
9 ;;;;
10 ;;;; This software is in the public domain and is provided with
11 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
12 ;;;; more information.
14 (in-package :cl-user)
16 (load "assertoid.lisp")
17 (load "compiler-test-util.lisp")
18 (use-package "ASSERTOID")
20 ;;;; Our little labrats and a few utilities
22 (defpackage :test-used)
24 (defpackage :test-unused)
26 (defpackage :test-aux (:export #:noslot #:noslot2))
28 (defpackage :test
29 (:use :test-used)
30 (:shadow #:shadowed)
31 (:export
32 #:*special*
33 #:car
34 #:cdr
35 #:class
36 #:constant
37 #:external
38 #:function
39 #:macro
40 #:noclass
41 #:noclass-slot
42 #:nocondition
43 #:nocondition-slot
44 #:nospecial
45 #:nostruct
46 #:nostruct2
47 #:nostruct-slot
48 #:nosymbol-macro
49 #:notype
50 #:num
51 #:numfun
52 #:shadowed
53 #:symbol-macro
54 #:unused
57 (defvar *uninterned* "UNINTERNED")
58 (defvar *interned* "INTERNED")
60 (defun maybe-unintern (name package)
61 (let ((s (find-symbol name package)))
62 (when s
63 (unintern s package))))
65 (defun set-test-locks (lock-p)
66 (dolist (p '(:test :test-aux :test-delete))
67 (when (find-package p)
68 (if lock-p
69 (sb-ext:lock-package p)
70 (sb-ext:unlock-package p)))))
72 (defun reset-test (lock)
73 "Reset TEST package to a known state, ensure that TEST-DELETE exists."
74 (unless (find-package :test-delete)
75 (make-package :test-delete))
76 (sb-ext:with-unlocked-packages (:test :test-aux)
77 (dolist (s '(test:nosymbol-macro
78 test:noclass test:nostruct test:nostruct2 test:nocondition))
79 (makunbound s)
80 (unintern s)
81 (intern (symbol-name s) :test))
82 (rename-package (find-package :test) :test)
83 (unexport (intern "INTERNAL" :test) :test)
84 (intern *interned* :test)
85 (use-package :test-used :test)
86 (export 'test::external :test)
87 (unuse-package :test-unused :test)
88 (defclass test:class () ())
89 (defun test:function () 'test:function)
90 (defmacro test:macro () ''test:macro)
91 (defparameter test:*special* 'test:*special*)
92 (defconstant test:constant 'test:constant)
93 (intern "UNUSED" :test)
94 (dolist (s '(test:nocondition-slot test:noclass-slot test:nostruct-slot
95 test-aux:noslot test-aux:noslot2))
96 (fmakunbound s))
97 (ignore-errors (progn
98 (fmakunbound 'test:unused)
99 (makunbound 'test:unused)))
100 (maybe-unintern *uninterned* :test)
101 (maybe-unintern "NOT-FROM-TEST" :test)
102 (defconstant test:num 0)
103 (define-symbol-macro test:symbol-macro "SYMBOL-MACRO")
104 (defun test:numfun (n) n)
105 (defun test:car (cons) (cl:car cons))
106 (defun (setf test:cdr) (obj cons) (setf (cl:cdr cons) obj))
107 (assert (not (find-symbol *uninterned* :test))))
108 (set-test-locks lock))
110 (defun tmp-fmakunbound (x)
111 "FMAKUNDBOUND x, then restore the original binding."
112 (let ((f (fdefinition x)))
113 (fmakunbound x)
114 (ignore-errors (setf (fdefinition x) f))))
116 (defmacro with-error-info ((string &rest args) &body forms)
117 `(handler-bind ((error (lambda (e)
118 (declare (ignorable e))
119 (format t ,string ,@args)
120 (finish-output))))
121 (progn ,@forms)))
123 ;;;; Test cases
125 ;;; A collection of forms that are legal both with and without package
126 ;;; locks.
127 (defvar *legal-forms*
128 '(;; package alterations that don't actually mutate the package
129 (intern *interned* :test)
130 (import 'test:unused :test)
131 (shadowing-import 'test:shadowed :test)
132 (export 'test:unused :test)
133 (unexport 'test::internal :test)
134 (let ((p (find-package :test)))
135 (rename-package p :test))
136 (use-package :test-used :test)
137 (unuse-package :test-unused :test)
138 (shadow "SHADOWED" :test)
139 (let ((s (with-unlocked-packages (:test)
140 (let ((s (intern *uninterned* :test)))
141 (unintern s :test)
142 s))))
143 (unintern s :test))
145 ;; binding and altering value
146 (let ((test:function 123))
147 (assert (eql test:function 123)))
148 (let ((test:*special* :foo))
149 (assert (eql test:*special* :foo)))
150 (progn
151 (setf test:*special* :quux)
152 (assert (eql test:*special* :quux)))
153 (let ((test:unused :zot))
154 (assert (eql test:unused :zot)))
156 ;; symbol-macrolet
157 (symbol-macrolet ((test:function :sym-ok))
158 (assert (eql test:function :sym-ok)))
159 (symbol-macrolet ((test:unused :sym-ok2))
160 (assert (eql test:unused :sym-ok2)))
162 ;; binding as a function
163 (flet ((test:*special* () :yes))
164 (assert (eql (test:*special*) :yes)))
165 (flet ((test:unused () :yes!))
166 (assert (eql (test:unused) :yes!)))
167 (labels ((test:*special* () :yes))
168 (assert (eql (test:*special*) :yes)))
169 (labels ((test:unused () :yes!))
170 (assert (eql (test:unused) :yes!)))
172 ;; binding as a macro
173 (macrolet ((test:*special* () :ok))
174 (assert (eql (test:*special*) :ok)))
177 ;;; A collection of forms that cause runtime package lock violations
178 ;;; on TEST, and will also signal an error on LOAD even if first
179 ;;; compiled with COMPILE-FILE with TEST unlocked.
180 (defvar *illegal-runtime-forms*
181 '(;; package alterations
182 (intern *uninterned* :test)
183 (import 'not-from-test :test)
184 (export 'test::internal :test)
185 (unexport 'test:external :test)
186 (shadowing-import 'not-from-test :test)
187 (let ((p (find-package :test)))
188 (rename-package p :test '(:test-nick)))
189 (use-package :test-unused :test)
190 (unuse-package :test-used :test)
191 (shadow 'not-from-test :test)
192 (unintern (or (find-symbol *interned* :test) (error "bugo")) :test)
193 (delete-package :test-delete)
195 ;; redefining or undefining as a function
196 (defun test:function () 'foo)
197 (setf (fdefinition 'test:function) (lambda () 'bar))
198 (setf (symbol-function 'test:function) (lambda () 'quux))
199 (tmp-fmakunbound 'test:function)
201 ;; defining or undefining as a macro or compiler macro
202 (defmacro test:unused () ''foo)
203 (setf (macro-function 'test:unused) (constantly 'foo))
204 (define-compiler-macro test:unused (&whole form arg)
205 (declare (ignore arg))
206 form)
207 (setf (compiler-macro-function 'test:unused) (constantly 'foo))
209 ;; type-specifier or structure
210 (progn
211 (defstruct test:nostruct test:nostruct-slot)
212 ;; test creation as well, since the structure-class won't be
213 ;; finalized before that
214 (make-nostruct :nostruct-slot :foo))
215 (defclass test:noclass ()
216 ((slot :initform nil :accessor test:noclass-slot)))
217 (deftype test:notype () 'string)
218 (define-condition test:nocondition (error)
219 ((slot :initform nil :accessor test:nocondition-slot)))
221 ;; symbol-macro
222 (define-symbol-macro test:nosymbol-macro 'foo)
224 ;; declaration proclamation
225 (proclaim '(declaration test:unused))
227 ;; declare special
228 (declaim (special test:nospecial))
229 (proclaim '(special test:nospecial))
231 ;; declare type
232 (declaim (type fixnum test:num))
233 (proclaim '(type fixnum test:num))
235 ;; declare ftype
236 (declaim (ftype (function (fixnum) fixnum) test:numfun))
237 (proclaim '(ftype (function (fixnum) fixnum) test:numfun))
239 ;; setf expanders
240 (defsetf test:car rplaca) ; strictly speaking wrong, but ok as a test
241 (defsetf test:car (cons) (new-car)
242 `(setf (car ,cons) ,new-car))
243 (define-setf-expander test:car (place)
244 (multiple-value-bind (dummies vals newval setter getter)
245 (get-setf-expansion place)
246 (declare (ignore newval setter))
247 (let ((store (gensym)))
248 (values dummies
249 vals
250 `(,store)
251 `(progn (rplaca ,getter ,store) ,store)
252 `(car ,getter)))))
254 ;; setf function names
255 (defun (setf test:function) (obj)
256 obj)
257 (tmp-fmakunbound '(setf test:cdr))
259 ;; define-method-combination
260 (define-method-combination test:unused)
262 ;; setf find-class
263 (setf (find-class 'test:class) (find-class 'standard-class))
266 ;;; Forms that cause violations on two distinct packages.
267 (defvar *illegal-double-forms*
268 '((defclass test:noclass () ((x :accessor test-aux:noslot)))
269 (define-condition test:nocondition (error)
270 ((x :accessor test-aux:noslot2)))))
272 ;;; A collection of forms that cause compile-time package lock
273 ;;; violations on TEST, and will not signal an error on LOAD if first
274 ;;; compiled by COMPILE-FILE with test unlocked. CAR is the affected
275 ;;; symbol, CDR the form affecting it.
276 (defvar *illegal-lexical-forms-alist*
277 '(;; binding
279 ;; binding as a function
280 (test:function . (flet ((test:function () :shite))
281 (test:function)))
282 (test:function . (labels ((test:function () :shite))
283 (test:function)))
284 (test:macro . (flet ((test:macro () :shite))
285 (test:macro)))
286 (test:macro . (labels ((test:macro () :shite))
287 (test:macro)))
289 ;; macrolet
290 (test:function . (macrolet ((test:function () :yuk))
291 (test:function)))
292 (test:macro . (macrolet ((test:macro () :yuk))
293 (test:macro)))
295 ;; setf name
296 (test:function . (flet (((setf test:function) (obj)
297 obj))
298 (setf (test:function) 1)))
300 ;; ftype
302 ;; The legacy interpreter doesn't do anything with ftype declarations
303 #+(or :sb-fasteval (not :interpreter))
304 (test:function . (locally
305 (declare (ftype function test:function))
306 (cons t t)))
308 ;; type
310 ;; Nor with type declarations
311 #+(or :sb-fasteval (not :interpreter))
312 (test:num . (locally
313 (declare (type fixnum test:num))
314 (cons t t)))
316 ;; special
317 (test:nospecial . (locally
318 (declare (special test:nospecial))
319 (cons t t)))
321 ;; declare ftype
322 #+(or :sb-fasteval (not :interpreter))
323 (test:numfun . (locally
324 (declare (ftype (function (fixnum) fixnum) test:numfun))
325 (cons t t)))))
327 (defvar *illegal-lexical-forms*
328 (mapcar #'cdr *illegal-lexical-forms-alist*))
330 (defvar *illegal-forms* (append *illegal-runtime-forms*
331 *illegal-lexical-forms*
332 *illegal-double-forms*))
334 ;;;; Running the tests
336 ;;; Unlocked. No errors nowhere.
337 (reset-test nil)
339 (with-test (:name :unlocked-package)
340 (dolist (form (append *legal-forms* *illegal-forms*))
341 (with-error-info ("Unlocked form: ~S~%" form)
342 (eval form))))
344 ;;; Locked. Errors for all illegal forms, none for legal.
345 (reset-test t)
347 (with-test (:name :locked-package/legal-forms)
348 (dolist (form *legal-forms*)
349 (with-error-info ("locked legal form: ~S~%" form)
350 (eval form))))
352 (with-test (:name :locked-package/illegal-runtime-forms)
353 (dolist (form (append *illegal-runtime-forms* *illegal-double-forms*))
354 (with-error-info ("locked illegal runtime form: ~S~%" form)
355 (let ((fun (compile nil `(lambda () ,form))))
356 (assert-error (funcall fun) sb-ext:package-lock-violation))
357 (assert-error (eval form) sb-ext:package-lock-violation))))
359 (with-test (:name :locked-package/illegal-lexical-forms)
360 (dolist (pair *illegal-lexical-forms-alist*)
361 (let ((form (cdr pair)))
362 (with-error-info ("compile locked illegal lexical form: ~S~%" form)
363 (let ((fun (compile nil `(lambda () ,form))))
364 (assert-error (funcall fun) program-error))
365 (assert-error (eval form)
366 ;; Let's not be pedantic here.
367 ;; PACKAGE-LOCK-VIOLATION is right,
368 ;; because the distinction between lexical analysis
369 ;; and running is artificial for interpreted code.
370 (or sb-ext:package-lock-violation program-error))))))
372 ;;; Locked, WITHOUT-PACKAGE-LOCKS
373 (reset-test t)
375 (dolist (form *illegal-runtime-forms*)
376 (with-error-info ("without-package-locks illegal runtime form: ~S~%" form)
377 (funcall (compile nil `(lambda () (without-package-locks ,form))))))
379 (dolist (form *illegal-lexical-forms*)
380 (let ((fun (without-package-locks (compile nil `(lambda () ,form)))))
381 (funcall fun))
382 (without-package-locks (eval form)))
384 ;;; Locked, DISABLE-PACKAGE-LOCKS
385 (reset-test t)
387 (dolist (pair *illegal-lexical-forms-alist*)
388 (destructuring-bind (sym . form) pair
389 (with-error-info ("disable-package-locks on illegal form: ~S~%"
390 form)
391 (funcall (compile nil `(lambda ()
392 (declare (disable-package-locks ,sym))
393 ,form)))
394 (eval `(locally
395 (declare (disable-package-locks ,sym))
396 ,form)))))
398 ;;; Locked, one error per "lexically apparent violated package", also
399 ;;; test restarts.
400 (reset-test t)
402 (with-test (:name :illegal-runtime-forms)
403 (dolist (form *illegal-runtime-forms*)
404 (with-error-info ("one error per form ~S~%" form)
405 (let ((errorp nil))
406 (handler-bind ((package-lock-violation (lambda (e)
407 (when errorp
408 (error "multiple errors ~%~a~% and ~%~a"
409 errorp e))
410 (setf errorp e)
411 (continue e))))
412 (eval form))))))
414 (dolist (form *illegal-double-forms*)
415 (with-error-info ("two errors per form: ~S~%" form)
416 (let ((error-count 0))
417 ;; check that we don't get multiple errors from a single form
418 (handler-bind ((package-lock-violation (lambda (x)
419 (declare (ignorable x))
420 (incf error-count)
421 (continue x))))
422 (eval form)
423 (unless (= 2 error-count)
424 (error "expected 2 errors per form, got ~A for ~A"
425 error-count form))))))
427 ;;; COMPILE-FILE when unlocked, LOAD locked -- *illegal-runtime-forms* only
429 ;;; This is not part of the interface, but it is the behaviour we want
430 (let* ((tmp "package-locks.tmp.lisp")
431 (fasl (compile-file-pathname tmp)))
432 (dolist (form *illegal-runtime-forms*)
433 (unwind-protect
434 (with-simple-restart (next "~S failed, continue with next test" form)
435 (reset-test nil)
436 (with-open-file (f tmp :direction :output)
437 (prin1 form f))
438 (multiple-value-bind (file warnings failure-p) (compile-file tmp)
439 (declare (ignore file warnings failure-p))
440 (set-test-locks t)
441 (assert-error (load fasl)
442 sb-ext:package-lock-violation)))
443 (when (probe-file tmp)
444 (delete-file tmp))
445 (when (probe-file fasl)
446 (delete-file fasl)))))
448 ;;;; Tests for enable-package-locks declarations
449 (reset-test t)
451 (dolist (pair *illegal-lexical-forms-alist*)
452 (destructuring-bind (sym . form) pair
453 (let ((fun (compile nil `(lambda ()
454 (declare (disable-package-locks ,sym))
455 ,form
456 (locally (declare (enable-package-locks ,sym))
457 ,form)))))
458 (assert-error (funcall fun) program-error))
459 (assert-error
460 (eval `(locally (declare (disable-package-locks ,sym))
461 ,form
462 (locally (declare (enable-package-locks ,sym))
463 ,form)))
464 (or sb-ext:package-lock-violation program-error))))
466 ;;;; See that trace on functions in locked packages doesn't break
467 ;;;; anything.
468 (assert (trace test:function :break t))
469 (untrace test:function)
471 ;;;; No bogus violations from defclass with accessors in a locked
472 ;;;; package. Reported by by Francois-Rene Rideau.
473 (assert (package-locked-p :sb-gray))
474 (multiple-value-bind (fun compile-errors)
475 (ignore-errors
476 (compile
478 '(lambda ()
479 (defclass fare-class ()
480 ((line-column :initform 0 :reader sb-gray:stream-line-column))))))
481 (assert (not compile-errors))
482 (assert fun)
483 (multiple-value-bind (class run-errors) (ignore-errors (funcall fun))
484 (assert (not run-errors))
485 (assert (eq class (find-class 'fare-class)))))
487 ;;;; No bogus violations from DECLARE's done by PCL behind the
488 ;;;; scenes. Reported by David Wragg on sbcl-help.
489 (reset-test t)
491 (defmethod pcl-type-declaration-method-bug ((test:*special* stream))
492 test:*special*)
493 (assert (eq *terminal-io* (pcl-type-declaration-method-bug *terminal-io*)))
495 ;; Interpreters don't walk into a method body until it's executed.
496 #-:interpreter
497 (assert-error
498 (eval
499 '(defmethod pcl-type-declaration-method-bug ((test:*special* stream))
500 (declare (type stream test:*special*))
501 test:*special*))
502 program-error)
504 ;;; Bogus package lock violations from LOOP
506 (assert (equal (loop :for *print-base* :from 2 :to 3 :collect *print-base*)
507 '(2 3)))
509 ;;; Package lock for DEFMACRO -> DEFUN and vice-versa.
510 (reset-test t)
511 (with-test (:name :bug-576637)
512 (assert-error (eval `(defun test:macro (x) x))
513 sb-ext:package-lock-violation)
514 (assert (eq 'test:macro (eval `(test:macro))))
515 (assert-error (eval `(defmacro test:function (x) x))
516 sb-ext:package-lock-violation)
517 (assert (eq 'test:function (eval `(test:function)))))
519 (defpackage :macro-killing-macro-1
520 (:use :cl)
521 (:lock t)
522 (:export #:to-die-for))
524 (defpackage :macro-killing-macro-2
525 (:use :cl :macro-killing-macro-1))
527 (ctu:file-compile
528 `((in-package :macro-killing-macro-1)
529 (defmacro to-die-for ()
530 :original))
531 :load t)
533 (with-test (:name :defmacro-killing-macro)
534 (ignore-errors
535 (ctu:file-compile
536 `((in-package :macro-killing-macro-2)
537 (defmacro to-die-for ()
538 :replacement))))
539 (assert (eq :original (macroexpand '(macro-killing-macro-1:to-die-for)))))
541 (with-test (:name :setf-macro-function-killing-macro)
542 (ignore-errors
543 (ctu:file-compile
544 `((in-package :macro-killing-macro-2)
545 (eval-when (:compile-toplevel)
546 (setf (macro-function 'to-die-for) (constantly :replacement2))))))
547 (assert (eq :original (macroexpand '(macro-killing-macro-1:to-die-for)))))
549 (with-test (:name :compile-time-defun-package-locked)
550 ;; Make sure compile-time side-effects of DEFUN are protected against.
551 (let ((inline-lambda (function-lambda-expression #'fill-pointer)))
552 ;; Make sure it's actually inlined...
553 (assert inline-lambda)
554 (assert (eq :ok
555 (handler-case
556 (ctu:file-compile `((defun fill-pointer (x) x)))
557 (sb-ext:symbol-package-locked-error (e)
558 (when (eq 'fill-pointer
559 (sb-ext:package-locked-error-symbol e))
560 :ok)))))
561 (assert (equal inline-lambda
562 (function-lambda-expression #'fill-pointer)))))
564 (with-test (:name :compile-time-defclass-package-locked)
565 ;; Compiling (DEFCLASS FTYPE ...) used to break SBCL, but the package
566 ;; locks didn't kick in till later.
567 (assert (eq :ok
568 (handler-case
569 (ctu:file-compile `((defclass ftype () ())))
570 (sb-ext:symbol-package-locked-error (e)
571 (when (eq 'ftype (sb-ext:package-locked-error-symbol e))
572 :ok)))))
573 ;; Check for accessor violations as well.
574 (assert (eq :ok
575 (handler-case
576 (ctu:file-compile `((defclass foo () ((ftype :reader ftype)))))
577 (sb-ext:symbol-package-locked-error (e)
578 (when (eq 'ftype (sb-ext:package-locked-error-symbol e))
579 :ok))))))
581 (with-test (:name :assert-symbol-home-package-unlocked)
582 (assert-error ; TODO use assert-signals
583 (sb-impl::assert-symbol-home-package-unlocked
584 'cl:cons "trying to foo ~S")
585 symbol-package-locked-error)
586 (assert-error
587 (sb-impl::assert-symbol-home-package-unlocked
588 'cl:cons "trying to ~*~S ~2:*~A~* as a ~S"
589 :foo :bar)
590 symbol-package-locked-error))
592 (with-test (:name :defcostant-locks)
593 (assert-error (defconstant test:constant 100)
594 symbol-package-locked-error))
596 (with-test (:name :defstruct-compile-time-locks)
597 (assert-error (ctu:file-compile
598 `((defstruct test:nostruct)))
599 symbol-package-locked-error)
600 (assert-error (ctu:file-compile
601 `((defstruct (a-struct-test.1
602 (:conc-name))
603 test:nostruct)))
604 symbol-package-locked-error)
605 (assert-error (ctu:file-compile
606 `((defstruct (a-struct-test.2
607 (:predicate test:nostruct)))))
608 symbol-package-locked-error)
609 (assert-error (ctu:file-compile
610 `((defstruct (a-struct-test.3
611 (:copier test:nostruct)))))
612 symbol-package-locked-error)
613 (assert-error (ctu:file-compile
614 `((defstruct (a-struct-test.4
615 (:constructor test:nostruct)))))
616 symbol-package-locked-error))