fix(call): kwargs 调用路径补齐省略形参的默认值

_translate_call_with_kwargs 此前对「位置/关键字均未提供的形参」直接跳过 → 调用实参数 < define 形参数,被调函数按 ABI 读未写寄存器/栈槽(remote.one(x = 1) 的 cap 读成 0,DefaultArgTest 断言失败)。改为:按 found_func mangled 名前缀取定义模块 SHA1,用全局默认表 find_func_defaults 取定义处默认值快照补齐(右对齐索引);取不到默认值时 fail-fast,绝不静默漏参/填零。跨模块默认值通道本就通(vpi 带默认值),无需改产物格式。
This commit is contained in:
TermiNexus committed 2026-10-03 12:08:32 +08:00
1 parent 692998820c
commit 3b465121cd
1 file changed
+50
+50
View File
@@ -6,6 +6,7 @@ import memhub
import string
import stdlib
import lib.core.Gen.Translator as HT
import lib.core.Gen.GenTypes as GenTypes
import lib.Stub.StubGen.VpiReader as VpiReader
import lib.core.Gen.GenApi as GenApi
@@ -718,6 +719,36 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
mc_src1: llvmlite.Value* = None
mc_num1: llvmlite.Value* = None
# 省略参数补齐用的默认参数表查询(与 CallGenMixin 非 kwargs 路径同一真源)。
# 根因:本路径此前对"位置/关键字均未提供的形参"直接跳过 → 调用实参数 <
# define 形参数,被调函数按 x64 ABI 读未写寄存器/栈槽(remote.one(x = 1)
# 的 cap 读成 0/垃圾,DefaultArgTest 断言失败)。
# 定义模块 SHA1 取 found_func 的 mangled 名前缀 "{sha1}.func"(普通跨模块/
# 同模块函数),取不到再回退当前模块 SHA1(同模块调用)。默认值表按
# 「名 + 定义模块 SHA1」登记(_register_global_defaults),注册时已对常量
# 快照,跨 1b reset 永久存活 ⇒ 跨模块也能取到定义处的真实默认值。
kw_callee_sha: str = None
kw_found_name: str = llvmlite.function_get_name(found_func)
if kw_found_name is not None:
if GenApi.sha1_prefix_len(kw_found_name) != 0:
kw_sha_buf: str = pool.alloc(17)
if kw_sha_buf is not None:
string.strncpy(kw_sha_buf, kw_found_name, 16)
kw_sha_buf[16] = '\0'
kw_callee_sha = kw_sha_buf
if kw_callee_sha is None and self.Gen.TypeGenBase is not None:
kw_callee_sha = self.Gen.TypeGenBase.CurrentModuleSha1
kw_gd: GenTypes.FuncDefaultsEntry* = None
if kw_callee_sha is not None:
kw_gd = self.Gen.CallGenLeafKit.find_func_defaults(func_name, kw_callee_sha)
kw_default_count: int = 0
kw_default_off: int = 0
if kw_gd is not None:
kw_default_count = kw_gd.DefaultCount
kw_default_off = kw_gd.ParamCount - kw_gd.DefaultCount
if kw_default_off < 0:
kw_default_off = 0
# 遍历函数参数链表(使用访问器获取 Head)
param_idx: sizet = 0
cur_param: llvmlite.Param* = llvmlite.function_get_param_head(found_func)
@@ -742,6 +773,25 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
arg_val = self.Gen.ExprGen.translate_value(builder, pool, mod, kw.value, None, 0, trans, param_ty)
break
# 位置/关键字均未提供该形参:用**定义处**的默认值补齐(默认值右对齐,
# 索引 = param_idx - param_count + default_count)。缺省且定义处无默认值
# 可用时 fail-fast——绝不静默漏参或填零(漏参会令被调函数按 ABI 读垃圾)。
if arg_val is None:
if kw_default_count > 0 and int(param_idx) >= kw_default_off:
kw_di: int = int(param_idx) - kw_default_off
if kw_di >= 0 and kw_di < kw_default_count:
arg_val = self.Gen.CallGenLeafKit._build_const_from_snapshot(
pool, mod, kw_gd, kw_di, trans, builder)
if arg_val is None:
kw_node: ast.AST* = None
if keywords is not None and kw_count > 0:
kw_node = keywords.get(0)
self.Gen.TypeGenErr.fatal_error(
kw_node,
f"调用 '{func_name}' 的某个形参既未按位置/关键字传入,"
f"定义处也无默认值可填充(拒绝静默漏参/填零)",
"TypeError")
if arg_val is not None:
# 类型转换(按参数类型,使用访问器)
if param_ty is not None: