fix(CallGenCall): 拆开 vtable_base 类型推断的变量复用(LLVMType* 与 StructEntry* 不可同一变量)

严格指针规则下 struct↔struct 隐式转换已禁止(仅允许派生→基类上转),原写法把 get_struct_type_from_value 的返回(LLVMType*)赋给 vc_entry: StructEntry* 再转手交给 find_struct_by_type,靠的是旧的无条件 bitcast。

改为各用独立变量(vb_ty / sp_ty),语义与改前逐字一致(仅去掉两次隐式 bitcast)。
This commit is contained in:
TermiNexus committed 2026-09-28 16:54:25 +08:00
1 parent 3bed3a70a6
commit 9c427aa548
1 file changed
+30 -26
+30 -26
View File
@@ -71,17 +71,21 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
vc_entry: GenTypes.StructEntry* = None
struct_ty: llvmlite.LLVMType* = None
if vtable_base is not None and vtable_base.Ty is not None:
vc_entry = self.Gen.StructGen.get_struct_type_from_value(vtable_base)
if vc_entry is not None:
# vc_entry 是 struct_ty(LLVMType),需要找 StructEntry
vc_entry = self.Gen.StructGen.find_struct_by_type(vc_entry)
# 中间结果(LLVMType)与 vc_entry(StructEntry)是**两个不同的结构体**,
# 不能复用同一个变量:严格指针规则禁止 struct↔struct 的隐式转换
# (仅允许派生→基类上转),复用会让 LLVMType* 赋给 StructEntry* 变量时
# 直接编译期报错。各自用独立变量,语义与改前逐字一致。
vb_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(vtable_base)
if vb_ty is not None:
# vb_ty 是 struct_ty(LLVMType),需要找 StructEntry
vc_entry = self.Gen.StructGen.find_struct_by_type(vb_ty)
if vc_entry is not None:
struct_ty = vc_entry.Ty
if struct_ty is None and self_ptr is not None and self_ptr.Ty is not None:
# fallback:vtable_base 无类型信息时退回 self_ptr(未调整场景两者一致)
vc_entry = self.Gen.StructGen.get_struct_type_from_value(self_ptr)
if vc_entry is not None:
vc_entry = self.Gen.StructGen.find_struct_by_type(vc_entry)
sp_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(self_ptr)
if sp_ty is not None:
vc_entry = self.Gen.StructGen.find_struct_by_type(sp_ty)
if vc_entry is not None:
struct_ty = vc_entry.Ty
if struct_ty is None:
@@ -637,25 +641,25 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
head = self.Gen.CallGenLib._coerce_args_to_def_params(pool, builder, call_name, head, total_count, None, 1, trans)
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
call_res_cmop: llvmlite.Value* = llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
# 值位置 volatile 构造:call 指令本身无 volatile 限定符,构造语义只能落在
# 内存存取上。逐字段 store 已由调用方(_translate_struct_ctor 等)带 volatile;
# __new__/__before_init__/__init__ 的写入发生在被调函数内部,调用点无法逐条
# 附加 volatile ⇒ 此处追加一次 volatile 屏障(对 self 指针做 i8 volatile load)。
# volatile 访问有副作用:不会被 DCE,且禁止优化器假设其前后内存不变,从而
# 保证本次构造对对象内存的写入不可被消除或跨越重排。仅对构造三方法生效,
# 不给普通方法调用引入额外访存。
if is_volatile != 0 and self_ptr is not None and self_ptr.Ty is not None:
if string.strcmp(method_name, "__new__") == 0 \
or string.strcmp(method_name, "__before_init__") == 0 \
or string.strcmp(method_name, "__init__") == 0:
cmop_i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
cmop_i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, cmop_i8_ty)
cmop_bar_ptr: llvmlite.Value* = self_ptr
if uint64(self_ptr.Ty) != uint64(cmop_i8_ptr_ty):
cmop_bar_ptr = llvmlite.build_bitcast(builder, self_ptr, cmop_i8_ptr_ty)
if cmop_bar_ptr is not None:
llvmlite.build_load(builder, cmop_i8_ty, cmop_bar_ptr, 1)
call_res_cmop: llvmlite.Value* = llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
# 值位置 volatile 构造:call 指令本身无 volatile 限定符,构造语义只能落在
# 内存存取上。逐字段 store 已由调用方(_translate_struct_ctor 等)带 volatile;
# __new__/__before_init__/__init__ 的写入发生在被调函数内部,调用点无法逐条
# 附加 volatile ⇒ 此处追加一次 volatile 屏障(对 self 指针做 i8 volatile load)。
# volatile 访问有副作用:不会被 DCE,且禁止优化器假设其前后内存不变,从而
# 保证本次构造对对象内存的写入不可被消除或跨越重排。仅对构造三方法生效,
# 不给普通方法调用引入额外访存。
if is_volatile != 0 and self_ptr is not None and self_ptr.Ty is not None:
if string.strcmp(method_name, "__new__") == 0 \
or string.strcmp(method_name, "__before_init__") == 0 \
or string.strcmp(method_name, "__init__") == 0:
cmop_i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
cmop_i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, cmop_i8_ty)
cmop_bar_ptr: llvmlite.Value* = self_ptr
if uint64(self_ptr.Ty) != uint64(cmop_i8_ptr_ty):
cmop_bar_ptr = llvmlite.build_bitcast(builder, self_ptr, cmop_i8_ptr_ty)
if cmop_bar_ptr is not None:
llvmlite.build_load(builder, cmop_i8_ty, cmop_bar_ptr, 1)
return call_res_cmop
# ============================================================
# _translate_method_call - 翻译方法调用 obj.method(args)