fix(tpv): 拓宽方向统一为单一真源,并修 TypeStr 变参与 should_zext_widen 缺参
三项独立缺陷(均来自类型系统盘点 _Type.md D7): 1) should_zext_widen 签名缺 trans 形参,函数体内的 trans 退化为隐式全局(恒 None),而 translate_binop 两处调用早已在传第 5 实参(被静默丢弃)⇒ 注释所 述「源无符号 → zext」补救从未生效:Name/Subscript 形态的无符号源(uint16/ uint32 变量、数组元素)在比较/二元路径恒被 sext 扩展(ide.vp/timer.vp 根因)。 修:should_zext_widen 补 trans 形参并明确为拓宽方向的单一真源; translate_compare 两处补传 trans;ExprGenBase._zext_or_sext_val 改为委托 should_zext_widen(wide_val=None 使「宽侧常量」启发式自然失效)。 2) _translate_t_type_cast 原以「目标类型名符号性」决策整数拓宽,且 target_name 未知时默认 zext,与 coerce_to_type / should_zext_widen 的默认 sext 极性相反。 修:统一由源的符号性决定(与 coerce 同源),并删除已无使用点的 target_name 形参(1 处签名 + 7 处调用点)。 3) TypeStr 生成(FuncEntry.TypeStr 的唯一生产者)与其现算现用副本 (ClassGenVTable._format_func_type_str)都未打印变参后缀 ...,而 FuncGenDef 对 *args 会设 IsVarArg=1,且继承方法强制走 TypeStr 回退 ⇒ vtable 中的函数 指针类型与真实签名不符。修:按 llvmlite IR 打印规则补齐(有参 ", ...", 无参 "...")。
This commit is contained in:
1 parent
c71642dca0
commit
b8470c1cae
7 files changed
+56
-36
No files matched your search
@@ -699,14 +699,14 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr,
|
||||
target_name: str = None,
|
||||
src_node: ast.AST | t.CPtr = None,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""类型转换:根据参数类型和目标类型选择转换方式
|
||||
|
||||
整数 → 整数拓宽时(对齐 TPC _HandleTypeCastLlvm L1723-1737):
|
||||
整数 → 整数拓宽:拓宽方向由**源**的符号性决定(与 coerce_to_type 的
|
||||
_zext_or_sext_val 同一规则),与目标类型无关(保号的 C 整数转换语义):
|
||||
源 i1(bool)→ zext
|
||||
目标类型无符号(target_name 命中 CUIntXXT 等)→ zext
|
||||
源 i8 → zext
|
||||
源表达式无符号(t.CUIntXXT(x) 强转 / 无符号注解变量)→ zext
|
||||
否则 → sext(有符号整数拓宽保持数值,如 i8 -50 → 0xFFFFFFCE)
|
||||
"""
|
||||
@@ -726,15 +726,18 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if val_bits == 1:
|
||||
# i1 是布尔值(来自 icmp/fcmp),无符号语义,必须 zext
|
||||
return llvmlite.build_zext(builder, val, target_ty)
|
||||
# 目标类型名已知且为有符号 → 按源符号性 sext/zext(对齐 TPC L1723-1737);
|
||||
# 目标名未知(int()/联合类型强转等)保持默认 zext(旧行为)
|
||||
need_sext: int = 0
|
||||
if target_name is not None and self.Gen.ExprGenOps._type_name_unsigned(target_name) == 0:
|
||||
if src_node is None or self.Gen.ExprGenOps._node_type_unsigned(pool, src_node, trans) == 0:
|
||||
need_sext = 1
|
||||
if need_sext != 0:
|
||||
return llvmlite.build_sext(builder, val, target_ty)
|
||||
return llvmlite.build_zext(builder, val, target_ty)
|
||||
# 统一拓宽方向(与 coerce_to_type 的 _zext_or_sext_val 同源):
|
||||
# i1/i8 → zext;源解析为无符号(t.CUIntXXT 强转 / 无符号注解变量)→ zext;
|
||||
# 否则 → sext(默认有符号)。
|
||||
# 说明:拓宽应保持**源**的数值语义,故由源符号性决定,与目标类型无关
|
||||
#(C 整数转换规则:有符号源拓宽即保号)。此前本处按「目标名符号性」决策,
|
||||
# 且 target_name 未知时默认 zext,与 coerce_to_type / should_zext_widen
|
||||
# 的默认 sext 极性相反 —— 同一窄→宽在强转路径与赋值/比较路径结果相反;
|
||||
# 且 `u64(x)`(x 为有符号 i32)被强制 zext,与 `y: uint64 = x` 的 sext
|
||||
# 不一致(负值场景两者位模式不同)。现统一为源符号性决定。
|
||||
if self.Gen.ExprGenBase._zext_or_sext_val(pool, val, src_node, trans) != 0:
|
||||
return llvmlite.build_zext(builder, val, target_ty)
|
||||
return llvmlite.build_sext(builder, val, target_ty)
|
||||
else:
|
||||
return llvmlite.build_trunc(builder, val, target_ty)
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if cty_val is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, cty_val, ctype_target,
|
||||
func_name, cty_arg0, trans)
|
||||
cty_arg0, trans)
|
||||
# t.CType 语法已确认:即使类型解析失败也不跌落到跨模块 FATAL
|
||||
return None
|
||||
# CConst const 标记:CConst(val, t.CPtr) → Ptr(i8)(const void*)。
|
||||
@@ -373,7 +373,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if cconst_arg is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, cconst_arg, cconst_ptr_ty,
|
||||
func_name, cargs.get(0), trans)
|
||||
cargs.get(0), trans)
|
||||
elif can == 1:
|
||||
return self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
@@ -421,7 +421,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if tc_arg_val is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, tc_arg_val, target_ty,
|
||||
func_name, tc_arg_node, trans)
|
||||
tc_arg_node, trans)
|
||||
# t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL
|
||||
return None
|
||||
|
||||
@@ -457,7 +457,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if mt_arg_val is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, mt_arg_val, mod_td_ty,
|
||||
func_name, cargs.get(0), trans)
|
||||
cargs.get(0), trans)
|
||||
|
||||
# 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等
|
||||
# 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换
|
||||
@@ -534,7 +534,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if bare_arg_val is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, bare_arg_val, bare_ty,
|
||||
bare_fn_name, bare_arg_node, trans)
|
||||
bare_arg_node, trans)
|
||||
if bare_ty is not None and can == 1:
|
||||
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
if bare_arg_node is not None:
|
||||
@@ -545,7 +545,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if bare_arg_val is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, bare_arg_val, bare_ty,
|
||||
bare_fn_name, bare_arg_node, trans)
|
||||
bare_arg_node, trans)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -1072,6 +1072,15 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
self._asm_append_cstr(ty_buf, 1024, param_part)
|
||||
cur = llvmlite.param_get_next(cur)
|
||||
first = 0
|
||||
# 变参函数追加 ...(对齐 llvmlite IR 打印规则,见 includes/llvmlite/__function.vp
|
||||
# L1145-1150:有参数时 ", ...",无参数时 "...")。此前遗漏 → 跨模块继承方法的
|
||||
# vtable 回退路径(ClassGenVTable 对继承方法强制 func_valid=0,只能用本文本)
|
||||
# 生成的函数类型缺 ...,与真实签名不符(本函数为 TypeStr 的唯一生产者)。
|
||||
if func.IsVarArg == 1:
|
||||
if first != 0:
|
||||
self._asm_append_cstr(ty_buf, 1024, "...")
|
||||
else:
|
||||
self._asm_append_cstr(ty_buf, 1024, ", ...")
|
||||
self._asm_append_cstr(ty_buf, 1024, ")")
|
||||
|
||||
# 深拷贝到 stdlib 区(TypeStr 跨文件永久存活)
|
||||
|
||||
@@ -143,7 +143,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if sub_cast_arg is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, sub_cast_arg, sub_cast_ty,
|
||||
gen_class_name, cl.args.get(0), trans)
|
||||
cl.args.get(0), trans)
|
||||
# 泛型类模板未找到:可能未 import 定义模块
|
||||
gt_err: str = pool.alloc(256)
|
||||
if gt_err is not None:
|
||||
|
||||
@@ -105,6 +105,13 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
self._vtable_strcat(buf, buf_size, param_buf)
|
||||
cur = llvmlite.param_get_next(cur)
|
||||
first = 0
|
||||
# 变参函数追加 ...(对齐 llvmlite IR 打印规则与 CallGenLeafKit._build_func_type_str:
|
||||
# 有参数时 ", ...",无参数时 "...")。此前遗漏 → 该回退文本生成的函数类型缺 ...。
|
||||
if func.IsVarArg == 1:
|
||||
if first != 0:
|
||||
self._vtable_strcat(buf, buf_size, "...")
|
||||
else:
|
||||
self._vtable_strcat(buf, buf_size, ", ...")
|
||||
self._vtable_strcat(buf, buf_size, ")")
|
||||
return 1
|
||||
# ============================================================
|
||||
|
||||
@@ -524,26 +524,18 @@ class ExprGenBase:
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""统一整数拓宽方向:1=zext(无符号语义),0=sext
|
||||
|
||||
规则(对齐 ExprGenOps.should_zext_widen / _node_type_unsigned):
|
||||
1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...)
|
||||
2. i8 → zext(系统编程中 i8 几乎总是无符号字节)
|
||||
3. AST 节点解析为无符号类型(t.CUIntXXT 强转/无符号类型名/BYTE 等)→ zext
|
||||
4. 否则 sext
|
||||
委托到 ExprGenOps.should_zext_widen(拓宽方向的**单一真源**),避免两套
|
||||
规则各自演化导致同一「窄→宽」在 coerce 路径与比较/二元路径结论相反。
|
||||
coerce 路径无「宽侧值」上下文,wide_val 传 None 使「宽侧常量超窄侧有符号
|
||||
范围」那条启发式自然失效;其余三条(i1/i8、源无符号、CDefine 高位常量)
|
||||
与旧实现一致或更强。
|
||||
|
||||
trans 供 _node_type_unsigned 经 SymTab 解析变量注解的符号性(Name/
|
||||
Subscript 形态必需);省略则仅能识别显式 t.CUIntXXT 强转。
|
||||
"""
|
||||
if val is None or val.Ty is None:
|
||||
return 0
|
||||
bits: int = self.get_llvm_type_bits(val.Ty)
|
||||
if bits == 1:
|
||||
return 1
|
||||
if bits == 8:
|
||||
return 1
|
||||
if node is not None:
|
||||
if self.Gen.ExprGenOps._node_type_unsigned(pool, node, trans) != 0:
|
||||
return 1
|
||||
return 0
|
||||
return self.Gen.ExprGenOps.should_zext_widen(pool, val, None, node, trans)
|
||||
|
||||
# ============================================================
|
||||
# translate_ptr_arith - 指针算术: ptr + int / ptr - int
|
||||
|
||||
@@ -164,9 +164,18 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
def should_zext_widen(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
narrow_val: llvmlite.Value | t.CPtr,
|
||||
wide_val: llvmlite.Value | t.CPtr,
|
||||
narrow_node: ast.AST | t.CPtr = None) -> int:
|
||||
narrow_node: ast.AST | t.CPtr = None,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""判断整数拓宽方向:1=zext(无符号语义),0=sext
|
||||
|
||||
**拓宽方向的单一真源**:ExprGenBase._zext_or_sext_val(coerce 路径)委托到此。
|
||||
trans 必须下传:_node_type_unsigned 对 Name/Subscript 形态需经 trans.SymTab 查
|
||||
变量/数组元素注解才能判定无符号。此前本函数签名缺 trans 形参,而
|
||||
translate_binop 两处调用**已在传第 5 参**(被静默丢弃),函数体内的 `trans`
|
||||
退化为隐式全局(恒 None)⇒ 「源无符号」规则对 Name/Subscript 恒不命中,
|
||||
无符号值被误用 sext 扩展(本注释原记的 ide.vp identify_data[60] /
|
||||
timer.vp sec 的 uint16/uint32→更宽 根因,补救从未真正接上)。
|
||||
|
||||
对齐 TPC 的 _check_node_unsigned / HandlesExprOps 拓宽规则:
|
||||
1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...)
|
||||
2. i8 → zext(系统编程中 i8 几乎总是无符号字节)
|
||||
@@ -647,12 +656,12 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
rhs_bits: int = self.get_llvm_type_bits(rhs.Ty)
|
||||
if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits:
|
||||
if lhs_bits < rhs_bits:
|
||||
if self.should_zext_widen(pool, lhs, rhs, cmp.left) != 0:
|
||||
if self.should_zext_widen(pool, lhs, rhs, cmp.left, trans) != 0:
|
||||
lhs = llvmlite.build_zext(builder, lhs, rhs.Ty)
|
||||
else:
|
||||
lhs = llvmlite.build_sext(builder, lhs, rhs.Ty)
|
||||
else:
|
||||
if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0:
|
||||
if self.should_zext_widen(pool, rhs, lhs, rhs_node, trans) != 0:
|
||||
rhs = llvmlite.build_zext(builder, rhs, lhs.Ty)
|
||||
else:
|
||||
rhs = llvmlite.build_sext(builder, rhs, lhs.Ty)
|
||||
|
||||
Reference in new issue
Block a user