diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 5bd63f2..cfef41a 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1014,6 +1014,29 @@ novirtual class AssignGenMixin: # life_of_expr - 求表达式当前值的生命期标签。 # target_ty 参与判定:裸本帧数组名在**指针**目标位置 = 数组退让(交出本帧栈地址), # 在同型聚合目标位置 = 按值拷贝(LIFE_VALUE)。 + # [TEMP-DIAG] life_of_expr 的 Name 分支判定输入快照(定位完删除)。 + # hit 语义:1=已登记 HEAP/STATIC 直接返回 / 2=裸数组名+指针目标(FRAME) / 3=裸数组名+值目标(VALUE) + # 4=值类型变量+值目标(VALUE,本次新增分支) / 5=指针或异型落到登记值 / 6=变量非指针落到登记值 + def _life_diag_name(self, trans: HT.Translator*, nm: str, rg: int, v: mlirlite.Value*, target_ty: mlirlite.LLVMType*, hit: int) -> int: + vptr: int = -1 + iptr: int = -1 + ikind: int = -1 + tptr: int = -1 + if v is not None and v.Ty is not None: + vptr = self.Gen.ExprGenBase.is_ptr_type(v.Ty) + if vptr != 0 and v.Ty.Pointee is not None: + iptr = self.Gen.ExprGenBase.is_ptr_type(v.Ty.Pointee) + ikind = int(v.Ty.Pointee.kind()) + if target_ty is not None: tptr = self.Gen.ExprGenBase.is_ptr_type(target_ty) + fn_s: str = None + if trans._cur_func is not None: fn_s = mlirlite.function_get_name(trans._cur_func) + if fn_s is None: fn_s = "?" + nm_s: str = nm + if nm_s is None: nm_s = "?" + stdio.printf("[LIFE-DIAG] fn=%s name=%s rg=%d hit=%d vptr=%d iptr=%d ikind=%d tptr=%d\n", + fn_s, nm_s, rg, hit, vptr, iptr, ikind, tptr) + return 0 + def life_of_expr(self, trans: HT.Translator*, node: ast.AST*, target_ty: mlirlite.LLVMType*) -> int: """表达式的 LifeTag;无法判定时 LIFE_UNKNOWN(保守放行)""" if node is None or trans is None: return GenTypes.LIFE_VALUE @@ -1038,13 +1061,20 @@ novirtual class AssignGenMixin: # 变量已登记为堆/静态生命期(如 `o: T* = new heap T()` 的指针变量):以登记为准, # 下面按"值类型"放宽只针对未登记的帧内局部变量,避免把堆/静态对象误放宽成值拷贝。 rg: int = self.Gen.VarGen.get_var_life(trans.SymTab, nm.id) - if rg == GenTypes.LIFE_HEAP or rg == GenTypes.LIFE_STATIC: return rg - if v.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(v.Ty) != 0: + res: int = rg + hit: int = 6 + if rg == GenTypes.LIFE_HEAP or rg == GenTypes.LIFE_STATIC: + hit = 1 + elif v.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(v.Ty) != 0: inner: mlirlite.LLVMType* = v.Ty.Pointee if inner is not None and inner.kind() == mlirlite.LLVMType.Array: # 本帧局部数组名:退让到指针目标交出栈地址;同型聚合目标是值拷贝 - if target_ty is not None and self.Gen.ExprGenBase.is_ptr_type(target_ty) != 0: return GenTypes.LIFE_FRAME - return GenTypes.LIFE_VALUE + if target_ty is not None and self.Gen.ExprGenBase.is_ptr_type(target_ty) != 0: + res = GenTypes.LIFE_FRAME + hit = 2 + else: + res = GenTypes.LIFE_VALUE + hit = 3 # 值类型(聚合/标量)局部变量:符号表登记的是入口块 alloca 指针(VarGenMixin.lookup_var), # 但读取这种变量就是**整块按值拷贝**,交出的是拷贝而非栈地址;当目标位置也是值类型 # (函数按值返回、赋值给值类型槽)时判 LIFE_VALUE。与上方裸数组名、下方 Call 分支的 @@ -1052,12 +1082,17 @@ novirtual class AssignGenMixin: # 此前只覆盖「裸数组名」,于是 `col: V3 = V3(...)` 后 `return col` 落到 get_var_life # 读回本帧 LIFE_FRAME,被 check_return_frame_decl 误报 LifetimeError。 # 只排除"变量值本身或目标位置是地址"的情形:`p: V3*` 的 `return p` 仍判帧生命期。 - if (inner is not None and target_ty is not None + elif (inner is not None and target_ty is not None and self.Gen.ExprGenBase.is_ptr_type(inner) == 0 and self.Gen.ExprGenBase.is_ptr_type(target_ty) == 0): - return GenTypes.LIFE_VALUE - # 指针变量/未定:读登记的生命期(默认 UNKNOWN) - return rg + res = GenTypes.LIFE_VALUE + hit = 4 + else: + hit = 5 + # [TEMP-DIAG] 只打"结果不是值拷贝"或"新增分支命中"的情况,避免刷屏(定位完删除) + if res != GenTypes.LIFE_VALUE or hit == 4: + self._life_diag_name(trans, nm.id, rg, v, target_ty, hit) + return res if k == ast.ASTKind.UnaryOp: uo: ast.UnaryOp* = ast.UnaryOp*(node) if uo.op == ast.OpKind.AddrOf and uo.operand is not None and uo.operand.kind() == ast.ASTKind.Name: @@ -1249,9 +1284,20 @@ novirtual class AssignGenMixin: if trans._cur_func is not None: rv_ty = mlirlite.function_get_ret_ty(trans._cur_func) # target_ty 必须传返回类型:裸本帧数组名在**指针**返回类型下是数组退让(交出栈地址), # 在同型聚合返回类型下是按值拷贝(LIFE_VALUE,不在此列)。 - if self.life_of_expr(trans, value, rv_ty) != GenTypes.LIFE_FRAME: return 0 + life_r: int = self.life_of_expr(trans, value, rv_ty) + if life_r != GenTypes.LIFE_FRAME: return 0 rk: int = GenApi.get_ret_kind_by_func(fd) if rk == GenApi.RET_KIND_FRAME: return 0 + # [TEMP-DIAG] 定义端拦截点输入(只在"判为帧生命期且未被 @life(ret(frame)) 放行"时打,定位完删除) + fn_d: str = None + if trans._cur_func is not None: fn_d = mlirlite.function_get_name(trans._cur_func) + if fn_d is None: fn_d = "?" + rvp: int = -1 + rvk: int = -1 + if rv_ty is not None: + rvp = self.Gen.ExprGenBase.is_ptr_type(rv_ty) + rvk = int(rv_ty.kind()) + stdio.printf("[RT-DIAG] fn=%s life=%d rk=%d rvptr=%d rvkind=%d\n", fn_d, life_r, rk, rvp, rvk) is_borrow_kind: int = 0 pi: int = -1 if rk >= GenApi.RET_KIND_BORROW_BASE: