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 的