fix(gen): 全局初始化器引用跨模块 vtable 时补 external 声明(④-a)

模块级对象全局的 storage 初始化器以符号名写入依赖类 vtable
(i8* @<dep_sha1>.<Cls>.vtable),此前不建 GlobalVariable ⇒ 单模块
OUTPUT_FULL 缺该符号声明,只能靠 BuildCombinedIR 合并依赖 stub 补入。

现于写初始化器前:跨模块(ModuleSha1 != 当前模块)且模块内无该全局时,
new_global_variable(..., Ptr(i8)) + module_add_global 补 external 声明
(对齐 CallGenLeafKit._make_vtable_ref_i8)。仅跨模块补,本模块类由
_generate_vtable 产出定义,避免同模块重复定义。

去 IR 化步骤④-a(生产者自足,FULL IR 自足化前置);未编译验证。
This commit is contained in:
TermiNexus committed 2026-10-03 08:39:13 +08:00
1 parent 324a22b6d1
commit ec9e950185
1 file changed
+16
+16
View File
@@ -1049,6 +1049,22 @@ novirtual class TranslatorGenMixin:
vt_sha1 = trans.ModuleSha1
vt_mangled: str = self.Gen.FuncGenBase._mangle_name_with_sha1(vt_sha1, vt_name_buf)
if vt_mangled is not None:
# 跨模块 vtable 只被本初始化器文本引用 ⇒ 模块内无对应 GlobalVariable ⇒
# 单模块 FULL IR 缺该符号声明(旧架构靠 BuildCombinedIR 合并依赖 stub
# 补入 external 声明)。此处补声明,使单模块 IR 自足(对齐
# CallGenLeafKit._make_vtable_ref_i8 的跨模块分支)。
# 仅跨模块补:本模块类由 _generate_vtable 产出定义,补声明会重复定义。
# LLVM 22 不透明指针 ⇒ 声明 pointee 用 i8* 即可(pointee 无语义)。
vt_cross: int = 0
if resolved_stg_entry.ModuleSha1 is not None and trans.ModuleSha1 is not None:
if string.strncmp(resolved_stg_entry.ModuleSha1, trans.ModuleSha1, 16) != 0:
vt_cross = 1
if vt_cross != 0 \
and self.Gen.ExprGenAttr.find_global_in_module(mod, vt_mangled) is None:
vt_decl_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
vt_gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, vt_mangled, vt_decl_ty)
if vt_gv is not None:
llvmlite.module_add_global(mod, vt_gv)
# 完整 struct 初始化器(LLVM 拒绝部分初始化):
# 字段 0 = __vtable__(i8* @vtable),其余用户字段按类型零值。
init_full_len: sizet = 16384