fix(tpc): 函数声明创建全部收口到唯一幂等入口,消除 DuplicatedNameError 裸抛

类别 a(编译器缺陷)+ b(机制漏豁免)。报错:翻译 lib\core\Gen\Expr\ExprGenName.vp
失败,报文只有名字 dddc595175f00c66.ExprGenAttr.find_global_in_module
⇒ llvmlite DuplicatedNameError(NameScope.register 对 GlobalValue
deduplicate_name=False,同名 global 再建必抛,__str__ 只回名字)。

根因(已取证,非猜测):
- llvmlite Module 里 `scope`(NameScope,注册/去重)与 `globals`(OrderedDict)
  是两套结构;`add_global` 只在构造时写入 ===> 「名字已在 scope._useset、
  但 globals 查不到」这一状态一旦出现,任何"先查 globals 再建"的守卫都会失效。
- 该状态由**清理不完整**制造:删旧名时只删"对象真名 existing_func.name/old_name",
  而字典键/目标名(func_name / MangledName)仍留在 scope._useset。
  别名注册(Gen.functions[短名] = 名为全名的对象)恰好让二者不同名。
- 另有若干创建点只看 Gen.functions、完全不看 module.globals(裸建 ir.Function),
  只要 module.globals 已有同名声明就裸抛 DuplicatedNameError。

本次收口(函数声明创建的唯一入口 = BaseGen._CreateOrReuseFuncDecl):
1. BaseGen._CreateOrReuseFuncDecl:新增"名字被非函数 global 占住"分支,把冲突
   双方(类型 + repr)报出来,替代原 llvmlite 只给名字的裸抛。
2. 清理不完整处补全为「同时清 真名 + 目标名」:
   - HandlesImports.py 模板 declare 装载(clearing func_name 之外还清 existing_func.name)
   - HandlesFunctions._replace_function_decl(clearing {old_name, MangledName})
   - 其 except 对 FailFastError 改为上抛(不再回退成复用旧声明)
3. 裸建 ir.Function 的创建点改走唯一入口(module.globals 同名则复用、
   签名冲突/非函数冲突则 fail-fast):
   - HandlesExprCall._HandleStaticMethodCallLlvm({sha1}.Class.Method)  ← 本现场形态
   - HandlesExprCall._HandleMethodCallLlvm 的 class_sha1 回退分支
   - HandlesExprCall._try_declare_c_lib_func / HandlesExprBuiltin._try_declare_c_lib_func
   - HandlesAssign 模块级全局赋值处的函数声明
   - HandlesImports.__before_init__ 声明(原查 NewFuncName 却建 MangledName)
   - HandlesFunctions._EmitFunctionLlvm(补登记 module.globals 已有声明,
     使既有的签名修复路径生效,而不是裸建撞名)

行为等价性:上述各点原先"撞名"时必然抛 DuplicatedNameError(即必失败),
收口后要么复用同一符号、要么 fail-fast 报出两侧签名/冲突类型,无静默降级。
This commit is contained in:
TermiNexus committed 2026-09-29 13:50:44 +08:00
1 parent 8c831a38d3
commit f4c8c48748
6 files changed
+68 -29

No files matched your search

+19 -8
View File
@@ -2578,7 +2578,10 @@ class ImportHandle(BaseHandle):
if StructType is not None:
StructPtrType = ir.PointerType(StructType)
NewFuncType = ir.FunctionType(ir.VoidType(), [StructPtrType])
NewFunc = ir.Function(Gen.module, NewFuncType, name=MangledName)
# 走唯一幂等入口:查的是 NewFuncName 而建的是 MangledName,二者不同名
# ⇒ 此处若裸建,MangledName 已被 stub / 调用点占住时必抛
# llvmlite DuplicatedNameError。
NewFunc = Gen._CreateOrReuseFuncDecl(MangledName, NewFuncType)
Gen.functions[NewFuncName] = NewFunc
bitfields = Gen.class_member_bitfields.get(ClassName, {})
if any(v > 0 for v in bitfields.values()):
@@ -3406,14 +3409,22 @@ class ImportHandle(BaseHandle):
existing_func = Gen.functions[func_name]
existing_ftype = getattr(existing_func, 'ftype', None) or existing_func.type.pointee
if str(existing_ftype) != str(func_type):
# 类型不一致:清理 module.globals + module.scope._useset 后重建,避免 DuplicatedNameError
old_name = existing_func.name
if old_name in Gen.module.globals:
del Gen.module.globals[old_name]
# 类型不一致:清理 module.globals + module.scope._useset 后重建,
# 避免 DuplicatedNameError。必须同时清 existing_func.name(真名)
# 与 func_name(字典键):别名场景下两者不同(如
# Gen.functions['ExprGenAttr.find_global_in_module'] 指向名为
# 'dddc595175f00c66.ExprGenAttr.find_global_in_module' 的对象),
# 只删真名会留下字典键仍占住 module.scope(llvmlite 按名字去重)
# → 重建仍抛 DuplicatedNameError(报文只有名字,不含冲突双方)。
module_scope = getattr(Gen.module, 'scope', None)
if getattr(module_scope, '_useset', None):
module_scope._useset.discard(old_name)
func = ir.Function(Gen.module, func_type, name=func_name)
_useset = getattr(module_scope, '_useset', None)
for _stale_name in {existing_func.name, func_name}:
_stale = Gen.module.globals.get(_stale_name)
if isinstance(_stale, ir.Function):
del Gen.module.globals[_stale_name]
if _useset is not None:
_useset.discard(_stale_name)
func = Gen._CreateOrReuseFuncDecl(func_name, func_type)
Gen.functions[func_name] = func
if '.' in func_name:
short_name = func_name.split('.', 1)[1]