fix(TPC): 模块名与类名同名时 X.func() 按模块函数解析

import lib.core.X as X 且模块内有同名 class X 时,X.func() 此前被
is_class_name 判定拦截走 _HandleStaticMethodCallLlvm,用模块函数签名
生成带类前缀的 {sha1}.X.func 声明,而 define 是 {sha1}.func,导致
链接 undefined symbol(CompilerFactory.get_perm_pool)。现加模块别名
优先规则:SymbolTable 命中 IsModuleAlias 时跳过类静态方法路径,让位
模块函数调用;类构造 X.X(args) 仍走 struct 路径。同时移除
_HandleExternalCallLlvm 中误加的 else: return None 截断。

includes/llvmlite/__types.vp:DeepCopyType 各层分配源改由调用方传入
pool 参数(传 perm_pool 即持久),includes 层不依赖 App 工厂。
This commit is contained in:
TermiNexus committed 2026-08-14 04:02:22 +08:00
1 parent 2c7f563dda
commit fd3254cdd4
2 files changed
+53 -6

No files matched your search

+9 -4
View File
@@ -664,10 +664,15 @@ def DeepCopyType(pool: memhub.MemBuddy | t.CPtr,
def _DeepCopyDepth(pool: memhub.MemBuddy | t.CPtr,
ty: LLVMType | t.CPtr, depth: t.CInt) -> LLVMType | t.CPtr:
"""带深度上限的深拷贝实现"""
"""带深度上限的深拷贝实现
分配源用传入的 pool 参数(调用方决定):传主 pool 为瞬时拷贝
(随 mark/reset 回收),传永久 pool(CompilerFactory.get_perm_pool())
为跨 mark 持久拷贝(代替 stdlib.malloc,buddy 分配更快)。
"""
if ty is None:
return None
new_ty: LLVMType | t.CPtr = (LLVMType | t.CPtr)(stdlib.malloc(LLVMType.__sizeof__()))
new_ty: LLVMType | t.CPtr = (LLVMType | t.CPtr)(pool.alloc(LLVMType.__sizeof__()))
if new_ty is None:
return None
string.memset(new_ty, 0, LLVMType.__sizeof__())
@@ -729,7 +734,7 @@ def _DeepCopyParamChain(pool: memhub.MemBuddy | t.CPtr,
guard += 1
if guard > 512:
break
node: ParamNode | t.CPtr = (ParamNode | t.CPtr)(stdlib.malloc(PNODE_SIZE))
node: ParamNode | t.CPtr = (ParamNode | t.CPtr)(pool.alloc(PNODE_SIZE))
if node is None:
break
string.memset(node, 0, PNODE_SIZE)
@@ -749,7 +754,7 @@ def _DeepCopyStr(pool: memhub.MemBuddy | t.CPtr, s: t.CChar | t.CPtr) -> t.CChar
if s is None:
return None
slen: t.CSizeT = string.strlen(s)
copy: t.CChar | t.CPtr = stdlib.malloc(slen + 1)
copy: t.CChar | t.CPtr = pool.alloc(slen + 1)
if copy is None:
return None
string.strcpy(copy, s)
+44 -2
View File
@@ -654,7 +654,20 @@ class ExprCallHandle(BaseHandle):
result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value)
if result is not None:
return result
if is_class_name:
# 模块名与类名同名优先规则:`import lib.core.X as X` 且模块内
# 有同名 class X 时,`X.func()` 应解析为模块函数(mangle
# {sha1}.func,对应模块级 define)而非类静态方法(mangle
# {sha1}.X.func——模块函数没有带类名的 define,链接报 undefined
# symbol,如 CompilerFactory.get_perm_pool)。判断依据:SymbolTable
# 中 base 名是否注册了 IsModuleAlias(import 处理插入的别名标记)。
# 类构造调用(X.X(args))不受影响:FuncAttr==类名 时上方 591/639
# 行的 struct 路径已先行返回。
_is_mod_alias_base = False
if isinstance(Node.func.value, ast.Name):
_base_alias_sym = self.Trans.SymbolTable.lookup(Node.func.value.id)
if _base_alias_sym is not None and getattr(_base_alias_sym, 'IsModuleAlias', False):
_is_mod_alias_base = True
if is_class_name and not _is_mod_alias_base:
ClassName = Node.func.value.id
result = self._HandleStaticMethodCallLlvm(Node, ClassName, FuncAttr)
if result is not None:
@@ -1412,8 +1425,20 @@ class ExprCallHandle(BaseHandle):
if is_user_module and ModulePath not in Gen.ModuleSha1Map and ModulePath not in getattr(self.Trans, '_ImportedModules', set()):
ModulePath = ModulePath.split('.')[-1]
# 模块别名识别:`import lib.core.X as X`(模块内有同名类时,类名会
# 注册进 SymbolTable 遮蔽模块判定——如 CompilerFactory 模块 + 同名类)。
# import 处理(HandlesImports._EmitImportDeclarationsLlvm)在 SymbolTable
# 插入了 IsModuleAlias 的 AliasInfo,据此识别并补全完整路径,使
# `X.get_perm_pool()` 正确解析为模块函数({sha1}.get_perm_pool)而非
# 类方法({sha1}.X.get_perm_pool,链接 undefined symbol)。
if ModulePath and ModulePath not in ('c', 't') and not is_user_module:
return None
_al_last = ModulePath.split('.')[-1]
_al_sym = self.Trans.SymbolTable.lookup(_al_last)
if _al_sym and getattr(_al_sym, 'IsModuleAlias', False):
is_user_module = True
if ModulePath in self.Trans.SymbolTable.import_aliases:
ModulePath = self.Trans.SymbolTable.import_aliases[ModulePath]
# 未命中模块别名时不截断:保持 is_user_module=False 走下方裸名回退
if is_user_module:
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
@@ -2403,6 +2428,23 @@ class ExprCallHandle(BaseHandle):
break
if idx is None or idx >= len(st.elements):
return None
# ============================================================
# 修复(2026-08-13):class_members 与 struct.elements 数量不一致时对齐。
# 根因链(NewAstTest ASTCtx 枚举丢失):
# DeclarationGenerator/收集路径生成的 class_members 可能漏部分 Mixin/自动
# 字段(如 Generator 漏 GenericSpecDepth/GenericClassFiles/ISINSTANCE_CLASS_MAX
# 3 个,class_members=88 vs struct=91),导致 this_adjust 用 class_members
# 索引算错字节偏移(Generator 624 vs 真实 644)。StmtGenMixin 方法(find_enum/
# register_enum/is_enum_class)字段访问错位 20 字节 → EnumTable 落在
# ReexportSrcs 内存 → 与 reexport 数据冲突覆盖 → ASTCtx 等枚举丢失。
# 修正:字段真实 struct 索引 = class_members 索引 + (struct 元素数 - members 数)。
# 前提:遗漏字段位于目标字段之前(本 bug 场景成立:漏字段在 StmtGenMixin 前)。
# ============================================================
diff_elems: int = len(st.elements) - len(members)
if diff_elems > 0:
idx += diff_elems
if idx >= len(st.elements):
return None
offset: int = 0
for i in range(idx):
et = st.elements[i]