fix(tpc): >> 符号性只按左操作数判定,去掉“残留变量名”误判(负数右移发成 lshr)

- 现场:`b: int64 = -196608; b >> 1` 发成 lshr ⇒ 负数变大正数;而同样注解的 `c: int64 = 0 - 196608; c >> 1` 却正确 ⇒ 与 RHS/位置相关(IntWidthTest Test 5/6)

- 根因:emit_binary_op 在 i32/i64 分支又用 self._last_var_name 重判符号性,而它只是“最近见过的变量名”,可能是上一条表达式残留的别的(无符号)变量 ⇒ 误判无符号

- 改动:① ExprGen.emit_binary_op 删除 i32/i64 的 _last_var_name 分支(符号性只信调用方;i8/i16 仍按宽度定无符号);② HandlesExprOps 的 `>>` 改用 _check_node_unsigned(Node.left),覆盖 Name 之外的形态

- 验收:Test/IntWidthTest(Test 5/6),目标 TPC 侧 9/9 PASS
This commit is contained in:
TermiNexus committed 2026-10-14 20:18:26 +08:00
1 parent 23b47053d9
commit 55a6856c4e
2 files changed
+11 -9

No files matched your search

+5 -3
View File
@@ -140,9 +140,11 @@ class ExprOpsHandle(BaseHandle):
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
elif RightVal.type.width > LeftVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
vname: str = Node.left.id
if vname in Gen.var_signedness and Gen.var_signedness[vname]:
# `>>` 的符号性按**左操作数**判定:Name 之外的形态(字段/下标/表达式)也要覆盖。
# 注意不要退回 emit_binary_op 里那个“残留变量名”判据(已移除,见 ExprGen.emit_binary_op):
# b: int64 = -196608; b >> 1 曾是误判成 lshr 的现场(IntWidthTest Test 5/6)。
if Op in ('>>', 'RShift'):
if Gen._check_node_unsigned(Node.left):
is_unsigned = True
# 双指针算术 fail-fast 已**下沉到单一收敛点** `Gen.emit_binary_op`
# (LLVMCG/ExprGen.py):BinOp 与 AugAssign(+=、-=、*= …)都经该函数,
+6 -6
View File
@@ -179,12 +179,12 @@ class ExprGenMixin:
is_unsigned = True
elif left.type.width == 16:
is_unsigned = True
elif left.type.width == 32:
if self._last_var_name:
is_unsigned = self._is_var_unsigned(self._last_var_name)
elif left.type.width == 64:
if self._last_var_name:
is_unsigned = self._is_var_unsigned(self._last_var_name)
# i32/i64 的符号性**只由调用方按左操作数判定**(调用方拿得到 Node.left,
# 见 HandlesExprOps / HandlesAugAssign)。此前这里又用 self._last_var_name
# 判一次,而它只是“最近见过的变量名”,可能是**上一条表达式残留的别的变量**:
# b: int64 = -196608
# b >> 1 # 若残留名恰好是某个无符号变量(t.CSizeT 等) ⇒ 误判无符号 ⇒ lshr
# 结果:负数右移变大正数(IntWidthTest Test 5/6 的 FAIL 即此)。
shift_ops: dict[str, Any] = {
'>>': self.builder.lshr if is_unsigned else self.builder.ashr,
'RShift': self.builder.lshr if is_unsigned else self.builder.ashr,