From 3b5d85ce9d54bc770d6a778893507d6d31d0ece4 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sun, 27 Sep 2026 00:19:44 +0800 Subject: [PATCH] =?UTF-8?q?fix(handles):=20=E8=A1=A5=E6=8C=87=E9=92=88?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E7=AC=A6=E7=9B=AE=E6=A0=87=E5=86=99=E5=85=A5?= =?UTF-8?q?=E4=B8=8E=E5=AE=9E=E5=8F=82=E8=A7=A3=E5=BC=95=E7=94=A8=EF=BC=8C?= =?UTF-8?q?=E6=B6=88=E9=99=A4=E9=9D=99=E9=BB=98=E4=B8=A2=E5=BC=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HandlesAssign: 新增 ast.UnaryOp 赋值目标分支(*p = v 复用 _StoreWithCoerce);Tuple/List 目标合并;删除 Tuple 分支里未绑定的死代码(UnboundLocalError) - HandlesAugAssign: 新增 ast.UnaryOp 目标分支实现真 *p += v,其余形态 fail-fast - HandlesExpr: 新增 ast.Starred 分支,值位置 *p 归一为 UnaryOp(Deref)(修 t.CPtr(*((uint64*)(blk))) 恒为 0) --- lib/core/Handles/HandlesAssign.py | 44 ++++++++++++++++++++-- lib/core/Handles/HandlesAugAssign.py | 56 +++++++++++++++++++++++++++- lib/core/Handles/HandlesExpr.py | 12 ++++++ 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index d3c536d..8547f17 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -492,7 +492,42 @@ class AssignHandle(BaseHandle): self._RaiseUnresolvedExpr("下标写入", Node.value, Gen) return self._HandleSubscriptStoreLlvm(Target, Value) - elif isinstance(Target, ast.Tuple): + elif isinstance(Target, ast.UnaryOp): + # 解引用写入 `*p = v`(与读侧同一节点形态)。 + # 解析链:语句级 Assign 走 vast_c.c ParseSimpleStmt 的 + # ParseExprList + SetStoreContext;`*p` 由 ParseFactor 产出 + # UnaryOp(op=Deref)(与 `*p` 读侧完全同形),而 SetStoreContext 只改 + # Attribute/Subscript/Name/Tuple/List/Starred 的 ctx,**不改 UnaryOp** + # ⇒ 赋值目标就是 UnaryOp(Deref)。 + # 此前本分派(Name/Attribute/Subscript/Tuple)无 UnaryOp 分支且无兜底 + # ⇒ 该语句被整条静默丢弃(既不落盘也不报错):memhub 的块头 + # `(order<<1)|1`、空闲链 next、canary 三处写入全不发射 ⇒ 块头恒为 0 + # (free 被拒)、free_lists 链读到未初始化 0xBE、池单调漏满 ⇒ 1 GiB OOM。 + # `&x`/`-x`/`~x` 作目标不是合法左值,故除 Deref 外一律 fail-fast。 + if not isinstance(Target.op, ast.Deref): + BadOp: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Target.op) + raise Exception( + f"赋值目标只支持单目 '*' 解引用('{BadOp}' 不是合法左值)" + f"{Gen._get_node_info()}" + ) + Ptr: ir.Value | None = self.HandleExprLlvm(Target.operand) + if Ptr is None: + self._RaiseUnresolvedExpr("解引用写入", Target.operand, Gen) + return + if not isinstance(Ptr.type, ir.PointerType): + raise Exception( + f"解引用赋值 '*' 的操作数必须是指针类型(类型推断退化," + f"实际 {Ptr.type}){Gen._get_node_info()}" + ) + DerefValue: ir.Value | None = self.HandleExprLlvm(Node.value) + if DerefValue is None: + self._RaiseUnresolvedExpr("解引用写入", Node.value, Gen) + return + self._StoreWithCoerce(DerefValue, Ptr) + elif isinstance(Target, (ast.Tuple, ast.List)): + # ast.List 与 ast.Tuple 字段表逐字相同(Nodes.py:119-120 均为 + # ('elts', 'ctx')),故 `[a, b] = f()` 与 `a, b = f()` 共用本分支。 + # 此前只认 Tuple ⇒ List 目标落入无分支区被静默丢弃(不落盘、不报错)。 if isinstance(Node.value, ast.Call): FuncName: str | None = None ModulePath: str | None = None @@ -586,8 +621,11 @@ class AssignHandle(BaseHandle): if isinstance(ret_type, ir.LiteralStructType): CReturnTypes = [None] * len(ret_type.elements) if CReturnTypes and len(Target.elts) == len(CReturnTypes): - if func is None: - func = Gen.functions.get(FuncName) + # 注:此处原有两行 `if func is None: func = ...`,但 func 只在上面 + # 「not CReturnTypes」分支里绑定;当 CReturnTypes 来自返回注解 + # (`-> tuple[T1, T2]`)时该分支未执行 ⇒ UnboundLocalError 崩溃。 + # 且紧接着的 `func = Gen.functions.get(FuncName)` 本就覆盖它, + # 故直接删除(`a, b = f()` 因此从未真正跑通)。 CallArgs: list[ir.Value | None] = [] for arg in Node.value.args: ArgVal: ir.Value | None = self.HandleExprLlvm(arg) diff --git a/lib/core/Handles/HandlesAugAssign.py b/lib/core/Handles/HandlesAugAssign.py index b32e0c2..a061ce1 100644 --- a/lib/core/Handles/HandlesAugAssign.py +++ b/lib/core/Handles/HandlesAugAssign.py @@ -239,4 +239,58 @@ class AugAssignHandle(BaseHandle): if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType): if NewVal.type.width > ElemPtr.type.pointee.width: NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result") - Gen._store(NewVal, ElemPtr) \ No newline at end of file + Gen._store(NewVal, ElemPtr) + elif isinstance(Node.target, ast.UnaryOp): + # 解引用增强赋值 `*p += v`:目标节点是 UnaryOp(Deref) + # (SetStoreContext 不改 UnaryOp 的 ctx),与 `*p = v` 同一形态。 + # 流程:操作数求值取指针 → load 当前值 → 二元运算 → store 回同址。 + if not isinstance(Node.target.op, ast.Deref): + BadOp: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.target.op) + raise Exception( + f"AugAssign 目标只支持单目 '*' 解引用('{BadOp}' 不是合法左值)" + f"{Gen._get_node_info()}" + ) + DerefPtr: ir.Value | None = self.HandleExprLlvm(Node.target.operand) + if DerefPtr is None: + raise Exception(f"解引用增量赋值 '*' 的操作数无法求值{Gen._get_node_info()}") + if not isinstance(DerefPtr.type, ir.PointerType): + raise Exception( + f"解引用增量赋值 '*' 的操作数必须是指针类型(实际 {DerefPtr.type})" + f"{Gen._get_node_info()}" + ) + DerefOp: str = self.Trans.ExprHandler.GetOpSymbol(Node.op) + DerefOld: ir.Value = Gen._load(DerefPtr, name="old_deref_val") + if isinstance(DerefOld.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if DerefOld.type.width < Value.type.width: + DerefOld = Gen.builder.zext(DerefOld, Value.type, name="zext_left_deref") + elif DerefOld.type.width > Value.type.width: + Value = Gen.builder.zext(Value, DerefOld.type, name="zext_right_deref") + elif isinstance(DerefOld.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if DerefOp in ('+', '-'): + if Value.type.width < 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_deref") + OffVal: ir.Value + if DerefOp == '-': + OffVal = Gen.builder.gep(DerefOld, [Gen.builder.neg(Value, name="neg_ptr_offset_deref")], name="ptr_sub_deref") + else: + OffVal = Gen.builder.gep(DerefOld, [Value], name="ptr_add_deref") + Gen._store(OffVal, DerefPtr) + return + DerefNew: ir.Value = Gen.emit_binary_op(DerefOp, DerefOld, Value, is_unsigned=is_unsigned, is_aug=True) + if isinstance(DerefNew.type, ir.IntType) and isinstance(DerefPtr.type.pointee, ir.IntType): + if DerefNew.type.width > DerefPtr.type.pointee.width: + DerefNew = Gen.builder.trunc(DerefNew, DerefPtr.type.pointee, name="trunc_deref_result") + Gen._store(DerefNew, DerefPtr) + else: + # fail-fast:目标形态未覆盖时绝不静默丢弃(对齐 TransPyV + # translate_augassign 的同名 fail-fast),避免"语句被整条丢掉、 + # 变量静默不变"。 + TargetOp: str | None = None + if isinstance(Node.target, ast.UnaryOp): + TargetOp = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.target.op) + raise Exception( + f"AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript/*解引用" + f"(当前 {type(Node.target).__name__}" + + (f" op='{TargetOp}'" if TargetOp else "") + + f"){Gen._get_node_info()}" + ) \ No newline at end of file diff --git a/lib/core/Handles/HandlesExpr.py b/lib/core/Handles/HandlesExpr.py index 2b631cb..30d7f36 100644 --- a/lib/core/Handles/HandlesExpr.py +++ b/lib/core/Handles/HandlesExpr.py @@ -76,6 +76,18 @@ class ExprHandle(BaseHandle): return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node) elif isinstance(Node, ast.UnaryOp): return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node) + elif isinstance(Node, ast.Starred): + # `*p` 出现在值位置(典型:调用实参 `f(*p)`):C/Python 解析器都按 + # Python `*args` 语义归类为 Starred(Load)(vast_c.c ParseCallTail、 + # ExprParser.py:543-548)。Viper 未实现解包 ⇒ 与 `*p` 读侧对齐,一律 + # 归一为 UnaryOp(Deref) 解引用读取(与 TransPyV ExprGenMixin 的同类归一 + # 逐字同口径)。此前无本分支 ⇒ 落到函数末尾兜底 `return i32 0`, + # 把 `f(*p)` 静默变成 `f(0)`。 + StarredInner: ast.expr | None = Node.value + if StarredInner is None: + raise Exception(f"值位置的单目 '*' 缺少操作数{Gen._get_node_info()}") + return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm( + ast.UnaryOp(op=ast.Deref(), operand=StarredInner)) elif isinstance(Node, ast.Call): return self.Trans.ExprCallHandle._HandleCallLlvm(Node) elif isinstance(Node, ast.Await):