fix(tpc): 函数声明创建幂等化,消除 DuplicatedNameError

同名声明只在 module.globals、不在 Gen.functions 时,旧代码会再走 ir.Function,而 llvmlite 的 NameScope 按名字去重(GlobalValue.deduplicate_name=False)必抛 DuplicatedNameError。GetOrCreateStubFuncDecl(含 check_existing=False 路径)、GetOrCreateFuncDecl、win32console 内建声明、output-stub 按需载入四处统一先复用 module.globals。真实事故:VarGenMixin.vp 同一模块两处 self.Gen.ExprGen.translate_value(...) 都走 check_existing=False,第二处崩在 llvmlite。
This commit is contained in:
TermiNexus committed 2026-09-27 16:18:37 +08:00
1 parent e33ac795ed
commit e1a2821bff
3 files changed
+38 -7

No files matched your search

+19 -2
View File
@@ -1144,6 +1144,14 @@ class BaseHandle:
replace_name 传递给 _replace_function_decl(通常为未 mangle 的 func_name)。
"""
if name not in Gen.functions:
# Gen.functions 未登记、但 module.globals 已有同名函数(本模块其它调用点
# 或依赖 stub 先建过声明)→ 复用并登记,绝不重建:llvmlite 的 NameScope
# 按名字去重(GlobalValue.deduplicate_name=False),重复 ir.Function 必抛
# DuplicatedNameError。
g_existing: Any = Gen.module.globals.get(name)
if g_existing is not None:
Gen.functions[name] = g_existing
return g_existing
func_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
func_decl = _ir.Function(Gen.module, func_type, name=name)
Gen.functions[name] = func_decl
@@ -1168,12 +1176,21 @@ class BaseHandle:
) -> Any:
"""创建 stub 函数声明,可选注册别名。
check_existing=False 时跳过存在性检查(用于确定不存在的场景)。
check_existing=False 时跳过 Gen.functions 存在性检查(用于确定不存在的场景),
但**仍复用 module.globals 里的同名声明**——llvmlite 的 NameScope 按名字去重
(GlobalValue.deduplicate_name=False),"强制新建同名 global"在 llvmlite 下
不成立、必抛 DuplicatedNameError,故此路必须幂等。
真实事故:同一模块两处 `self.Gen.ExprGen.translate_value(...)`(VarGenMixin.vp)
都走 check_existing=False,第一处建声明成功、第二处抛 DuplicatedNameError。
"""
if check_existing and decl_name in Gen.functions:
func_decl = Gen.functions[decl_name]
else:
func_decl = _ir.Function(Gen.module, stub_func_type, name=decl_name)
g_ex_decl: Any = Gen.module.globals.get(decl_name)
if g_ex_decl is not None:
func_decl = g_ex_decl
else:
func_decl = _ir.Function(Gen.module, stub_func_type, name=decl_name)
Gen.functions[decl_name] = func_decl
if alias and alias != decl_name:
if not check_existing or alias not in Gen.functions:
+10 -4
View File
@@ -1936,10 +1936,16 @@ class ExprCallHandle(BaseHandle):
if ModulePath and 'win32console' in ModulePath and func_name in win32_apis:
ret_type, param_types = win32_apis[func_name]
if func_name not in Gen.functions:
func_type = ir.FunctionType(ret_type, param_types)
func_decl = ir.Function(Gen.module, func_type, name=func_name)
func_decl.linkage = 'external'
Gen.functions[func_name] = func_decl
# module.globals 已有同名声明(其它路径/依赖 stub 先建)→ 直接登记复用,
# 不重建(llvmlite NameScope 按名字去重,重建必抛 DuplicatedNameError)
g_ex_w32: Any = Gen.module.globals.get(func_name)
if g_ex_w32 is not None:
Gen.functions[func_name] = g_ex_w32
else:
func_type = ir.FunctionType(ret_type, param_types)
func_decl = ir.Function(Gen.module, func_type, name=func_name)
func_decl.linkage = 'external'
Gen.functions[func_name] = func_decl
call_args = []
if Node.args:
arg_val = self.HandleExprLlvm(Node.args[0])
+9 -1
View File
@@ -3398,7 +3398,15 @@ class ImportHandle(BaseHandle):
at_pos: int = stripped.rindex('@', 0, paren_pos)
func_name: str = stripped[at_pos + 1:paren_pos].strip().strip('"')
if func_name not in Gen.functions:
func = ir.Function(Gen.module, func_type, name=func_name)
# module.globals 已有同名声明 → 复用(llvmlite NameScope
# 按名字去重,重复 ir.Function 必抛 DuplicatedNameError;
# 此前该异常被下方 except 静默吞掉 → 声明未登记 → 后续
# 调用点找不到签名)
g_ex_stub = Gen.module.globals.get(func_name)
if g_ex_stub is not None:
func = g_ex_stub
else:
func = ir.Function(Gen.module, func_type, name=func_name)
Gen.functions[func_name] = func
if '.' in func_name:
short_fn = func_name.split('.', 1)[1]