fix(handles): 补指针操作符目标写入与实参解引用,消除静默丢弃
- 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)
This commit is contained in:
1 parent
58050a1ab2
commit
3b5d85ce9d
3 files changed
+108
-4
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
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()}"
|
||||
)
|
||||
@@ -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):
|
||||
|
||||
Reference in new issue
Block a user