From 7ee6ebe6b03f43e38cc539568c82d3cb0850d852 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 15:14:31 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E7=B1=BB=E5=9E=8B=E8=BD=AC=E6=8D=A2):=20in?= =?UTF-8?q?t=E2=86=92i1=20=E7=9B=AE=E6=A0=87=E6=94=B9=E4=B8=BA=E7=9C=9F?= =?UTF-8?q?=E5=80=BC=E5=BD=92=E4=B8=80=E5=8C=96=20!=3D=200=EF=BC=8C?= =?UTF-8?q?=E4=B8=8E=20bool(x)/if=20=E6=9D=A1=E4=BB=B6=E5=90=8C=E5=88=A4?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类别:a(编译器缺陷)。TPC 侧此前对 i1 目标一律 trunc(取最低位):运行时值 2 → 最低位 0 → false,而同一值在 `if 2:` / `bool(2)`(icmp ne 0)为真 ⇒ 条件上下文与 落存储/强转两处结论相反(静默语义分裂)。 - MemoryOps._CoerceIntToI1(新增,唯一判据源):非 i1 整数 → `icmp ne x, 0`。 - MemoryOps._coerce_value:窄化且目标位宽 == 1 时走 _CoerceIntToI1。 - HandlesAnnAssign._StoreWithCoerce:同上(self.字段 / obj.字段 落存储)。 - HandlesExprCall._HandleTypeCastLlvm:显式强转目标 i1 时同上。 与 TransPyV 侧同批修复(coerce_to_type / _translate_t_type_cast)对齐。 注:TPC 的 `bool` 注解仍是 i8(t.CBool.Size=8),故 `b: bool = 2` 仍按 i8 保位存储 (int(b)=2);本次只覆盖**真 i1 目标**,双端 bool 位宽差异见 SymbolUtils.py:1218-1223 已记录的全局语义分裂。 --- lib/core/Handles/HandlesAnnAssign.py | 7 ++++++- lib/core/Handles/HandlesExprCall.py | 7 ++++++- lib/core/LLVMCG/MemoryOps.py | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 49edd1c..2c9ef8c 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -248,7 +248,12 @@ class AnnAssignHandle(BaseHandle): else Gen._ZeroConst(TargetType)) elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType): if TargetType.width < Value.type.width: - Value = Gen.builder.trunc(Value, TargetType, name="trunc") + # 目标 i1:真值归一化 `x != 0`(与 bool(x)/if 条件同一判据), + # 不是 trunc 取最低位(运行时值 2 会得 false,与 `if 2:` 相反) + if TargetType.width == 1: + Value = Gen._CoerceIntToI1(Value, name="bool_norm") + else: + Value = Gen.builder.trunc(Value, TargetType, name="trunc") else: Value = Gen.builder.zext(Value, TargetType, name="zext") elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType): diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 5216603..16daa92 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -2276,7 +2276,12 @@ class ExprCallHandle(BaseHandle): Gen._unsigned_results[id(result)] = True return result if val.type.width > target_type.width: - result = Gen.builder.trunc(val, target_type, name="trunc_cast") + # 目标 i1:真值归一化 `x != 0`(与 bool(x) 内建 / if 条件 / 落存储 + # 同一判据),不是 trunc 取最低位(运行时值 2 会得 false) + if target_type.width == 1: + result = Gen._CoerceIntToI1(val, name="bool_norm_cast") + else: + result = Gen.builder.trunc(val, target_type, name="trunc_cast") if is_dst_unsigned: Gen._unsigned_results[id(result)] = True return result diff --git a/lib/core/LLVMCG/MemoryOps.py b/lib/core/LLVMCG/MemoryOps.py index ccd7444..1340f4e 100644 --- a/lib/core/LLVMCG/MemoryOps.py +++ b/lib/core/LLVMCG/MemoryOps.py @@ -578,6 +578,21 @@ class MemoryOpsMixin: return self._load(GVar, name=name) return None + def _CoerceIntToI1(self, val: ir.Value, name: str = "bool_norm") -> ir.Value: + """整数 → **i1** 目标的真值归一化(C 6.3.1.2 `_Bool` 转换语义):`x != 0` → 1/0。 + + 判据与三处真值化上下文**同一**:`bool(x)` 内建(HandlesExprBuiltin.py:74/76)、 + 条件 `if/while`(HandlesIf.py:196)、`and/or` 操作数(HandlesExprOps.py:122-127)。 + 此前「落存储」(本文件 `_coerce_value`、HandlesAnnAssign._StoreWithCoerce)与 + 「显式强转」(HandlesExprCall._HandleTypeCastLlvm)对 i1 目标都走 `trunc` + (取最低位)⇒ 运行时值 2 得 0 → false,与 `if 2:` 的真值结论相反 + (静默语义分裂);值 3 得 true 而同值域下 `!= 0` 亦为 true,故只在偶数非零时暴露。 + 非整数 / 已是 i1 原样返回。 + """ + if not isinstance(val.type, ir.IntType) or val.type.width == 1: + return val + return self.builder.icmp_signed('!=', val, self._ZeroConst(val.type), name=name) + def _coerce_value(self, val: ir.Value, target_type: ir.Type, Node: Any = None) -> ir.Value | None: if val.type == target_type: return val @@ -593,6 +608,9 @@ class MemoryOpsMixin: return val if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.IntType): if target_type.width < val.type.width: + # 目标 i1:真值归一化(与 bool(x)/if 条件同一判据),不是 trunc 取最低位 + if target_type.width == 1: + return self._CoerceIntToI1(val, name="bool_norm_store") return self.builder.trunc(val, target_type, name="trunc_store") elif val.type.width == 1: # i1 是布尔值(来自 icmp/fcmp/__contains__ 归一化),无符号语义,