fix(cast): 无损口径对齐 TPV + 规则③豁免构造物化(p: Point = Point() 放行,真实 Foo*→Foo 仍禁)
_ScalarConvertLossless 改为与 TPV 一致:int↔int 全向允许、float↔float 全向允许、int→float 需目标浮点位宽≥源整数位宽、float→int 不允许(此前把整数↔浮点一律判有损,两侧不一致) 新增 _ValueNodeOf / _CtorCallStructType:指针→非基本值分支先豁免构造物化(Call 被调方命中 Gen.structs 且类型同一),其余保持禁止;报文前缀与 TPV 逐字一致;诊断沿用 _DescribeValueNode 已知未覆盖:TPC 无对称的“值→指针”检查;泛型构造不豁免;别名导入的类名可能命不中(保守不豁免,只误报不漏放)
This commit is contained in:
1 parent
d7158bd336
commit
9f8190d58f
1 file changed
+100
-21
+100
-21
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
from typing import Any
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
@@ -191,10 +192,11 @@ class MemoryOpsMixin:
|
||||
|
||||
@staticmethod
|
||||
def _ScalarConvertLossless(Src: Any, Dst: Any) -> bool:
|
||||
"""既有整数/浮点规则下的「无损」判定:同族且目标位宽 >= 源位宽。
|
||||
|
||||
整数→整数 / 浮点→浮点:按位宽(宽化无损、同宽无损、窄化有损);
|
||||
整数↔浮点:跨类别,一律视为非无损(有损)。
|
||||
"""基本标量「无损」判定(与 TransPyV `_scalar_convert_reason` 同口径,逐条照搬):
|
||||
- 整数 ↔ 整数:**所有方向都允许**(高→低是安全降级;低→高无损);
|
||||
- 浮点 ↔ 浮点:**所有方向都允许**;
|
||||
- 整数 → 浮点:允许 ⇔ **目标浮点位宽 ≥ 源整数位宽**(否则有损 → 禁);
|
||||
- 浮点 → 整数:**不允许**(有损 → 禁)。
|
||||
"""
|
||||
def _FloatBits(x: Any) -> int:
|
||||
if isinstance(x, ir.DoubleType):
|
||||
@@ -202,12 +204,22 @@ class MemoryOpsMixin:
|
||||
if isinstance(x, ir.FloatType):
|
||||
return 32
|
||||
return 0
|
||||
if isinstance(Src, ir.IntType) and isinstance(Dst, ir.IntType):
|
||||
return Dst.width >= Src.width
|
||||
sb: int = _FloatBits(Src)
|
||||
db: int = _FloatBits(Dst)
|
||||
if sb and db:
|
||||
return db >= sb
|
||||
s_int: bool = isinstance(Src, ir.IntType)
|
||||
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
|
||||
# 浮点 ↔ 浮点:允许
|
||||
if s_flt and d_flt:
|
||||
return True
|
||||
# 整数 → 浮点:目标浮点位宽 ≥ 源整数位宽才无损
|
||||
if s_int and d_flt:
|
||||
return d_flt >= Src.width
|
||||
# 浮点 → 整数:有损,禁止
|
||||
if s_flt and d_int:
|
||||
return False
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
@@ -218,7 +230,9 @@ class MemoryOpsMixin:
|
||||
① 通用指针(t.CPtr/i8*)为通配:与任何 T* **双向**互转放行(须同级)。
|
||||
② T* → U*(皆非通用):允许 ⇔ 被指类型 T → U 无损;非基本类型
|
||||
(结构体/类/联合)一律不允许 ⇒ Foo*→Bar* 禁止。
|
||||
③ 非基本类型 T 与 T* 之间的隐式转换(Foo ↔ Foo*)一律禁止(层数不同)。
|
||||
③ 非基本类型 T 与 T* 之间的隐式转换(Foo ↔ Foo*)一律禁止(层数不同);
|
||||
**唯一例外**是「构造物化」——该豁免需 AST 层判据,故在 coerce 调用点
|
||||
由 _CtorCallStructType 单独放行(本判据只给出「禁」的结论)。
|
||||
④ 完全相同类型不算转换 ⇒ 放行。
|
||||
Reason 供报文说明「哪一级不允许 + 原因(非基本类型/有损/层数不同)」。
|
||||
"""
|
||||
@@ -249,6 +263,58 @@ class MemoryOpsMixin:
|
||||
return (False, '指针与标量(须显式 cast)')
|
||||
return (False, '非基本类型(结构体/类/联合)')
|
||||
|
||||
@staticmethod
|
||||
def _ValueNodeOf(Node: Any = None) -> Any:
|
||||
"""把「外层语句节点」下沉到其「值子表达式节点」(与 TransPyV _value_node_of 同口径)。
|
||||
|
||||
Assign/AnnAssign/AugAssign/Expr/Return 取 .value;非语句节点原样返回。
|
||||
规则③的「构造物化」豁免须看到**真正被转换的那个右值表达式**(如 `p: Point = Point()`
|
||||
里的 `Point()`),而 coerce 入口常收到外层语句节点,故统一在此下沉。
|
||||
"""
|
||||
if Node is None:
|
||||
return None
|
||||
if isinstance(Node, ast.Assign):
|
||||
return Node.value
|
||||
if isinstance(Node, ast.AnnAssign):
|
||||
return Node.value
|
||||
if isinstance(Node, ast.AugAssign):
|
||||
return Node.value
|
||||
if isinstance(Node, ast.Expr):
|
||||
return Node.value
|
||||
if isinstance(Node, ast.Return):
|
||||
return Node.value
|
||||
return Node
|
||||
|
||||
def _CtorCallStructType(self, Node: Any = None) -> Any:
|
||||
"""AST 层判定:Node(或其值子节点)是否为「类/构造调用」右值;是则返回其构造的
|
||||
聚合类型(IdentifiedStruct/LiteralStruct),否则返回 None。
|
||||
|
||||
规则③(非基本类型值 ↔ 指针隐式转换一律禁止)的**唯一例外**是「构造物化」:
|
||||
右值来自该类型的构造调用时放行(构造语义,非类型转换)。判据复用本仓既有的
|
||||
「Call 的被调方是类/构造」口径(见 HandlesExprCall._HandleCallLlvm 的分派):
|
||||
- callee 裸名/属性名命中已注册类(`Gen.structs`)→ 构造;
|
||||
- 泛型类模板特化(Box(42))需类型实参推断,静态取不到类型 → 保守返回 None。
|
||||
"""
|
||||
N: Any = MemoryOpsMixin._ValueNodeOf(Node)
|
||||
if not isinstance(N, ast.Call):
|
||||
return None
|
||||
Func: Any = getattr(N, 'func', None)
|
||||
ClassName: str | None = None
|
||||
if isinstance(Func, ast.Name):
|
||||
ClassName = Func.id
|
||||
elif isinstance(Func, ast.Attribute):
|
||||
ClassName = Func.attr
|
||||
if not ClassName:
|
||||
return None
|
||||
ST: Any = getattr(self, 'structs', {}).get(ClassName)
|
||||
if ST is None:
|
||||
return None
|
||||
if isinstance(ST, ir.PointerType):
|
||||
ST = ST.pointee
|
||||
if not isinstance(ST, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
return None
|
||||
return ST
|
||||
|
||||
def _alloca(self, typ: ir.Type, name: str = '', align: int | None = None, size: ir.Value | None = None) -> ir.AllocaInstr:
|
||||
if align is None:
|
||||
align = self._get_align(typ)
|
||||
@@ -434,16 +500,29 @@ class MemoryOpsMixin:
|
||||
# 指针→非指针值的隐式 load(结构体/数组按值回读)属类型信息缺失,
|
||||
# 须显式解引用(c.Deref(p) / *p)或显式强转。基本标量目标已在上方
|
||||
# 「指针隐式转整数」分支 fail-fast,此处只兜非基本类型。
|
||||
Allowed3: bool
|
||||
Reason3: str
|
||||
Allowed3, Reason3 = self._ClassifyPtrImplicitConvert(val.type, target_type)
|
||||
if not Allowed3:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转换已禁止({Reason3}):不能把指针类型 {val.type} 隐式转为 {target_type};"
|
||||
f"如需转换请显式 cast(解引用 c.Deref(p) / *p,或显式强转)"
|
||||
f"{self._DescribeValueNode(Node)}"
|
||||
)
|
||||
# **唯一例外=「构造物化」**:右值来自该类型的构造调用时放行,如
|
||||
# `p: Point = Point()`(参照 GCC 构造语义:这是构造,不是类型转换)。
|
||||
CtorST: Any = self._CtorCallStructType(Node)
|
||||
CtorExempt: bool = False
|
||||
if CtorST is not None:
|
||||
if CtorST == target_type:
|
||||
CtorExempt = True
|
||||
elif (isinstance(CtorST, ir.IdentifiedStructType)
|
||||
and isinstance(target_type, ir.IdentifiedStructType)
|
||||
and CtorST.name == target_type.name):
|
||||
CtorExempt = True
|
||||
if not CtorExempt:
|
||||
Allowed3: bool
|
||||
Reason3: str
|
||||
Allowed3, Reason3 = self._ClassifyPtrImplicitConvert(val.type, target_type)
|
||||
if not Allowed3:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"非基本类型的值/指针隐式转换已禁止(构造物化除外,{Reason3}):"
|
||||
f"不能把指针类型 {val.type} 隐式转为值类型 {target_type};"
|
||||
f"如需解引用请显式 c.Deref(p) / *p,或显式强转"
|
||||
f"{self._DescribeValueNode(Node)}"
|
||||
)
|
||||
if val.type.pointee == target_type:
|
||||
return self.builder.load(val, name="Load_struct_for_store")
|
||||
if isinstance(val.type.pointee, ir.IdentifiedStructType) and isinstance(target_type, ir.IdentifiedStructType):
|
||||
|
||||
Reference in new issue
Block a user