From 2a798dd643a9a4e27e8cf07254b77ff1588b305d Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 15:14:32 +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=8D=E5=86=8D=20trunc=20=E5=8F=96=E6=9C=80=E4=BD=8E?= =?UTF-8?q?=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类别:a(编译器缺陷)。`b: bool = f()`(f 运行时返回偶数非零,如 2)此前经 coerce_to_type 的窄化分支走 trunc ⇒ 最低位 0 ⇒ false,而同一值在 `if 2:` / `bool(2)`(icmp ne 0)为真 —— 两处判据相反(静默语义分裂)。 - ExprGenBase.coerce_to_type:整数窄化分支前先判目标位宽 == 1 ⇒ `icmp ne x, 0` (C 6.3.1.2 的 _Bool 转换语义)。归一化不丢位,故对 i1 目标不再适用下方 「窄化截断溢出」常量诊断(先返回)——`b: bool = 2` 由编译期 OverflowError 变为正确的 true。 - CallGenCtor._translate_t_type_cast:显式 `t.CBool(x)` 与隐式落存储同一判据。 判据与 bool(x)(CallGenDispatch.vp:255-281)、条件归一化(AsyncGenMixin.vp:1611 _normalize_cond)、and/or 操作数三处统一。App/ 与 includes/ 全量检索未见 `: bool = …(& | >> | // | |)` 位提取写法,既有代码无依赖 trunc 取最低位的点。 生效需重新自举 TransPyV.exe(并清缓存)。 --- App/lib/core/Gen/Call/CallGenCtor.vp | 7 +++++++ App/lib/core/Gen/Expr/ExprGenBase.vp | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index 96e13d1..2d72794 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -686,6 +686,13 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): return llvmlite.build_zext(builder, val, target_ty) return llvmlite.build_sext(builder, val, target_ty) else: + # 目标 i1(bool / t.CBool):显式强转 `t.CBool(x)` 与隐式落存储 + # **同一判据** —— 真值归一化 `x != 0 → 1/0`(coerce_to_type 的同名 + # 分支、CallGenDispatch 的 bool(x)、条件归一化三处一致),不是 + # trunc(取最低位,会让 x=2 得 false 而 `if 2:` 为真)。 + if target_bits == 1: + zero_tc: llvmlite.Value* = llvmlite.const_int(pool, val_bits, 0) + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero_tc) return llvmlite.build_trunc(builder, val, target_ty) # 整数 → 浮点: sitofp diff --git a/App/lib/core/Gen/Expr/ExprGenBase.vp b/App/lib/core/Gen/Expr/ExprGenBase.vp index cf0a29b..c0b944b 100644 --- a/App/lib/core/Gen/Expr/ExprGenBase.vp +++ b/App/lib/core/Gen/Expr/ExprGenBase.vp @@ -865,6 +865,17 @@ novirtual class ExprGenBase: if val_bits != 0 and target_bits != 0: if val_bits == target_bits: return val + # 目标 i1(bool / t.CBool):**真值归一化** `x != 0 → 1/0`(C 6.3.1.2 的 + # _Bool 转换语义),不是 trunc(取最低位)。判据与 `bool(x)` + # (CallGenDispatch.vp:255-281)、条件归一化(AsyncGenMixin.vp:1611 + # _normalize_cond)、and/or 操作数三处**同一**:同一个运行时值 2 在 + # `if 2:` 里为真,赋给 bool 变量/字段/形参必须同样为真。此处此前走 trunc + # ⇒ 值 2 取最低位得 0 → false,与条件上下文结论相反(静默语义分裂); + # 值 3 得 true 而同值域下 `!= 0` 亦为 true,故只在偶数非零时暴露。 + # 归一化不丢位 ⇒ 下方「窄化截断溢出」常量诊断对 i1 目标不适用(先返回)。 + if target_bits == 1: + zero_i1: llvmlite.Value* = llvmlite.const_int(builder.Pool, val_bits, 0) + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero_i1) if val_bits < target_bits: # 统一 zext/sext(问题2修正):i1/i8 默认 zext;AST 节点解析为 # 无符号类型(t.CUIntXXT 强转/无符号类型名)走 zext;否则 sext。