diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 3ec3f1b..acee9e0 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -830,11 +830,56 @@ novirtual class AssignGenMixin: self.Gen.VarGen.set_var_life(trans.SymTab, tnm.id, life) return 0 + # _CurFuncIsEntryMain - 当前正在翻译的函数是否为**入口 main**(1=是 / 0=否)。 + # 嵌套函数不算:它们的帧不是进程生命期,不能享受豁免。 + def _CurFuncIsEntryMain(self, trans: HT.Translator*) -> int: + """当前函数是否为入口 main(按 llirlite 函数名判,与 FuncGenDef 对 main 不改名同口径)""" + if trans is None or trans._cur_func is None: return 0 + nm: str = mlirlite.function_get_name(trans._cur_func) + if nm is None: return 0 + return 1 if string.strcmp(nm, "main") == 0 else 0 + + # _TypeIsPtrToStruct - 该 LLVM 类型是否为"指向结构体的指针"(1=是 / 0=否)。 + def _TypeIsPtrToStruct(self, ty: mlirlite.LLVMType*) -> int: + """ty 是否为"指针且 pointee 是已登记的结构体"(标量指针如 i8*/i32* 返回 0)""" + if ty is None: return 0 + if self.Gen.ExprGenBase.is_ptr_type(ty) == 0: return 0 + po: mlirlite.LLVMType* = ty.Pointee + if po is None: return 0 + return 1 if self.Gen.StructGen.find_struct_by_type(po) is not None else 0 + + # _ExprIsStructPtr - 该右值表达式是否为"指向结构体的指针"(1=是 / 0=否/判不定)。 + # 覆盖两条常见来源:① 变量名(按其槽的值类型 `Ptr(StructTy)` 判); + # ② 裸构造 `T(...)`(T 是已登记结构体 → 结果类型即 T*)。 + def _ExprIsStructPtr(self, trans: HT.Translator*, node: ast.AST*) -> int: + """右值是否为结构体指针(供 main 豁免判据用;判不定一律 0=照常受检)""" + if trans is None or node is None: return 0 + k: int = node.kind() + if k == ast.ASTKind.Name: + nm: ast.Name* = ast.Name*(node) + if nm.id is None: return 0 + slot: mlirlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) + if slot is None: slot = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id) + if slot is None or slot.Ty is None: return 0 + return self._TypeIsPtrToStruct(slot.Ty.Pointee) + if k == ast.ASTKind.Call: + cl: ast.Call* = ast.Call*(node) + cn: str = self.Gen.ExprGenBase.get_func_name(cl.func) + if cn is None: return 0 + return 1 if self.Gen.StructGen.get_struct_type(cn) is not None else 0 + return 0 + # fail_if_life_escapes - 汇点检查:被写出表达式的生命期为 LIFE_FRAME → LifetimeError。 # 这是 GenApi.fail_if_stack_addr_escape 的唯一实现(语法判据已并入 life_of_expr)。 + # 例外(main 栈上结构体):入口 main 的帧生命期 = 进程生命期,其栈上的**结构体对象** + # 在本帧返回(= 进程退出)后不可能再被使用,故 main 内把结构体指针写进长命存储不报 + # (如 `argparse._mbuddy = mb`,mb 是裸构造 `MemBuddy(...)` 的帧内结构体)。 + # **只豁免结构体指针**:标量指针(`&local` / 栈数组退让 / ret(frame) 返回 int*)仍受检, + # 以保留既有负向工程(NewLifetimeFieldEscapeTest / NewLifetimeAnnFieldEscapeTest 等)。 def fail_if_life_escapes(self, node: ast.AST*, where: str, trans: HT.Translator*, target_ty: mlirlite.LLVMType*, leak_func: str = None, leak_param: int = -1) -> int: """Fail fast (LifetimeError) when the written-out value is frame-lifetime storage""" if node is None or trans is None: return 0 + if self._CurFuncIsEntryMain(trans) != 0 and self._ExprIsStructPtr(trans, node) != 0: return 0 if self.life_of_expr(trans, node, target_ty) != GenTypes.LIFE_FRAME: return 0 # 报文里给出名字(&x / x),便于定位;前缀单独存放,避免 str 相加(str 是 i8*,无 '+' 语义) nm_txt: str = "expression"