chore(diag): life 判定加全量诊断 [LIFE-DIAG]/[RT-DIAG] - 定位 return col 误判

This commit is contained in:
TermiNexus committed 2026-10-15 21:54:08 +08:00
1 parent 5dc483e256
commit cbadc356f9
1 file changed
+55 -9
+55 -9
View File
@@ -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: