fix(tpc): 函数声明创建前自检签名与半注册名字,DuplicatedNameError 不再裸抛
类别 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 形参
拦下;悬空名字报状态事实;同签名二次调用仍幂等复用。
This commit is contained in:
1 parent
f28ff1b414
commit
4734a54aed
2 files changed
+65
-2
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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 的
|
||||
|
||||
Reference in new issue
Block a user