From f4c8c48748bb688ce6591b142f2c4ec8734de5be Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 29 Sep 2026 13:50:44 +0800 Subject: [PATCH] =?UTF-8?q?fix(tpc):=20=E5=87=BD=E6=95=B0=E5=A3=B0?= =?UTF-8?q?=E6=98=8E=E5=88=9B=E5=BB=BA=E5=85=A8=E9=83=A8=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=E5=88=B0=E5=94=AF=E4=B8=80=E5=B9=82=E7=AD=89=E5=85=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E6=B6=88=E9=99=A4=20DuplicatedNameError=20=E8=A3=B8?= =?UTF-8?q?=E6=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类别 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 报出两侧签名/冲突类型,无静默降级。 --- lib/core/Handles/HandlesAssign.py | 5 ++-- lib/core/Handles/HandlesExprBuiltin.py | 6 ++--- lib/core/Handles/HandlesExprCall.py | 17 ++++++++------ lib/core/Handles/HandlesFunctions.py | 32 ++++++++++++++++++-------- lib/core/Handles/HandlesImports.py | 27 +++++++++++++++------- lib/core/LLVMCG/BaseGen.py | 10 ++++++++ 6 files changed, 68 insertions(+), 29 deletions(-) diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index 357f7c2..6e7c6b5 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -594,8 +594,9 @@ class AssignHandle(BaseHandle): llvm_param_types.append(lp) func_type: ir.FunctionType = ir.FunctionType(ret_type, llvm_param_types) MangledName: str = Gen._mangle_func_name(FuncName) - func_decl: ir.Function = ir.Function(Gen.module, func_type, name=MangledName) - Gen.functions[MangledName] = func_decl + # 走唯一幂等入口(module.globals 已有同名声明复用 / + # 类型冲突 fail-fast),避免裸建抛 DuplicatedNameError。 + func_decl: ir.Function = Gen._CreateOrReuseFuncDecl(MangledName, func_type) Gen.functions[FuncName] = func_decl if not MultiRetTypes and FuncName: func: ir.Function | None = Gen.functions.get(FuncName) diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py index 5825804..0615343 100644 --- a/lib/core/Handles/HandlesExprBuiltin.py +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -576,9 +576,9 @@ class ExprBuiltinHandle(BaseHandle): param_types: list[ir.Type] ret_type, param_types = self._C_LIB_FUNCS[func_name]() func_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) - func: ir.Function = ir.Function(Gen.module, func_type, name=func_name) - Gen.functions[func_name] = func - return func + # C 库声明名固定(malloc/strlen/...),同一模块内多次调用必须复用同一符号: + # 裸建会在第二次抛 llvmlite DuplicatedNameError。 + return Gen._CreateOrReuseFuncDecl(func_name, func_type) def _FailFastLenUnsupported(self, arg_node: ast.AST, Gen: LlvmGeneratorMixin, val: ir.Value | None, reason: str) -> None: diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 6026f47..052c010 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -1220,8 +1220,9 @@ class ExprCallHandle(BaseHandle): if ClassName in Gen.structs and not is_static: llvm_param_types.insert(0, ir.PointerType(Gen.structs[ClassName])) func_type = ir.FunctionType(ret_type, llvm_param_types) - func = ir.Function(Gen.module, func_type, name=MangledName) - Gen.functions[MangledName] = func + # 走唯一幂等入口:module.globals 已有同名函数(stub / 调用点先建) + # 时复用,避免 llvmlite DuplicatedNameError;类型不同则 fail-fast。 + func = Gen._CreateOrReuseFuncDecl(MangledName, func_type) # 方法实际定义类(多继承 this 调整用) method_anc_st: str | None = None # 若 MangledName 只有 stub 声明(无函数体),也走 MRO 回退找定义类方法 @@ -3910,8 +3911,10 @@ class ExprCallHandle(BaseHandle): # 避免 llvmlite DuplicatedNameError(如 gen.__init__ / ImportsHandle.HandleImport) func = Gen._find_function(FullMethodName) if func is None: - func = ir.Function(Gen.module, func_type, name=FullMethodName) - Gen.functions[FullMethodName] = func + # 走唯一幂等入口(module.globals 同名函数复用 / 类型冲突 fail-fast), + # 不再裸建 ir.Function —— Guard 只看 Gen.functions 时漏掉 + # module.globals 已有声明会抛 llvmlite DuplicatedNameError。 + func = Gen._CreateOrReuseFuncDecl(FullMethodName, func_type) if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == struct_type: call_self = ObjVal else: @@ -4010,9 +4013,9 @@ class ExprCallHandle(BaseHandle): return None ret_type, param_types = self._C_LIB_FUNCS[func_name]() func_type = ir.FunctionType(ret_type, param_types) - func = ir.Function(Gen.module, func_type, name=func_name) - Gen.functions[func_name] = func - return func + # C 库声明名固定(malloc/strlen/...),同一模块内多次调用必须复用同一符号: + # 裸建会在第二次抛 llvmlite DuplicatedNameError。 + return Gen._CreateOrReuseFuncDecl(func_name, func_type) def _FailFastLenUnsupported(self, arg_node: ast.AST, Gen: LlvmGeneratorMixin, val: ir.Value | None, reason: str) -> None: diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index 5ecaab7..fee0b04 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -1309,19 +1309,29 @@ class FunctionHandle(BaseHandle): return old_func try: old_name: str = old_func.name - if old_name in getattr(Gen.module, 'globals', {}): - del Gen.module.globals[old_name] + # 必须同时清 old_name(对象真名)与 MangledName(字典键 / 目标名): + # 别名场景下二者不同,只清真名会让 MangledName 仍占住 module.scope + # (llvmlite 按名字去重)→ 重建抛 DuplicatedNameError。 module_scope: Any = getattr(Gen.module, 'scope', None) - if getattr(module_scope, '_useset', None): - module_scope._useset.discard(old_name) + for _stale_name in {old_name, MangledName}: + _stale: Any = Gen.module.globals.get(_stale_name) + if isinstance(_stale, ir.Function): + del Gen.module.globals[_stale_name] + if getattr(module_scope, '_useset', None): + module_scope._useset.discard(_stale_name) if getattr(Gen.module, '_guessed_names', None): Gen.module._guessed_names.discard(FuncName) - new_func: ir.Function = ir.Function(Gen.module, NewFuncType, name=MangledName) + new_func: ir.Function = Gen._CreateOrReuseFuncDecl(MangledName, NewFuncType) Gen.functions[MangledName] = new_func if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: Gen.functions[FuncName] = new_func return new_func except Exception as ex: + from lib.core.LLVMCG.FuncGen import FailFastError + if isinstance(ex, FailFastError): + # 同名符号冲突(函数签名分裂 / 名字被非函数 global 占住):必须终止, + # 不能回退成"复用旧声明"——那正是 declare/define 分裂的现场。 + raise traceback.print_exc() Gen.functions[MangledName] = old_func if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: @@ -1737,18 +1747,22 @@ class FunctionHandle(BaseHandle): if not IsUserMarkedExport and FuncName in Gen._export_funcs: Gen._export_funcs.discard(FuncName) MangledName = Gen._mangle_func_name(FuncName) + # 补登记:module.globals 已有同名函数(stub 声明 / 调用点先建)但未登记到 + # Gen.functions 时,先登记再走下方判定 —— 否则 1750 分支裸建 ir.Function + # 会抛 llvmlite DuplicatedNameError(报文只有名字,不含冲突双方)。 + _g_existing_fn: Any = Gen.module.globals.get(MangledName) + if MangledName not in Gen.functions and isinstance(_g_existing_fn, ir.Function): + Gen.functions[MangledName] = _g_existing_fn if MangledName in Gen.functions: func = Gen.functions[MangledName] if getattr(func, 'name', MangledName) != MangledName: - func = ir.Function(Gen.module, FuncType, name=MangledName) - Gen.functions[MangledName] = func + func = Gen._CreateOrReuseFuncDecl(MangledName, FuncType) else: existing_type = getattr(func, 'ftype', None) if existing_type and existing_type != FuncType: func = self._replace_function_decl(Gen, FuncName, FuncType) else: - func = ir.Function(Gen.module, FuncType, name=MangledName) - Gen.functions[MangledName] = func + func = Gen._CreateOrReuseFuncDecl(MangledName, FuncType) if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: Gen.functions[FuncName] = func func.attributes.add('noredzone') diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 6620688..35dd0ac 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -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] diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index 8e5496d..2884e2c 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -892,6 +892,16 @@ class BaseGenMixin: 真因,绝不静默复用错签名(会让调用点按错签名传参)。 """ existing: Any = self.module.globals.get(name) + if existing is not None and not isinstance(existing, ir.Function): + # 名字被非函数 global 占住(全局变量 / vtable / 字符串常量…):llvmlite 的 + # NameScope 按名字去重,再建同名 ir.Function 必抛 DuplicatedNameError + # (报文只有名字,不含冲突类型)⇒ 在此把冲突双方摊开,避免裸抛。 + from lib.core.LLVMCG.FuncGen import FailFastError + raise FailFastError( + f"同名全局符号冲突:'{name}' 已在 module.globals 中登记,但不是函数" + f"({type(existing).__name__}):{existing!r}" + f"\n 函数声明无法复用该符号(llvmlite NameScope 按名字去重);" + f"请核对该名字是否同时被用作全局变量 / vtable / 字符串常量。") if isinstance(existing, ir.Function): _old_type: Any = getattr(existing, 'ftype', None) if _old_type is None or str(_old_type) == str(func_type):