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__ 归一化),无符号语义,