feat(cast): 指针隐式转换按“同级+被指类型无损”判定(通用指针 t.CPtr/i8* 通配),并修诊断错位
_ptr_cast_reason 统一判据:层数不同→禁;完全相同类型→放行;任一侧通用指针(i8*/t.CPtr)→放行;否则按被指类型:非基本类型→禁,基本标量按既有无损规则(int↔int、float↔float、int→float 需目标浮点位宽≥源整数位宽、float→int 有损) 4 处禁令与新增的“指针→指针”处统一走 _value_node_of/_cast_fail_where:外层 Assign(kind=3) 下沉到真正被转换的值节点;列号按有符号打印(-1/未知打 -,不再出现 4294967295);附源码片段 未动“聚合值↔指针”那条路径(构造返回指针 load 回结构体,如 p: Point = Point()):LLVM 层无法与真实 Foo*→Foo 区分,禁止会直接编不过;规则③在该轴上的收紧待 AST 层区分构造调用后另做
This commit is contained in:
1 parent
59a9fc5b1f
commit
ee50ce61fe
1 file changed
+274
-14
@@ -5,6 +5,7 @@ import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.Projectrans.Utils as Utils
|
||||
@@ -12,6 +13,22 @@ import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 指针间隐式转换判定码(coerce_to_type 的「指针 → 指针」分支使用)
|
||||
#
|
||||
# 由 _ptr_cast_reason 统一给出,供报错说明「哪一级不允许 + 为什么」:
|
||||
# PC_OK 允许(含规则 1 通用指针通配、规则 4 完全相同不视为转换)
|
||||
# PC_DEPTH 指针层数不同(禁)
|
||||
# PC_NONBASIC 被指类型是非基本类型(结构体/类/联合/数组等):非基本类型与其
|
||||
# 指针之间、以及不同非基本类型的指针之间一律不允许(规则 2/3)
|
||||
# PC_LOSSY 被指类型之间转换有损(整数→浮点位宽不足 / 浮点→整数)(规则 2)
|
||||
# ============================================================
|
||||
define PC_OK = 0
|
||||
define PC_DEPTH = 1
|
||||
define PC_NONBASIC = 2
|
||||
define PC_LOSSY = 3
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenBase - ExprGenMixin 拆分(阶段 D):表达式基础工具(类型判断/指针层级/coerce)
|
||||
# ============================================================
|
||||
@@ -318,46 +335,115 @@ novirtual class ExprGenBase:
|
||||
if loaded is None: return obj_ptr
|
||||
return loaded
|
||||
# ============================================================
|
||||
# _value_node_of - 把「外层语句节点」下沉到其「值子表达式节点」
|
||||
#
|
||||
# 诊断错位修复(2026-09-28):赋值/返回等路径传给 coerce_to_type 的 node 常是
|
||||
# 外层语句节点(实测 Assign,kind=3,col_offset=-1),导致报错打成
|
||||
# `出错表达式: 表达式 kind=3(列 -1)`,指不到真正出错的子表达式。
|
||||
# 此处把语句节点(Assign/AnnAssign/AugAssign/Expr/Return)换成其 value 子节点,
|
||||
# 使报错定位到真正被转换的那个值表达式。非语句节点原样返回。
|
||||
# ============================================================
|
||||
def _value_node_of(self, node: ast.AST*) -> ast.AST*:
|
||||
"""语句节点 → 其值子表达式节点;非语句/无值则原样返回"""
|
||||
if node is None:
|
||||
return node
|
||||
k: int = node.kind()
|
||||
v: ast.AST* = None
|
||||
if k == ast.ASTKind.Assign:
|
||||
v = (ast.Assign*(node)).value
|
||||
elif k == ast.ASTKind.AnnAssign:
|
||||
v = (ast.AnnAssign*(node)).value
|
||||
elif k == ast.ASTKind.AugAssign:
|
||||
v = (ast.AugAssign*(node)).value
|
||||
elif k == ast.ASTKind.Expr:
|
||||
v = (ast.Expr*(node)).value
|
||||
elif k == ast.ASTKind.Return:
|
||||
v = (ast.Return*(node)).value
|
||||
if v is None:
|
||||
return node
|
||||
return v
|
||||
# ============================================================
|
||||
# _source_snippet - 尽力取「源码片段」(行文本),失败返回空串
|
||||
#
|
||||
# 报文风格对齐本仓既有「源码片段 + 行:列」(源行由 TypeGenErr.fatal_error 的
|
||||
# Traceback 帧也会打印;此处再在报文内附一份,便于单行错误消息自洽可读)。
|
||||
# 行文本由 stdlib.malloc 分配,拼进 f-string 后立即 free。
|
||||
# ============================================================
|
||||
def _source_snippet(self, lineno: int) -> str:
|
||||
"""尽力读取第 lineno 行源码文本,拼成片段;取不到返回空串"""
|
||||
if lineno <= 0:
|
||||
return ""
|
||||
file_name: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if file_name is None:
|
||||
return ""
|
||||
line: str = self.Gen.TypeGenErr.read_source_line(file_name, lineno)
|
||||
if line is None:
|
||||
return ""
|
||||
body: str = GenApi.escape_fstring_copy(f"\n 源码: {line}")
|
||||
stdlib.free(line)
|
||||
return body
|
||||
# ============================================================
|
||||
# _cast_fail_where - 隐式转换失败时报出**出错的表达式**(→ 定位到具体实参)
|
||||
#
|
||||
# 调用点只传 AST 节点,报错原本只有"调用所在行",多实参时看不出是哪一个
|
||||
# (如 `_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)`
|
||||
# 报指针→整数,无法判断是哪个实参)。此处按节点形态给出可读名:
|
||||
# Name→'id'、Attribute→'.attr'、Call/Subscript→形态名,并附列号(源码行已
|
||||
# 由 traceback 打出,列号即可指到具体实参)。
|
||||
# Name→'id'、Attribute→'.attr'、Call/Subscript→形态名,并附**行:列**。
|
||||
#
|
||||
# 诊断错位修复(2026-09-28):
|
||||
# ① 先经 _value_node_of 把外层语句节点(Assign kind=3 等)下沉到真正被转换的
|
||||
# 值子表达式节点,再按形态描述;
|
||||
# ② 列号 col_offset 缺省为 -1,此前按无符号格式化成 4294967295;现按有符号
|
||||
# 打印,未知(<0)一律显示 '-',绝不出现 4294967295;
|
||||
# ③ 尽力附源码片段(行 + 列 + 源行文本)。
|
||||
# ============================================================
|
||||
def _cast_fail_where(self, node: ast.AST*) -> str:
|
||||
"""取隐式转换失败的定位文本(出错表达式 + 列号)
|
||||
"""取隐式转换失败的定位文本(出错表达式 + 行:列 + 源码片段)
|
||||
|
||||
返回值会**逃逸本函数**(被 coerce_to_type 拼进更大的报文),而 f-string 结果
|
||||
指向当前函数的栈缓冲 ⇒ 每处都经 GenApi.escape_fstring_copy 显式拷到 stdlib 堆
|
||||
(历史事故:直接 return f"..." 让调用方读到已弹栈的帧,ASan
|
||||
stack-buffer-underflow in vsnprintf)。
|
||||
"""
|
||||
node = self._value_node_of(node)
|
||||
if node is None:
|
||||
return "节点未知(无 AST 信息)"
|
||||
k: int = node.kind()
|
||||
pos: int = -1
|
||||
where: str = None
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None:
|
||||
pos = nm.col_offset
|
||||
return GenApi.escape_fstring_copy(f"Name '{nm.id}'(列 {pos})")
|
||||
where = f"Name '{nm.id}'"
|
||||
elif k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is not None:
|
||||
pos = at.col_offset
|
||||
return GenApi.escape_fstring_copy(f"属性 '.{at.attr}'(列 {pos})")
|
||||
where = f"属性 '.{at.attr}'"
|
||||
elif k == ast.ASTKind.Call:
|
||||
pos = (ast.Call*(node)).col_offset
|
||||
return GenApi.escape_fstring_copy(f"调用结果 Call(列 {pos})")
|
||||
where = "调用结果 Call"
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
pos = (ast.Subscript*(node)).col_offset
|
||||
return GenApi.escape_fstring_copy(f"下标表达式 Subscript(列 {pos})")
|
||||
where = "下标表达式 Subscript"
|
||||
elif k == ast.ASTKind.Constant:
|
||||
pos = (ast.Constant*(node)).col_offset
|
||||
return GenApi.escape_fstring_copy(f"常量 Constant(列 {pos})")
|
||||
return GenApi.escape_fstring_copy(f"表达式 kind={k}(列 {pos})")
|
||||
where = "常量 Constant"
|
||||
if where is None:
|
||||
where = f"表达式 kind={k}"
|
||||
# 列号按**有符号**打印:col_offset 未知/缺省为 -1,若按无符号会打成
|
||||
# 4294967295;未知一律显示 '-'。
|
||||
col_txt: str = "-"
|
||||
if pos >= 0:
|
||||
col_txt = f"{pos}"
|
||||
# 行号:node.lineno 缺省为 0/负,未知显示 '-'。
|
||||
ln: int = node.lineno
|
||||
ln_txt: str = "-"
|
||||
if ln > 0:
|
||||
ln_txt = f"{ln}"
|
||||
snippet: str = self._source_snippet(ln)
|
||||
return GenApi.escape_fstring_copy(f"{where}(行 {ln_txt},列 {col_txt}){snippet}")
|
||||
|
||||
# ============================================================
|
||||
# IsNoneValue - 判据:源值是否为 None(空值常量),返回 1=是 / 0=否
|
||||
@@ -421,6 +507,165 @@ novirtual class ExprGenBase:
|
||||
return llvmlite.ConstFloat(pool, target_ty, 0.0)
|
||||
return llvmlite.ConstZero(pool, target_ty)
|
||||
# ============================================================
|
||||
# _is_universal_ptr_ty - 判据:类型是否为「通用指针」(t.CPtr / i8* = void*)
|
||||
#
|
||||
# 规则 1(通用指针是通配):t.CPtr 与 i8*(void*,裸 str/bytes 那一族的指针形态)
|
||||
# 视为「任意指针」,与任何 T* 双向隐式互转都放行。
|
||||
# 判据:单层 Ptr 且 pointee 为 i8(t.CPtr = Ptr(Int8);Ptr(Void) 工厂已回退为
|
||||
# Ptr(Int8),故 void* 在 LLVM 层同样表现为 Ptr(i8))。char* 同属 i8*,一并视为通用指针。
|
||||
# 多级指针(如 i8**)不是通用指针(需逐级比较 pointee)。
|
||||
# 返回 1=是 / 0=否。
|
||||
# ============================================================
|
||||
def _is_universal_ptr_ty(self, ty: llvmlite.LLVMType*) -> int:
|
||||
"""ty 是否为通用指针(i8*/t.CPtr),1=是 / 0=否"""
|
||||
if ty is None or self.is_ptr_type(ty) == 0:
|
||||
return 0
|
||||
if self.get_ptr_level(ty) != 1:
|
||||
return 0
|
||||
pointee: llvmlite.LLVMType* = ty.Pointee
|
||||
if pointee is None:
|
||||
return 1
|
||||
if self.get_llvm_type_bits(pointee) == 8:
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _is_basic_scalar_ty - 判据:类型是否为基本类型(整数/浮点),1=是 / 0=否
|
||||
#
|
||||
# 非基本类型 = 结构体/类/联合/数组/函数等(LLVM 层 Struct/Array/Func)。
|
||||
# 规则 2/3:非基本类型一律不允许参与指针间隐式转换(除完全相同类型,见规则 4)。
|
||||
# ============================================================
|
||||
def _is_basic_scalar_ty(self, ty: llvmlite.LLVMType*) -> int:
|
||||
"""ty 是否为基本类型(整数/浮点),1=是 / 0=否"""
|
||||
if ty is None:
|
||||
return 0
|
||||
if self.get_llvm_type_bits(ty) != 0:
|
||||
return 1
|
||||
if self.get_llvm_float_bits(ty) != 0:
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _scalar_convert_reason - 基本标量 T → U 是否无损(沿用 coerce_to_type 既有规则)
|
||||
#
|
||||
# 整数/浮点:沿用既有规则(高→低允许安全降级、低→高无损;整数→浮点需浮点位宽
|
||||
# ≥ 整数位宽;浮点→整数不允许)。
|
||||
# 返回 PC_OK(无损/允许)或 PC_LOSSY(有损/禁止)。
|
||||
# ============================================================
|
||||
def _scalar_convert_reason(self, src_pt: llvmlite.LLVMType*,
|
||||
dst_pt: llvmlite.LLVMType*) -> int:
|
||||
"""基本标量 src_pt → dst_pt 的隐式转换判定码(PC_OK / PC_LOSSY)"""
|
||||
s_int: int = self.get_llvm_type_bits(src_pt)
|
||||
d_int: int = self.get_llvm_type_bits(dst_pt)
|
||||
s_flt: int = self.get_llvm_float_bits(src_pt)
|
||||
d_flt: int = self.get_llvm_float_bits(dst_pt)
|
||||
# 整数 ↔ 整数:高→低安全降级、低→高无损,均允许
|
||||
if s_int != 0 and d_int != 0:
|
||||
return PC_OK
|
||||
# 浮点 ↔ 浮点:允许
|
||||
if s_flt != 0 and d_flt != 0:
|
||||
return PC_OK
|
||||
# 整数 → 浮点:浮点位宽 ≥ 整数位宽才无损
|
||||
if s_int != 0 and d_flt != 0:
|
||||
if d_flt >= s_int:
|
||||
return PC_OK
|
||||
return PC_LOSSY
|
||||
# 浮点 → 整数:有损,禁止
|
||||
if s_flt != 0 and d_int != 0:
|
||||
return PC_LOSSY
|
||||
return PC_OK
|
||||
# ============================================================
|
||||
# _pointee_convert_reason - 被指类型 src_pt → dst_pt(T*→U* 的 T→U 关系)判定码
|
||||
#
|
||||
# 规则 2:T* → U*(T、U 都非通用指针)允许 ⇔ 被指类型 T → U 无损。
|
||||
# 规则 3:非基本类型 T 与其指针 T* 之间(值/指针互换)一律禁止——此处体现为
|
||||
# 被指类型一侧是「非基本值类型」、另一侧是「其指针(或其它的基本/非基本类型)」
|
||||
# 时一律不匹配 ⇒ PC_NONBASIC。
|
||||
# 被指类型仍是指针(T** → U**):递归按指针规则判。
|
||||
# ============================================================
|
||||
def _pointee_convert_reason(self, pool: memhub.MemBuddy*,
|
||||
src_pt: llvmlite.LLVMType*,
|
||||
dst_pt: llvmlite.LLVMType*) -> int:
|
||||
"""被指类型 src_pt → dst_pt 的判定码(PC_OK/PC_NONBASIC/PC_LOSSY/PC_DEPTH)"""
|
||||
if src_pt is None or dst_pt is None:
|
||||
return PC_OK
|
||||
s_is_ptr: int = self.is_ptr_type(src_pt)
|
||||
d_is_ptr: int = self.is_ptr_type(dst_pt)
|
||||
if s_is_ptr != 0 or d_is_ptr != 0:
|
||||
# 一侧是指针、另一侧不是(如被指类型 Foo vs Foo*)→ 非基本类型值/指针互换,禁止
|
||||
if s_is_ptr == 0 or d_is_ptr == 0:
|
||||
return PC_NONBASIC
|
||||
# 两侧都是指针:递归
|
||||
return self._ptr_cast_reason(pool, src_pt, dst_pt)
|
||||
# 一侧是非基本类型(结构体/类/联合/数组/函数)→ 一律禁止
|
||||
if self._is_basic_scalar_ty(src_pt) == 0 or self._is_basic_scalar_ty(dst_pt) == 0:
|
||||
return PC_NONBASIC
|
||||
return self._scalar_convert_reason(src_pt, dst_pt)
|
||||
# ============================================================
|
||||
# _ptr_cast_reason - 指针 → 指针隐式转换的判定码(新规则单一真源)
|
||||
#
|
||||
# 规则 1:通用指针(t.CPtr / i8*)与任何 T* 双向互转都放行 ⇒ PC_OK。
|
||||
# 规则 2:T* → U*(T、U 都非通用指针)允许 ⇔ 被指类型 T → U 无损;非基本类型
|
||||
# 一律不允许。
|
||||
# 规则 3:非基本类型 T 与其指针 T* 之间一律禁止。
|
||||
# 规则 4:完全相同类型(指针深度与被指类型都相同,含 Foo* → Foo*)不算转换 ⇒ PC_OK。
|
||||
# 返回 PC_OK(允许)/ PC_DEPTH / PC_NONBASIC / PC_LOSSY。
|
||||
# ============================================================
|
||||
def _ptr_cast_reason(self, pool: memhub.MemBuddy*,
|
||||
src_ty: llvmlite.LLVMType*,
|
||||
dst_ty: llvmlite.LLVMType*) -> int:
|
||||
"""指针 → 指针对隐式转换的判定码(PC_OK 表示允许)"""
|
||||
if src_ty is None or dst_ty is None:
|
||||
return PC_OK
|
||||
slev: int = self.get_ptr_level(src_ty)
|
||||
dlev: int = self.get_ptr_level(dst_ty)
|
||||
if slev == 0 or dlev == 0:
|
||||
return PC_OK
|
||||
# 层数不同 → 禁止(无论被指类型)
|
||||
if slev != dlev:
|
||||
return PC_DEPTH
|
||||
# 规则 4:完全相同类型(层数 + 逐级被指类型都相同)不算转换
|
||||
if self.Gen.AssignGen._stg_ty_equal(pool, src_ty, dst_ty) != 0:
|
||||
return PC_OK
|
||||
# 规则 1:通用指针是通配(i8* ↔ 任何 T*)
|
||||
if self._is_universal_ptr_ty(src_ty) != 0 or self._is_universal_ptr_ty(dst_ty) != 0:
|
||||
return PC_OK
|
||||
# 规则 2/3:逐级比较被指类型
|
||||
return self._pointee_convert_reason(pool, src_ty.Pointee, dst_ty.Pointee)
|
||||
# ============================================================
|
||||
# _type_text - LLVM 类型的可读文本(TypePrint),供报文使用(失败返回 "?")
|
||||
# ============================================================
|
||||
def _type_text(self, pool: memhub.MemBuddy*,
|
||||
ty: llvmlite.LLVMType*) -> str:
|
||||
"""LLVM 类型文本(TypePrint);失败返回 "?" """
|
||||
if ty is None:
|
||||
return "?"
|
||||
buf: str = pool.alloc(256)
|
||||
if buf is None:
|
||||
return "?"
|
||||
llvmlite.TypePrint(buf, 256, ty, pool)
|
||||
if buf[0] == 0:
|
||||
return "?"
|
||||
return buf
|
||||
# ============================================================
|
||||
# _ptr_cast_reason_text - 把指针间隐式转换的禁止原因写成可读文本
|
||||
#
|
||||
# 报文写清「哪一级不允许 + 为什么(非基本类型 / 有损 / 层数不同)」,并给出
|
||||
# 源/目标 LLVM 类型文本。返回值会逃逸 ⇒ 经 escape_fstring_copy 拷到 stdlib 堆。
|
||||
# ============================================================
|
||||
def _ptr_cast_reason_text(self, code: int, pool: memhub.MemBuddy*,
|
||||
src_ty: llvmlite.LLVMType*,
|
||||
dst_ty: llvmlite.LLVMType*) -> str:
|
||||
"""指针间隐式转换禁止原因的可读文本(含源/目标类型)"""
|
||||
why: str = "原因未知"
|
||||
if code == PC_DEPTH:
|
||||
why = f"指针层数不同(源 {self.get_ptr_level(src_ty)} 级 → 目标 {self.get_ptr_level(dst_ty)} 级)"
|
||||
elif code == PC_NONBASIC:
|
||||
why = "被指类型是非基本类型(结构体/类/联合/数组等):非基本类型与其指针之间、以及不同非基本类型的指针之间一律不允许隐式转换"
|
||||
elif code == PC_LOSSY:
|
||||
why = "被指类型之间的转换有损(整数→浮点位宽不足 / 浮点→整数)"
|
||||
s_txt: str = self._type_text(pool, src_ty)
|
||||
d_txt: str = self._type_text(pool, dst_ty)
|
||||
return GenApi.escape_fstring_copy(f"指针隐式转指针已禁止:{why};源类型 {s_txt} → 目标类型 {d_txt}")
|
||||
# ============================================================
|
||||
# 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si
|
||||
# ============================================================
|
||||
def coerce_to_type(self, builder: llvmlite.IRBuilder*,
|
||||
@@ -478,7 +723,8 @@ novirtual class ExprGenBase:
|
||||
if val.IsConst == 1 and val.IntVal == 0:
|
||||
return llvmlite.build_inttoptr(builder, llvmlite.const_int64(builder.Pool, 0), target_ty)
|
||||
m_i2p: str = "整数隐式转指针已禁止:必须显式强转为指针(如 t.CPtr(x))才能把整数赋给指针类型"
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"{m_i2p};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"{m_i2p};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
return val
|
||||
# Pointer -> integer: rejected (symmetric with the integer -> pointer rule above).
|
||||
# No implicit pointer <-> integer conversion is allowed; an explicit cast is
|
||||
@@ -486,7 +732,8 @@ novirtual class ExprGenBase:
|
||||
# through to the build_load branch below, copying the pointee's first byte.)
|
||||
if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and self.is_ptr_type(target_ty) == 0:
|
||||
m_p2i: str = "指针隐式转整数已禁止:必须显式强转(如 uint64(p) / t.CInt64T(p) / int(p))才能把指针赋给整数类型"
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"{m_p2i};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"{m_p2i};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
return val
|
||||
if val_bits != 0 and target_bits != 0:
|
||||
if val_bits == target_bits:
|
||||
@@ -520,7 +767,8 @@ novirtual class ExprGenBase:
|
||||
# float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径)
|
||||
if (val_fbits != 0 and self.is_ptr_type(target_ty) != 0) or \
|
||||
(self.is_ptr_type(val.Ty) != 0 and target_fbits != 0):
|
||||
self.Gen.TypeGenErr.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"unsupported type conversion: float <-> ptr;出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
return val
|
||||
if val_fbits != 0 and target_fbits != 0:
|
||||
if val_fbits == target_fbits:
|
||||
@@ -558,10 +806,22 @@ novirtual class ExprGenBase:
|
||||
target_kind: int = target_ty.kind()
|
||||
if target_kind == llvmlite.LLVMType.Struct or target_kind == llvmlite.LLVMType.Array:
|
||||
return llvmlite.build_load(builder, target_ty, val)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "指针隐式转非指针值已禁止:必须显式解引用(c.Deref(p) / *p)或显式强转(uint64(p))", "CastError")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"指针隐式转非指针值已禁止:必须显式解引用(c.Deref(p) / *p)或显式强转(uint64(p));出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
return val
|
||||
# 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针)
|
||||
# 指针 → 指针: 隐式转换须满足两条新规则(见 _ptr_cast_reason 单一真源):
|
||||
# 规则 1 通用指针(t.CPtr / i8*)与任何 T* 双向互转都放行;
|
||||
# 规则 2 T* → U* 允许 ⇔ 被指类型 T → U 无损,非基本类型一律禁止;
|
||||
# 规则 3 非基本类型 T 与其指针 T* 之间一律禁止;
|
||||
# 规则 4 完全相同类型(含 Foo* → Foo*)不算转换,照常通过。
|
||||
# 违反者沿用既有 fail-fast 风格报错(CastError + 「…已禁止:」前缀)。
|
||||
if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) != 0:
|
||||
pc: int = self._ptr_cast_reason(builder.Pool, val.Ty, target_ty)
|
||||
if pc != PC_OK:
|
||||
reason: str = self._ptr_cast_reason_text(pc, builder.Pool, val.Ty, target_ty)
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"{reason};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
return val
|
||||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||||
return val
|
||||
|
||||
|
||||
Reference in new issue
Block a user