aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/errors/lend_branch.zc6
-rw-r--r--tests/errors/lend_give.zc6
-rw-r--r--tests/errors/lend_return.zc6
-rw-r--r--tests/errors/lend_unrestored.zc6
-rw-r--r--tests/errors/move_live_owner.zc5
-rw-r--r--tests/errors/recast_plain.zc6
-rw-r--r--tests/errors/unused.zc2
-rw-r--r--tests/programs/ownmove.zc39
-rwxr-xr-xtests/runerr.sh4
-rwxr-xr-xtests/test.sh5
10 files changed, 80 insertions, 5 deletions
diff --git a/tests/errors/lend_branch.zc b/tests/errors/lend_branch.zc
new file mode 100644
index 0000000..594047f
--- /dev/null
+++ b/tests/errors/lend_branch.zc
@@ -0,0 +1,6 @@
+namespace;
+include rt;
+
+// expect: buf: is lent to global sink; assign the global again before the block that lent it ends
+word sink;
+fn main() { word buf = rt.new(4); sink = m*buf; if (buf[0]) { sink = 0; } return 0; }
diff --git a/tests/errors/lend_give.zc b/tests/errors/lend_give.zc
new file mode 100644
index 0000000..2fd2f5b
--- /dev/null
+++ b/tests/errors/lend_give.zc
@@ -0,0 +1,6 @@
+namespace;
+include rt;
+
+// expect: buf: is lent to global sink; assign the global again before giving the local away
+word sink;
+fn main() { word buf = rt.new(4); sink = m*buf; rt.free(buf); sink = 0; return 0; }
diff --git a/tests/errors/lend_return.zc b/tests/errors/lend_return.zc
new file mode 100644
index 0000000..b0c4b53
--- /dev/null
+++ b/tests/errors/lend_return.zc
@@ -0,0 +1,6 @@
+namespace;
+include rt;
+
+// expect: buf: is lent to global sink; assign the global again before the block that lent it ends
+word sink;
+fn main() { word buf = rt.new(4); sink = m*buf; if (buf[0]) return 1; sink = 0; return 0; }
diff --git a/tests/errors/lend_unrestored.zc b/tests/errors/lend_unrestored.zc
new file mode 100644
index 0000000..1b316df
--- /dev/null
+++ b/tests/errors/lend_unrestored.zc
@@ -0,0 +1,6 @@
+namespace;
+include rt;
+
+// expect: buf: is lent to global sink; assign the global again before the block that lent it ends
+word sink;
+fn main() { word buf = rt.new(4); sink = m*buf; buf[0] = 1; return 0; }
diff --git a/tests/errors/move_live_owner.zc b/tests/errors/move_live_owner.zc
new file mode 100644
index 0000000..e36909c
--- /dev/null
+++ b/tests/errors/move_live_owner.zc
@@ -0,0 +1,5 @@
+namespace;
+include rt;
+
+// expect: still owns an object; overwriting it would leak it
+fn main() { word r = rt.new(4); { word n = rt.new(8); n[0] = 1; r = n; } r[0] = 2; return 0; }
diff --git a/tests/errors/recast_plain.zc b/tests/errors/recast_plain.zc
new file mode 100644
index 0000000..7d26f3c
--- /dev/null
+++ b/tests/errors/recast_plain.zc
@@ -0,0 +1,6 @@
+namespace;
+include rt;
+
+// expect: p: isn't an owned object, so there is no ownership to recast
+word sink;
+fn main() { word p = m*rt.new(4); sink = d*p; return 0; }
diff --git a/tests/errors/unused.zc b/tests/errors/unused.zc
index 5c88ce3..7a1c7e4 100644
--- a/tests/errors/unused.zc
+++ b/tests/errors/unused.zc
@@ -1,5 +1,5 @@
namespace;
include rt;
-// expect: x is never read
+// expect: x: owned object is never used
fn main() { let x = rt.new(3); return 0; }
diff --git a/tests/programs/ownmove.zc b/tests/programs/ownmove.zc
new file mode 100644
index 0000000..76a2a17
--- /dev/null
+++ b/tests/programs/ownmove.zc
@@ -0,0 +1,39 @@
+namespace;
+include rt;
+
+// moves between owned locals and bounded lends of a local to a global.
+word sink;
+// the scratch buffer is lent to sink while helper reads it through the global.
+int helper() { return sink[0] + sink[1]; }
+int lend(int a, int b) {
+ word buf = rt.new(4);
+ buf[0] = a; buf[1] = b;
+ word saved = sink;
+ sink = m*buf;
+ int s = helper();
+ buf[0] = s;
+ sink = saved;
+ return buf[0];
+}
+// a replacement built in an inner block becomes the outer owner once the old one is released.
+int grow(int n) {
+ word r = rt.new(2);
+ r[0] = n;
+ if (n > 0) {
+ word bigger = rt.new(8);
+ bigger[0] = r[0] * 10;
+ rt.free(r);
+ r = bigger;
+ }
+ return r[0];
+}
+fn main() {
+ rt.put_n(lend(3, 4)); rt.put_c(32);
+ rt.put_n(grow(5)); rt.put_c(32);
+ rt.put_n(grow(0)); rt.put_c(32);
+ int i = 0;
+ while (i < 100) { grow(i); i++; }
+ rt.gc();
+ rt.put_n(sink == 0); rt.put_c(10);
+ return 0;
+}
diff --git a/tests/runerr.sh b/tests/runerr.sh
index 23ea054..f7e668c 100755
--- a/tests/runerr.sh
+++ b/tests/runerr.sh
@@ -1,9 +1,9 @@
#!/bin/bash
# runs every .zc in a folder (tests/errors by default) and checks the compiler
-# rejects it with the message on its first line: // expect: ...
+# rejects it with the message on its first `// expect: ...` line
vm=${1:-zy}; dir=${2:-$(dirname "$0")/errors}; pass=0; fail=0
for f in "$dir"/*.zc; do
- want=$(head -1 "$f" | sed 's#^// expect: ##')
+ want=$(grep -m1 '^// expect: ' "$f" | sed 's#^// expect: ##')
got=$($vm < "$f" 2>&1 | head -1)
if [[ "$got" == *"$want"* ]]; then pass=$((pass+1)); else fail=$((fail+1)); echo "FAIL $(basename $f): got [$got]"; fi
done
diff --git a/tests/test.sh b/tests/test.sh
index b80f548..16aa1a9 100755
--- a/tests/test.sh
+++ b/tests/test.sh
@@ -116,6 +116,7 @@ run(){ # $1 = vm command, $2 = label
chk "$($vm < tests/programs/o3push.zc | md5sum)" "$(md5sum < tests/programs/o3push.expected)" "$l push and pop of a growable array are inline in o3"
chk "$($vm < tests/programs/o3copy.zc)" "520507 1005" "$l o3 copies of a loop variable read the source instead"
chk "$($vm < tests/programs/borrowmove.zc)" "6" "$l storing into a borrowed object moves it"
+ chk "$($vm < tests/programs/ownmove.zc)" "7 50 0 1" "$l an owned local moves into a released owner, and a global borrows a local until it is restored"
chk "$($vm < tests/programs/alias.zc)" "11 22 4 8" "$l aliases of a live owner: arithmetic, field, index"
chk "$($vm < tests/programs/quarantine.zc)" "0 1234" "$l quarantine: stale alias reads intact data, second free is a no-op"
chk "$($vm < tests/programs/recycle.zc)" "1 0 1" "$l recycle returns a dropped block to its size class"
@@ -160,7 +161,7 @@ ABC" "$l o3 lifts byte loads and stores"
chk "$($vm < examples/strings.zc)" "hello, zc
9 42" "$l byte string example"
chk "$(ZC_BSTR=zybyte $vm < tests/programs/bstr_io.zc)" "byte-io 7 7 1 6 122 101" "$l byte-string file and getenv"
- chk "$($vm < tests/programs/manyerrors.zc | tr '\n' '/')" "zc: line 3: expected an expression, found ';'/zc: line 4: x: m object is never used/zc: line 5: type error: initializer: expected char*, got int/zc: line 6: expected ';', found '}'/zc: 4 errors/" "$l several errors in one run"
+ chk "$($vm < tests/programs/manyerrors.zc | tr '\n' '/')" "zc: line 6: expected an expression, found ';'/zc: line 7: x: owned object is never used/zc: line 8: type error: initializer: expected char*, got int/zc: line 9: expected ';', found '}'/zc: 4 errors/" "$l several errors in one run"
chk "$($vm < tests/programs/overflow_return.zc 2>&1)" "zy: return stack overflow" "$l return stack overflow is caught"
chk "$($vm < tests/programs/overflow_data.zc 2>&1)" "zy: data stack overflow" "$l data stack overflow is caught"
chk "$($vm < tests/programs/overflow_frame.zc 2>&1)" "zc: out of heap memory" "$l frame growth stops at a configured memory limit"
@@ -489,7 +490,7 @@ s_lsp() {
if bash src/tools/mklsp.sh $T/lsp >/dev/null 2>&1; then
lsp=$T/lsp/zclsp
chk "$($lsp < examples/hello.zc)" "no errors" "lsp: a clean program"
- chk "$($lsp < tests/errors/back_to_m.zc | head -1 | cut -d' ' -f2-)" "error: $(head -1 tests/errors/back_to_m.zc | sed 's#^// expect: ##')" "lsp: the compiler's own message"
+ chk "$($lsp < tests/errors/back_to_m.zc | head -1 | cut -d' ' -f2-)" "error: $(grep -m1 '^// expect: ' tests/errors/back_to_m.zc | sed 's#^// expect: ##')" "lsp: the compiler's own message"
h=$($lsp < examples/opt_test.zc)
for w in "is never read" "is never reassigned; make it a const" "is a shift; write << 3" "unannotated numeric literal 1234" "new inside a loop" "stack buffer"; do
case "$h" in *"$w"*) chk 1 1 "lsp hint: $w";; *) chk 0 1 "lsp hint: $w";; esac