diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/errors/lend_branch.zc | 6 | ||||
| -rw-r--r-- | tests/errors/lend_give.zc | 6 | ||||
| -rw-r--r-- | tests/errors/lend_return.zc | 6 | ||||
| -rw-r--r-- | tests/errors/lend_unrestored.zc | 6 | ||||
| -rw-r--r-- | tests/errors/move_live_owner.zc | 5 | ||||
| -rw-r--r-- | tests/errors/recast_plain.zc | 6 | ||||
| -rw-r--r-- | tests/errors/unused.zc | 2 | ||||
| -rw-r--r-- | tests/programs/ownmove.zc | 39 | ||||
| -rwxr-xr-x | tests/runerr.sh | 4 | ||||
| -rwxr-xr-x | tests/test.sh | 5 |
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 |
