From 4734a54aed0592a4fc59e7aff154ac3a61ee7536 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 29 Sep 2026 20:45:26 +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=89=8D=E8=87=AA=E6=A3=80=E7=AD=BE?= =?UTF-8?q?=E5=90=8D=E4=B8=8E=E5=8D=8A=E6=B3=A8=E5=86=8C=E5=90=8D=E5=AD=97?= =?UTF-8?q?=EF=BC=8CDuplicatedNameError=20=E4=B8=8D=E5=86=8D=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(编译器缺陷):llvmlite 的 Function.__init__ 顺序是 NamedValue.__init__ → _set_name → module.scope.register(name) 【名字占用】 → 逐形参 Argument(...) / ReturnValue(...)(内部 assert isinstance(typ, types.Type)) → module.add_global(self) 【进入 globals】 中间任一步抛错,Python 都不会回滚 scope ⇒ 留下"半注册"名字:module.globals 查无、 module.scope 已占用。而 _EmitFunctionForwardDeclLlvm 的 `except Exception` 在非严格 模式**静默 pass**(严格模式也只 LogWarning)⇒ 真因(返回类型或形参不是 llvmlite Type,典型 None=注解未解析出来)被吞掉,直到定义阶段 _EmitFunctionLlvm → _CreateOrReuseFuncDecl 才以 DuplicatedNameError 暴露,报文只有名字、没有两侧信息 (现场:972cf2b7756765d5.ImportsGenMixin._index_imported_module,本次构建 723s 后失败)。 - BaseGen._CreateOrReuseFuncDecl(唯一幂等入口)新增两条**创建前**自检: ① 签名自检:return_type 与 args 逐项必须是 ir.Type,否则在名字注册之前就报出 "哪个位置 / 什么类型 / 完整签名 / 当前节点位置"; ② 悬空名字自检:name 已进 module.scope 而 module.globals 无对象 ⇒ 直接报出 "此前同名创建中途失败且异常被吞",不再落到裸 DuplicatedNameError。 - HandlesFunctions._EmitFunctionForwardDeclLlvm:该 except 不再吞非 FailFastError 异常(原:非严格静默 pass / 严格仅 warning)⇒ 改抛 FailFastError,附函数名、 本次签名、原始异常类型与消息、当前节点位置。 本地冒烟(5 例全过):合法签名建成功;None 返回类型拦下且不留半注册名字;None 形参 拦下;悬空名字报状态事实;同签名二次调用仍幂等复用。 --- lib/core/Handles/HandlesFunctions.py | 14 ++++++-- lib/core/LLVMCG/BaseGen.py | 53 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index fee0b04..7732f5b 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -1280,8 +1280,18 @@ class FunctionHandle(BaseHandle): if isinstance(_e, FailFastError): # 签名冲突 = declare/define 分裂,必须终止(不吞) raise - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") + # 其余异常同样必须终止:本 try 块内只有「创建/复用声明 + 挂属性」, + # 失败即该声明不可用(调用点会按错签名传参)。原实现非严格模式静默 + # `pass`、严格模式仅 LogWarning —— 正是它把 llvmlite 的 AssertionError + # (形参类型不是 types.Type 时 `Argument(...)` 断言失败,见 + # BaseGen._CreateOrReuseFuncDecl 的创建前自检注释)吞成"名字半注册": + # 名字已进 module.scope、未进 module.globals,直到定义阶段才以 + # DuplicatedNameError(报文只有名字)暴露,真因与现场彻底脱节。 + raise FailFastError( + f"函数前置声明创建失败:'{MangledName}'" + f"\n · 本次签名: {FuncType}" + f"\n · 原始异常: {type(_e).__name__}: {_e}" + + Gen._get_node_info()) else: existing = Gen.functions[MangledName] existing_type: ir.FunctionType | None = getattr(existing, 'ftype', None) diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index 056fad2..bf62eda 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -964,6 +964,59 @@ class BaseGenMixin: · 已有但类型不同 ⇒ fail-fast 报出两侧签名 —— 这是 declare / define 分裂的 真因,绝不静默复用错签名(会让调用点按错签名传参)。 """ + # ---- 创建前自检(两条,都是"进了 llvmlite 就不可救"的状态)---- + # 背景:llvmlite 的 `Function.__init__` 顺序是 + # NamedValue.__init__ → _set_name → module.scope.register(name) 【名字占用】 + # ... 逐形参 `Argument(...)`(内部 assert isinstance(typ, types.Type))... + # module.add_global(self) 【进入 globals】 + # 中间任一步抛错,Python 都不会回滚 scope ⇒ 留下"半注册"的名字:globals 查无、 + # scope 却已占用。此后同一名字再建必抛 DuplicatedNameError(报文只有名字、 + # 没有两侧信息)。现场:972cf2b7756765d5.ImportsGenMixin._index_imported_module + # —— 上游首建失败被 `except Exception` 静默吞掉,只剩这个裸报错。 + # ① 签名自检:返回类型/任一形参不是 llvmlite Type(典型 None=注解未解析出来) + # 会在 `Argument(...)` / `ReturnValue(...)` 处 assert 失败,而失败点在名字 + # 注册之后(见上)⇒ 在此先行判定,给出可定位报文。 + _bad_desc: str | None = None + _bad_ty: Any = None + _ret_ty: Any = getattr(func_type, 'return_type', None) + if not isinstance(_ret_ty, ir.Type): + _bad_desc = '返回类型' + _bad_ty = _ret_ty + else: + for _ai, _at in enumerate(getattr(func_type, 'args', ()) or ()): + if not isinstance(_at, ir.Type): + _bad_desc = f'第 {_ai} 个形参类型' + _bad_ty = _at + break + if _bad_desc is not None: + from lib.core.LLVMCG.FuncGen import FailFastError + raise FailFastError( + f"函数声明签名非法:'{name}' 的{_bad_desc}是 " + f"{type(_bad_ty).__name__}({str(_bad_ty)[:80]}),不是 llvmlite 类型" + f"\n · 本次签名: {func_type}" + f"\n 成因:该处注解未解析出 llvmlite Type(解析失败返回 None / 拿到的是" + f"符号表条目等非类型对象)。llvmlite 会在 Argument(...)/ReturnValue(...) " + f"处 assert 失败,而失败点落在「名字已进 module.scope、尚未 add_global」" + f"之间 ⇒ 留下半注册名字,后续同名创建只报 DuplicatedNameError。" + f"\n 修法:核对上面这个位置在声明侧(源码注解 / .vpi stub)为何解析不出类型。" + + self._get_node_info()) + # ② 悬空名字自检:scope 已占用而 globals 无对象 ⇒ 上一次同名创建中途失败 + # (异常被吞/未走完 add_global)。此处若继续新建只会得到裸 DuplicatedNameError, + # 故直接报出状态事实(不静默清理:真因在"上一处被吞的创建失败",清理会掩盖它)。 + _mod_scope: Any = getattr(self.module, 'scope', None) + if (name not in self.module.globals and _mod_scope is not None + and getattr(_mod_scope, 'is_used', None) is not None + and _mod_scope.is_used(name)): + from lib.core.LLVMCG.FuncGen import FailFastError + raise FailFastError( + f"函数声明名字悬空占用:'{name}' 已进 module.scope,但 module.globals " + f"中无对应对象——llvmlite 的 Function 在「名字注册」与 add_global 之间" + f"失败时不会回滚 scope。" + f"\n ⇒ 说明**此前对同名函数的创建中途失败且异常被吞**(真因在那一处," + f"不在本次调用)。本次继续新建只会得到裸 DuplicatedNameError。" + f"\n 修法:先修掉上一处被吞的创建失败(形参类型非法 / 签名解析失败)," + f"半注册名字随之消失。" + + self._get_node_info()) existing: Any = self.module.globals.get(name) if existing is not None and not isinstance(existing, ir.Function): # 名字被非函数 global 占住(全局变量 / vtable / 字符串常量…):llvmlite 的