feat(cast): 指针隐式转换新规则 + None 可隐式转任意类型 + 诊断错位修复(9 文件)
MemoryOps._ClassifyPtrImplicitConvert:同类型放行;层数不同禁;任一侧通用指针(i8*)放行;皆非通用按被指类型(非基本类型禁、基本标量按位宽无损);指针与非基本值互换禁 _IsNoneValue 收敛:AST None 常量 或 指针型 null 常量 → 放行任意目标(指针目标给 null,非指针目标给零值);整数 0 不误命中;短路口覆盖 9 处禁令 诊断:新增 BaseGen._DescribeValueNode(子表达式下沉 + 有符号列号 + 源码片段),9 处禁令统一使用,不再打印外层 Assign 与 4294967295 列号 注:TPC 侧规则③比 TPV 更严(指针→非基本值恒禁),可能与既有按值回读冲突;待实机编译确认后再统一两侧口径
This commit is contained in:
1 parent
35de6321f6
commit
d7158bd336
9 files changed
+318
-66
No files matched your search
@@ -218,31 +218,43 @@ class AnnAssignHandle(BaseHandle):
|
||||
self._StoreWithCoerce(Value, MemberPtr)
|
||||
break
|
||||
|
||||
def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value) -> None:
|
||||
def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value, Node: ast.AST | None = None) -> None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if isinstance(Ptr.type, ir.PointerType):
|
||||
TargetType: ir.Type = Ptr.type.pointee
|
||||
if Value.type != TargetType:
|
||||
if isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
# None(空值常量)允许隐式转换为任意字段类型:指针→空指针,其余→零值。
|
||||
if Gen._IsNoneValue(Value, Node):
|
||||
Value = (ir.Constant(TargetType, None) if isinstance(TargetType, ir.PointerType)
|
||||
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")
|
||||
else:
|
||||
Value = Gen.builder.zext(Value, TargetType, name="zext")
|
||||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType):
|
||||
Allowed: bool
|
||||
Reason: str
|
||||
Allowed, Reason = Gen._ClassifyPtrImplicitConvert(Value.type, TargetType)
|
||||
if not Allowed:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转换已禁止({Reason}):不能把指针类型 {Value.type} 隐式转为 {TargetType};"
|
||||
f"如需转换请显式 cast(如 t.CPtr(...))"
|
||||
f"{Gen._DescribeValueNode(Node)}"
|
||||
)
|
||||
Value = Gen.builder.bitcast(Value, TargetType, name="ptr_bitcast")
|
||||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
Value = Gen.builder.inttoptr(Value, TargetType, name="int_to_ptr")
|
||||
elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.PointerType):
|
||||
if isinstance(Value, ir.Constant) and Value.constant is None:
|
||||
# null 指针常量赋给整数字段 → 0(C 空指针常量语义)
|
||||
Value = ir.Constant(TargetType, 0)
|
||||
else:
|
||||
# 指针 → 整数:隐式转换一律禁止(与 TransPyV coerce_to_type 同口径)
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:不能把指针类型 {Value.type} 赋给整数类型 {TargetType};"
|
||||
f"如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
)
|
||||
# 指针 → 整数:隐式转换一律禁止(与 TransPyV coerce_to_type 同口径)
|
||||
# (None 已在上方短路为零值,不会落到这里)。
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:不能把指针类型 {Value.type} 赋给整数类型 {TargetType};"
|
||||
f"如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{Gen._DescribeValueNode(Node)}"
|
||||
)
|
||||
Gen._store(Value, Ptr)
|
||||
|
||||
def _HandleGenericListLiteralAssign(self, VarName: str, Node: ast.AnnAssign, Gen: LlvmCodeGenerator, list_sub: ast.Subscript) -> None:
|
||||
@@ -892,29 +904,42 @@ class AnnAssignHandle(BaseHandle):
|
||||
if InitValue:
|
||||
try:
|
||||
if InitValue.type != VarType:
|
||||
if isinstance(InitValue.type, ir.IntType) and isinstance(VarType, ir.IntType):
|
||||
if Gen._IsNoneValue(InitValue, Node.value):
|
||||
# None(空值常量)允许隐式转换为任意变量类型:
|
||||
# 指针→空指针,其余→零值(整数 0 / 浮点 0.0 / 聚合 zeroinitializer)。
|
||||
InitValue = (ir.Constant(VarType, None) if isinstance(VarType, ir.PointerType)
|
||||
else Gen._ZeroConst(VarType))
|
||||
elif isinstance(InitValue.type, ir.IntType) and isinstance(VarType, ir.IntType):
|
||||
if VarType.width > InitValue.type.width:
|
||||
InitValue = Gen.builder.zext(InitValue, VarType, name=f"zext_{VarName}")
|
||||
elif VarType.width < InitValue.type.width:
|
||||
InitValue = Gen.builder.trunc(InitValue, VarType, name=f"trunc_{VarName}")
|
||||
elif isinstance(InitValue.type, ir.PointerType) and isinstance(VarType, ir.PointerType):
|
||||
Allowed: bool
|
||||
Reason: str
|
||||
Allowed, Reason = Gen._ClassifyPtrImplicitConvert(InitValue.type, VarType)
|
||||
if not Allowed:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转换已禁止({Reason}):不能用指针类型 {InitValue.type} 初始化 "
|
||||
f"{VarName}: {VarType};如需转换请显式 cast(如 t.CPtr(...))"
|
||||
f"{Gen._DescribeValueNode(Node.value)}"
|
||||
)
|
||||
InitValue = Gen.builder.bitcast(InitValue, VarType, name=f"cast_{VarName}")
|
||||
elif isinstance(VarType, ir.PointerType) and isinstance(InitValue.type, ir.IntType):
|
||||
InitValue = Gen.builder.inttoptr(InitValue, VarType, name=f"int2ptr_{VarName}")
|
||||
elif isinstance(VarType, ir.IntType) and isinstance(InitValue.type, ir.PointerType):
|
||||
if isinstance(InitValue, ir.Constant) and InitValue.constant is None:
|
||||
# null 指针常量初始化整数变量 → 0(C 空指针常量语义)
|
||||
InitValue = ir.Constant(VarType, 0)
|
||||
else:
|
||||
# 指针 → 整数:隐式转换一律禁止(与 TransPyV coerce_to_type 同口径)
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:不能用指针类型 {InitValue.type} 初始化整数变量 "
|
||||
f"{VarName}: {VarType};如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
)
|
||||
# 指针 → 整数:隐式转换一律禁止(与 TransPyV coerce_to_type 同口径)
|
||||
# (None 已在上方短路为零值,不会落到这里)。
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:不能用指针类型 {InitValue.type} 初始化整数变量 "
|
||||
f"{VarName}: {VarType};如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{Gen._DescribeValueNode(Node.value)}"
|
||||
)
|
||||
# 大端局部变量:存储时 bswap
|
||||
InitValue = Gen._apply_bswap_if_big(InitValue, TypeInfo.ByteOrder, f"bswap_store_{VarName}")
|
||||
Gen._store(InitValue, var)
|
||||
Gen._store(InitValue, var, Node=Node.value)
|
||||
except (TypeError, ValueError) as _e:
|
||||
# 仅回退 llvmlite 自身的类型/值错误;FailFastError 等一律上抛(不吞)
|
||||
if _config_mode == "strict":
|
||||
|
||||
@@ -365,23 +365,23 @@ class AssignHandle(BaseHandle):
|
||||
Loaded_differ = False
|
||||
if Loaded_differ:
|
||||
try:
|
||||
Coerced: ir.Value | None = Gen._coerce_value(LoadedValue, TargetType)
|
||||
Coerced: ir.Value | None = Gen._coerce_value(LoadedValue, TargetType, Node.value)
|
||||
if Coerced is not None:
|
||||
LoadedValue = Coerced
|
||||
except AssertionError:
|
||||
pass
|
||||
Gen._store(LoadedValue, VarPtr)
|
||||
Gen._store(LoadedValue, VarPtr, Node=Node.value)
|
||||
elif types_differ:
|
||||
try:
|
||||
Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType)
|
||||
Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType, Node.value)
|
||||
if Coerced is not None:
|
||||
Gen._store(Coerced, VarPtr)
|
||||
Gen._store(Coerced, VarPtr, Node=Node.value)
|
||||
else:
|
||||
Gen._store(Value, VarPtr)
|
||||
Gen._store(Value, VarPtr, Node=Node.value)
|
||||
except AssertionError:
|
||||
Gen._store(Value, VarPtr)
|
||||
Gen._store(Value, VarPtr, Node=Node.value)
|
||||
else:
|
||||
Gen._store(Value, VarPtr)
|
||||
Gen._store(Value, VarPtr, Node=Node.value)
|
||||
if VarName not in Gen.variables:
|
||||
# 检查是否为模块级全局变量
|
||||
# main 函数代表模块级作用域,直接修改全局变量
|
||||
@@ -391,12 +391,12 @@ class AssignHandle(BaseHandle):
|
||||
IsMainScope: bool = CurrentFuncName == 'main' or CurrentFuncName.endswith('.main')
|
||||
if VarName in Gen.module.globals and (VarName in Gen.global_vars or IsMainScope):
|
||||
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
|
||||
Gen._store(Value, GVar)
|
||||
Gen._store(Value, GVar, Node=Node.value)
|
||||
Gen.variables[VarName] = GVar
|
||||
elif isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType):
|
||||
LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}")
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(LoadedValue.type, name=VarName)
|
||||
Gen._store(LoadedValue, var)
|
||||
Gen._store(LoadedValue, var, Node=Node.value)
|
||||
Gen.variables[VarName] = var
|
||||
else:
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
|
||||
@@ -523,7 +523,7 @@ class AssignHandle(BaseHandle):
|
||||
if DerefValue is None:
|
||||
self._RaiseUnresolvedExpr("解引用写入", Node.value, Gen)
|
||||
return
|
||||
self._StoreWithCoerce(DerefValue, Ptr)
|
||||
self._StoreWithCoerce(DerefValue, Ptr, Node.value)
|
||||
elif isinstance(Target, (ast.Tuple, ast.List)):
|
||||
# ast.List 与 ast.Tuple 字段表逐字相同(Nodes.py:119-120 均为
|
||||
# ('elts', 'ctx')),故 `[a, b] = f()` 与 `a, b = f()` 共用本分支。
|
||||
@@ -1300,13 +1300,15 @@ class AssignHandle(BaseHandle):
|
||||
MemberPtr: ir.Value = Gen.builder.gep(LoadedPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||||
self._StoreWithCoerce(Value, MemberPtr)
|
||||
|
||||
def _StoreArrElemWithCoerceBswap(self, Value: ir.Value, Ptr: ir.Value, arr_byte_order: str) -> None:
|
||||
def _StoreArrElemWithCoerceBswap(self, Value: ir.Value, Ptr: ir.Value, arr_byte_order: str,
|
||||
Node: ast.AST | None = None) -> None:
|
||||
"""对数组元素存储应用 bswap 后再 coerce 存储"""
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
Value = Gen._apply_bswap_if_big(Value, arr_byte_order, "bswap_arr_store")
|
||||
self._StoreWithCoerce(Value, Ptr)
|
||||
self._StoreWithCoerce(Value, Ptr, Node)
|
||||
|
||||
def _HandleSubscriptStoreLlvm(self, Target: ast.Subscript, Value: ir.Value) -> None:
|
||||
def _HandleSubscriptStoreLlvm(self, Target: ast.Subscript, Value: ir.Value,
|
||||
Node: ast.AST | None = None) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
# pointee-volatile 基址名后缀(与 HandlesExprAttr._HandleSubscriptLlvm 同款);
|
||||
# 空后缀 ⇒ 下标 GEP 名仍是 "subscript",既有代码 IR 逐字节不变。
|
||||
@@ -1382,7 +1384,7 @@ class AssignHandle(BaseHandle):
|
||||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store")
|
||||
ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name=f"subscript{_PVSuffix}")
|
||||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order)
|
||||
self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order, Node)
|
||||
return
|
||||
if isinstance(ValueVal.type, ir.PointerType):
|
||||
pointee: ir.Type = ValueVal.type.pointee
|
||||
@@ -1531,12 +1533,16 @@ class AssignHandle(BaseHandle):
|
||||
f"(`rawptr[T] | t.CPtr` 或 `rawptr[rawptr[T]]`)后再赋值;"
|
||||
f"或把基座显式转为 t.CPtr(无类型指针)后按 8 字节指针语义写入。{SrcInfo}")
|
||||
|
||||
def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value) -> None:
|
||||
def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value, Node: ast.AST | None = None) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Ptr.type, ir.PointerType):
|
||||
TargetType: ir.Type = Ptr.type.pointee
|
||||
if Value.type != TargetType:
|
||||
if isinstance(TargetType, ir.ArrayType) and isinstance(Value.type, ir.PointerType):
|
||||
if Gen._IsNoneValue(Value, Node):
|
||||
# None(空值常量)允许隐式转换为任意目标类型:指针→空指针,其余→零值。
|
||||
Value = (ir.Constant(TargetType, None) if isinstance(TargetType, ir.PointerType)
|
||||
else Gen._ZeroConst(TargetType))
|
||||
elif isinstance(TargetType, ir.ArrayType) and isinstance(Value.type, ir.PointerType):
|
||||
ElemType: ir.Type = TargetType.element
|
||||
ElemSize: int = Gen._get_struct_size(ElemType)
|
||||
for i in range(TargetType.count):
|
||||
@@ -1557,18 +1563,25 @@ class AssignHandle(BaseHandle):
|
||||
continue
|
||||
Gen._store(SrcVal, DstElem)
|
||||
return
|
||||
if isinstance(TargetType, ir.PointerType) and isinstance(Value, ir.Constant) and Value.constant is None:
|
||||
Value = ir.Constant(TargetType, None)
|
||||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType):
|
||||
try:
|
||||
Value = Gen.builder.bitcast(Value, TargetType, name="null_ptr_bitcast")
|
||||
except Exception: # 回退:bitcast 失败时设为 null 常量
|
||||
Value = ir.Constant(TargetType, None)
|
||||
# 新增指针隐式转换规则①/②:通用指针通配放行;非通用 T*→U* 仅在
|
||||
# 被指类型无损时放行,非基本/有损/层数不同 fail-fast。
|
||||
Allowed: bool
|
||||
Reason: str
|
||||
Allowed, Reason = Gen._ClassifyPtrImplicitConvert(Value.type, TargetType)
|
||||
if not Allowed:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转换已禁止({Reason}):不能把指针类型 {Value.type} 隐式转为 {TargetType};"
|
||||
f"如需转换请显式 cast(如 t.CPtr(...))"
|
||||
f"{Gen._DescribeValueNode(Node)}"
|
||||
)
|
||||
Value = Gen.builder.bitcast(Value, TargetType, name="ptr_bitcast")
|
||||
else:
|
||||
Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType)
|
||||
Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType, Node)
|
||||
if Coerced is not None:
|
||||
Value = Coerced
|
||||
Gen._store(Value, Ptr)
|
||||
Gen._store(Value, Ptr, Node=Node)
|
||||
|
||||
|
||||
def _get_int_ptr(self, target: ast.expr) -> ir.Value | None:
|
||||
|
||||
@@ -179,6 +179,9 @@ class ExprHandle(BaseHandle):
|
||||
elem_val: Any = self.HandleExprLlvm(elem, VarType=elem_type)
|
||||
if elem_val is None:
|
||||
continue
|
||||
# None(空值常量)允许隐式转换为任意元素类型 ⇒ 物化为目标元素类型零值。
|
||||
if Gen._IsNoneValue(elem_val, elem):
|
||||
elem_val = Gen._ZeroConst(elem_llvm_type)
|
||||
|
||||
byte_offset: int = i
|
||||
if elem_type == 'i32':
|
||||
@@ -209,10 +212,12 @@ class ExprHandle(BaseHandle):
|
||||
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
|
||||
elif isinstance(elem_val.type, ir.PointerType):
|
||||
# 指针 → 整数:隐式转换一律禁止(元素值是指针、元素类型是整数)
|
||||
# (None 已在上方短路为零值,不会落到这里)。
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:数组字面量第 {i} 个元素是指针类型 {elem_val.type},"
|
||||
f"但目标元素类型是 i8;如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{Gen._DescribeValueNode(elem)}"
|
||||
)
|
||||
elif elem_type == 'i32':
|
||||
if isinstance(elem_val.type, ir.IntType):
|
||||
@@ -222,10 +227,12 @@ class ExprHandle(BaseHandle):
|
||||
elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}")
|
||||
elif isinstance(elem_val.type, ir.PointerType):
|
||||
# 指针 → 整数:隐式转换一律禁止(ptrtoint 到 i32 还会截断地址)
|
||||
# (None 已在上方短路为零值,不会落到这里)。
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:数组字面量第 {i} 个元素是指针类型 {elem_val.type},"
|
||||
f"但目标元素类型是 i32;如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{Gen._DescribeValueNode(elem)}"
|
||||
)
|
||||
elif elem_type == 'i16':
|
||||
if isinstance(elem_val.type, ir.IntType):
|
||||
|
||||
@@ -182,7 +182,10 @@ class ExprLambdaHandle(BaseHandle):
|
||||
if not ThenEndBB.is_terminated:
|
||||
Gen.builder.position_at_end(ThenEndBB)
|
||||
if BodyVal.type != result_type:
|
||||
if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if Gen._IsNoneValue(BodyVal, Node.body):
|
||||
# None(空值常量)允许隐式转换为任意结果类型 ⇒ 物化为零值。
|
||||
BodyVal = Gen._ZeroConst(result_type)
|
||||
elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if BodyVal.type.width < result_type.width:
|
||||
BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext")
|
||||
else:
|
||||
@@ -205,13 +208,17 @@ class ExprLambdaHandle(BaseHandle):
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:条件表达式两分支类型不一致({BodyVal.type} / {result_type});"
|
||||
f"如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{Gen._DescribeValueNode(Node.body)}"
|
||||
)
|
||||
Gen.builder.branch(MergeBB)
|
||||
# 在 ElseBB 末尾添加类型转换(如果需要)和分支
|
||||
if not ElseEndBB.is_terminated:
|
||||
Gen.builder.position_at_end(ElseEndBB)
|
||||
if OrelseVal.type != result_type:
|
||||
if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if Gen._IsNoneValue(OrelseVal, Node.orelse):
|
||||
# None(空值常量)允许隐式转换为任意结果类型 ⇒ 物化为零值。
|
||||
OrelseVal = Gen._ZeroConst(result_type)
|
||||
elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if OrelseVal.type.width < result_type.width:
|
||||
OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext")
|
||||
else:
|
||||
@@ -233,6 +240,7 @@ class ExprLambdaHandle(BaseHandle):
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:条件表达式两分支类型不一致({OrelseVal.type} / {result_type});"
|
||||
f"如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{Gen._DescribeValueNode(Node.orelse)}"
|
||||
)
|
||||
Gen.builder.branch(MergeBB)
|
||||
Gen.builder.position_at_start(MergeBB)
|
||||
|
||||
@@ -78,7 +78,7 @@ class ReturnHandle(BaseHandle):
|
||||
Gen._closure_return_types[short_name] = (fn_return_type, nonlocal_types)
|
||||
# 返回闭包结构体指针(bitcast 到 i8*)
|
||||
closure_ret: ir.Value = Gen.builder.bitcast(closure_ptr, i8_ptr_type, name="closure_ret")
|
||||
Gen.emit_return(closure_ret)
|
||||
Gen.emit_return(closure_ret, Node.value)
|
||||
return
|
||||
active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen)
|
||||
if getattr(self.Trans, 'CurrentMultiRetTypes', None) and self.Trans.CurrentMultiRetTypes and Node.value:
|
||||
@@ -133,7 +133,7 @@ class ReturnHandle(BaseHandle):
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(result)
|
||||
Gen.emit_return(result, Node.value)
|
||||
return
|
||||
if Node.value:
|
||||
# 本函数返回类型即"使用处宽度":先取回返回类型再翻译值,供 CDefine 常量
|
||||
@@ -159,7 +159,7 @@ class ReturnHandle(BaseHandle):
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(zero_val)
|
||||
Gen.emit_return(zero_val, Node.value)
|
||||
return
|
||||
if getattr(self.Trans, 'CurrentMultiRetTypes', None) and self.Trans.CurrentMultiRetTypes:
|
||||
struct_type: ir.Type = Gen.func.ftype.return_type
|
||||
@@ -197,7 +197,7 @@ class ReturnHandle(BaseHandle):
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(result)
|
||||
Gen.emit_return(result, Node.value)
|
||||
return
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
@@ -208,7 +208,7 @@ class ReturnHandle(BaseHandle):
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(Val)
|
||||
Gen.emit_return(Val, Node.value)
|
||||
else:
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
|
||||
@@ -960,6 +960,39 @@ class BaseGenMixin:
|
||||
info += f"\n → {source_line}"
|
||||
return info
|
||||
|
||||
def _DescribeValueNode(self, Node: Any = None) -> str:
|
||||
"""把「真正被转换的值节点」渲染成一段诊断文本,供隐式转换禁令引用。
|
||||
|
||||
报文风格照本仓既有「表达式文本 + 位置 + 源码片段」:
|
||||
表达式 '<unparse>'(<节点形态>,位置 文件:行:列),源码: <该行>
|
||||
关键:**列号按有符号打印**——未知(无属性 / <0)时打印 '-',绝不把 col_offset
|
||||
的 -1 当无符号打成 4294967295(此前 TPV 侧诊断错位的根因)。取不到节点时
|
||||
回退当前语句上下文(_get_node_info 风格),不再固定打印外层 Assign。
|
||||
"""
|
||||
if Node is None:
|
||||
return self._get_node_info()
|
||||
try:
|
||||
Expr: str = ast.unparse(Node)
|
||||
except Exception:
|
||||
Expr = getattr(Node, 'attr', '') or getattr(Node, 'id', '') or '<expr>'
|
||||
RawLine: int = getattr(Node, 'lineno', 0) or 0
|
||||
Col: Any = getattr(Node, 'col_offset', -1)
|
||||
Line: int = RawLine or self._current_lineno or 0
|
||||
Loc: str = self._current_source_file or ''
|
||||
if Line > 0:
|
||||
Loc += f":{Line}"
|
||||
Loc += f":{Col}" if isinstance(Col, int) and Col >= 0 else ":-"
|
||||
Code: str = ''
|
||||
if Line > 0:
|
||||
try:
|
||||
Code = (self._get_source_line(Line) or '').strip()
|
||||
except Exception:
|
||||
Code = ''
|
||||
Text: str = f";出错表达式: 表达式 '{Expr}'({type(Node).__name__} 形态,位置 {Loc})"
|
||||
if Code:
|
||||
Text += f",源码: {Code}"
|
||||
return Text
|
||||
|
||||
# ========== const / volatile:判定、登记与报文(两侧同口径) ==========
|
||||
# 语义唯一来源见 Debugger/type-descriptors.md。TPC 与 TransPyV 必须**同判据、
|
||||
# 同报文**;任何未消除的差异都列在该文档的「已知差异」一节。
|
||||
|
||||
@@ -294,7 +294,7 @@ class ExprGenMixin:
|
||||
return self.builder.sitofp(val, ftype, name="int2float")
|
||||
return val
|
||||
|
||||
def emit_return(self, value: ir.Value | None = None) -> None:
|
||||
def emit_return(self, value: ir.Value | None = None, Node: Any = None) -> None:
|
||||
if not self.builder or self.builder.block.is_terminated:
|
||||
return
|
||||
if value is not None:
|
||||
@@ -327,8 +327,22 @@ class ExprGenMixin:
|
||||
else:
|
||||
if self.func and hasattr(self.func, 'ftype'):
|
||||
ret_type: ir.Type = self.func.ftype.return_type
|
||||
# None(空值常量)允许隐式转换为任意返回类型:指针目标→空指针,
|
||||
# 其余目标→目标类型零值(整数 0 / 浮点 0.0 / 聚合 zeroinitializer)。
|
||||
if not isinstance(ret_type, ir.VoidType) and self._IsNoneValue(value, Node):
|
||||
value = self._ZeroConst(ret_type)
|
||||
if ret_type != value.type:
|
||||
if isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.PointerType):
|
||||
Allowed: bool
|
||||
Reason: str
|
||||
Allowed, Reason = self._ClassifyPtrImplicitConvert(value.type, ret_type)
|
||||
if not Allowed:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转换已禁止({Reason}):函数 {self.func.name} 声明返回 {ret_type},"
|
||||
f"但 return 的是指针类型 {value.type};如需转换请显式 cast(如 t.CPtr(...))"
|
||||
f"{self._DescribeValueNode(Node)}"
|
||||
)
|
||||
value = self.builder.bitcast(value, ret_type, name="ret_cast")
|
||||
elif isinstance(value.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType):
|
||||
if isinstance(ret_type, ir.IntType):
|
||||
@@ -338,6 +352,7 @@ class ExprGenMixin:
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:函数 {self.func.name} 声明返回 {ret_type},"
|
||||
f"但 return 的是指针类型 {value.type};如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{self._DescribeValueNode(Node)}"
|
||||
)
|
||||
elif isinstance(value.type.pointee, ret_type.__class__) and not isinstance(value.type.pointee, ir.IntType):
|
||||
value = self._load(value, name="ret_Load")
|
||||
@@ -350,6 +365,7 @@ class ExprGenMixin:
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:函数 {self.func.name} 声明返回 {ret_type},"
|
||||
f"但 return 的是指针类型 {Loaded.type};如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{self._DescribeValueNode(Node)}"
|
||||
)
|
||||
elif isinstance(ret_type, ir.IntType) and isinstance(value.type, ir.IntType):
|
||||
if value.type.width < ret_type.width:
|
||||
|
||||
@@ -165,6 +165,16 @@ class FuncGenMixin:
|
||||
else:
|
||||
adjusted.append(elem_ptr)
|
||||
else:
|
||||
# 新增指针隐式转换规则①/②:通用指针通配放行;非通用
|
||||
# T*→U* 仅在无损时放行,非基本/有损/层数不同 fail-fast。
|
||||
Allowed: bool
|
||||
Reason: str
|
||||
Allowed, Reason = self._ClassifyPtrImplicitConvert(arg.type, param.type)
|
||||
if not Allowed:
|
||||
raise FailFastError(
|
||||
f"指针隐式转换已禁止({Reason}):调用 {func.name} 第 {i} 个实参"
|
||||
f" {arg.type} 不能隐式转为形参 {param.type};如需转换请显式 cast"
|
||||
f"(如 t.CPtr(...)){self._DescribeValueNode()}")
|
||||
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
|
||||
else:
|
||||
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
|
||||
+150
-10
@@ -1,4 +1,5 @@
|
||||
from __future__ import annotations
|
||||
from typing import Any
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
@@ -137,6 +138,117 @@ class MemoryOpsMixin:
|
||||
return ir.Constant(typ, None)
|
||||
return ir.Constant(typ, 0)
|
||||
|
||||
# ============================================================
|
||||
# 隐式转换公共判据:None(空值常量)/ 指针层级 / 基本类型 / 无损
|
||||
#
|
||||
# 语义唯一来源与 TransPyV 对齐(ExprGenBase.IsNoneValue、coerce_to_type)。
|
||||
# 收敛于此,供赋值 / 返回 / 实参 / 数组元素等所有 coerce 入口复用,避免
|
||||
# 各处各自演化出相反结论。
|
||||
# ============================================================
|
||||
|
||||
@staticmethod
|
||||
def _IsNoneValue(val: Any, node: Any = None) -> bool:
|
||||
"""None 判据:True=空值常量(None),False=否。
|
||||
|
||||
None 无语义类型信息,**允许隐式转换为任意类型**:指针目标→空指针,
|
||||
其余目标→目标类型零值(整数 0 / 浮点 0.0 / 聚合 zeroinitializer)。故
|
||||
「指针↔整数」「指针↔非指针值」「指针↔指针(非基本/有损/层数不同)」
|
||||
这类针对**真实类型值**的隐式转换禁令都要对 None 短路放行。
|
||||
|
||||
两条判据(任一命中):
|
||||
① AST 层:node 是 Constant 且 value is None;
|
||||
② 值层(主判据):已生成好的 **空指针常量**(ir.Constant 且 constant is None
|
||||
且类型为指针)。整数常量 0 的类型是整数,不会误命中。
|
||||
"""
|
||||
if node is not None and type(node).__name__ == 'Constant' and getattr(node, 'value', 1) is None:
|
||||
return True
|
||||
return (isinstance(val, ir.Constant) and val.constant is None
|
||||
and isinstance(val.type, ir.PointerType))
|
||||
|
||||
@staticmethod
|
||||
def _PtrLevel(typ: Any) -> int:
|
||||
"""指针层级:PointerType 嵌套层数(0=非指针)。"""
|
||||
n: int = 0
|
||||
while isinstance(typ, ir.PointerType):
|
||||
n += 1
|
||||
typ = typ.pointee
|
||||
return n
|
||||
|
||||
@staticmethod
|
||||
def _IsGenericPtrType(typ: Any) -> bool:
|
||||
"""通用指针(t.CPtr / void*):指针链末端为 i8(i8* / i8** / ... 均算)。"""
|
||||
if not isinstance(typ, ir.PointerType):
|
||||
return False
|
||||
p: Any = typ.pointee
|
||||
while isinstance(p, ir.PointerType):
|
||||
p = p.pointee
|
||||
return isinstance(p, ir.IntType) and p.width == 8
|
||||
|
||||
@staticmethod
|
||||
def _IsBasicScalarType(typ: Any) -> bool:
|
||||
"""基本类型 = 整数/浮点(含布尔 i1);结构体/类/联合/数组/指针一律非基本。"""
|
||||
return isinstance(typ, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
|
||||
@staticmethod
|
||||
def _ScalarConvertLossless(Src: Any, Dst: Any) -> bool:
|
||||
"""既有整数/浮点规则下的「无损」判定:同族且目标位宽 >= 源位宽。
|
||||
|
||||
整数→整数 / 浮点→浮点:按位宽(宽化无损、同宽无损、窄化有损);
|
||||
整数↔浮点:跨类别,一律视为非无损(有损)。
|
||||
"""
|
||||
def _FloatBits(x: Any) -> int:
|
||||
if isinstance(x, ir.DoubleType):
|
||||
return 64
|
||||
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
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _ClassifyPtrImplicitConvert(Src: Any, Dst: Any) -> tuple[bool, str]:
|
||||
"""隐式转换判据:返回 (Allowed, Reason)。
|
||||
|
||||
规则(用户决定,与 TransPyV 同口径):
|
||||
① 通用指针(t.CPtr/i8*)为通配:与任何 T* **双向**互转放行(须同级)。
|
||||
② T* → U*(皆非通用):允许 ⇔ 被指类型 T → U 无损;非基本类型
|
||||
(结构体/类/联合)一律不允许 ⇒ Foo*→Bar* 禁止。
|
||||
③ 非基本类型 T 与 T* 之间的隐式转换(Foo ↔ Foo*)一律禁止(层数不同)。
|
||||
④ 完全相同类型不算转换 ⇒ 放行。
|
||||
Reason 供报文说明「哪一级不允许 + 原因(非基本类型/有损/层数不同)」。
|
||||
"""
|
||||
if Src == Dst:
|
||||
return (True, '同类型(不构成转换)')
|
||||
s_ptr: bool = isinstance(Src, ir.PointerType)
|
||||
d_ptr: bool = isinstance(Dst, ir.PointerType)
|
||||
if s_ptr and d_ptr:
|
||||
if MemoryOpsMixin._PtrLevel(Src) != MemoryOpsMixin._PtrLevel(Dst):
|
||||
return (False, '层数不同')
|
||||
if MemoryOpsMixin._IsGenericPtrType(Src) or MemoryOpsMixin._IsGenericPtrType(Dst):
|
||||
return (True, '通用指针通配')
|
||||
sp: Any = Src.pointee
|
||||
dp: Any = Dst.pointee
|
||||
if sp == dp:
|
||||
return (True, '被指类型相同')
|
||||
if MemoryOpsMixin._IsBasicScalarType(sp) and MemoryOpsMixin._IsBasicScalarType(dp):
|
||||
if MemoryOpsMixin._ScalarConvertLossless(sp, dp):
|
||||
return (True, '被指类型无损')
|
||||
return (False, '被指类型有损')
|
||||
return (False, '非基本类型(结构体/类/联合)')
|
||||
if not s_ptr and not d_ptr:
|
||||
return (True, '非指针间(本判据不裁决)')
|
||||
# 一方指针、一方非指针:基本标量走既有「指针隐式转整数」禁令;非基本
|
||||
# 类型即规则③(T ↔ T* 隐式互转)。
|
||||
other: Any = Dst if s_ptr else Src
|
||||
if MemoryOpsMixin._IsBasicScalarType(other):
|
||||
return (False, '指针与标量(须显式 cast)')
|
||||
return (False, '非基本类型(结构体/类/联合)')
|
||||
|
||||
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)
|
||||
@@ -244,9 +356,16 @@ class MemoryOpsMixin:
|
||||
return self._load(GVar, name=name)
|
||||
return None
|
||||
|
||||
def _coerce_value(self, val: ir.Value, target_type: ir.Type) -> ir.Value | None:
|
||||
def _coerce_value(self, val: ir.Value, target_type: ir.Type, Node: Any = None) -> ir.Value | None:
|
||||
if val.type == target_type:
|
||||
return val
|
||||
# None(空值常量)允许隐式转换为任意类型:指针目标→空指针,其余目标→
|
||||
# 目标类型零值(整数 0 / 浮点 0.0 / 聚合 zeroinitializer)。收敛到
|
||||
# _IsNoneValue 单一判据,任何「指针↔整数 / 指针↔非指针值」禁令都不拦 None。
|
||||
if self._IsNoneValue(val, Node):
|
||||
if isinstance(target_type, ir.PointerType):
|
||||
return ir.Constant(target_type, None)
|
||||
return self._ZeroConst(target_type)
|
||||
if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
return val
|
||||
@@ -260,26 +379,33 @@ class MemoryOpsMixin:
|
||||
else:
|
||||
return self.builder.sext(val, target_type, name="sext_store")
|
||||
if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.PointerType):
|
||||
if isinstance(val, ir.Constant) and val.constant is None:
|
||||
return ir.Constant(target_type, None)
|
||||
# 新增指针隐式转换规则①/②:通用指针通配双向放行;非通用 T*→U* 仅在
|
||||
# 被指类型无损时放行,非基本类型/有损/层数不同一律 fail-fast。
|
||||
Allowed: bool
|
||||
Reason: str
|
||||
Allowed, Reason = self._ClassifyPtrImplicitConvert(val.type, target_type)
|
||||
if not Allowed:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转换已禁止({Reason}):不能把指针类型 {val.type} 隐式转为 {target_type};"
|
||||
f"如需转换请显式 cast(如 t.CPtr(...))"
|
||||
f"{self._DescribeValueNode(Node)}"
|
||||
)
|
||||
return self.builder.bitcast(val, target_type, name="ptr_bitcast_store")
|
||||
if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.IntType):
|
||||
if val.type.width < 64:
|
||||
val = self.builder.zext(val, ir.IntType(64), name="zext_ptr_store")
|
||||
return self.builder.inttoptr(val, target_type, name="int_to_ptr_store")
|
||||
if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.PointerType):
|
||||
if isinstance(val, ir.Constant) and val.constant is None:
|
||||
# null 指针常量赋给 int 字段 → 0。绝不能对 null 做 load
|
||||
# (此前 pointee.width == target.width 时直接 load null,
|
||||
# 生成 `load i32, i32* null` → ASAN access-violation)
|
||||
return ir.Constant(target_type, 0)
|
||||
# 指针 → 整数:隐式转换一律禁止(与 TransPyV coerce_to_type 同口径)。
|
||||
# 原先三条路径都是静默的:同宽直接 load 指针所指物的位模式、≤8 位 load
|
||||
# 首字节、其余 ptrtoint 截断地址——把"类型写错"藏到运行期。
|
||||
# None(空指针常量)已在上方短路为目标零值,不会落到这里。
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针隐式转整数已禁止:不能把指针类型 {val.type} 赋给整数类型 {target_type};"
|
||||
f"如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))"
|
||||
f"{self._DescribeValueNode(Node)}"
|
||||
)
|
||||
if isinstance(target_type, ir.FloatType) and isinstance(val.type, ir.DoubleType):
|
||||
return self.builder.fptrunc(val, target_type, name="fptrunc_store")
|
||||
@@ -304,6 +430,20 @@ class MemoryOpsMixin:
|
||||
if trimmed and len(trimmed) == val.type.count:
|
||||
return ir.Constant(target_type, trimmed[:target_type.count])
|
||||
if isinstance(val.type, ir.PointerType) and not isinstance(target_type, ir.PointerType):
|
||||
# 规则③:非基本类型 T 与 T* 之间的隐式转换(Foo ↔ Foo*)一律禁止——
|
||||
# 指针→非指针值的隐式 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)}"
|
||||
)
|
||||
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):
|
||||
@@ -314,7 +454,7 @@ class MemoryOpsMixin:
|
||||
return None
|
||||
|
||||
def _store(self, val: ir.Value, ptr: ir.Value, align: int | None = None,
|
||||
volatile: bool | None = None) -> ir.StoreInstr:
|
||||
volatile: bool | None = None, Node: Any = None) -> ir.StoreInstr:
|
||||
if align is None:
|
||||
if isinstance(ptr.type, ir.PointerType):
|
||||
align = self._get_align(ptr.type.pointee)
|
||||
@@ -350,7 +490,7 @@ class MemoryOpsMixin:
|
||||
# 防止 `store i32* null, i32*` 类型错乱 IR)
|
||||
val = ir.Constant(target_type, 0)
|
||||
else:
|
||||
coerced: ir.Value | None = self._coerce_value(val, target_type)
|
||||
coerced: ir.Value | None = self._coerce_value(val, target_type, Node)
|
||||
if coerced is not None:
|
||||
val = coerced
|
||||
else:
|
||||
|
||||
Reference in new issue
Block a user