aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 02:35:04 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 02:40:51 +0330
commit31ae48845492c12f2745c7f4c0cd2ea448e0942a (patch)
treebcd26f483f4774fbcbae9c621050b10b3b53f295 /tests
parentgenmap: default genome reservation 0x70000 words (the genome had 197 words le... (diff)
destructors: reassigning an m owner that still holds a value frees the old value first, running its drop (right side first, then the free, then the store), with hint: x: reassigning frees the old value; a new value that is part of the old one is an error; u, d and captured owners keep the leak error; the new value's size, leaf type and drop are recorded like a declaration's; spec 6.8.5, 6.15.2
Diffstat (limited to 'tests')
-rw-r--r--tests/conformance/6-ownership/drop_reassign.zc25
-rw-r--r--tests/conformance/6-ownership/overwrite_frees.zc (renamed from tests/conformance/6-ownership/overwrite_leaks.zc)4
-rw-r--r--tests/conformance/6-ownership/reassign_moves_inner_owner.zc5
-rw-r--r--tests/data/reassign_hint.zc2
-rw-r--r--tests/errors/leak_overwrite.zc4
-rw-r--r--tests/errors/move_live_owner.zc5
-rw-r--r--tests/errors/reassign_from_own_child.zc6
-rwxr-xr-xtests/test.sh1
-rw-r--r--tests/xref.baseline21
9 files changed, 55 insertions, 18 deletions
diff --git a/tests/conformance/6-ownership/drop_reassign.zc b/tests/conformance/6-ownership/drop_reassign.zc
new file mode 100644
index 0000000..89f233e
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_reassign.zc
@@ -0,0 +1,25 @@
+// expect: a drop1 b drop2 3 drop3 drop10 drop11 12 t:7 t:8 9 t:9 drop12
+// destructors 6.8.5, 6.15.2: reassigning an owner that still holds a value frees the old value first, running its drop; the right side is computed before the free
+include rt;
+struct t { int v; void drop() { rt.put_s("t:"); rt.put_n(this.v); rt.put_s(" "); } }
+int* mk(int v) { return drop(heap(v), fn() { rt.put_s("drop"); rt.put_n(*this); rt.put_s(" "); }); }
+fn main() {
+ int* p = heap(1);
+ p.drop = fn() { rt.put_s("drop"); rt.put_n(*this); rt.put_s(" "); };
+ rt.put_s("a ");
+ p = heap(2);
+ p.drop = fn() { rt.put_s("drop"); rt.put_n(*this); rt.put_s(" "); };
+ rt.put_s("b ");
+ p = mk(*p + 1);
+ rt.put_n(*p); rt.put_s(" ");
+ int i = 10;
+ while (i < 13) { p = mk(i); i++; }
+ rt.put_n(*p); rt.put_s(" ");
+ t* s = rt.new(t); s.v = 7;
+ s = rt.new(t); s.v = 8;
+ t* u = rt.new(t); u.v = 9;
+ s = u;
+ rt.put_n(s.v); rt.put_s(" ");
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/overwrite_leaks.zc b/tests/conformance/6-ownership/overwrite_frees.zc
index a9b0138..9ae60d0 100644
--- a/tests/conformance/6-ownership/overwrite_leaks.zc
+++ b/tests/conformance/6-ownership/overwrite_frees.zc
@@ -1,5 +1,5 @@
-// expect error: a: still owns an object; overwriting it would leak it
-// spec 6.8.5
+// expect: 0/
+// spec 6.8.5: overwriting a variable that still owns frees the old object first
include rt;
void pn(int x) { rt.put_n(x); rt.put_c(10); }
fn main() { int* a = rt.new(1); a[0] = 1; a = rt.new(1); pn(a[0]); return 0; }
diff --git a/tests/conformance/6-ownership/reassign_moves_inner_owner.zc b/tests/conformance/6-ownership/reassign_moves_inner_owner.zc
new file mode 100644
index 0000000..d66d886
--- /dev/null
+++ b/tests/conformance/6-ownership/reassign_moves_inner_owner.zc
@@ -0,0 +1,5 @@
+// expect: 1 2/
+// spec 6.8.5: r still owns; assigning n frees r's object and moves n's into r, so n's block end frees nothing
+include rt;
+fn main() { word r = rt.new(4); { word n = rt.new(8); n[0] = 1; r = n; } rt.put_n(r[0]); r[0] = 2; rt.put_c(32); rt.put_n(r[0]); rt.put_c(10); return 0; }
+// zc0: skip
diff --git a/tests/data/reassign_hint.zc b/tests/data/reassign_hint.zc
new file mode 100644
index 0000000..6fd9a0c
--- /dev/null
+++ b/tests/data/reassign_hint.zc
@@ -0,0 +1,2 @@
+include rt;
+fn main() { int* p = rt.new(int); *p = 1; p = rt.new(int); return *p; }
diff --git a/tests/errors/leak_overwrite.zc b/tests/errors/leak_overwrite.zc
index 50fecfa..45febed 100644
--- a/tests/errors/leak_overwrite.zc
+++ b/tests/errors/leak_overwrite.zc
@@ -1,5 +1,7 @@
namespace;
include rt;
+// a u object still has to leave its block, so overwriting it is not a free (spec 6.8.5)
// expect: x: still owns an object
-fn main() { let x = rt.new(1); x = rt.new(2); return x[0]; }
+int*.u mk() { int*.u x = rt.new(1); x = rt.new(2); return x; }
+fn main() { let p = mk(); return p[0]; }
diff --git a/tests/errors/move_live_owner.zc b/tests/errors/move_live_owner.zc
deleted file mode 100644
index e36909c..0000000
--- a/tests/errors/move_live_owner.zc
+++ /dev/null
@@ -1,5 +0,0 @@
-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/reassign_from_own_child.zc b/tests/errors/reassign_from_own_child.zc
new file mode 100644
index 0000000..4a23e51
--- /dev/null
+++ b/tests/errors/reassign_from_own_child.zc
@@ -0,0 +1,6 @@
+namespace;
+include rt;
+
+struct node { node* next; int v; }
+// expect: a: reassigning frees the old value, and the new value is part of it
+fn main() { node* a = rt.new(node); a.next = rt.new(node); a = a.next; return 0; }
diff --git a/tests/test.sh b/tests/test.sh
index e93472c..9aee6d0 100755
--- a/tests/test.sh
+++ b/tests/test.sh
@@ -579,6 +579,7 @@ s_lsp() {
done
chk "$($lsp < examples/struct_closure_opt.zc | grep -c error)" "0" "lsp: methods and closures check clean"
case "$($lsp < tests/data/drop_hint.zc)" in *"value with drop is never bound; it drops at the end of this statement"*) chk 1 1 "lsp hint: a value with drop that is never bound";; *) chk 0 1 "lsp hint: a value with drop that is never bound";; esac
+ case "$($lsp < tests/data/reassign_hint.zc)" in *"p: reassigning frees the old value"*) chk 1 1 "lsp hint: reassigning an owner frees the old value";; *) chk 0 1 "lsp hint: reassigning an owner frees the old value";; esac
# a file of a larger build checks on its own: its bodyless declarations are not errors in check mode
for f in src/runtime/rt.zc src/runtime/run.zc src/lsp/server.zc; do chk "$($lsp < $f | grep -c ': error:')" "0" "lsp: $f checks alone"; done
# the compiler is several files that only make sense together: check them as one document
diff --git a/tests/xref.baseline b/tests/xref.baseline
index b8b1e1f..1660302 100644
--- a/tests/xref.baseline
+++ b/tests/xref.baseline
@@ -25,6 +25,7 @@ argowner args
argowner_fact args
argtemporary args
arrloc arrvalue chk_reset
+asg_quiet assigncheck reassign_free
asgcap reserve_assignment
asm_fixes reserve_asm_references
asm_labelcap reserve_asm_labels
@@ -291,14 +292,14 @@ lkeycap local_bind
lkeyn local_bind zc_init
lkeys local_bind
lkeys_initial
-lleaf assigncheck embed_bind localdecl reserve_locals
+lleaf assigncheck embed_bind expr localdecl reassign_free reserve_locals
lleaf_initial
lname newloc reserve_locals
-lnsz assigncheck embed_bind localdecl reserve_locals
+lnsz assigncheck embed_bind expr localdecl reassign_free reserve_locals
lnsz_initial
local_captured clocap_at newloc reserve_locals
local_cell capture_cell newloc reserve_locals
-local_dropset drop_attach localdecl newloc reserve_locals
+local_dropset drop_attach expr localdecl newloc reassign_free reserve_locals
local_end_info assigncheck end_owner newloc reserve_locals
local_ended assigncheck end_owner newloc reserve_locals
local_origin assigncheck newloc reserve_locals
@@ -379,8 +380,8 @@ nclo chk_reset closure
ndfr defer_drop kw_defer
nenh blob_load build_image_grow chk_reset enhdef
nerr chk_begin chk_reset errat prescan replace_function
-newleaf array_dynamic_literal array_pop call heap_box localdecl newtyped
-newsz array_dynamic_literal array_pop call chk_reset heap_box localdecl newtyped
+newleaf array_dynamic_literal array_pop call expr heap_box localdecl newtyped
+newsz array_dynamic_literal array_pop call chk_reset expr heap_box localdecl newtyped
nfact chk_reset fdrop putfact
nfixu fixnew zc_init
ngbind call chk_reset primary
@@ -691,8 +692,8 @@ uname add_unop reserve_unary
uncap reserve_unary
useq add_unop reserve_unary
vislo build_image_grow chk_unit start syntax_resident
-xaf af_forget args array_cap array_dynamic_literal array_len array_literal_tokens array_pop bin call chk_reset drop_attach drop_member expr field heap_box incdec kw_share_value kwcall methcall newtyped postfix_tail primary ternary unary
-xbor array_cap array_dynamic_literal array_len array_literal_tokens array_pop assigncheck bin blockexpr call chk_reset closure discard drop_attach drop_member enhcall field fn_begin heap_box kw_share_value kwcall methcall postfix_tail primary ternary typearg unary
+xaf af_forget args array_cap array_dynamic_literal array_len array_literal_tokens array_pop bin call chk_reset drop_attach drop_member expr field heap_box incdec kw_share_value kwcall methcall newtyped postfix_tail primary reassign_free ternary unary
+xbor array_cap array_dynamic_literal array_len array_literal_tokens array_pop assigncheck bin blockexpr call chk_reset closure discard drop_attach drop_member enhcall field fn_begin heap_box kw_share_value kwcall methcall postfix_tail primary reassign_free ternary typearg unary
xc_file xc_init
xc_fn closure fndef
xc_hook xc_init
@@ -701,14 +702,14 @@ xc_src unit_stdin
xcls array_cap array_len array_pop array_push array_resize chk_reset ctx_pop kw_asm kwcall quote_tokens
xconst array_dynamic_literal array_literal_tokens bin call chk_reset closure drop_attach heap_box kw_share_value methcall postfix_tail primary unary
xcval array_literal_tokens primary unary
-xfloat array_dynamic_literal array_len array_literal_tokens array_pop array_push array_resize bin blockexpr call closure drop_attach expr fcoerce femit ftest heap_box incdec kw_cfunc kw_for methcall postfix_tail primary ternary unary
+xfloat array_dynamic_literal array_len array_literal_tokens array_pop array_push array_resize bin blockexpr call closure drop_attach expr fcoerce femit ftest heap_box incdec kw_cfunc kw_for methcall postfix_tail primary reassign_free ternary unary
xgive argcheck args chk_reset
xlend assigncheck expr unary
xlenloc array_len bin call closure enhcall methcall postfix_tail primary unary
xprojection ctx_pop field postfix_tail primary
xstamp array_dynamic_literal array_len bin call closure enhcall methcall newtyped postfix_tail primary unary
-xstr array_dynamic_literal array_len array_literal_tokens bin blockexpr call closure drop_attach heap_box incdec methcall postfix_tail primary unary
-xty args array_cap array_dynamic_literal array_len array_literal_tokens array_pop array_push array_resize bin blockexpr call closure ctx_pop drop_attach drop_member enhcall expr fcoerce field ftest heap_box kw_cfunc kw_share_value kw_sizeof kw_typeof kwcall methcall newtyped postfix_tail primary ternary unary
+xstr array_dynamic_literal array_len array_literal_tokens bin blockexpr call closure drop_attach heap_box incdec methcall postfix_tail primary reassign_free unary
+xty args array_cap array_dynamic_literal array_len array_literal_tokens array_pop array_push array_resize bin blockexpr call closure ctx_pop drop_attach drop_member enhcall expr fcoerce field ftest heap_box kw_cfunc kw_share_value kw_sizeof kw_typeof kwcall methcall newtyped postfix_tail primary reassign_free ternary unary
xvk array_dynamic_literal array_literal_tokens bin blockexpr chk_reset ctx_pop expr field fn_begin incdec kw_share_value kwcall postfix_tail primary ternary unary vf_coerce vf_effect vf_forget
xvv blockexpr primary unary vf_coerce
xzero array_dynamic_literal array_literal_tokens bin blockexpr call closure drop_attach enhcall expr field heap_box incdec kwcall methcall newtyped postfix_tail primary ternary unary