From a175ffd5d18d2883279c94d727f5966ecda409ab Mon Sep 17 00:00:00 2001 From: zinc Date: Thu, 15 Oct 2026 02:44:26 +0330 Subject: rt: gc_drops finalizes a droppable value that reaches itself (a cycle, or a drop capturing its own value), one per collection, each once; before, each waited for the other forever; spec 6.15.3, drop_gc_cycle.zc, drop_gc_self_capture.zc, design doc lists what landed --- tests/conformance/6-ownership/drop_gc_cycle.zc | 23 ++++++++++++++++++++++ .../6-ownership/drop_gc_self_capture.zc | 7 +++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/conformance/6-ownership/drop_gc_cycle.zc create mode 100644 tests/conformance/6-ownership/drop_gc_self_capture.zc (limited to 'tests/conformance') 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 -- cgit v1.2.3