aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/conformance/6-ownership/drop_gc_cycle.zc23
-rw-r--r--tests/conformance/6-ownership/drop_gc_self_capture.zc7
2 files changed, 30 insertions, 0 deletions
diff --git a/tests/conformance/6-ownership/drop_gc_cycle.zc b/tests/conformance/6-ownership/drop_gc_cycle.zc
new file mode 100644
index 0000000..01db6b8
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_gc_cycle.zc
@@ -0,0 +1,23 @@
+// expect: 0 1 2 2 0/
+// destructors 6.15.3: two unreachable values with drops that reach each other are finalized one per collection (each is in a cycle, so nothing outside it drops first), each exactly once, then freed
+include rt;
+int n;
+word g;
+struct node { node* other; int v; void drop() { n++; } }
+unchecked fn make() {
+ node* a = rt.new(node); node* b = rt.new(node);
+ a.v = 1; b.v = 2; a.other = b; b.other = a;
+ g = a;
+ return 0;
+}
+fn main() {
+ make();
+ rt.gc(); rt.put_n(n); rt.put_c(32);
+ g = 0;
+ rt.gc(); rt.put_n(n); rt.put_c(32);
+ rt.gc(); rt.put_n(n); rt.put_c(32);
+ rt.gc(); rt.gc(); rt.put_n(n); rt.put_c(32);
+ rt.put_n(rt.dcount); rt.put_c(10); // both entries are gone with their blocks
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_gc_self_capture.zc b/tests/conformance/6-ownership/drop_gc_self_capture.zc
new file mode 100644
index 0000000..444211d
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_gc_self_capture.zc
@@ -0,0 +1,7 @@
+// expect: drop 3 0/
+// destructors 6.15.3: a value its own drop reaches (the closure captures it) is a cycle of one, so the collector still finalizes it once, then frees it
+include rt;
+word g;
+unchecked fn make() { word p = heap(3); word q = p; p.drop = fn() { rt.put_s("drop "); rt.put_n(*q); rt.put_c(32); }; g = p; return 0; }
+fn main() { make(); g = 0; rt.gc(); rt.gc(); rt.gc(); rt.put_n(rt.dcount); rt.put_c(10); return 0; }
+// zc0: skip