From 54b8a8918bb63c98a8f58e823033232243647562 Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 10:39:47 +0000 Subject: zc: add the defer statement defer expr; and defer { ... } register code that runs when the enclosing block ends: at the end of the block, and at return, break and continue that leave it. the tokens are kept at the defer and compiled again at each exit (block_close, body, kw_return, kw_break, kw_continue), newest first, before the block's variables are released, so the analyzer sees a deferred rt.free(p) as the transfer of p where it runs. names mean what they meant at the defer; values are read when it runs. return, break and continue inside a deferred statement are errors, reported once. works in unchecked code and closures (own base per function context). --- tests/errors/defer_freed_twice.zc | 10 ++++++++++ tests/errors/defer_moved.zc | 11 +++++++++++ tests/errors/defer_moved_early.zc | 14 ++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/errors/defer_freed_twice.zc create mode 100644 tests/errors/defer_moved.zc create mode 100644 tests/errors/defer_moved_early.zc (limited to 'tests/errors') diff --git a/tests/errors/defer_freed_twice.zc b/tests/errors/defer_freed_twice.zc new file mode 100644 index 0000000..d4fe08d --- /dev/null +++ b/tests/errors/defer_freed_twice.zc @@ -0,0 +1,10 @@ +namespace; +include rt; + +// expect: p: used after it was given away +fn main() { + int* p = rt.new(int); + defer rt.free(p); + rt.free(p); + return 0; +} diff --git a/tests/errors/defer_moved.zc b/tests/errors/defer_moved.zc new file mode 100644 index 0000000..d6086cd --- /dev/null +++ b/tests/errors/defer_moved.zc @@ -0,0 +1,11 @@ +namespace; +include rt; + +// expect: p: used after it was given away +fn take(int* .d p) { rt.free(p); return 0; } +fn main() { + int* p = rt.new(int); + defer rt.free(p); + take(p); + return 0; +} diff --git a/tests/errors/defer_moved_early.zc b/tests/errors/defer_moved_early.zc new file mode 100644 index 0000000..2c6feb9 --- /dev/null +++ b/tests/errors/defer_moved_early.zc @@ -0,0 +1,14 @@ +namespace; +include rt; + +// expect: p: used after it was given away +fn take(int* .d p) { rt.free(p); return 0; } +fn main(a) { + int* p = rt.new(int); + defer rt.free(p); + if (a) { + take(p); + return 1; + } + return 0; +} -- cgit v1.2.3