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:
1 parent
e33ac795ed
commit
e1a2821bff
3 files changed
+38
-7
No files matched your search
@@ -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:
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in new issue
Block a user