fix(lifetime): 值类型变量按值拷贝判据改为双非指针(不再依赖类型打印比较),堆/静态登记优先

This commit is contained in:
TermiNexus committed 2026-10-15 21:47:30 +08:00
1 parent 6b86f846ca
commit 5dc483e256
1 file changed
+15 -10
+15 -10
View File
@@ -1035,24 +1035,29 @@ novirtual class AssignGenMixin:
if GenApi.is_nonlocal_name(trans, nm.id) != 0: return GenTypes.LIFE_UNKNOWN if GenApi.is_nonlocal_name(trans, nm.id) != 0: return GenTypes.LIFE_UNKNOWN
v: mlirlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) v: mlirlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
if v is None: return GenTypes.LIFE_STATIC if v is None: return GenTypes.LIFE_STATIC
# 变量已登记为堆/静态生命期(如 `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: if v.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(v.Ty) != 0:
inner: mlirlite.LLVMType* = v.Ty.Pointee inner: mlirlite.LLVMType* = v.Ty.Pointee
if inner is not None and inner.kind() == mlirlite.LLVMType.Array: 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 if target_ty is not None and self.Gen.ExprGenBase.is_ptr_type(target_ty) != 0: return GenTypes.LIFE_FRAME
return GenTypes.LIFE_VALUE return GenTypes.LIFE_VALUE
# 值类型(聚合)局部变量的存储是入口块 alloca(符号表登记的是 alloca 指针,见 # 值类型(聚合/标量)局部变量:符号表登记的是入口块 alloca 指针(VarGenMixin.lookup_var),
# VarGenMixin.lookup_var),但**目标位置是同型聚合值**时语义是值拷贝:交出的是整块 # 但读取这种变量就是**整块按值拷贝**,交出的是拷贝而非栈地址;当目标位置也是值类型
# 拷贝,与源帧无关 ⇒ LIFE_VALUE。与下方 Call 分支的裸构造 `T(...)` 同口径。 # (函数按值返回、赋值给值类型槽)时判 LIFE_VALUE。与上方裸数组名、下方 Call 分支的
# 此前只对「裸数组名(inner 是 Array)」给了这条口径,于是 `col: V3 = V3(...)` 后 # 裸构造 `T(...)` 同口径。
# `return col` 落到 get_var_life 读回本帧 LIFE_FRAME,被 check_return_frame_decl 误拦 # 此前只覆盖「裸数组名」,于是 `col: V3 = V3(...)` 后 `return col` 落到 get_var_life
# (LifetimeError: stack address escapes)。 # 读回本帧 LIFE_FRAME,被 check_return_frame_decl 误报 LifetimeError。
# 只排除"变量值本身或目标位置是地址"的情形:`p: V3*` 的 `return p` 仍判帧生命期。
if (inner is not None and target_ty is not None if (inner is not None and target_ty is not None
and self.Gen.ExprGenBase.is_ptr_type(target_ty) == 0 and self.Gen.ExprGenBase.is_ptr_type(inner) == 0
and self._stg_ty_equal(trans.Pool, inner, target_ty) != 0): and self.Gen.ExprGenBase.is_ptr_type(target_ty) == 0):
return GenTypes.LIFE_VALUE return GenTypes.LIFE_VALUE
# 指针/标量变量:读登记的生命期(默认 UNKNOWN) # 指针变量/未定:读登记的生命期(默认 UNKNOWN)
return self.Gen.VarGen.get_var_life(trans.SymTab, nm.id) return rg
if k == ast.ASTKind.UnaryOp: if k == ast.ASTKind.UnaryOp:
uo: ast.UnaryOp* = ast.UnaryOp*(node) 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: if uo.op == ast.OpKind.AddrOf and uo.operand is not None and uo.operand.kind() == ast.ASTKind.Name: