Deobfuscate pointer preservation in gencgc a tiny bit.
[sbcl.git] / tests / array.pure.lisp
blob1bebea08d851b6d082be9269929e2f74b0396283
1 ;;;; This software is part of the SBCL system. See the README file for
2 ;;;; more information.
3 ;;;;
4 ;;;; While most of SBCL is derived from the CMU CL system, the test
5 ;;;; files (like this one) were written from scratch after the fork
6 ;;;; from CMU CL.
7 ;;;;
8 ;;;; This software is in the public domain and is provided with
9 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
10 ;;;; more information.
12 (in-package :cl-user)
14 ;;; Array initialization has complicated defaulting for :ELEMENT-TYPE,
15 ;;; and both compile-time and run-time logic takes a whack at it.
16 (with-test (:name (make-array :element-type :bug-126))
17 (let ((testcases '(;; Bug 126, confusion between high-level default string
18 ;; initial element #\SPACE and low-level default array
19 ;; element #\NULL, is gone.
20 (#\null (make-array 11 :element-type 'character) simple-string)
21 (#\space (make-string 11 :initial-element #\space) string)
22 (#\* (make-string 11 :initial-element #\*))
23 (#\null (make-string 11))
24 (#\null (make-string 11 :initial-element #\null))
25 (#\x (make-string 11 :initial-element #\x))
26 ;; And the other tweaks made when fixing bug 126 didn't
27 ;; mess things up too badly either.
28 (0 (make-array 11) simple-vector)
29 (nil (make-array 11 :initial-element nil))
30 (12 (make-array 11 :initial-element 12))
31 (0 (make-array 11 :element-type '(unsigned-byte 4)) (simple-array (unsigned-byte 4) (*)))
32 (12 (make-array 11
33 :element-type '(unsigned-byte 4)
34 :initial-element 12)))))
35 (dolist (testcase testcases)
36 (destructuring-bind (expected-result form &optional type) testcase
37 (unless (eql expected-result (aref (eval form) 3))
38 (error "expected ~S in EVAL ~S" expected-result form))
39 (unless (eql expected-result
40 (aref (funcall (checked-compile `(lambda () ,form)
41 :allow-warnings t))
42 3))
43 (error "expected ~S in FUNCALL COMPILE ~S" expected-result form))
44 ;; also do some testing of compilation and verification that
45 ;; errors are thrown appropriately.
46 (unless (eql expected-result
47 (funcall (checked-compile `(lambda () (aref ,form 3))
48 :allow-warnings t)))
49 (error "expected ~S in COMPILED-AREF ~S" expected-result form))
50 (when type
51 (unless (eql expected-result
52 (funcall (checked-compile `(lambda ()
53 (let ((x ,form))
54 (declare (type ,type x))
55 (aref x 3)))
56 :allow-warnings t)))
57 (error "expected ~S in COMPILED-DECLARED-AREF ~S" expected-result form)))
58 (when (ignore-errors (aref (eval form) 12))
59 (error "error not thrown in EVAL ~S" form))
60 (when (ignore-errors (aref (funcall (checked-compile `(lambda () ,form)
61 :allow-warnings t))
62 12))
63 (error "error not thrown in FUNCALL COMPILE ~S" form))
64 (when (ignore-errors (funcall (checked-compile `(lambda () (aref ,form 12))
65 :allow-warnings t)))
66 (error "error not thrown in COMPILED-AREF ~S" form))
67 (when type
68 (when (ignore-errors (funcall
69 (checked-compile `(lambda ()
70 (let ((x ,form))
71 (declare (type ,type x))
72 (aref x 12)))
73 :allow-warnings t)))
74 (error "error not thrown in COMPILED-DECLARED-AREF ~S" form)))))))
76 ;;; On the SPARC, until sbcl-0.7.7.20, there was a bug in array
77 ;;; references for small vector elements (spotted by Raymond Toy); the
78 ;;; bug persisted on the PPC until sbcl-0.7.8.20.
79 (let (vector)
80 (loop for i below 64
81 for list = (make-list 64 :initial-element 1)
82 do (setf (nth i list) 0)
83 do (setf vector (make-array 64 :element-type 'bit
84 :initial-contents list))
85 do (assert (= (funcall
86 (compile nil
87 `(lambda (rmdr)
88 (declare (type (simple-array bit (*)) rmdr)
89 (optimize (speed 3) (safety 0)))
90 (aref rmdr ,i)))
91 vector)
92 0))))
94 ;;; Following refactoring of sequence functions to detect bad type
95 ;;; specifiers, REVERSE was left broken on vectors with fill pointers.
96 (with-test (:name :reverse-fill-pointer.string)
97 (let ((a (make-array 10
98 :fill-pointer 5
99 :element-type 'character
100 :initial-contents "abcdefghij")))
101 (assert (string= (reverse a) "edcba"))))
103 (with-test (:name :reverse-fill-pointer.fixnum)
104 (let ((a (make-array 10
105 :fill-pointer 6
106 :element-type 'fixnum
107 :initial-contents '(0 1 2 3 4 5 7 8 9 10))))
108 (assert (equalp (reverse a) #(5 4 3 2 1 0)))))
110 ;;; ARRAY-IN-BOUNDS-P should work when given non-INDEXes as its
111 ;;; subscripts (and return NIL, of course)
112 (with-test (:name array-in-bounds-p)
113 (macrolet
114 ((test-case (array subscript expected)
115 `(progn
116 (assert (,(if expected 'progn 'not)
117 (array-in-bounds-p ,array ,subscript)))
118 (assert (,(if expected 'progn 'not)
119 (funcall (checked-compile `(lambda (array subscript)
120 (array-in-bounds-p array subscript)))
121 ,array ,subscript))))))
122 (let ((a (make-array 10 :fill-pointer 5)))
123 (test-case a -1 nil)
124 (test-case a 3 t)
125 (test-case a 7 t)
126 (test-case a 11 nil)
127 (test-case a (1+ most-positive-fixnum) nil))))
129 ;;; arrays of bits should work:
130 (let ((a (make-array '(10 10) :element-type 'bit :adjustable t)))
131 (setf (bit a 0 0) 1)
132 (assert (= (bit a 0 0) 1)))
133 (let ((a (make-array '(10 10) :element-type 'bit)))
134 (setf (sbit a 0 0) 1)
135 (assert (= (sbit a 0 0) 1)))
137 (let ((x (copy-seq #*0011))
138 (y (copy-seq #*0101)))
139 (assert (equalp (bit-and x y nil) #*0001)))
141 ;;; arrays of NIL should work, FSVO "work".
142 (let ((a (make-array '(10 10) :element-type 'nil)))
143 (assert (= (array-total-size a) 100))
144 (assert (equal (array-dimensions a) '(10 10)))
145 (assert (eq (array-element-type a) 'nil)))
147 (assert (eq (upgraded-array-element-type 'nil) 'nil))
149 (with-test (:name (aref 0 :compile-time-error))
150 (multiple-value-bind (fun fail)
151 (checked-compile `(lambda () (aref (make-array 0) 0))
152 :allow-warnings t)
153 (assert fail)
154 (assert-error (funcall fun) sb-int:invalid-array-index-error)))
156 (with-test (:name (aref 1 :compile-time-error))
157 (multiple-value-bind (fun fail)
158 (checked-compile `(lambda () (aref (make-array 1) 1))
159 :allow-warnings t)
160 (assert fail)
161 (assert-error (funcall fun) sb-int:invalid-array-index-error)))
163 (with-test (:name (make-array :element-type :compile-time-error))
164 (multiple-value-bind (fun fail warnings style-warnings)
165 (checked-compile `(lambda () (make-array 5 :element-type 'undefined-type))
166 :allow-style-warnings t)
167 (declare (ignore fun fail warnings))
168 (assert style-warnings)))
170 (flet ((opaque-identity (x) x))
171 (declare (notinline opaque-identity))
172 ;; we used to have leakage from cross-compilation hosts of the INDEX
173 ;; type, which prevented us from actually using all the large array
174 ;; dimensions that we promised. Let's make sure that we can create
175 ;; an array with more than 2^24 elements, since that was a symptom
176 ;; from the CLISP and OpenMCL hosts.
177 (let ((big-array (opaque-identity
178 (make-array (expt 2 26) :element-type 'bit))))
179 (assert (= (length big-array) (expt 2 26)))))
181 ;;; Bug reported by Kalle Olavi Niemitalo for CMUCL through Debian BTS
182 (let ((array (make-array nil :initial-contents nil)))
183 (assert (eql (aref array) nil)))
185 (let ((f (compile nil '(lambda ()
186 (let ((a (make-array '(4)
187 :element-type 'base-char
188 :initial-element #\z)))
189 (setf (aref a 0) #\a)
190 (setf (aref a 1) #\b)
191 (setf (aref a 2) #\c)
192 a)))))
193 (assert (= (length (funcall f)) 4)))
195 (let ((x (make-array nil :initial-element 'foo)))
196 (adjust-array x nil)
197 (assert (eql (aref x) 'foo)))
199 ;;; BUG 315: "no bounds check for access to displaced array"
200 ;;; reported by Bruno Haible sbcl-devel "various SBCL bugs" from CLISP
201 ;;; test suite.
202 (locally (declare (optimize (safety 3) (speed 0)))
203 (let* ((x (make-array 10 :fill-pointer 4 :element-type 'character
204 :initial-element #\space :adjustable t))
205 (y (make-array 10 :fill-pointer 4 :element-type 'character
206 :displaced-to x)))
207 (assert (eq x (adjust-array x '(5))))
208 (assert (eq :error (handler-case
209 (char y 0)
210 (sb-int:invalid-array-error (e)
211 (assert (eq y (type-error-datum e)))
212 (assert (equal `(vector character 10)
213 (type-error-expected-type e)))
214 :error))))))
216 ;;; MISC.527: bit-vector bitwise operations used LENGTH to get a size
217 ;;; of a vector
218 (with-test (:name (bit-vector :bitwise-operations))
219 (flet ((bit-vector-equal (v1 v2)
220 (and (bit-vector-p v1) (bit-vector-p v2)
221 (equal (array-dimension v1 0) (array-dimension v2 0))
222 (loop for i below (array-dimension v1 0)
223 always (eql (aref v1 i) (aref v2 i))))))
224 (let* ((length 1024)
225 (v1 (make-array length :element-type 'bit :fill-pointer 0))
226 (v2 (make-array length :element-type 'bit :fill-pointer 1)))
227 (loop for i from 0 below length
228 for x1 in '#1=(0 0 1 1 . #1#)
229 and x2 in '#2=(0 1 0 1 . #2#)
230 do (setf (aref v1 i) x1)
231 do (setf (aref v2 i) x2))
232 (loop for (bf lf) in '((bit-and logand)
233 (bit-andc1 logandc1)
234 (bit-andc2 logandc2)
235 (bit-eqv logeqv)
236 (bit-ior logior)
237 (bit-nand lognand)
238 (bit-nor lognor)
239 (bit-orc1 logorc1)
240 (bit-orc2 logorc2)
241 (bit-xor logxor)
242 ((lambda (x y) (bit-not x)) #.(lambda (x y)
243 (declare (ignore y))
244 (lognot x))))
245 for fun = (checked-compile `(lambda (v)
246 (declare (type (array bit (*)) v))
247 (declare (optimize (speed 3) (safety 0)))
248 (,bf v ,v2))
249 :allow-style-warnings t)
250 for r1 = (funcall fun v1)
251 and r2 = (coerce (loop for i below length
252 collect (logand 1 (funcall lf (aref v1 i) (aref v2 i))))
253 'bit-vector)
254 do (assert (bit-vector-equal r1 r2))))))
256 (with-test (:name (adjust-array fill-pointer))
257 ;; CLHS, ADJUST-ARRAY: An error of type error is signaled if
258 ;; fill-pointer is supplied and non-nil but array has no fill pointer.
259 (assert (eq :good
260 (handler-case
261 (let ((array (make-array 12)))
262 (assert (not (array-has-fill-pointer-p array)))
263 (adjust-array array 12 :fill-pointer t)
264 array)
265 (type-error ()
266 :good)))))
268 (with-test (:name (adjust-array :multidimensional))
269 (let ((ary (make-array '(2 2))))
270 ;; SBCL used to give multidimensional arrays a bogus fill-pointer
271 (assert (not (array-has-fill-pointer-p (adjust-array ary '(2 2)))))))
273 (with-test (:name :%set-fill-pointer/error)
274 (let ((v (make-array 3 :fill-pointer 0)))
275 (handler-case
276 (progn
277 (setf (fill-pointer v) 12)
278 (error "WTF"))
279 (error (e)
280 (assert (eql 12 (type-error-datum e)))
281 (assert (equal '(integer 0 3) (type-error-expected-type e)))))))
283 (with-test (:name array-storage-vector)
284 (let ((vec (vector 1 2 3)))
285 (assert (eq vec (sb-ext:array-storage-vector vec)))
286 (assert (equalp (vector 1 2 3 4)
287 (sb-ext:array-storage-vector
288 (make-array '(2 2) :initial-contents '((1 2) (3 4))))))
289 (assert (eq 'fixnum (array-element-type
290 (sb-ext:array-storage-vector (make-array '(3 4 5)
291 :element-type 'fixnum)))))
292 (assert (not (array-has-fill-pointer-p
293 (sb-ext::array-storage-vector
294 (make-array 5 :fill-pointer 4)))))))
296 (with-test (:name :invalid-array-index-error)
297 (let ((array (make-array '(3 3 3))))
298 (assert
299 (eq :right
300 (handler-case
301 (eval `(aref ,array 0 1 3))
302 (sb-int:invalid-array-index-error (e)
303 (when (and (eq array (sb-kernel::invalid-array-index-error-array e))
304 (= 3 (type-error-datum e))
305 (equal '(integer 0 (3)) (type-error-expected-type e)))
306 :right)))))))
308 (with-test (:name :out-of-bounds-error-details)
309 (assert (eq :good
310 (handler-case
311 (flet ((test (array i)
312 (aref array i)))
313 (test (eval '(vector 0 1 2 3)) 6))
314 (sb-int:invalid-array-index-error (e)
315 (when (and (equal '(integer 0 (4))
316 (type-error-expected-type e))
317 (eql 6 (type-error-datum e)))
318 :good))))))
320 (with-test (:name :odd-keys-for-make-array)
321 (multiple-value-bind (fun fail warnings)
322 (checked-compile `(lambda (m) (make-array m 1))
323 :allow-warnings 'simple-warning)
324 (declare (ignore fun fail))
325 (assert (= 1 (length warnings)))))
328 (with-test (:name :bug-1096359)
329 (let ((a (make-array 1 :initial-element 5)))
330 (assert (equalp (adjust-array a 2 :initial-element 10)
331 #(5 10)))))
333 (with-test (:name (:make-array-transform-unknown-type :bug-1156095))
334 (assert
335 (handler-case
336 (compile nil `(lambda () (make-array '(1 2)
337 :element-type ',(gensym))))
338 (style-warning ()
340 (:no-error (&rest args)
341 (declare (ignore args))
342 nil))))
344 (with-test (:name :dont-make-array-bad-keywords)
345 ;; This used to get a heap exhaustion error because of trying
346 ;; to make the array before checking keyword validity.
347 (handler-case
348 (locally
349 (declare (notinline make-array))
350 (make-array (1- array-total-size-limit)
351 :initial-contents '(a b c) :initial-element 9))
352 (simple-error (c)
353 (assert
354 (string= (simple-condition-format-control c)
355 "Can't specify both :INITIAL-ELEMENT and :INITIAL-CONTENTS")))))
357 (with-test (:name :make-array-sanity-check-dims-first)
358 ;; A full call to %MAKE-ARRAY will signal a TYPE-ERROR on these inputs
359 ;; instead of trying to consume a massive amount of memory.
360 ;; Additionally, the relevent IR1 transform should give up.
361 (locally
362 (declare (notinline make-array))
363 (assert-error (make-array `(-1 -1 ,(- (ash array-dimension-limit -2) 4)))
364 type-error))
365 (locally
366 (declare (inline make-array))
367 (assert-error (make-array `(-1 -1 ,(- (ash array-dimension-limit -2) 4)))
368 type-error)))
370 (with-test (:name :make-array-size-overflow)
371 ;; 1-bit fixnum tags make array limits overflow the word length
372 ;; when converted to bytes
373 (when (= sb-vm:n-fixnum-tag-bits 1)
374 (assert-error (make-array (1- array-total-size-limit)) error)))
376 (with-test (:name :adjust-non-adjustable-array)
377 (let* ((a (make-array '(2 3) :initial-contents '((0 1 2) (3 4 5))))
378 (b (adjust-array a '(2 2))))
379 (setf (aref a 0 0) 11)
380 (assert (zerop (aref b 0 0)))
381 (assert (not (eq a b)))))
383 (with-test (:name :check-bound-elision)
384 (assert-error (funcall (checked-compile
385 `(lambda (x)
386 (char "abcd" x)))
388 sb-int:invalid-array-index-error)
389 (assert (eql (funcall (checked-compile
390 `(lambda (x)
391 (declare (optimize (safety 0)))
392 ;; Strings are null-terminated for C interoperability
393 (char "abcd" x)))
395 #\Nul)))
397 (with-test (:name :adjust-array-transform)
398 (assert (equalp (funcall
399 (checked-compile
400 `(lambda ()
401 (adjust-array #(1 2 3) 3 :displaced-to #(4 5 6)))))
402 #(4 5 6))))
404 (with-test (:name :adjust-array-fill-pointer)
405 (let ((array (make-array 10 :fill-pointer t)))
406 (assert (= (fill-pointer (adjust-array array 5 :fill-pointer 2))
407 2))))
409 (with-test (:name :adjust-array-initial-element)
410 (assert (equal (funcall
411 (checked-compile
412 `(lambda (x)
413 (adjust-array x 5 :initial-element #\x)))
414 "abc")
415 "abcxx")))
417 (with-test (:name :array-initial-contents-1)
418 (flet ((f (x y)
419 (sb-int:dx-let ((a (make-array `(,x ,y)
420 :initial-contents
421 '((a b c) (1 2 3)))))
422 (eval a)
423 nil)))
424 (f 2 3)
425 (assert-error (f 3 2))))
427 (with-test (:name :array-initial-contents-2)
428 (labels ((compute-contents () '((a b c) (1 2 3)))
429 (f (x y)
430 (sb-int:dx-let ((a (make-array `(,x ,y)
431 :initial-contents
432 (compute-contents))))
433 (eval a)
434 nil)))
435 (declare (notinline compute-contents))
436 (f 2 3)
437 (assert-error (f 3 2))))
439 (with-test (:name :array-initial-contents-3)
440 (multiple-value-bind (f warningp errorp)
441 ;; FIXME: should be CHECKED-COMPILE
442 (let ((*error-output* (make-broadcast-stream)))
443 (compile nil '(lambda (z)
444 (symbol-macrolet ((x (+ 1 1)) (y (* 2 1)))
445 (make-array `(,x ,y)
446 :initial-contents
447 `((,z ,z 1) (,z ,z ,z)))))))
448 (assert (and f warningp errorp))))