diff --git a/App/lib/core/Gen/CallGenCall.vp b/App/lib/core/Gen/CallGenCall.vp index 411cb00..dfd7cb9 100644 --- a/App/lib/core/Gen/CallGenCall.vp +++ b/App/lib/core/Gen/CallGenCall.vp @@ -79,15 +79,28 @@ class CallGenCall(CallGenBase.CallGenBase): vtable_base = self_ptr # 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + # 必须用 vtable_base(对象头)的类型而非 self_ptr:多继承 this 调整后 + # self_ptr 已 bitcast 成父类指针(如 ColorM*),用其解析会得到父类 + # vtable 布局(单槽 {i8*})→ method_index/method_count 按父类算, + # GEP 槽位错位读到别的函数(MultiInheritTest color_code 虚调用读到 + # area FAILED 根因)。vtable_base 是接收者静态类型指针(vtable 所在 + # 位置),其 VTableMethods 才是最终对象实际存储的完整 vtable 布局。 vc_entry: GenTypes.StructEntry | t.CPtr = None struct_ty: llvmlite.LLVMType | t.CPtr = None - if self_ptr.Ty is not None: - vc_entry = self.Gen.StructGen.get_struct_type_from_value(self_ptr) + 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) 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) + if vc_entry is not None: + struct_ty = vc_entry.Ty if struct_ty is None: struct_ty = self.Gen.StructGen.get_struct_type(class_name) if struct_ty is None: @@ -420,6 +433,48 @@ class CallGenCall(CallGenBase.CallGenBase): mdf_default_count = mdf_gd.DefaultCount mdf_param_count = mdf_gd.ParamCount + # 跨模块 stub 未注入兜底(同 _translate_method_call):found_func 为 + # None 且函数表无 ParamCount 时,用 vpi 文本缓存补全参数数,默认 + # 参数填充(含零值兜底)随即生效,declare/call 与 define 对齐。 + vpi_pa: str = None + if mdf_param_count == 0 and found_func is None: + vpi_sha1_p: str = None + if cmop_entry is not None and cmop_entry.ModuleSha1 is not None: + vpi_sha1_p = cmop_entry.ModuleSha1 + else: + vpi_sha1_p = self.Gen.StructGen.get_struct_sha1(class_name) + if vpi_sha1_p is not None: + vpi_pa = self.Gen.CallGenBase._vpi_method_param_annot( + pool, vpi_sha1_p, class_name, method_name) + if vpi_pa is not None and vpi_pa[0] != '\0': + vpi_pc2: int = 1 + vi2: t.CSizeT = 0 + while vpi_pa[vi2] != '\0': + if vpi_pa[vi2] == '@': + vpi_pc2 += 1 + vi2 += 1 + mdf_param_count = vpi_pc2 - 1 # 非 self 参数数 + + # [修复 2026-08-25] found_func 参数数回退(同 _translate_method_call): + # 函数表/默认表无 ParamCount 但 found_func(declare)已找到时用其参数数 + # 作补全基准,否则省略默认参数(如 translate_value 的 target_ty=None) + # 的调用补全不触发 → call 实参 < define 形参 → ABI 错位读栈残留垃圾。 + # 排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__):含 raise 函数 + # 定义尾部注入 2 个 EH 形参,计入会让 _emit_eh_guarded_call 追加真实 + # EH 实参前先补 zeroinitializer 占位 → 双重注入 call 实参多 2(TestFBProject + # raise_disk() 崩溃根因,与 CallGenMixin 零值兜底同源)。 + if mdf_param_count == 0 and found_func is not None: + ppcnt_f2: int = 0 + ppn_f2: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + while ppn_f2 is not None: + fp_nm_f2: str = llvmlite.param_get_name(ppn_f2) + if fp_nm_f2 is None or (string.strcmp(fp_nm_f2, "%__eh_msg_out__") != 0 + and string.strcmp(fp_nm_f2, "%__eh_code_out__") != 0): + ppcnt_f2 += 1 + ppn_f2 = llvmlite.param_get_next(ppn_f2) + if ppcnt_f2 > 1: + mdf_param_count = ppcnt_f2 - 1 # 非 self 非 EH 参数数 + # 计算需要填充的参数(不含 self) # extra_count = 已提供的非 self 参数数量 # mdf_param_count = 函数定义的非 self 参数数量 @@ -470,6 +525,40 @@ class CallGenCall(CallGenBase.CallGenBase): llvmlite.value_set_next(tail, zero_val) tail = zero_val total_count += 1 + elif vpi_pa is not None: + # found_func 为 None(stub 未注入):用 vpi 参数注解解析 + # 缺失参数类型(段索引 mdf_pi+1,跳过首参 self 空段), + # 值取类型零值(默认参数值恰为零值;查不到 ≠ 无默认值)。 + seg_idx_v: int = mdf_pi + 1 + seg_no_v: int = 0 + seg_cur_v: t.CSizeT = 0 + while seg_no_v < seg_idx_v and vpi_pa[seg_cur_v] != '\0': + if vpi_pa[seg_cur_v] == '@': + seg_no_v += 1 + seg_cur_v += 1 + seg_start_v: t.CSizeT = seg_cur_v + seg_len_v: t.CSizeT = 0 + while vpi_pa[seg_start_v + seg_len_v] != '\0' \ + and vpi_pa[seg_start_v + seg_len_v] != '@': + seg_len_v += 1 + if seg_no_v == seg_idx_v: + pty_v: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if seg_len_v > 0: + seg_buf_v: bytes = stdlib.malloc(seg_len_v + 1) + if seg_buf_v is not None: + string.strncpy(seg_buf_v, vpi_pa + seg_start_v, seg_len_v) + seg_buf_v[seg_len_v] = '\0' + rty_v: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenBase._vpi_resolve_param_annot_ty( + pool, seg_buf_v) + if rty_v is not None: + pty_v = rty_v + stdlib.free(seg_buf_v) + zero_val_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, pty_v) + if zero_val_v is not None: + llvmlite.value_set_next(zero_val_v, None) + llvmlite.value_set_next(tail, zero_val_v) + tail = zero_val_v + total_count += 1 mdf_pi += 1 elif found_func is not None: # 无默认参数信息但有 found_func:用零值兜底填充缺失参数 @@ -558,6 +647,36 @@ class CallGenCall(CallGenBase.CallGenBase): # 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value if found_func is None: self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) + # [根治] declare 创建后按形参类型 coerce 实参(与上方 found_func 路径 + # 的 L588-611 同逻辑,缺失导致字面量 0=i32 传 i64 形参(t.CSizeT)未提升: + # llc 按 i32 布局栈参(movl 4 字节写)→ i64 形参高 4 字节残留垃圾 → + # callee 读 can=[垃圾][count] 崩溃,SlotsBugTest/StringIterTest 根因, + # 反汇编 movl 实锤)。coerce 使 IR call 实参与 declare 形参类型一致。 + dc_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) + if dc_func is not None and head is not None: + dc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(dc_func) + dc_node: llvmlite.Value | t.CPtr = head + dc_new_head: llvmlite.Value | t.CPtr = head + dc_prev: llvmlite.Value | t.CPtr = None + while dc_node is not None: + dc_next: llvmlite.Value | t.CPtr = dc_node.Next + dc_cur: llvmlite.Value | t.CPtr = dc_node + if dc_param is not None: + dc_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(dc_param) + if dc_pty is not None: + dc_c: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, dc_node, dc_pty, None) + if dc_c is not None: + dc_cur = dc_c + dc_param = llvmlite.param_get_next(dc_param) + dc_cur.Next = None + if dc_prev is None: + dc_new_head = dc_cur + else: + dc_prev.Next = dc_cur + dc_prev = dc_cur + dc_node = dc_next + head = dc_new_head return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) # ============================================================ @@ -648,45 +767,64 @@ class CallGenCall(CallGenBase.CallGenBase): mixin_anc_name: str = None mixin_anc_sha1: str = None if found_func is None: - sc_i: int = 0 - sc_n: int = self.Gen.StructGen.get_struct_count() - while sc_i < sc_n and found_func is None and mixin_hit == 0: - cand_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen._get_struct_entry(sc_i) - if cand_entry is not None and cand_entry.Name is not None: - cand_name: str = cand_entry.Name - if string.strcmp(cand_name, class_name) != 0: - # 泛型特化类名含 '['(list[...]/dict[...]):跳过, - # 不是兄弟 Mixin 候选(见上方注释) - if string.strchr(cand_name, '[') is not None: - sc_i += 1 - continue - cand_lookup: str = pool.alloc(128) - if cand_lookup is not None: - viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name) - cand_func: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, cand_lookup) - if cand_func is not None: - found_func = cand_func - mc_anc = cand_name - else: - # 跨模块 Mixin(定义类在另一文件,本地 IR 无 define): - # 用候选类模块 sha1 查 text.ll 返回类型,命中即锁定定义类, - # 后续 ret_anc_* 据此构造 {sha1}.{class}.{method} 调用名。 - # 否则 ret_anc_sha1 停在调用类自身 sha1,_dep_text_ll_exists - # 查自身 text.ll(Phase A 翻译中未生成)→ 永久 pending 死锁 - # (ClassGenVTable._mangle_name → 7871cc1aabebfc33 根因)。 - if mixin_hit == 0: - cand_sha1_cx: str = self.Gen.StructGen.get_struct_sha1(cand_name) - if cand_sha1_cx is not None \ - and self._dep_text_ll_exists(pool, cand_sha1_cx) != 0: - cand_ret_cx: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, cand_sha1_cx, cand_name, method_name) - if cand_ret_cx is not None: - mixin_hit = 1 - mixin_ret_ty = cand_ret_cx - mixin_anc_name = cand_name - mixin_anc_sha1 = cand_sha1_cx - sc_i += 1 + # 兄弟 Mixin 兜底仅对"接收者类属于当前模块"的场景适用:self 调用兄弟 + # Mixin 方法时接收者是本类(与候选兄弟类同模块)。接收者类是跨模块类 + # (如 self.Gen.TypeGenResolve 的 TypeGenResolve,定义在另一模块)时, + # 其方法必须经该类自身模块(text.ll/vpi)解析——若本模块恰好定义了 + # 同名方法 {Cand}.{method},本兜底会误绑定:最坏情况绑定到正在编译的 + # 函数自身 → ImportsGenMixin.set_current_file 内 self.Gen.TypeGenResolve. + # set_current_file(...) 被编译成自调用 → 无限递归 stack-overflow + # (二代编 FuncTest 崩溃根因)。接收者类模块无法确定时保持原行为。 + sib_recv_local: int = 1 + if trans is not None and trans.ModuleSha1 is not None: + sib_recv_sha1: str = None + if mc_entry is not None and mc_entry.ModuleSha1 is not None: + sib_recv_sha1 = mc_entry.ModuleSha1 + else: + sib_recv_sha1 = self.Gen.StructGen.get_struct_sha1(class_name) + if sib_recv_sha1 is not None: + if string.strcmp(sib_recv_sha1, trans.ModuleSha1) != 0: + sib_recv_local = 0 + if sib_recv_local != 0: + sc_i: int = 0 + sc_n: int = self.Gen.StructGen.get_struct_count() + while sc_i < sc_n and found_func is None and mixin_hit == 0: + cand_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen._get_struct_entry(sc_i) + if cand_entry is not None and cand_entry.Name is not None: + cand_name: str = cand_entry.Name + if string.strcmp(cand_name, class_name) != 0: + # 泛型特化类名含 '['(list[...]/dict[...]):跳过, + # 不是兄弟 Mixin 候选(见上方注释) + if string.strchr(cand_name, '[') is not None: + sc_i += 1 + continue + cand_lookup: str = pool.alloc(128) + if cand_lookup is not None: + viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name) + cand_func: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, cand_lookup) + if cand_func is not None: + found_func = cand_func + mc_anc = cand_name + else: + # 跨模块 Mixin(定义类在另一文件,本地 IR 无 define): + # 用候选类模块 sha1 查 text.ll 返回类型,命中即锁定定义类, + # 后续 ret_anc_* 据此构造 {sha1}.{class}.{method} 调用名。 + # 否则 ret_anc_sha1 停在调用类自身 sha1,_dep_text_ll_exists + # 查自身 text.ll(Phase A 翻译中未生成)→ 永久 pending 死锁 + # (ClassGenVTable._mangle_name → 7871cc1aabebfc33 根因)。 + if mixin_hit == 0: + cand_sha1_cx: str = self.Gen.StructGen.get_struct_sha1(cand_name) + if cand_sha1_cx is not None \ + and self._dep_text_ll_exists(pool, cand_sha1_cx) != 0: + cand_ret_cx: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, cand_sha1_cx, cand_name, method_name) + if cand_ret_cx is not None: + mixin_hit = 1 + mixin_ret_ty = cand_ret_cx + mixin_anc_name = cand_name + mixin_anc_sha1 = cand_sha1_cx + sc_i += 1 # 确定调用名(默认 "ClassName.method";found_func 未命中时沿 MRO 用 # 方法实际定义类的 SHA1 构造,如 Module.append → AST 定义的 append, @@ -1178,8 +1316,10 @@ class CallGenCall(CallGenBase.CallGenBase): break arg_val_k: llvmlite.Value | t.CPtr = None if arg_node_k is not None: + # 先取形参类型(char 字面量 → str 形参需物化字符串,见 translate_constant) + pty_k0: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) arg_val_k = self.Gen.ExprGen.translate_value( - builder, pool, mod, arg_node_k, None, 0, trans) + builder, pool, mod, arg_node_k, None, 0, trans, pty_k0) if arg_val_k is None: # 缺失参数:零值兜底(保持参数数量匹配)。 # kw 省略的形参可能有默认值(查不到默认表 ≠ 无默认值), @@ -1204,15 +1344,13 @@ class CallGenCall(CallGenBase.CallGenBase): arg_node: ast.AST | t.CPtr = cargs.get(ai) if arg_node is None: continue - arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if arg_val is None: - continue - # 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) - # 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT) - # 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃 + # 先取形参类型:单引号单字符字面量(CONST_CHAR)传给 str/指针 + # 形参时需物化 1 字符字符串(translate_constant 依据 target_ty 判定), + # 否则 coerce inttoptr 把字符值当指针 → strlen 访问低地址崩溃。 + pp: llvmlite.Param | t.CPtr = None + pty: llvmlite.LLVMType | t.CPtr = None if found_func is not None: - pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + pp = llvmlite.function_get_param_head(found_func) pi: int = 0 while pp is not None and pi < ai + 1: if pi == ai + 1: @@ -1220,10 +1358,18 @@ class CallGenCall(CallGenBase.CallGenBase): pp = llvmlite.param_get_next(pp) pi += 1 if pp is not None: - pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) - if pty is not None: - arg_val = self.Gen.ExprGenBase.coerce_to_type( - builder, arg_val, pty, arg_node) + pty = llvmlite.param_get_ty(pp) + arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node, None, 0, trans, pty) + if arg_val is None: + continue + # 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) + # 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT) + # 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃 + if found_func is not None: + if pty is not None: + arg_val = self.Gen.ExprGenBase.coerce_to_type( + builder, arg_val, pty, arg_node) else: # found_func=None(跨模块 stub 未注入):数组实参按 C 语义 # 衰减为元素指针(对齐 TPC _decay_array_to_ptr)。否则 @@ -1270,6 +1416,53 @@ class CallGenCall(CallGenBase.CallGenBase): mdf_default_count = mdf_gd.DefaultCount mdf_param_count = mdf_gd.ParamCount + # 跨模块 stub 未注入兜底:如 self.Gen.ExprGenCdef.method 经 Generator + # 属性访问调用依赖模块方法,依赖收集不加载其 vpi → 函数表无 + # ParamCount/默认参数 → 调用点缺参 → 被调函数读栈残留 + # (IterTest 跨模块 CDefine 查找 depth=160 假递归根因)。用 vpi + # 文本缓存补全参数数,下方默认参数填充(含零值兜底)随即生效, + # declare/call 与 define 参数数对齐。 + vpi_pa: str = None + if mdf_param_count == 0 and found_func is None: + vpi_sha1_p: str = None + if mc_entry is not None and mc_entry.ModuleSha1 is not None: + vpi_sha1_p = mc_entry.ModuleSha1 + else: + vpi_sha1_p = self.Gen.StructGen.get_struct_sha1(class_name) + if vpi_sha1_p is not None: + vpi_pa = self.Gen.CallGenBase._vpi_method_param_annot( + pool, vpi_sha1_p, class_name, method_name) + if vpi_pa is not None and vpi_pa[0] != '\0': + vpi_pc2: int = 1 + vi2: t.CSizeT = 0 + while vpi_pa[vi2] != '\0': + if vpi_pa[vi2] == '@': + vpi_pc2 += 1 + vi2 += 1 + mdf_param_count = vpi_pc2 - 1 # 非 self 参数数 + + # [修复 2026-08-25] found_func 参数数回退:函数表/默认表无 ParamCount + # (mdf_param_count==0)但 found_func(模块内 declare)已找到时,用其 + # 参数数作补全基准。缺它:省略默认参数(如 translate_value 的 + # target_ty=None)的调用补全不触发 → call 实参(8) < define 形参(9) + # → x64 ABI 第 9 参读栈残留垃圾 → is_ptr_type(0x40) 崩溃(SlotsBugTest + # 二代编 translate_assign/AugAssign 崩溃根因)。 + # 排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__):含 raise 方法 + # 定义尾部注入 2 个 EH 形参,计入会让补全先补 zeroinitializer 占位, + # _emit_eh_guarded_call 再追加真实 EH 实参 → 双重注入(TestFBProject + # raise_disk() 崩溃同源,与 _call_method_on_ptr/CallGenMixin 一致)。 + if mdf_param_count == 0 and found_func is not None: + ppcnt_f: int = 0 + ppn_f: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + while ppn_f is not None: + fp_nm_f: str = llvmlite.param_get_name(ppn_f) + if fp_nm_f is None or (string.strcmp(fp_nm_f, "%__eh_msg_out__") != 0 + and string.strcmp(fp_nm_f, "%__eh_code_out__") != 0): + ppcnt_f += 1 + ppn_f = llvmlite.param_get_next(ppn_f) + if ppcnt_f > 1: + mdf_param_count = ppcnt_f - 1 # 非 self 非 EH 参数数 + # 计算需要填充的参数(不含 self) # arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建) # mdf_param_count = 函数定义的非 self 参数数量 @@ -1317,6 +1510,40 @@ class CallGenCall(CallGenBase.CallGenBase): llvmlite.value_set_next(tail, zero_val) tail = zero_val total_count += 1 + elif vpi_pa is not None: + # found_func 为 None(stub 未注入):用 vpi 参数注解解析 + # 缺失参数类型(段索引 mdf_pi+1,跳过首参 self 空段), + # 值取类型零值(默认参数值恰为零值;查不到 ≠ 无默认值)。 + seg_idx_v: int = mdf_pi + 1 + seg_no_v: int = 0 + seg_cur_v: t.CSizeT = 0 + while seg_no_v < seg_idx_v and vpi_pa[seg_cur_v] != '\0': + if vpi_pa[seg_cur_v] == '@': + seg_no_v += 1 + seg_cur_v += 1 + seg_start_v: t.CSizeT = seg_cur_v + seg_len_v: t.CSizeT = 0 + while vpi_pa[seg_start_v + seg_len_v] != '\0' \ + and vpi_pa[seg_start_v + seg_len_v] != '@': + seg_len_v += 1 + if seg_no_v == seg_idx_v: + pty_v: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if seg_len_v > 0: + seg_buf_v: bytes = stdlib.malloc(seg_len_v + 1) + if seg_buf_v is not None: + string.strncpy(seg_buf_v, vpi_pa + seg_start_v, seg_len_v) + seg_buf_v[seg_len_v] = '\0' + rty_v: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenBase._vpi_resolve_param_annot_ty( + pool, seg_buf_v) + if rty_v is not None: + pty_v = rty_v + stdlib.free(seg_buf_v) + zero_val_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, pty_v) + if zero_val_v is not None: + llvmlite.value_set_next(zero_val_v, None) + llvmlite.value_set_next(tail, zero_val_v) + tail = zero_val_v + total_count += 1 mdf_pi += 1 # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 @@ -1508,12 +1735,11 @@ class CallGenCall(CallGenBase.CallGenBase): arg_node_sp: ast.AST | t.CPtr = cargs_sp.get(ai_sp) if arg_node_sp is None: continue - arg_val_sp: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, mod, arg_node_sp, None, 0, trans) - if arg_val_sp is None: - continue + # 先取形参类型(char 字面量 → str 形参需物化字符串,见 translate_constant) + pp_sp: llvmlite.Param | t.CPtr = None + pty_sp: llvmlite.LLVMType | t.CPtr = None if found_func is not None: - pp_sp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + pp_sp = llvmlite.function_get_param_head(found_func) pi_sp: int = 0 while pp_sp is not None and pi_sp < ai_sp + 1: if pi_sp == ai_sp + 1: @@ -1521,10 +1747,14 @@ class CallGenCall(CallGenBase.CallGenBase): pp_sp = llvmlite.param_get_next(pp_sp) pi_sp += 1 if pp_sp is not None: - pty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_sp) - if pty_sp is not None: - arg_val_sp = self.Gen.ExprGenBase.coerce_to_type( - builder, arg_val_sp, pty_sp, arg_node_sp) + pty_sp = llvmlite.param_get_ty(pp_sp) + arg_val_sp: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, mod, arg_node_sp, None, 0, trans, pty_sp) + if arg_val_sp is None: + continue + if pty_sp is not None: + arg_val_sp = self.Gen.ExprGenBase.coerce_to_type( + builder, arg_val_sp, pty_sp, arg_node_sp) else: # found_func=None:数组实参按 C 语义衰减为元素指针 # (与 _translate_method_call 一致,避免 declare 类型不匹配)