From 70390858d8a287d9e9caedaf725690378d30de05 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 8 Oct 2026 20:42:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(gen):=20=E5=8D=8F=E7=A8=8B=E4=BD=93?= =?UTF-8?q?=E9=87=8C=E7=9A=84=20new=20heap=20slife=20fail-fast=EF=BC=88?= =?UTF-8?q?=E9=87=8A=E6=94=BE=E7=82=B9=E6=97=A0=E6=B3=95=E7=A1=AE=E5=AE=9A?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AsyncGenMixin 的状态机会把协程 body 拆成多个 state 块并多次转译,编译器无法确定 slife 的释放点;此前是静默漏释放。新增锚点 trans._coro_body_func(Translator 字段 + init 置 None),只在 body 翻译期间由 translate_async_function 设置并保存/恢复旧值;_translate_new_expr 以**函数对象同一性**(_coro_body_func == _cur_func)判定并 fatal_error(LifetimeError)。嵌套普通函数会换掉 _cur_func 故不误报;new stack 与 hlife 不受影响。 --- App/lib/core/Gen/AsyncGenMixin.vp | 6 ++++++ App/lib/core/Gen/Call/CallGenCtor.vp | 9 +++++++++ App/lib/core/Gen/Translator.vp | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/App/lib/core/Gen/AsyncGenMixin.vp b/App/lib/core/Gen/AsyncGenMixin.vp index 1633233..224746f 100644 --- a/App/lib/core/Gen/AsyncGenMixin.vp +++ b/App/lib/core/Gen/AsyncGenMixin.vp @@ -883,7 +883,13 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase): trans._cur_builder = builder seg_bb: mlirlite.BasicBlock* = mlirlite.BasicBlock*(state_bbs[0]) mlirlite.position_at_end(builder, seg_bb) + # M3 硬约束锚点:登记"正在翻译其 body 的协程函数",CallGenCtor._translate_new_expr 据此对 + # 协程体内的 `new heap slife` fail-fast(协程体被状态机拆分,释放点无法确定)。 + # 保存/恢复旧值:协程里再定义协程时不会把外层的标记冲掉。 + old_coro_body: mlirlite.Function* = trans._coro_body_func + trans._coro_body_func = func self._handle_segment(trans, builder, pool, mod, fd.children) + trans._coro_body_func = old_coro_body # body fell through -> implicit return (ret=0 + done=1 + br exit) if mlirlite.builder_cur_block_is_terminated(builder) == 0: zret: mlirlite.Value* = mlirlite.const_int32(pool, 0) diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index bf1622a..845bf55 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -333,6 +333,15 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): if pool is None or builder is None or new_node is None or trans is None: return None src: int = new_node.Source life: int = new_node.Life + # M3 硬约束:async 函数体被状态机拆成多个 state 块,释放点无法确定 → + # `new heap slife`(编译器独占释放的那种)在协程体里 fail-fast,绝不让"登记了却永不释放" + # 静默通过。判定用**函数对象同一性**(trans._coro_body_func,见 AsyncGenMixin 的登记点): + # 协程体内嵌套的普通函数会换掉 _cur_func,所以不会误报。 + # `new stack`(帧内 alloca,无需释放)与 `hlife`(自行管理)不受影响。 + if trans._coro_body_func is not None and trans._cur_func is not None: + if uint64(trans._coro_body_func) == uint64(trans._cur_func) and self._new_is_owned_heap(new_node) != 0: + self.Gen.TypeGenErr.fatal_error(new_node, "`new heap slife ...` cannot be used inside an async function body: the coroutine body is split into state blocks, so the compiler cannot place the release point; use `new heap hlife ...` (and manage it yourself), or move the `slife` allocation into a regular function", "LifetimeError") + return None # 缺省规则(§3.2 / D3):来源缺省 = heap;生命期缺省由来源决定 # stack → slife(帧生命期;故 `new stack T(...)` 不写 slife 也等效) # heap / memgr → hlife(自由生命期) diff --git a/App/lib/core/Gen/Translator.vp b/App/lib/core/Gen/Translator.vp index 1ea59bc..80e2457 100644 --- a/App/lib/core/Gen/Translator.vp +++ b/App/lib/core/Gen/Translator.vp @@ -76,6 +76,10 @@ novirtual class Translator: _coro_frame: mlirlite.Value* _coro_next_state: int _coro_nseg: int + # M3 硬约束锚点:正在翻译其 body 的协程函数(= create_/resume_ 那个合成函数)。 + # 只有 body 翻译期间非 None,且与 _cur_func 同一对象才算"在协程体里"——嵌套的普通函数 + # 会换掉 _cur_func,故不会误报。用于禁止协程体内的 `new heap slife`(释放点无法确定)。 + _coro_body_func: mlirlite.Function* # M2: async parameter table (char* array, 8 bytes/item) + pre-scan counts _coro_params: str _coro_param_count: int @@ -283,6 +287,7 @@ novirtual class Translator: self._coro_frame = None self._coro_next_state = 1 self._coro_nseg = 0 + self._coro_body_func = None self._coro_params = None self._coro_param_count = 0 self._coro_hoist_count = 0