X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=tests%2Fcompiler.impure.lisp;h=c0f5b0a2c1aec994bd9b6fbbe4ed12c4daca396f;hb=cf49f2d086069a9c1b57f501df9a6a0bd3a34c3c;hp=33936a536dab2d4183ad55ace6828723b9166839;hpb=d4fb62259d04a4513d6ae20ca9f2487c4dfe1c1a;p=sbcl.git diff --git a/tests/compiler.impure.lisp b/tests/compiler.impure.lisp index 33936a5..c0f5b0a 100644 --- a/tests/compiler.impure.lisp +++ b/tests/compiler.impure.lisp @@ -10,12 +10,20 @@ ;;;; While most of SBCL is derived from the CMU CL system, the test ;;;; files (like this one) were written from scratch after the fork ;;;; from CMU CL. -;;;; +;;;; ;;;; This software is in the public domain and is provided with ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. +(in-package :cl-user) + +(when (eq sb-ext:*evaluator-mode* :interpret) + (sb-ext:exit :code 104)) + +(load "test-util.lisp") +(load "compiler-test-util.lisp") (load "assertoid.lisp") +(use-package "TEST-UTIL") (use-package "ASSERTOID") ;;; Old CMU CL code assumed that the names of "keyword" arguments are @@ -46,9 +54,9 @@ (let (num x) (flet ((digs () (setq num index)) - (z () - (let () - (setq x nil)))) + (z () + (let () + (setq x nil)))) (when (and (digs) (digs)) x)))) ;;; Bug 132: The compiler used to fail to compile INTEGER-valued CATCH @@ -68,8 +76,8 @@ (flet ((wufn () (glorp table1 4.9))) (gleep *uustk* #'wufn "#1" (list))) (if (eql (lo foomax 3.2)) - (values) - (error "not ~S" '(eql (lo foomax 3.2)))) + (values) + (error "not ~S" '(eql (lo foomax 3.2)))) (values))) ;;; A simpler test case for bug 150: The compiler died with the ;;; same type error when trying to compile this. @@ -84,9 +92,9 @@ (defun bug147 (string ind) (flet ((digs () (let (old-index) - (if (and (< ind ind) - (typep (char string ind) '(member #\1))) - nil)))))) + (if (and (< ind ind) + (typep (char string ind) '(member #\1))) + nil)))))) ;;; bug reported and fixed by Matthias Hoelzl sbcl-devel 2002-05-13 (defmacro foo-2002-05-13 () ''x) @@ -120,24 +128,24 @@ (defstruct something-known-to-be-a-struct x y) (multiple-value-bind (fun warnings-p failure-p) (compile nil - '(lambda () - (labels ((a1 (a2 a3) - (cond (t (a4 a2 a3)))) - (a4 (a2 a3 a5 a6) - (declare (type (or simple-vector null) a5 a6)) - (something-known-to-be-a-struct-x a5)) - (a8 (a2 a3) - (a9 #'a1 a10 a2 a3)) - (a11 (a2 a3) - (cond ((and (funcall a12 a2) - (funcall a12 a3)) - (funcall a13 a2 a3)) - (t - (when a14 - (let ((a15 (a1 a2 a3))) - )) - a16)))) - (values #'a17 #'a11)))) + '(lambda () + (labels ((a1 (a2 a3) + (cond (t (a4 a2 a3)))) + (a4 (a2 a3 a5 a6) + (declare (type (or simple-vector null) a5 a6)) + (something-known-to-be-a-struct-x a5)) + (a8 (a2 a3) + (a9 #'a1 a10 a2 a3)) + (a11 (a2 a3) + (cond ((and (funcall a12 a2) + (funcall a12 a3)) + (funcall a13 a2 a3)) + (t + (when a14 + (let ((a15 (a1 a2 a3))) + )) + a16)))) + (values #'a17 #'a11)))) ;; Python sees the structure accessor on the known-not-to-be-a-struct ;; A5 value and is very, very disappointed in you. (But it doesn't ;; signal BUG any more.) @@ -149,10 +157,10 @@ ;;; spotted and fixed by Raymond Toy for CMUCL) (defun logand-sparc-bogons (a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10) (declare (type (unsigned-byte 32) a0) - (type (signed-byte 32) a1 a2 a3 a4 a5 a6 a7 a8 a9 a10) - ;; to ensure that the call is a candidate for - ;; transformation - (optimize (speed 3) (safety 0) (compilation-speed 0) (debug 0))) + (type (signed-byte 32) a1 a2 a3 a4 a5 a6 a7 a8 a9 a10) + ;; to ensure that the call is a candidate for + ;; transformation + (optimize (speed 3) (safety 0) (compilation-speed 0) (debug 0))) (values ;; the call that fails compilation (logand a0 a10) @@ -165,7 +173,7 @@ ;;; except that there was no non-VOP definition of DATA-VECTOR-REF, so ;;; it would fail. (defun bug192 () - (funcall + (funcall (LAMBDA (TEXT I L ) (LABELS ((G908 (I) (LET ((INDEX @@ -208,65 +216,65 @@ (labels ((alpha-equal-bound-term-lists (listx listy) (or (and (null listx) (null listy)) - (and listx listy - (let ((bindings-x (bindings-of-bound-term (car listx))) - (bindings-y (bindings-of-bound-term (car listy)))) - (if (and (null bindings-x) (null bindings-y)) - (alpha-equal-terms (term-of-bound-term (car listx)) - (term-of-bound-term (car listy))) - (and (= (length bindings-x) (length bindings-y)) - (prog2 - (enter-binding-pairs (bindings-of-bound-term (car listx)) - (bindings-of-bound-term (car listy))) - (alpha-equal-terms (term-of-bound-term (car listx)) - (term-of-bound-term (car listy))) - (exit-binding-pairs (bindings-of-bound-term (car listx)) - (bindings-of-bound-term (car listy))))))) - (alpha-equal-bound-term-lists (cdr listx) (cdr listy))))) + (and listx listy + (let ((bindings-x (bindings-of-bound-term (car listx))) + (bindings-y (bindings-of-bound-term (car listy)))) + (if (and (null bindings-x) (null bindings-y)) + (alpha-equal-terms (term-of-bound-term (car listx)) + (term-of-bound-term (car listy))) + (and (= (length bindings-x) (length bindings-y)) + (prog2 + (enter-binding-pairs (bindings-of-bound-term (car listx)) + (bindings-of-bound-term (car listy))) + (alpha-equal-terms (term-of-bound-term (car listx)) + (term-of-bound-term (car listy))) + (exit-binding-pairs (bindings-of-bound-term (car listx)) + (bindings-of-bound-term (car listy))))))) + (alpha-equal-bound-term-lists (cdr listx) (cdr listy))))) (alpha-equal-terms (termx termy) (if (and (variable-p termx) - (variable-p termy)) - (equal-bindings (id-of-variable-term termx) - (id-of-variable-term termy)) - (and (equal-operators-p (operator-of-term termx) (operator-of-term termy)) - (alpha-equal-bound-term-lists (bound-terms-of-term termx) - (bound-terms-of-term termy)))))) + (variable-p termy)) + (equal-bindings (id-of-variable-term termx) + (id-of-variable-term termy)) + (and (equal-operators-p (operator-of-term termx) (operator-of-term termy)) + (alpha-equal-bound-term-lists (bound-terms-of-term termx) + (bound-terms-of-term termy)))))) (or (eq termx termy) - (and termx termy - (with-variable-invocation (alpha-equal-terms termx termy)))))) + (and termx termy + (with-variable-invocation (alpha-equal-terms termx termy)))))) (defun bug65-2 () ; from Bob Rogers cmucl-imp 1999-07-28 ;; Given an FSSP alignment file named by the argument . . . (labels ((get-fssp-char () - (get-fssp-char)) - (read-fssp-char () - (get-fssp-char))) + (get-fssp-char)) + (read-fssp-char () + (get-fssp-char))) ;; Stub body, enough to tickle the bug. (list (read-fssp-char) - (read-fssp-char)))) + (read-fssp-char)))) (defun bug70 ; from David Young cmucl-help 30 Nov 2000 (item sequence &key (test #'eql)) (labels ((find-item (obj seq test &optional (val nil)) - (let ((item (first seq))) - (cond ((null seq) - (values nil nil)) - ((funcall test obj item) - (values val seq)) - (t - (find-item obj - (rest seq) - test - (nconc val `(,item)))))))) + (let ((item (first seq))) + (cond ((null seq) + (values nil nil)) + ((funcall test obj item) + (values val seq)) + (t + (find-item obj + (rest seq) + test + (nconc val `(,item)))))))) (find-item item sequence test))) (defun bug109 () ; originally from CMU CL bugs collection, reported as ; SBCL bug by MNA 2001-06-25 - (labels + (labels ((eff (&key trouble) - (eff) - ;; nil - ;; Uncomment and it works - )) + (eff) + ;; nil + ;; Uncomment and it works + )) (eff))) ;;; bug 192a, fixed by APD "more strict type checking" patch @@ -308,14 +316,19 @@ ;;; BUG 48a. and b. (symbol-macrolet handling), fixed by Eric Marsden ;;; and Raymond Toy for CMUCL, fix ported for sbcl-0.7.6.18. (multiple-value-bind (function warnings-p failure-p) - (compile nil '(lambda () (symbol-macrolet ((t nil)) t))) + (compile nil '(lambda () + ;; not interested in the package lock violation here + (declare (sb-ext:disable-package-locks t)) + (symbol-macrolet ((t nil)) t))) (assert failure-p) (assert (raises-error? (funcall function) program-error))) (multiple-value-bind (function warnings-p failure-p) (compile nil - '(lambda () - (symbol-macrolet ((*standard-input* nil)) - *standard-input*))) + '(lambda () + ;; not interested in the package lock violation here + (declare (sb-ext:disable-package-locks *standard-input*)) + (symbol-macrolet ((*standard-input* nil)) + *standard-input*))) (assert failure-p) (assert (raises-error? (funcall function) program-error))) (multiple-value-bind (function warnings-p failure-p) @@ -337,7 +350,7 @@ (declare (optimize (speed 3) (safety 1) (debug 1))) (if x t (if y t (dont-constrain-if-too-much x y)))) -(assert (null (dont-constrain-if-too-much-aux nil nil))) +(assert (null (dont-constrain-if-too-much-aux nil nil))) ;;; TYPE-ERROR confusion ca. sbcl-0.7.7.24, reported and fixed by ;;; APD sbcl-devel 2002-09-14 @@ -580,7 +593,7 @@ ;;; bug 172: macro lambda lists were too permissive until 0.7.9.28 ;;; (fix provided by Matthew Danish) on sbcl-devel (assert (null (ignore-errors - (defmacro bug172 (&rest rest foo) `(list ,rest ,foo))))) + (defmacro bug172 (&rest rest foo) `(list ,rest ,foo))))) ;;; embedded THEs (defun check-embedded-thes (policy1 policy2 x y) @@ -608,7 +621,7 @@ (assert (equal (check-embedded-thes 3 0 2 :a) '(2 :a))) (assert (typep (check-embedded-thes 3 0 4 2.5f0) 'type-error)) -(assert (equal (check-embedded-thes 1 0 4 :b) '(4 :b))) +(assert (equal (check-embedded-thes 1 0 3 :b) '(3 :b))) (assert (typep (check-embedded-thes 1 0 1.0 2.5f0) 'type-error)) @@ -627,9 +640,9 @@ (defun to-be-inlined (y) (frob y))) (assert (= (call-inlined 3) - ;; we should have inlined the previous definition, so the - ;; new one won't show up yet. - 4)) + ;; we should have inlined the previous definition, so the + ;; new one won't show up yet. + 4)) (defun call-inlined (z) (to-be-inlined z)) (assert (= (call-inlined 3) 6)) @@ -650,7 +663,7 @@ (defun bug219-a-aux () (bug219-a 2)) (assert (= (bug219-a-aux) - (if *bug219-a-expanded-p* 4 3))) + (if *bug219-a-expanded-p* 4 3))) (defvar *bug219-a-temp* 3) (assert (= (bug219-a *bug219-a-temp*) 4)) @@ -670,7 +683,7 @@ (defun bug219-b (x) x) (assert (= (bug219-b-aux2 1) - (if *bug219-b-expanded-p* 3 1))) + (if *bug219-b-expanded-p* 3 1))) ;;; bug 224: failure in unreachable code deletion (defmacro do-optimizations (&body body) @@ -742,11 +755,11 @@ ;;; WHN's original report (defun debug-return-catch-break1 () (with-open-file (s "/tmp/foo" - :direction :output - :element-type (list - 'signed-byte - (1+ - (integer-length most-positive-fixnum)))) + :direction :output + :element-type (list + 'signed-byte + (1+ + (integer-length most-positive-fixnum)))) (read-byte s) (read-byte s) (read-byte s) @@ -761,8 +774,8 @@ ;;; can understand. Here's a simple test for that on a function ;;; that's likely to return a hairier list than just a lambda: (macrolet ((def (fn) `(progn - (declaim (inline ,fn)) - (defun ,fn (x) (1+ x))))) + (declaim (inline ,fn)) + (defun ,fn (x) (1+ x))))) (def bug228)) (let ((x (function-lambda-expression #'bug228))) (when x @@ -813,9 +826,9 @@ (+ x y)) (defun baz8alpha04 (this kids) (flet ((n-i (&rest rest) - ;; Removing the #+NIL here makes the bug go away. - #+nil (format t "~&in N-I REST=~S~%" rest) - (apply #'frob8alpha04 this rest))) + ;; Removing the #+NIL here makes the bug go away. + #+nil (format t "~&in N-I REST=~S~%" rest) + (apply #'frob8alpha04 this rest))) (n-i kids))) ;;; failed in 0.8alpha.0.4 with "The value 13 is not of type LIST." (assert (= (baz8alpha04 12 13) 25)) @@ -870,7 +883,7 @@ (unless (< a b) (truncate (expt a b)))) (assert (equal (multiple-value-list (expt-derive-type-bug 1 1)) - '(1 0))) + '(1 0))) ;;; Problems with type checking in functions with EXPLICIT-CHECK ;;; attribute (reported by Peter Graves) @@ -893,23 +906,538 @@ ;;;; MUFFLE-CONDITIONS test (corresponds to the test in the manual) (defvar *compiler-note-count* 0) -#-alpha ; KLUDGE +#-(or alpha x86-64) ; FIXME: make a better test! (handler-bind ((sb-ext:compiler-note (lambda (c) - (declare (ignore c)) - (incf *compiler-note-count*)))) + (declare (ignore c)) + (incf *compiler-note-count*)))) (let ((fun - (compile nil - '(lambda (x) - (declare (optimize speed) (fixnum x)) - (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) - (values (* x 5) ; no compiler note from this - (locally - (declare (sb-ext:unmuffle-conditions sb-ext:compiler-note)) - ;; this one gives a compiler note - (* x -5))))))) + (compile nil + '(lambda (x) + (declare (optimize speed) (fixnum x)) + (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) + (values (* x 5) ; no compiler note from this + (locally + (declare (sb-ext:unmuffle-conditions sb-ext:compiler-note)) + ;; this one gives a compiler note + (* x -5))))))) (assert (= *compiler-note-count* 1)) (assert (equal (multiple-value-list (funcall fun 1)) '(5 -5))))) +(handler-case + (eval '(flet ((%f (&key) nil)) (%f nil nil))) + (error (c) :good) + (:no-error (val) (error "no error: ~S" val))) +(handler-case + (eval '(labels ((%f (&key x) x)) (%f nil nil))) + (error (c) :good) + (:no-error (val) (error "no error: ~S" val))) + +;;; PROGV must not bind constants, or violate declared types -- ditto for SET. +(assert (raises-error? (set pi 3))) +(assert (raises-error? (progv '(pi s) '(3 pi) (symbol-value x)))) +(declaim (cons *special-cons*)) +(assert (raises-error? (set '*special-cons* "nope") type-error)) +(assert (raises-error? (progv '(*special-cons*) '("no hope") (car *special-cons*)) type-error)) + +;;; No bogus warnings for calls to functions with complex lambda-lists. +(defun complex-function-signature (&optional x &rest y &key z1 z2) + (cons x y)) +(with-test (:name :complex-call-doesnt-warn) + (handler-bind ((warning #'error)) + (compile nil '(lambda (x) (complex-function-signature x :z1 1 :z2 2))))) + +(with-test (:name :non-required-args-update-info) + (let ((name (gensym "NON-REQUIRE-ARGS-TEST")) + (*evaluator-mode* :compile)) + (eval `(defun ,name (x) x)) + (assert (equal '(function (t) (values t &optional)) + (sb-kernel:type-specifier (sb-int:info :function :type name)))) + (eval `(defun ,name (x &optional y) (or x y))) + (assert (equal '(function (t &optional t) (values t &optional)) + (sb-kernel:type-specifier (sb-int:info :function :type name)))))) + +;;;; inline & maybe inline nested calls + +(defun quux-marker (x) x) +(declaim (inline foo-inline)) +(defun foo-inline (x) (quux-marker x)) +(declaim (maybe-inline foo-maybe-inline)) +(defun foo-maybe-inline (x) (quux-marker x)) + +(with-test (:name :nested-inline-calls) + (let ((fun (compile nil `(lambda (x) + (foo-inline (foo-inline (foo-inline x))))))) + (assert (= 0 (ctu:count-full-calls "FOO-INLINE" fun))) + (assert (= 3 (ctu:count-full-calls "QUUX-MARKER" fun))))) + +(with-test (:name :nested-maybe-inline-calls) + (let ((fun (compile nil `(lambda (x) + (declare (optimize (space 0))) + (foo-maybe-inline (foo-maybe-inline (foo-maybe-inline x))))))) + (assert (= 0 (ctu:count-full-calls "FOO-MAYBE-INLINE" fun))) + (assert (= 1 (ctu:count-full-calls "QUUX-MARKER" fun))))) + +(with-test (:name :inline-calls) + (let ((fun (compile nil `(lambda (x) + (list (foo-inline x) + (foo-inline x) + (foo-inline x)))))) + (assert (= 0 (ctu:count-full-calls "FOO-INLINE" fun))) + (assert (= 3 (ctu:count-full-calls "QUUX-MARKER" fun))))) + +(with-test (:name :maybe-inline-calls) + (let ((fun (compile nil `(lambda (x) + (declare (optimize (space 0))) + (list (foo-maybe-inline x) + (foo-maybe-inline x) + (foo-maybe-inline x)))))) + (assert (= 0 (ctu:count-full-calls "FOO-MAYBE-INLINE" fun))) + (assert (= 1 (ctu:count-full-calls "QUUX-MARKER" fun))))) + +(with-test (:name :bug-405) + ;; These used to break with a TYPE-ERROR + ;; The value NIL is not of type SB-C::PHYSENV. + ;; in MERGE-LETS. + (ctu:file-compile + '((LET (outer-let-var) + (lambda () + (print outer-let-var) + (MULTIPLE-VALUE-CALL 'some-function + (MULTIPLE-VALUE-CALL (LAMBDA (a) 'foo) + 1)))))) + (ctu:file-compile + '((declaim (optimize (debug 3))) + (defstruct bug-405-foo bar) + (let () + (flet ((i (x) (frob x (bug-405-foo-bar foo)))) + (i :five)))))) + +;;; bug 235a +(declaim (ftype (function (cons) number) bug-235a-aux)) +(declaim (inline bug-235a-aux)) +(defun bug-235a-aux (c) + (the number (car c))) +(with-test (:name :bug-235a) + (let ((fun (compile nil + `(lambda (x y) + (values (locally (declare (optimize (safety 0))) + (bug-235a-aux x)) + (locally (declare (optimize (safety 3))) + (bug-235a-aux y))))))) + (assert + (eq :error + (handler-case + (funcall fun '(:one) '(:two)) + (type-error (e) + (assert (eq :two (type-error-datum e))) + (assert (eq 'number (type-error-expected-type e))) + :error)))))) + +(with-test (:name :compiled-debug-funs-leak) + (sb-ext:gc :full t) + (let ((usage-before (sb-kernel::dynamic-usage))) + (dotimes (x 10000) + (let ((f (compile nil '(lambda () + (error "X"))))) + (handler-case + (funcall f) + (error () nil)))) + (sb-ext:gc :full t) + (let ((usage-after (sb-kernel::dynamic-usage))) + (when (< (+ usage-before 2000000) usage-after) + (error "Leak"))))) + +;;; PROGV compilation and type checking when the declared type +;;; includes a FUNCTION subtype. +(declaim (type (or (function (t) (values boolean &optional)) string) + *hairy-progv-var*)) +(defvar *hairy-progv-var* #'null) +(with-test (:name :hairy-progv-type-checking) + (assert (eq :error + (handler-case + (progv '(*hairy-progv-var*) (list (eval 42)) + *hairy-progv-var*) + (type-error () :error)))) + (assert (equal "GOOD!" + (progv '(*hairy-progv-var*) (list (eval "GOOD!")) + *hairy-progv-var*)))) + +(with-test (:name :fill-complex-single-float) + (assert (every (lambda (x) (eql x #c(-1.0 -2.0))) + (funcall + (lambda () + (make-array 2 + :element-type '(complex single-float) + :initial-element #c(-1.0 -2.0))))))) + +(with-test (:name :make-array-symbol-as-initial-element) + (assert (every (lambda (x) (eq x 'a)) + (funcall + (compile nil + `(lambda () + (make-array 12 :initial-element 'a))))))) + +;;; This non-minimal test-case catches a nasty error when loading +;;; inline constants. +(deftype matrix () + `(simple-array single-float (16))) +(declaim (ftype (sb-int:sfunction (single-float single-float single-float single-float + single-float single-float single-float single-float + single-float single-float single-float single-float + single-float single-float single-float single-float) + matrix) + matrix) + (inline matrix)) +(defun matrix (m11 m12 m13 m14 + m21 m22 m23 m24 + m31 m32 m33 m34 + m41 m42 m43 m44) + (make-array 16 + :element-type 'single-float + :initial-contents (list m11 m21 m31 m41 + m12 m22 m32 m42 + m13 m23 m33 m43 + m14 m24 m34 m44))) +(declaim (ftype (sb-int:sfunction ((simple-array single-float (3)) single-float) matrix) + rotate-around)) +(defun rotate-around (a radians) + (let ((c (cos radians)) + (s (sin radians)) + ;; The 1.0 here was misloaded on x86-64. + (g (- 1.0 (cos radians)))) + (let* ((x (aref a 0)) + (y (aref a 1)) + (z (aref a 2)) + (gxx (* g x x)) (gxy (* g x y)) (gxz (* g x z)) + (gyy (* g y y)) (gyz (* g y z)) (gzz (* g z z))) + (matrix + (+ gxx c) (- gxy (* s z)) (+ gxz (* s y)) 0.0 + (+ gxy (* s z)) (+ gyy c) (- gyz (* s x)) 0.0 + (- gxz (* s y)) (+ gyz (* s x)) (+ gzz c) 0.0 + 0.0 0.0 0.0 1.0)))) +(with-test (:name :regression-1.0.29.54) + (assert (every #'= + '(-1.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 1.0) + (rotate-around + (make-array 3 :element-type 'single-float) (coerce pi 'single-float)))) + ;; Same bug manifests in COMPLEX-ATANH as well. + (assert (= (atanh #C(-0.7d0 1.1d0)) #C(-0.28715567731069275d0 0.9394245539093365d0)))) + +(with-test (:name :slot-value-on-structure) + (let ((f (compile nil `(lambda (x a b) + (declare (something-known-to-be-a-struct x)) + (setf (slot-value x 'x) a + (slot-value x 'y) b) + (list (slot-value x 'x) + (slot-value x 'y)))))) + (assert (equal '(#\x #\y) + (funcall f + (make-something-known-to-be-a-struct :x "X" :y "Y") + #\x #\y))) + (assert (not (ctu:find-named-callees f))))) + +(defclass some-slot-thing () + ((slot :initarg :slot))) +(with-test (:name :with-slots-the) + (let ((x (make-instance 'some-slot-thing :slot "foo"))) + (with-slots (slot) (the some-slot-thing x) + (assert (equal "foo" slot))))) + +;;; Missing &REST type in proclamation causing a miscompile. +(declaim (ftype + (function + (sequence unsigned-byte + &key (:initial-element t) (:initial-contents sequence)) + (values sequence &optional)) + bug-458354)) +(defun bug-458354 + (sequence length + &rest keys + &key (initial-element nil iep) (initial-contents nil icp)) + (declare (sb-ext:unmuffle-conditions style-warning)) + (declare (ignorable keys initial-element iep initial-contents icp)) + (apply #'sb-sequence:make-sequence-like sequence length keys)) +(with-test (:name :bug-458354) + (assert (equalp #((a b) (a b)) (bug-458354 #(1 2) 2 :initial-element '(a b))))) + +(with-test (:name :bug-542807) + (handler-bind ((style-warning #'error)) + (eval '(defstruct bug-542807 slot))) + (let (conds) + (handler-bind ((style-warning (lambda (c) + (push c conds)))) + (eval '(defstruct bug-542807 slot))) + (assert (= 1 (length conds))) + (assert (typep (car conds) 'sb-kernel::redefinition-with-defun)))) + +(with-test (:name :defmacro-not-list-lambda-list) + (assert (raises-error? (eval `(defmacro ,(gensym) "foo")) + type-error))) + +(with-test (:name :bug-308951) + (let ((x 1)) + (dotimes (y 10) + (let ((y y)) + (when (funcall (eval #'(lambda (x) (eql x 2))) y) + (defun bug-308951-foo (z) + (incf x (incf y z)))))) + (defun bug-308951-bar (z) + (bug-308951-foo z) + (values x))) + (assert (= 4 (bug-308951-bar 1)))) + +(declaim (inline bug-308914-storage)) +(defun bug-308914-storage (x) + (the (simple-array flt (*)) (bug-308914-unknown x))) + +(with-test (:name :bug-308914-workaround) + ;; This used to hang in ORDER-UVL-SETS. + (handler-case + (with-timeout 10 + (compile nil + `(lambda (lumps &key cg) + (let ((nodes (map 'list (lambda (lump) + (bug-308914-storage lump)) + lumps))) + (setf (aref nodes 0) 2) + (assert (every #'~= (apply #'concatenate 'list nodes) '(2 3 6 9))))))) + (sb-ext:timeout () + (error "Hang in ORDER-UVL-SETS?")))) + +(declaim (inline inlined-function-in-source-path)) +(defun inlined-function-in-source-path (x) + (+ x x)) + +(with-test (:name :inlined-function-in-source-path) + (let ((output + (with-output-to-string (*error-output*) + (compile nil `(lambda (x) + (declare (optimize speed)) + (funcall #'inlined-function-in-source-path x)))))) + ;; We want the name + (assert (search "INLINED-FUNCTION-IN-SOURCE-PATH" output)) + ;; ...not the leaf. + (assert (not (search "DEFINED-FUN" output))))) + +(defmacro bug-795705 () + t) + +(with-test (:name :bug-795705) + (assert (macro-function 'bug-795705)) + (fmakunbound 'bug-795705) + (assert (not (macro-function 'bug-795705)))) + +(with-test (:name (load-time-value :type-derivation)) + (let ((name 'load-time-value-type-derivation-test)) + (labels ((funtype (fun) + (sb-kernel:type-specifier + (sb-kernel:single-value-type + (sb-kernel:fun-type-returns + (sb-kernel:specifier-type + (sb-kernel:%simple-fun-type fun)))))) + (test (type1 type2 form value-cell-p) + (let* ((lambda-form `(lambda () + (load-time-value ,form))) + (core-fun (compile nil lambda-form)) + (core-type (funtype core-fun)) + (core-cell (ctu:find-value-cell-values core-fun)) + (defun-form `(defun ,name () + (load-time-value ,form))) + (file-fun (progn + (ctu:file-compile (list defun-form) :load t) + (symbol-function name))) + (file-type (funtype file-fun)) + (file-cell (ctu:find-value-cell-values file-fun))) + (if value-cell-p + (assert (and core-cell file-cell)) + (assert (not (or core-cell file-cell)))) + (unless (subtypep core-type type1) + (error "core: wanted ~S, got ~S" type1 core-type)) + (unless (subtypep file-type type2) + (error "file: wanted ~S, got ~S" type2 file-type))))) + (let ((* 10)) + (test '(integer 11 11) 'number + '(+ * 1) nil)) + (let ((* "fooo")) + (test '(integer 4 4) 'unsigned-byte + '(length *) nil)) + (test '(integer 10 10) '(integer 10 10) 10 nil) + (test 'cons 'cons '(cons t t) t)))) + +(with-test (:name (load-time-value :errors)) + (multiple-value-bind (warn fail) + (ctu:file-compile + `((defvar *load-time-value-error-value* 10) + (declaim (fixnum *load-time-value-error-value*)) + (defun load-time-value-error-test-1 () + (the list (load-time-value *load-time-value-error-value*)))) + :load t) + (assert warn) + (assert fail)) + (handler-case (load-time-value-error-test-1) + (type-error (e) + (and (eql 10 (type-error-datum e)) + (eql 'list (type-error-expected-type e))))) + (multiple-value-bind (warn2 fail2) + (ctu:file-compile + `((defun load-time-value-error-test-2 () + (the list (load-time-value 10)))) + :load t) + (assert warn2) + (assert fail2)) + (handler-case (load-time-value-error-test-2) + (type-error (e) + (and (eql 10 (type-error-datum e)) + (eql 'list (type-error-expected-type e)))))) + +;;;; tests for compiler output +(with-test (:name :unexpected-compiler-output) + (let* ((*error-output* (make-string-output-stream)) + (output (with-output-to-string (*standard-output*) + (compile-file "compiler-output-test.lisp" + :print nil :verbose nil)))) + (unless (zerop (length output)) + (error "Unexpected output: ~S" output)))) + +(with-test (:name :bug-493380) + (flet ((test (forms) + (catch 'debug + (let ((*debugger-hook* (lambda (condition if) + (throw 'debug + (if (typep condition 'serious-condition) + :debug + :oops))))) + (multiple-value-bind (warned failed) (ctu:file-compile forms) + (when (and warned failed) + :failed)))))) + (assert (eq :failed (test "(defun"))) + (assert (eq :failed (test "(defun no-pkg::foo ())"))) + (assert (eq :failed (test "(cl:no-such-sym)"))) + (assert (eq :failed (test "..."))))) + +(defun cmacro-signals-error () :fun) +(define-compiler-macro cmacro-signals-error () (error "oops")) + +(with-test (:name :cmacro-signals-error) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda () (cmacro-signals-error))) + (assert (and fun warn fail)) + (assert (eq :fun (funcall fun))))) + +(defun cmacro-with-simple-key (&key a) + (format nil "fun=~A" a)) +(define-compiler-macro cmacro-with-simple-key (&whole form &key a) + (if (constantp a) + (format nil "cmacro=~A" (eval a)) + form)) + +(with-test (:name (:cmacro-with-simple-key :no-key)) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda () (cmacro-with-simple-key))) + (assert (and (not warn) (not fail))) + (assert (string= "cmacro=NIL" (funcall fun))))) + +(with-test (:name (:cmacro-with-simple-key :constant-key)) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda () (cmacro-with-simple-key :a 42))) + (assert (and (not warn) (not fail))) + (assert (string= "cmacro=42" (funcall fun))))) + +(with-test (:name (:cmacro-with-simple-key :variable-key)) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda (x) (cmacro-with-simple-key x 42))) + (assert (and (not warn) (not fail))) + (assert (string= "fun=42" (funcall fun :a))))) + +(defun cmacro-with-nasty-key (&key ((nasty-key var))) + (format nil "fun=~A" var)) +(define-compiler-macro cmacro-with-nasty-key (&whole form &key ((nasty-key var))) + (if (constantp var) + (format nil "cmacro=~A" (eval var)) + form)) + +(with-test (:name (:cmacro-with-nasty-key :no-key)) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda () (cmacro-with-nasty-key))) + (assert (and (not warn) (not fail))) + (assert (string= "cmacro=NIL" (funcall fun))))) + +(with-test (:name (:cmacro-with-nasty-key :constant-key)) + ;; This bogosity is thanks to cmacro lambda lists being /macro/ lambda + ;; lists. + (multiple-value-bind (fun warn fail) + (compile nil `(lambda () (cmacro-with-nasty-key 'nasty-key 42))) + (assert (and (not warn) (not fail))) + (assert (string= "fun=42" (funcall fun))))) + +(with-test (:name (:cmacro-with-nasty-key :variable-key)) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda (nasty-key) (cmacro-with-nasty-key nasty-key 42))) + (assert (and (not warn) (not fail))) + (assert (string= "fun=42" (funcall fun 'nasty-key))))) + +(defconstant tricky-key 'tricky-key) +(defun cmacro-with-tricky-key (&key ((tricky-key var))) + (format nil "fun=~A" var)) +(define-compiler-macro cmacro-with-tricky-key (&whole form &key ((tricky-key var))) + (if (constantp var) + (format nil "cmacro=~A" (eval var)) + form)) + +(with-test (:name (:cmacro-with-tricky-key :no-key)) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda () (cmacro-with-tricky-key))) + (assert (and (not warn) (not fail))) + (assert (string= "cmacro=NIL" (funcall fun))))) + +(with-test (:name (:cmacro-with-tricky-key :constant-quoted-key)) + ;; This bogosity is thanks to cmacro lambda lists being /macro/ lambda + ;; lists. + (multiple-value-bind (fun warn fail) + (compile nil `(lambda () (cmacro-with-tricky-key 'tricky-key 42))) + (assert (and (not warn) (not fail))) + (assert (string= "fun=42" (funcall fun))))) + +(with-test (:name (:cmacro-with-tricky-key :constant-unquoted-key)) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda () (cmacro-with-tricky-key tricky-key 42))) + (assert (and (not warn) (not fail))) + (assert (string= "cmacro=42" (funcall fun))))) + +(with-test (:name (:cmacro-with-tricky-key :variable-key)) + (multiple-value-bind (fun warn fail) + (compile nil `(lambda (x) (cmacro-with-tricky-key x 42))) + (assert (and (not warn) (not fail))) + (assert (string= "fun=42" (funcall fun 'tricky-key))))) + +(defun test-function-983 (x) x) +(define-compiler-macro test-function-983 (x) x) + +(with-test (:name :funcall-compiler-macro) + (assert + (handler-case + (and (compile nil + `(lambda () + (funcall (function test-function-983 junk) 1))) + nil) + (sb-c:compiler-error () t)))) + +(defsetf test-984 %test-984) + +(with-test (:name :setf-function-with-setf-expander) + (assert + (handler-case + (and + (defun (setf test-984) ()) + nil) + (style-warning () t)))) + +(with-test (:name :compile-setf-function) + (defun (setf compile-setf) ()) + (assert (equal (compile '(setf compile-setf)) + '(setf compile-setf)))) + + ;;;; tests not in the problem domain, but of the consistency of the ;;;; compiler machinery itself @@ -926,55 +1454,1007 @@ (dolist (template (fun-info-templates (info :function :info function))) (when (template-more-results-type template) (format t "~&Template ~A has :MORE results, and translates ~A.~%" - (template-name template) - function) + (template-name template) + function) (return nil)) (when (eq (template-result-types template) :conditional) ;; dunno. (return t)) (let ((types (template-result-types template)) - (result-type (fun-type-returns (info :function :type function)))) + (result-type (fun-type-returns (info :function :type function)))) (cond - ((values-type-p result-type) - (do ((ltypes (append (args-type-required result-type) - (args-type-optional result-type)) - (rest ltypes)) - (types types (rest types))) - ((null ltypes) - (unless (null types) - (format t "~&More types than ltypes in ~A, translating ~A.~%" - (template-name template) - function) - (return nil))) - (when (null types) - (unless (null ltypes) - (format t "~&More ltypes than types in ~A, translating ~A.~%" - (template-name template) - function) - (return nil))))) - ((eq result-type (specifier-type nil)) - (unless (null types) - (format t "~&Template ~A returns values for function ~A with RESULT-TYPE NIL.~%" - (template-name template) - function) - (return nil))) - ((/= (length types) 1) - (format t "~&Template ~A isn't returning 1 value for ~A.~%" - (template-name template) - function) - (return nil)) - (t t))))) + ((values-type-p result-type) + (do ((ltypes (append (args-type-required result-type) + (args-type-optional result-type)) + (rest ltypes)) + (types types (rest types))) + ((null ltypes) + (unless (null types) + (format t "~&More types than ltypes in ~A, translating ~A.~%" + (template-name template) + function) + (return nil))) + (when (null types) + (unless (null ltypes) + (format t "~&More ltypes than types in ~A, translating ~A.~%" + (template-name template) + function) + (return nil))))) + ((eq result-type (specifier-type nil)) + (unless (null types) + (format t "~&Template ~A returns values for function ~A with RESULT-TYPE NIL.~%" + (template-name template) + function) + (return nil))) + ((/= (length types) 1) + (format t "~&Template ~A isn't returning 1 value for ~A.~%" + (template-name template) + function) + (return nil)) + (t t))))) (defun identify-suspect-vops (&optional (env (first - (last *info-environment*)))) + (last *info-environment*)))) (do-info (env :class class :type type :name name :value value) (when (and (eq class :function) (eq type :type)) ;; OK, so we have an entry in the INFO database. Now, if ... (let* ((info (info :function :info name)) - (templates (and info (fun-info-templates info)))) - (when templates - ;; ... it has translators - (grovel-results name)))))) + (templates (and info (fun-info-templates info)))) + (when templates + ;; ... it has translators + (grovel-results name)))))) (identify-suspect-vops) +;;;; bug 305: INLINE/NOTINLINE causing local ftype to be lost + +(define-condition optimization-error (error) ()) + +(labels ((compile-lambda (type sense) + (handler-bind ((compiler-note (lambda (_) + (declare (ignore _)) + (error 'optimization-error)))) + (values + (compile + nil + `(lambda () + (declare + ,@(when type '((ftype (function () (integer 0 10)) bug-305))) + (,sense bug-305) + (optimize speed)) + (1+ (bug-305)))) + nil))) + (expect-error (sense) + (multiple-value-bind (f e) (ignore-errors (compile-lambda nil sense)) + (assert (not f)) + (assert (typep e 'optimization-error)))) + (expect-pass (sense) + (multiple-value-bind (f e) (ignore-errors (compile-lambda t sense)) + (assert f) + (assert (not e))))) + (expect-error 'inline) + (expect-error 'notinline) + (expect-pass 'inline) + (expect-pass 'notinline)) + +;;; bug 211e: bogus style warning from duplicated keyword argument to +;;; a local function. +(handler-bind ((style-warning #'error)) + (let ((f (compile nil '(lambda () + (flet ((foo (&key y) (list y))) + (list (foo :y 1 :y 2))))))) + (assert (equal '((1)) (funcall f))))) + +;;; check that EQL is optimized when other argument is (OR SYMBOL FIXNUM). +(handler-bind ((compiler-note #'error)) + (let ((f1 (compile nil '(lambda (x1 y1) + (declare (type (or symbol fixnum) x1) + (optimize speed)) + (eql x1 y1)))) + (f2 (compile nil '(lambda (x2 y2) + (declare (type (or symbol fixnum) y2) + (optimize speed)) + (eql x2 y2))))) + (let ((fix (random most-positive-fixnum)) + (sym (gensym)) + (e-count 0)) + (assert (funcall f1 fix fix)) + (assert (funcall f2 fix fix)) + (assert (funcall f1 sym sym)) + (assert (funcall f2 sym sym)) + (handler-bind ((type-error (lambda (c) + (incf e-count) + (continue c)))) + (flet ((test (f x y) + (with-simple-restart (continue "continue with next test") + (funcall f x y) + (error "fell through with (~S ~S ~S)" f x y)))) + (test f1 "oops" 42) + (test f1 (1+ most-positive-fixnum) 42) + (test f2 42 "oops") + (test f2 42 (1+ most-positive-fixnum)))) + (assert (= e-count 4))))) + +;;; bug #389 (Rick Taube sbcl-devel) +(defun bes-jn (unn ux) + (let ((nn unn) (x ux)) + (let* ((n (floor (abs nn))) + (besn + (if (= n 0) + (bes-j0 x) + (if (= n 1) + (bes-j1 x) + (if (zerop x) + 0.0 + (let ((iacc 40) + (ans 0.0) + (bigno 1.0e+10) + (bigni 1.0e-10)) + (if (> (abs x) n) + (do ((tox (/ 2.0 (abs x))) + (bjm (bes-j0 (abs x))) + (bj (bes-j1 (abs x))) + (j 1 (+ j 1)) + (bjp 0.0)) + ((= j n) (setf ans bj)) + (setf bjp (- (* j tox bj) bjm)) + (setf bjm bj) + (setf bj bjp)) + (let ((tox (/ 2.0 (abs x))) + (m + (* 2 + (floor + (/ (+ n (sqrt (* iacc n))) + 2)))) + (jsum 0.0) + (bjm 0.0) + (sum 0.0) + (bjp 0.0) + (bj 1.0)) + (do ((j m (- j 1))) + ((= j 0)) + (setf bjm (- (* j tox bj) bjp)) + (setf bjp bj) + (setf bj bjm) + (when (> (abs bj) bigno) + (setf bj (* bj bigni)) + (setf bjp (* bjp bigni)) + (setf ans (* ans bigni)) + (setf sum (* sum bigni))) + (if (not (= 0 jsum)) (incf sum bj)) + (setf jsum (- 1 jsum)) + (if (= j n) (setf ans bjp))) + (setf sum (- (* 2.0 sum) bj)) + (setf ans (/ ans sum)))) + (if (and (minusp x) (oddp n)) + (- ans) + ans))))))) + (if (and (minusp nn) (oddp nn)) (- besn) besn)))) + + +;;; bug 233b: lvar lambda-var equality in constraint propagation + +;; Put this in a separate function. +(defun test-constraint-propagation/ref () + (let ((x nil)) + (if (multiple-value-prog1 x (setq x t)) + 1 + x))) + +(test-util:with-test (:name (:compiler :constraint-propagation :ref)) + (assert (eq t (test-constraint-propagation/ref)))) + +;; Put this in a separate function. +(defun test-constraint-propagation/typep (x y) + (if (typep (multiple-value-prog1 x (setq x y)) + 'double-float) + (+ x 1d0) + (+ x 2))) + +(test-util:with-test (:name (:compiler :constraint-propagation :typep)) + (assert (= 6.0d0 (test-constraint-propagation/typep 1d0 5)))) + +(test-util:with-test (:name (:compiler :constraint-propagation :eq/eql)) + (assert (eq :right (let ((c :wrong)) + (if (eq (let ((x c)) + (setq c :right) + x) + :wrong) + c + 0))))) + +;;; Put this in a separate function. +(defun test-constraint-propagation/cast (x) + (when (the double-float (multiple-value-prog1 + x + (setq x (1+ x)))) + x)) + +(test-util:with-test (:name (:compiler :constraint-propagation :cast)) + (assert (assertoid:raises-error? + (test-constraint-propagation/cast 1) type-error))) + +;;; bug #399 +(let ((result (make-array 50000 :fill-pointer 0 :adjustable t))) + (defun string->html (string &optional (max-length nil)) + (when (and (numberp max-length) + (> max-length (array-dimension result 0))) + (setf result (make-array max-length :fill-pointer 0 :adjustable t))) + (let ((index 0) + (left-quote? t)) + (labels ((add-char (it) + (setf (aref result index) it) + (incf index)) + (add-string (it) + (loop for ch across it do + (add-char ch)))) + (loop for char across string do + (cond ((char= char #\<) + (add-string "<")) + ((char= char #\>) + (add-string ">")) + ((char= char #\&) + (add-string "&")) + ((char= char #\') + (add-string "'")) + ((char= char #\newline) + (add-string "
")) + ((char= char #\") + (if left-quote? (add-string "“") (add-string "”")) + (setf left-quote? (not left-quote?))) + (t + (add-char char)))) + (setf (fill-pointer result) index) + (coerce result 'string))))) + +;;; Callign thru constant symbols +(require :sb-introspect) + +(declaim (inline target-fun)) +(defun target-fun (arg0 arg1) + (+ arg0 arg1)) +(declaim (notinline target-fun)) + +(defun test-target-fun-called (fun res) + (assert (member #'target-fun + (sb-introspect:find-function-callees #'caller-fun-1))) + (assert (equal (funcall fun) res))) + +(defun caller-fun-1 () + (funcall 'target-fun 1 2)) +(test-target-fun-called #'caller-fun-1 3) + +(defun caller-fun-2 () + (declare (inline target-fun)) + (apply 'target-fun 1 '(3))) +(test-target-fun-called #'caller-fun-2 4) + +(defun caller-fun-3 () + (flet ((target-fun (a b) + (- a b))) + (list (funcall #'target-fun 1 4) (funcall 'target-fun 1 4)))) +(test-target-fun-called #'caller-fun-3 (list -3 5)) + +;;; Reported by NIIMI Satoshi +;;; Subject: [Sbcl-devel] compilation error with optimization +;;; Date: Sun, 09 Apr 2006 17:36:05 +0900 +(defun test-minimal-debug-info-for-unstored-but-used-parameter (n a) + (declare (optimize (speed 3) + (debug 1))) + (if (= n 0) + 0 + (test-minimal-debug-info-for-unstored-but-used-parameter (1- n) a))) + +;;; &KEY arguments with non-constant defaults. +(declaim (notinline opaque-identity)) +(defun opaque-identity (x) x) +(defstruct tricky-defaults + (fun #'identity :type function) + (num (opaque-identity 3) :type fixnum)) +(macrolet ((frob (form expected-expected-type) + `(handler-case ,form + (type-error (c) (assert (eq (type-error-expected-type c) + ',expected-expected-type))) + (:no-error (&rest vals) (error "~S returned values: ~S" ',form vals))))) + (frob (make-tricky-defaults :fun 3) function) + (frob (make-tricky-defaults :num #'identity) fixnum)) + +(let ((fun (compile nil '(lambda (&key (key (opaque-identity 3))) + (declare (optimize safety) (type integer key)) + key)))) + (assert (= (funcall fun) 3)) + (assert (= (funcall fun :key 17) 17)) + (handler-case (funcall fun :key t) + (type-error (c) (assert (eq (type-error-expected-type c) 'integer))) + (:no-error (&rest vals) (error "no error")))) + +;;; Basic compiler-macro expansion +(define-compiler-macro test-cmacro-0 () ''expanded) + +(assert (eq 'expanded (funcall (lambda () (test-cmacro-0))))) + +;;; FUNCALL forms in compiler macros, lambda-list parsing +(define-compiler-macro test-cmacro-1 + (&whole whole a (a2) &optional b &rest c &key d) + (list whole a a2 b c d)) + +(macrolet ((test (form a a2 b c d) + `(let ((form ',form)) + (destructuring-bind (whole a a2 b c d) + (funcall (compiler-macro-function 'test-cmacro-1) form nil) + (assert (equal whole form)) + (assert (eql a ,a)) + (assert (eql a2 ,a2)) + (assert (eql b ,b)) + (assert (equal c ,c)) + (assert (eql d ,d))))) ) + (test (funcall 'test-cmacro-1 1 (x) 2 :d 3) 1 'x 2 '(:d 3) 3) + (test (test-cmacro-1 11 (y) 12 :d 13) 11 'y 12 '(:d 13) 13)) + +;;; FUNCALL forms in compiler macros, expansions +(define-compiler-macro test-cmacro-2 () ''ok) + +(assert (eq 'ok (funcall (lambda () (funcall 'test-cmacro-2))))) +(assert (eq 'ok (funcall (lambda () (funcall #'test-cmacro-2))))) + +;;; Shadowing of compiler-macros by local functions +(define-compiler-macro test-cmacro-3 () ''global) + +(defmacro find-cmacro-3 (&environment env) + (compiler-macro-function 'test-cmacro-3 env)) + +(assert (funcall (lambda () (find-cmacro-3)))) +(assert (not (funcall (lambda () (flet ((test-cmacro-3 ())) + (find-cmacro-3)))))) +(assert (eq 'local (funcall (lambda () (flet ((test-cmacro-3 () 'local)) + (test-cmacro-3)))))) +(assert (eq 'local (funcall (lambda () (flet ((test-cmacro-3 () 'local)) + (funcall #'test-cmacro-3)))))) +(assert (eq 'global (funcall (lambda () (flet ((test-cmacro-3 () 'local)) + (funcall 'test-cmacro-3)))))) + +;;; Local NOTINLINE & INLINE +(defun test-cmacro-4 () 'fun) +(define-compiler-macro test-cmacro-4 () ''macro) + +(assert (eq 'fun (funcall (lambda () + (declare (notinline test-cmacro-4)) + (test-cmacro-4))))) + +(assert (eq 'macro (funcall (lambda () + (declare (inline test-cmacro-4)) + (test-cmacro-4))))) + +;;; SETF function compiler macros +(define-compiler-macro (setf test-cmacro-4) (&whole form value) ''ok) + +(assert (eq 'ok (funcall (lambda () (setf (test-cmacro-4) 'zot))))) +(assert (eq 'ok (funcall (lambda () (funcall #'(setf test-cmacro-4) 'zot))))) + +;;; Step instrumentation breaking type-inference +(handler-bind ((warning #'error)) + (assert (= 42 (funcall (compile nil '(lambda (v x) + (declare (optimize sb-c:insert-step-conditions)) + (if (typep (the function x) 'fixnum) + (svref v (the function x)) + (funcall x)))) + nil (constantly 42))))) + +;;; bug 368: array type intersections in the compiler +(defstruct e368) +(defstruct i368) +(defstruct g368 + (i368s (make-array 0 :fill-pointer t) :type (or (vector i368) null))) +(defstruct s368 + (g368 (error "missing :G368") :type g368 :read-only t)) +(declaim (ftype (function (fixnum (vector i368) e368) t) r368)) +(declaim (ftype (function (fixnum (vector e368)) t) h368)) +(defparameter *h368-was-called-p* nil) +(defun nsu (vertices e368) + (let ((i368s (g368-i368s (make-g368)))) + (let ((fuis (r368 0 i368s e368))) + (format t "~&FUIS=~S~%" fuis) + (or fuis (h368 0 i368s))))) +(defun r368 (w x y) + (declare (ignore w x y)) + nil) +(defun h368 (w x) + (declare (ignore w x)) + (setf *h368-was-called-p* t) + (make-s368 :g368 (make-g368))) +(let ((nsu (nsu #() (make-e368)))) + (format t "~&NSU returned ~S~%" nsu) + (format t "~&*H368-WAS-CALLED-P*=~S~%" *h368-was-called-p*) + (assert (s368-p nsu)) + (assert *h368-was-called-p*)) + +;;; bug 367: array type intersections in the compiler +(defstruct e367) +(defstruct i367) +(defstruct g367 + (i367s (make-array 0 :fill-pointer t) :type (or (vector i367) null))) +(defstruct s367 + (g367 (error "missing :G367") :type g367 :read-only t)) +(declaim (ftype (function ((vector i367) e367) (or s367 null)) r367)) +(declaim (ftype (function ((vector e367)) (values)) h367)) +(defun frob-367 (v w) + (let ((x (g367-i367s (make-g367)))) + (let* ((y (or (r367 x w) + (h367 x))) + (z (s367-g367 y))) + (format t "~&Y=~S Z=~S~%" y z) + (g367-i367s z)))) +(defun r367 (x y) (declare (ignore x y)) nil) +(defun h367 (x) (declare (ignore x)) (values)) +(multiple-value-bind (res err) (ignore-errors (frob-367 0 (make-e367))) + (assert (not res)) + (assert (typep err 'type-error))) + +(handler-case + (delete-file (compile-file "circ-tree-test.lisp")) + (storage-condition (e) + (error e))) + +;;; warnings due to step-insturmentation +(defclass debug-test-class () ()) +(handler-case + (compile nil '(lambda () + (declare (optimize (debug 3))) + (defmethod print-object ((x debug-test-class) s) + (call-next-method)))) + ((and (not style-warning) warning) (e) + (error e))) + +;;; program-error from bad lambda-list keyword +(assert (eq :ok + (handler-case + (funcall (lambda (&whole x) + (list &whole x))) + (program-error () + :ok)))) +#+sb-eval +(assert (eq :ok + (handler-case + (let ((*evaluator-mode* :interpret)) + (funcall (eval '(lambda (&whole x) + (list &whole x))))) + (program-error () + :ok)))) + +;;; ignore &environment +(handler-bind ((style-warning #'error)) + (compile nil '(lambda () + (defmacro macro-ignore-env (&environment env) + (declare (ignore env)) + :foo))) + (compile nil '(lambda () + (defmacro macro-no-env () + :foo)))) + +(dolist (*evaluator-mode* '(#+sb-eval :interpret :compile)) + (disassemble (eval '(defun disassemble-source-form-bug (x y z) + (declare (optimize debug)) + (list x y z))))) + +;;; long-standing bug in defaulting unknown values on the x86-64, +;;; since changing the calling convention (test case by Christopher +;;; Laux sbcl-help 30-06-2007) + +(defun default-values-bug-demo-sub () + (format t "test") + nil) +(compile 'default-values-bug-demo-sub) + +(defun default-values-bug-demo-main () + (multiple-value-bind (a b c d e f g h) + (default-values-bug-demo-sub) + (if a (+ a b c d e f g h) t))) +(compile 'default-values-bug-demo-main) + +(assert (default-values-bug-demo-main)) + +;;; copy propagation bug reported by Paul Khuong + +(defun local-copy-prop-bug-with-move-arg (x) + (labels ((inner () + (values 1 0))) + (if x + (inner) + (multiple-value-bind (a b) + (inner) + (values b a))))) + +(assert (equal '(0 1) (multiple-value-list (local-copy-prop-bug-with-move-arg nil)))) +(assert (equal '(1 0) (multiple-value-list (local-copy-prop-bug-with-move-arg t)))) + +;;;; with-pinned-objects & unwind-protect, using all non-tail conventions + +(defun wpo-quux () (list 1 2 3)) +(defvar *wpo-quux* #'wpo-quux) + +(defun wpo-call () + (unwind-protect + (sb-sys:with-pinned-objects (*wpo-quux*) + (values (funcall *wpo-quux*))))) +(assert (equal '(1 2 3) (wpo-call))) + +(defun wpo-multiple-call () + (unwind-protect + (sb-sys:with-pinned-objects (*wpo-quux*) + (funcall *wpo-quux*)))) +(assert (equal '(1 2 3) (wpo-multiple-call))) + +(defun wpo-call-named () + (unwind-protect + (sb-sys:with-pinned-objects (*wpo-quux*) + (values (wpo-quux))))) +(assert (equal '(1 2 3) (wpo-call-named))) + +(defun wpo-multiple-call-named () + (unwind-protect + (sb-sys:with-pinned-objects (*wpo-quux*) + (wpo-quux)))) +(assert (equal '(1 2 3) (wpo-multiple-call-named))) + +(defun wpo-call-variable (&rest args) + (unwind-protect + (sb-sys:with-pinned-objects (*wpo-quux*) + (values (apply *wpo-quux* args))))) +(assert (equal '(1 2 3) (wpo-call-variable))) + +(defun wpo-multiple-call-variable (&rest args) + (unwind-protect + (sb-sys:with-pinned-objects (*wpo-quux*) + (apply #'wpo-quux args)))) +(assert (equal '(1 2 3) (wpo-multiple-call-named))) + +(defun wpo-multiple-call-local () + (flet ((quux () + (wpo-quux))) + (unwind-protect + (sb-sys:with-pinned-objects (*wpo-quux*) + (quux))))) +(assert (equal '(1 2 3) (wpo-multiple-call-local))) + +;;; bug 417: toplevel NIL confusing source path logic +(handler-case + (delete-file (compile-file "bug-417.lisp")) + (sb-ext:code-deletion-note (e) + (error e))) + +;;; unknown values return convention getting disproportionate +;;; amounts of values. +(declaim (notinline one-value two-values)) +(defun one-value (x) + (not x)) +(defun two-values (x y) + (values y x)) +(defun wants-many-values (x y) + (multiple-value-bind (a b c d e f) + (one-value y) + (assert (and (eql (not y) a) + (not (or b c d e f))))) + (multiple-value-bind (a b c d e f) + (two-values y x) + (assert (and (eql a x) (eql b y) + (not (or c d e f))))) + (multiple-value-bind (a b c d e f g h i) + (one-value y) + (assert (and (eql (not y) a) + (not (or b c d e f g h i))))) + (multiple-value-bind (a b c d e f g h i) + (two-values y x) + (assert (and (eql a x) (eql b y) + (not (or c d e f g h i))))) + (multiple-value-bind (a b c d e f g h i j k l m n o p q r s) + (one-value y) + (assert (and (eql (not y) a) + (not (or b c d e f g h i j k l m n o p q r s))))) + (multiple-value-bind (a b c d e f g h i j k l m n o p q r s) + (two-values y x) + (assert (and (eql a x) (eql b y) + (not (or c d e f g h i j k l m n o p q r s)))))) +(wants-many-values 1 42) + +;;; constant coalescing + +(defun count-code-constants (x f) + (let ((code (sb-kernel:fun-code-header f)) + (n 0)) + (loop for i from sb-vm::code-constants-offset below (sb-kernel:get-header-data code) + do (when (equal x (sb-kernel:code-header-ref code i)) + (incf n))) + n)) + +(defvar *lambda*) + +(defun compile2 (lambda) + (let* ((lisp "compiler-impure-tmp.lisp") + (fasl (compile-file-pathname lisp))) + (unwind-protect + (progn + (with-open-file (f lisp :direction :output) + (prin1 `(setf *lambda* ,lambda) f)) + (multiple-value-bind (fasl warn fail) (compile-file lisp) + (declare (ignore warn)) + (when fail + (error "File-compiling ~S failed." lambda)) + (let ((*lambda* nil)) + (load fasl) + (values *lambda* (compile nil lambda))))) + (ignore-errors (delete-file lisp)) + (ignore-errors (delete-file fasl))))) + +;; named and unnamed +(defconstant +born-to-coalesce+ '.born-to-coalesce.) +(multiple-value-bind (file-fun core-fun) + (compile2 '(lambda () + (let ((x (cons +born-to-coalesce+ nil)) + (y (cons '.born-to-coalesce. nil))) + (list x y)))) + (assert (= 1 (count-code-constants '.born-to-coalesce. file-fun))) + (assert (= 1 (count-code-constants '.born-to-coalesce. core-fun)))) + +;; some things must retain identity under COMPILE, but we want to coalesce them under COMPILE-FILE +(defun assert-coalescing (constant) + (let ((value (copy-seq (symbol-value constant)))) + (multiple-value-bind (file-fun core-fun) + (compile2 `(lambda () + (let ((x (cons ,constant nil)) + (y (cons ',value nil))) + (list x y)))) + (assert (= 1 (count-code-constants value file-fun))) + (assert (= 2 (count-code-constants value core-fun))) + (let* ((l (funcall file-fun)) + (a (car (first l))) + (b (car (second l)))) + (assert (and (equal value a) + (equal a b) + (eq a b)))) + (let* ((l (funcall core-fun)) + (a (car (first l))) + (b (car (second l)))) + (assert (and (equal value a) + (equal a b) + (not (eq a b)))))))) + +(defconstant +born-to-coalesce2+ "maybe coalesce me!") +(assert-coalescing '+born-to-coalesce2+) + +(defconstant +born-to-coalesce3+ #*01101001011101110100011) +(assert-coalescing '+born-to-coalesce3+) + +(defconstant +born-to-coalesce4+ '(foo bar "zot" 123 (nested "quux") #*0101110010)) +(assert-coalescing '+born-to-coalesce4+) + +(defclass some-constant-thing () ()) + +;;; correct handling of nested things loaded via SYMBOL-VALUE +(defvar *sneaky-nested-thing* (list (make-instance 'some-constant-thing))) +(defconstant +sneaky-nested-thing+ *sneaky-nested-thing*) +(multiple-value-bind (file-fun core-fun) (compile2 '(lambda () +sneaky-nested-thing+)) + (assert (equal *sneaky-nested-thing* (funcall file-fun))) + (assert (equal *sneaky-nested-thing* (funcall core-fun)))) + +;;; catch constant modifications thru undefined variables +(defun sneak-set-dont-set-me (x) + (ignore-errors (setq dont-set-me x))) +(defconstant dont-set-me 42) +(assert (not (sneak-set-dont-set-me 13))) +(assert (= 42 dont-set-me)) +(defun sneak-set-dont-set-me2 (x) + (ignore-errors (setq dont-set-me2 x))) +(defconstant dont-set-me2 (make-instance 'some-constant-thing)) +(assert (not (sneak-set-dont-set-me2 13))) +(assert (typep dont-set-me2 'some-constant-thing)) + +;;; check that non-trivial constants are EQ across different files: this is +;;; not something ANSI either guarantees or requires, but we want to do it +;;; anyways. +(defconstant +share-me-1+ #-inline-constants 123.456d0 #+inline-constants nil) +(defconstant +share-me-2+ "a string to share") +(defconstant +share-me-3+ (vector 1 2 3)) +(defconstant +share-me-4+ (* 2 most-positive-fixnum)) +(multiple-value-bind (f1 c1) (compile2 '(lambda () (values +share-me-1+ + +share-me-2+ + +share-me-3+ + +share-me-4+ + #-inline-constants pi))) + (multiple-value-bind (f2 c2) (compile2 '(lambda () (values +share-me-1+ + +share-me-2+ + +share-me-3+ + +share-me-4+ + #-inline-constants pi))) + (flet ((test (fa fb) + (mapc (lambda (a b) + (assert (eq a b))) + (multiple-value-list (funcall fa)) + (multiple-value-list (funcall fb))))) + (test f1 c1) + (test f1 f2) + (test f1 c2)))) + +;;; user-defined satisfies-types cannot be folded +(deftype mystery () '(satisfies mysteryp)) +(defvar *mystery* nil) +(defun mysteryp (x) (eq x *mystery*)) +(defstruct thing (slot (error "missing") :type mystery)) +(defun test-mystery (m) (when (eq :mystery (thing-slot m)) :ok)) +(setf *mystery* :mystery) +(assert (eq :ok (test-mystery (make-thing :slot :mystery)))) + +;;; Singleton types can also be constant. +(test-util:with-test (:name :propagate-singleton-types-to-eql) + (macrolet ((test (type value &aux (fun (gensym "FUN"))) + `(progn + (declaim (ftype (function () (values ,type &optional)) ,fun)) + (defun ,fun () + ',value) + (lambda (x) + (if (eql x (,fun)) + nil + (eql x (,fun))))))) + (values + (test (eql foo) foo) + (test (integer 0 0) 0) + (test (double-float 0d0 0d0) 0d0) + (test (eql #\c) #\c)))) + +(declaim (ftype (function () (integer 42 42)) bug-655581)) +(defun bug-655581 () + 42) +(declaim (notinline bug-655581)) +(test-util:with-test (:name :bug-655581) + (multiple-value-bind (type derived) + (funcall (compile nil `(lambda () + (ctu:compiler-derived-type (bug-655581))))) + (assert derived) + (assert (equal '(integer 42 42) type)))) + +(test-util:with-test (:name :clear-derived-types-on-set-fdefn) + (let ((*evaluator-mode* :compile) + (*derive-function-types* t)) + (eval `(progn + (defun clear-derived-types-on-set-fdefn-1 () + "foo") + (setf (symbol-function 'clear-derived-types-on-set-fdefn-1) + (constantly "foobar")) + (defun clear-derived-types-on-set-fdefn-2 () + (length (clear-derived-types-on-set-fdefn-1))))) + (assert (= 6 (clear-derived-types-on-set-fdefn-2))))) + +(test-util:with-test (:name (:bug-655126 :derive-function-types t)) + (let ((*evaluator-mode* :compile) + (*derive-function-types* t)) + (eval `(defun bug-655126 (x) x)) + ;; Full warnings are ok due to *derive-function-types* = T. + (assert (eq :full-warning + (handler-case + (eval `(defun bug-655126-2 () + (bug-655126))) + ((and warning (not style-warning)) () + :full-warning)))) + (assert (eq 'bug-655126 + (handler-case + (eval `(defun bug-655126 (x y) + (cons x y))) + ((and warning (not sb-kernel:redefinition-warning)) () + :oops)))) + (assert (eq :full-warning + (handler-case + (eval `(defun bug-655126 (x) + (bug-655126 x y))) + ((and warning + (not style-warning) + (not sb-kernel:redefinition-warning)) () + :full-warning)))))) + +(test-util:with-test (:name (:bug-655126 :derive-function-types nil)) + (let ((*evaluator-mode* :compile)) + (eval `(defun bug-655126/b (x) x)) + ;; Just style-warning here. + (assert (eq :style-warning + (handler-case + (eval `(defun bug-655126-2/b () + (bug-655126/b))) + (style-warning () + :style-warning)))) + (assert (eq 'bug-655126/b + (handler-case + (eval `(defun bug-655126/b (x y) + (cons x y))) + ((and warning (not sb-kernel:redefinition-warning)) () + :oops)))) + ;; Bogus self-call is always worth a full one. + (assert (eq :full-warning + (handler-case + (eval `(defun bug-655126/b (x) + (bug-655126/b x y))) + ((and warning + (not style-warning) + (not sb-kernel:redefinition-warning)) () + :full-warning)))))) + +(test-util:with-test (:name :bug-657499) + ;; Don't trust derived types within the compilation unit. + (ctu:file-compile + `((declaim (optimize safety)) + (defun bug-657499-foo () + (cons t t)) + (defun bug-657499-bar () + (let ((cons (bug-657499-foo))) + (setf (car cons) 3) + cons))) + :load t) + (locally (declare (optimize safety)) + (setf (symbol-function 'bug-657499-foo) (constantly "foobar")) + (assert (eq :type-error + (handler-case + (funcall 'bug-657499-bar) + (type-error (e) + (assert (eq 'cons (type-error-expected-type e))) + (assert (equal "foobar" (type-error-datum e))) + :type-error)))))) + +(declaim (unsigned-byte *symbol-value-test-var*)) +(defvar *symbol-value-test-var*) + +(declaim (unsigned-byte **global-symbol-value-test-var**)) +(defglobal **global-symbol-value-test-var** 0) + +(test-util:with-test (:name :symbol-value-type-derivation) + (let ((fun (compile + nil + `(lambda () + *symbol-value-test-var*)))) + (assert (equal '(function () (values unsigned-byte &optional)) + (%simple-fun-type fun)))) + (let ((fun (compile + nil + `(lambda () + **global-symbol-value-test-var**)))) + (assert (equal '(function () (values unsigned-byte &optional)) + (%simple-fun-type fun)))) + (let ((fun (compile + nil + `(lambda (*symbol-value-test-var*) + (declare (fixnum *symbol-value-test-var*)) + (symbol-value '*symbol-value-test-var*)))) + (ufix (type-specifier (specifier-type `(and unsigned-byte fixnum))))) + (assert (equal `(function (,ufix) (values ,ufix &optional)) + (%simple-fun-type fun)))) + (let ((fun (compile + nil + `(lambda () + (declare (fixnum **global-symbol-value-test-var**)) + (symbol-global-value '**global-symbol-value-test-var**)))) + (ufix (type-specifier (specifier-type `(and unsigned-byte fixnum))))) + (assert (equal `(function () (values ,ufix &optional)) + (%simple-fun-type fun))))) + +(test-util:with-test (:name :mv-bind-to-let-type-propagation) + (let ((f (compile nil `(lambda (x) + (declare (optimize speed) + (type (integer 20 50) x)) + (< (truncate x 10) 1)))) + (g (compile nil `(lambda (x) + (declare (optimize speed) + (type (integer 20 50) x)) + (< (nth-value 1 (truncate x 10)) 10)))) + (h (compile nil `(lambda (x) + (declare (optimize speed) + (type (integer 20 50) x)) + (multiple-value-bind (q r) + (truncate x 10) + (declare (ignore r)) + (< q 1))))) + (type0 '(function ((integer 20 50)) (values null &optional))) + (type1 '(function ((integer 20 50)) (values (member t) &optional)))) + (assert (equal type0 (sb-kernel:%simple-fun-type f))) + (assert (equal type1 (sb-kernel:%simple-fun-type g))) + (assert (equal type0 (sb-kernel:%simple-fun-type h))))) + +(test-util:with-test (:name :bug-308921) + (let ((*check-consistency* t)) + (ctu:file-compile + `((let ((exported-symbols-alist + (loop for symbol being the external-symbols of :cl + collect (cons symbol + (concatenate 'string + "#" + (string-downcase symbol)))))) + (defun hyperdoc-lookup (symbol) + (cdr (assoc symbol exported-symbols-alist))))) + :load nil))) + +(test-util:with-test (:name :bug-308941) + (multiple-value-bind (warn fail) + (let ((*check-consistency* t)) + (ctu:file-compile + "(eval-when (:compile-toplevel :load-toplevel :execute) + (defstruct foo3)) + (defstruct bar + (foo #.(make-foo3)))" + :load nil)) + ;; ...but the compiler should not break. + (assert (and warn fail)))) + +(test-util:with-test (:name :bug-903821) + (let* ((fun (compile nil '(lambda (x n) + (declare (sb-ext:word x) + (type (integer 0 #.(1- sb-vm:n-word-bits)) n) + (optimize speed)) + (logandc2 x (ash -1 n))))) + (trace-output + (with-output-to-string (*trace-output*) + (eval `(trace ,(intern (format nil "ASH-LEFT-MOD~D" sb-vm::n-word-bits) "SB-VM"))) + (assert (= 7 (funcall fun 15 3)))))) + (assert (string= "" trace-output)))) + +(test-util:with-test (:name :bug-997528) + (let ((fun (compile nil '(lambda (x) + (declare (optimize (speed 0) (space 0)) + (type (integer -228645653448155482 -228645653447928749) x)) + (floor 1.0 (the (integer -228645653448151677 -228645653448150900) x)))))) + (multiple-value-bind (quo rem) + (funcall fun -228645653448151381) + (assert (= quo -1)) + (assert (= rem (float -228645653448151381)))))) + +(defmacro def-many-code-constants () + `(defun many-code-constants () + ,@(loop for i from 0 below 1000 + collect `(print ,(format nil "hi-~d" i))))) + +(test-util:with-test (:name :many-code-constants) + (def-many-code-constants) + (assert (search "hi-999" + (with-output-to-string (*standard-output*) + (many-code-constants))))) + +(test-util:with-test (:name :bug-943953) + ;; we sometimes splice compiler structures like clambda in + ;; source, and our error reporting would happily use that + ;; as source forms. + (let* ((src "bug-943953.lisp") + (obj (compile-file-pathname src))) + (unwind-protect (compile-file src) + (ignore-errors (delete-file obj))))) + +(declaim (inline vec-1177703)) +(defstruct (vec-1177703 (:constructor vec-1177703 (&optional x))) + (x 0.0d0 :type double-float)) + +(declaim (inline norm-1177703)) +(defun norm-1177703 (v) + (vec-1177703 (sqrt (vec-1177703-x v)))) + +(test-util:with-test (:name :bug-1177703) + (compile nil `(lambda (x) + (norm-1177703 (vec-1177703 x))))) + +(declaim (inline call-1035721)) +(defun call-1035721 (function) + (lambda (x) + (funcall function x))) + +(declaim (inline identity-1035721)) +(defun identity-1035721 (x) + x) + +(test-util:with-test (:name :bug-1035721) + (compile nil `(lambda () + (list + (call-1035721 #'identity-1035721) + (lambda (x) + (identity-1035721 x)))))) + +(test-util:with-test (:name :expt-type-derivation-and-method-redefinition) + (defmethod expt-type-derivation ((x list) &optional (y 0.0)) + (declare (type float y)) + (expt 2 y)) + ;; the redefinition triggers a type lookup of the old + ;; fast-method-function's type, which had a bogus type specifier of + ;; the form (double-float 0) from EXPT type derivation + (defmethod expt-type-derivation ((x list) &optional (y 0.0)) + (declare (type float y)) + (expt 2 y))) ;;; success -(quit :unix-status 104)