From 5dc483e256efc1c45ab269679b4d83eff380625e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 15 Oct 2026 21:47:30 +0800 Subject: [PATCH] =?UTF-8?q?fix(lifetime):=20=E5=80=BC=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E6=8C=89=E5=80=BC=E6=8B=B7=E8=B4=9D=E5=88=A4?= =?UTF-8?q?=E6=8D=AE=E6=94=B9=E4=B8=BA=E5=8F=8C=E9=9D=9E=E6=8C=87=E9=92=88?= =?UTF-8?q?(=E4=B8=8D=E5=86=8D=E4=BE=9D=E8=B5=96=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=89=93=E5=8D=B0=E6=AF=94=E8=BE=83)=EF=BC=8C=E5=A0=86/?= =?UTF-8?q?=E9=9D=99=E6=80=81=E7=99=BB=E8=AE=B0=E4=BC=98=E5=85=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/core/Gen/AssignGenMixin.vp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 9c3397c..5bd63f2 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1035,24 +1035,29 @@ novirtual class AssignGenMixin: 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) 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: 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 - # 值类型(聚合)局部变量的存储是入口块 alloca(符号表登记的是 alloca 指针,见 - # VarGenMixin.lookup_var),但**目标位置是同型聚合值**时语义是值拷贝:交出的是整块 - # 拷贝,与源帧无关 ⇒ LIFE_VALUE。与下方 Call 分支的裸构造 `T(...)` 同口径。 - # 此前只对「裸数组名(inner 是 Array)」给了这条口径,于是 `col: V3 = V3(...)` 后 - # `return col` 落到 get_var_life 读回本帧 LIFE_FRAME,被 check_return_frame_decl 误拦 - # (LifetimeError: stack address escapes)。 + # 值类型(聚合/标量)局部变量:符号表登记的是入口块 alloca 指针(VarGenMixin.lookup_var), + # 但读取这种变量就是**整块按值拷贝**,交出的是拷贝而非栈地址;当目标位置也是值类型 + # (函数按值返回、赋值给值类型槽)时判 LIFE_VALUE。与上方裸数组名、下方 Call 分支的 + # 裸构造 `T(...)` 同口径。 + # 此前只覆盖「裸数组名」,于是 `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 - and self.Gen.ExprGenBase.is_ptr_type(target_ty) == 0 - and self._stg_ty_equal(trans.Pool, inner, target_ty) != 0): + 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 self.Gen.VarGen.get_var_life(trans.SymTab, nm.id) + # 指针变量/未定:读登记的生命期(默认 UNKNOWN) + return rg 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: