From 3b16334f5db49821540e98df240ab0db1872fe75 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 10 Oct 2026 21:57:25 +0800 Subject: [PATCH] =?UTF-8?q?feat(types):=20=E7=A6=81=E6=AD=A2=E9=9A=90?= =?UTF-8?q?=E5=BC=8F=E7=AA=84=E5=8C=96=EF=BC=88=E6=95=B4=E6=95=B0=20?= =?UTF-8?q?=E9=AB=98=E2=86=92=E4=BD=8E=EF=BC=89=E2=80=94=E2=80=94=5Fcoerce?= =?UTF-8?q?=5Fvalue=20=E4=B8=8E=20pointee=20=E5=88=A4=E6=8D=AE=E5=90=8C?= =?UTF-8?q?=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与 TransPyV 同口径:_coerce_value 的 int→int 窄化分支改为 fail-fast(隐式窄化禁止),仅豁免 ① 目标 i1 真值归一化 ② 编译期常量且值落进目标位宽;_ScalarConvertLossless 的 int↔int 改为 Dst.width>=Src.width。 --- lib/core/LLVMCG/MemoryOps.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/core/LLVMCG/MemoryOps.py b/lib/core/LLVMCG/MemoryOps.py index 7d5b685..1b609f5 100644 --- a/lib/core/LLVMCG/MemoryOps.py +++ b/lib/core/LLVMCG/MemoryOps.py @@ -198,7 +198,7 @@ class MemoryOpsMixin: @staticmethod def _ScalarConvertLossless(Src: Any, Dst: Any) -> bool: """基本标量「无损」判定(与 TransPyV `_scalar_convert_reason` 同口径,逐条照搬): - - 整数 ↔ 整数:**所有方向都允许**(高→低是安全降级;低→高无损); + - 整数 ↔ 整数:允许 ⇔ **目标位宽 ≥ 源位宽**(低→高无损;高→低是**有损窄化**,禁); - 浮点 ↔ 浮点:**所有方向都允许**; - 整数 → 浮点:允许 ⇔ **目标浮点位宽 ≥ 源整数位宽**(否则有损 → 禁); - 浮点 → 整数:**不允许**(有损 → 禁)。 @@ -213,9 +213,9 @@ class MemoryOpsMixin: d_int: bool = isinstance(Dst, ir.IntType) s_flt: int = _FloatBits(Src) d_flt: int = _FloatBits(Dst) - # 整数 ↔ 整数:高→低安全降级、低→高无损,均允许 + # 整数 ↔ 整数:低→高无损放行;高→低有损窄化,禁 if s_int and d_int: - return True + return Dst.width >= Src.width # 浮点 ↔ 浮点:允许 if s_flt and d_flt: return True @@ -656,7 +656,20 @@ class MemoryOpsMixin: # 目标 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") + # 隐式窄化**禁止**(规则 2026-10-10 收紧,取代"整数↔整数 所有方向都允许"): + # 位宽高→低会丢高位,必须显式 cast 或加宽目标类型。 + # 唯一豁免:源是**编译期常量且值落进目标位宽**(无信息损失)。 + if isinstance(val, ir.Constant) and isinstance(val.constant, int): + Lo: int = -(1 << (target_type.width - 1)) + Hi: int = (1 << target_type.width) - 1 + if Lo <= val.constant <= Hi: + return self.builder.trunc(val, target_type, name="trunc_const_store") + from lib.core.LLVMCG.FuncGen import FailFastError + raise FailFastError( + f"隐式窄化禁止:{val.type.width} 位整数不能隐式赋给 {target_type.width} 位类型" + f"(会丢高位);请显式转换(如 int32(x) / t.CInt32T(x))或把目标类型加宽" + f"{self._DescribeValueNode(Node)}" + ) elif val.type.width == 1: # i1 是布尔值(来自 icmp/fcmp/__contains__ 归一化),无符号语义, # 必须用 zext 而非 sext,否则 i1 的 1 会被符号扩展为 -1