# 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.
-# FIXME: the functions below should be in their own file, sourced by
-# each of the *.test.sh scripts.
-
-# Check that compiling and loading the file $1 generates an error
-# at load time; also that just loading it directly (into the
-# interpreter) generates an error.
-expect_load_error ()
-{
- # Test compiling and loading.
- $SBCL <<EOF
- (compile-file "$1")
- ;;; But loading the file should fail.
- (multiple-value-bind (value0 value1) (ignore-errors (load *))
- (assert (null value0))
- (format t "VALUE1=~S (~A)~%" value1 value1)
- (assert (typep value1 'error)))
- (sb-ext:quit :unix-status 52)
-EOF
- if [ $? != 52 ]; then
- echo compile-and-load $1 test failed: $?
- exit 1
- fi
-
- # Test loading into the interpreter.
- $SBCL <<EOF
- (multiple-value-bind (value0 value1) (ignore-errors (load "$1"))
- (assert (null value0))
- (format t "VALUE1=~S (~A)~%" value1 value1)
- (assert (typep value1 'error)))
- (sb-ext:quit :unix-status 52)
-EOF
- if [ $? != 52 ]; then
- echo load-into-interpreter $1 test failed: $?
- exit 1
- fi
-}
-
-# Test that a file compiles cleanly, with no ERRORs, WARNINGs or
-# STYLE-WARNINGs.
-expect_clean_compile ()
-{
- $SBCL <<EOF
- (multiple-value-bind (pathname warnings-p failure-p)
- (compile-file "$1")
- (declare (ignore pathname))
- (assert (not warnings-p))
- (assert (not failure-p))
- (sb-ext:quit :unix-status 52))
-EOF
- if [ $? != 52 ]; then
- echo clean-compile $1 test failed: $?
- exit 1
- fi
-}
-
-expect_warned_compile ()
-{
- $SBCL <<EOF
- (multiple-value-bind (pathname warnings-p failure-p)
- (compile-file "$1")
- (declare (ignore pathname))
- (assert warnings-p)
- (assert (not failure-p))
- (sb-ext:quit :unix-status 52))
-EOF
- if [ $? != 52 ]; then
- echo warn-compile $1 test failed: $?
- exit 1
- fi
-}
-
-expect_failed_compile ()
-{
- $SBCL <<EOF
- (multiple-value-bind (pathname warnings-p failure-p)
- (compile-file "$1")
- (declare (ignore pathname warnings-p))
- (assert failure-p)
- (sb-ext:quit :unix-status 52))
-EOF
- if [ $? != 52 ]; then
- echo fail-compile $1 test failed: $?
- exit 1
- fi
-}
+. ./expect.sh
base_tmpfilename="compiler-test-$$-tmp"
tmpfilename="$base_tmpfilename.lisp"
# having the same name.
cat > $tmpfilename <<EOF
(in-package :cl-user)
- (defun foo (x)
+ (defun foo (x)
(flet ((baz (y) (load y)))
(declare (notinline baz))
(baz x)))
- (defun bar (x)
+ (defun bar (x)
(flet ((baz (y) (load y)))
(declare (notinline baz))
(baz x)))
EOF
expect_clean_compile $tmpfilename
+# This shouldn't fail because it's not really a multiple definition
+cat > $tmpfilename <<EOF
+ (in-package :cl-user)
+ (eval-when (:compile-toplevel :load-toplevel :execute)
+ (defun foo (x) x))
+EOF
+expect_clean_compile $tmpfilename
+
+# Likewise
+cat > $tmpfilename <<EOF
+ (in-package :cl-user)
+ (eval-when (:compile-toplevel)
+ (defun foo (x) x))
+ (defun foo (x) x)
+EOF
+expect_clean_compile $tmpfilename
+
# This shouldn't fail despite the apparent type mismatch, because of
# the NOTINLINE declamation.
cat > $tmpfilename <<EOF
EOF
expect_clean_compile $tmpfilename
+# This shouldn't fail, but did until sbcl-0.8.10.4x
+cat > $tmpfilename <<EOF
+ (in-package :cl-user)
+ (declaim (inline foo))
+ (defun foo (x)
+ (1+ x))
+ (defun bar (y)
+ (list (foo y) (if (> y 1) (funcall (if (> y 0) #'foo #'identity) y))))
+EOF
+expect_clean_compile $tmpfilename
+
# This shouldn't fail despite the apparent type mismatch, because of
# the NOTINLINE declaration.
cat > $tmpfilename <<EOF
(in-package :cl-user)
(defun foo (x) (list x))
- (defun bar (x)
+ (defun bar (x)
(declare (notinline foo))
(1+ (foo x)))
EOF
EOF
expect_clean_compile $tmpfilename
+# NOTINLINE on known functions shouldn't inhibit type inference
+# (spotted by APD sbcl-devel 2003-06-14)
+cat > $tmpfilename <<EOF
+ (in-package :cl-user)
+ (defun foo (x)
+ (declare (notinline list))
+ (1+ (list x)))
+EOF
+expect_failed_compile $tmpfilename
+
+# ERROR wants to check its format string for sanity...
+cat > $tmpfilename <<EOF
+ (in-package :cl-user)
+ (defun foo (x)
+ (when x
+ (error "~S")))
+EOF
+expect_failed_compile $tmpfilename
+
+# ... but it (ERROR) shouldn't complain about being unable to optimize
+# when it's uncertain about its argument's type
+cat > $tmpfilename <<EOF
+ (in-package :cl-user)
+ (defun foo (x)
+ (error x))
+EOF
+fail_on_compiler_note $tmpfilename
+
+# test case from Rudi for some CLOS WARNINGness that shouldn't have
+# been there
+cat > $tmpfilename <<EOF
+ #+sb-eval (eval-when (:compile-toplevel)
+ (setf sb-ext:*evaluator-mode* :compile))
+
+ (eval-when (:compile-toplevel :load-toplevel :execute)
+ (defstruct buffer-state
+ (output-index 0)))
+
+ (defclass buffered-stream-mixin ()
+ ((buffer-state :initform (make-buffer-state))))
+
+ (defgeneric frob (stream))
+ (defmethod frob ((stream t))
+ nil)
+ (defmethod frob ((stream buffered-stream-mixin))
+ (symbol-macrolet
+ ((index (buffer-state-output-index (slot-value stream 'buffer-state))))
+ (setf index 0))
+ (call-next-method))
+EOF
+expect_clean_compile $tmpfilename
+
+# undeclared unbound variables should cause a full warning, as they
+# invoke undefined behaviour
+cat > $tmpfilename <<EOF
+ (defun foo () x)
+EOF
+expect_failed_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+ (declaim (special *x*))
+ (defun foo () *x*)
+EOF
+expect_clean_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+ (defun foo () (declare (special x)) x)
+EOF
+expect_clean_compile $tmpfilename
+
+# MUFFLE-CONDITIONS tests
+cat > $tmpfilename <<EOF
+ (defun foo ()
+ (declare (muffle-conditions style-warning))
+ (bar))
+EOF
+expect_clean_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+ (defun foo ()
+ (declare (muffle-conditions code-deletion-note))
+ (if t (foo) (foo)))
+EOF
+fail_on_compiler_note $tmpfilename
+
+cat > $tmpfilename <<EOF
+ (defun foo (x y)
+ (declare (muffle-conditions compiler-note))
+ (declare (optimize speed))
+ (+ x y))
+EOF
+fail_on_compiler_note $tmpfilename
+
+cat > $tmpfilename <<EOF
+ (declaim (muffle-conditions compiler-note))
+ (defun foo (x y)
+ (declare (optimize speed))
+ (+ x y))
+EOF
+fail_on_compiler_note $tmpfilename
+
+cat > $tmpfilename <<EOF
+ (declaim (muffle-conditions compiler-note))
+ (defun foo (x y)
+ (declare (unmuffle-conditions compiler-note))
+ (declare (optimize speed))
+ (+ x y))
+EOF
+expect_compiler_note $tmpfilename
+
+# undefined variable causes a WARNING
+cat > $tmpfilename <<EOF
+ (declaim (muffle-conditions warning))
+ (declaim (unmuffle-conditions style-warning))
+ (defun foo () x)
+EOF
+expect_clean_compile $tmpfilename
+
+# top level LOCALLY behaves nicely
+cat > $tmpfilename <<EOF
+ (locally
+ (declare (muffle-conditions warning))
+ (defun foo () x))
+EOF
+expect_clean_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+ (locally
+ (declare (muffle-conditions warning))
+ (defun foo () x))
+ (defun bar () x)
+EOF
+expect_failed_compile $tmpfilename
+
+# This should fail, and fail nicely -- not eg. loop trying to dump
+# references to the unbound variable.
+cat > $tmpfilename <<EOF
+(defmacro macro-with-unbound-variables (foo)
+ \`(print ,bar))
+
+(macro-with-unbound-variables 'xxx)
+EOF
+expect_failed_compile $tmpfilename
+
+# This should fail, as the MAKE-LOAD-FORM must be used for
+# externalizing conditions, and the method for CONDITION must signal
+# an error.
+cat > $tmpfilename <<EOF
+(defvar *oops* #.(make-condition 'condition))
+EOF
+expect_failed_compile $tmpfilename
+
+# This should fail, as the MAKE-LOAD-FORM must be used for objects,
+# and the method for STANDARD.OBJECT is required to signal an error.
+cat > $tmpfilename <<EOF
+(defvar *oops* #.(make-instance 'standard-object))
+EOF
+expect_failed_compile $tmpfilename
+
+# This should be clean
+cat > $tmpfilename <<EOF
+(defvar *string* (make-string 10 :element-type 'base-char))
+EOF
+expect_clean_compile $tmpfilename
+
+# This should style-warn (but not warn or otherwise fail) as the call
+# to FORMAT has too many arguments, which is bad style but not
+# otherwise fatal.
+cat > $tmpfilename <<EOF
+(defun foo (a b)
+ (format nil "abc~~def" a b))
+EOF
+expect_warned_compile $tmpfilename
+
+# Tests that destructive-functions on known-constant data cause
+# compile-time warnings.
+cat > $tmpfilename <<EOF
+(let ((string "foo"))
+ (defun foo ()
+ (setf string "bar")))
+EOF
+expect_clean_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+(defun foo ()
+ (let (result)
+ (nreverse result)))
+EOF
+expect_clean_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+(defun bar ()
+ (let ((result ""))
+ (nreverse result)))
+EOF
+expect_clean_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+(let ((string "foo"))
+ (defun foo ()
+ (replace string "bar")))
+EOF
+expect_failed_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+(defun foo ()
+ (setf (char "bar" 0) #\1))
+EOF
+expect_failed_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+(let ((foo '(1 2 3)))
+ (defun foo ()
+ (nconc foo foo)))
+EOF
+expect_failed_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+(declaim (optimize (speed 3) (space 0) (safety 0)))
+
+(defun foo (bar)
+ (last bar))
+EOF
+expect_clean_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+(defstruct foo
+ (bar #p"/tmp/"))
+EOF
+expect_clean_compile $tmpfilename
+
+cat > $tmpfilename <<EOF
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (defstruct foox)
+ (defmethod make-load-form ((foo foox) &optional env)
+ (declare (ignore env))
+ '(make-foox)))
+(defstruct bar
+ (foo #.(make-foox)))
+EOF
+expect_clean_compile $tmpfilename
+
rm $tmpfilename
rm $compiled_tmpfilename
-# success
+# success
exit 104