fix(compiler): storage vtable 初始化改完整 struct 初始化器(LLVM 拒绝部分初始化)

llc 报 initializer has wrong # elements。__vtable__ 字段(索引 0)= i8* @vtable,其余用户字段按类型生成零值(Ptr→null/Int→0/Float→0.0/Array→zeroinitializer),列全 FieldCount 字段。
This commit is contained in:
TermiNexus committed 2026-08-29 18:46:18 +08:00
1 parent fa4c69f95d
commit 23e7f5b1fb
1 file changed
+53 -6
+53 -6
View File
@@ -439,6 +439,32 @@ class TranslatorGenMixin:
str_len + 1, str_len + 1, str_name_buf)
return init_buf
def _stg_field_zero_text(self, pool: memhub.MemBuddy | t.CPtr,
fty: llvmlite.LLVMType | t.CPtr,
ty_str: str) -> str:
"""按 LLVM 类型生成 storage struct 字段的零值初始化器文本
LLVM struct 初始化器必须列全所有字段(部分初始化 llc 报
"initializer with struct type has wrong # elements")。
Ptr→null、Int→0、Float→0.0、Array/Struct→zeroinitializer。
"""
if fty is None or ty_str is None:
return None
buf: str = pool.alloc(160)
if buf is None:
return None
match fty:
case llvmlite.LLVMType.Ptr(_):
viperlib.snprintf(buf, 160, "%s null", ty_str)
case llvmlite.LLVMType.Int(_):
viperlib.snprintf(buf, 160, "%s 0", ty_str)
case llvmlite.LLVMType.Float(_):
viperlib.snprintf(buf, 160, "%s 0.0", ty_str)
case _:
# Array / Struct 等 aggregate → zeroinitializer
viperlib.snprintf(buf, 160, "%s zeroinitializer", ty_str)
return buf
# ============================================================
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
#
@@ -682,14 +708,35 @@ class TranslatorGenMixin:
viperlib.snprintf(vt_name_buf, 128, "%s.vtable", resolved_stg_entry.Name)
vt_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vt_name_buf)
if vt_mangled is not None:
vt_init_len: t.CSizeT = t.CSizeT(string.strlen(vt_mangled)) + 32
vt_init_buf: str = pool.alloc(vt_init_len)
if vt_init_buf is not None:
# 完整 struct 初始化器(LLVM 拒绝部分初始化):
# 字段 0 = __vtable__(i8* @vtable),其余用户字段按类型零值。
init_full_len: t.CSizeT = 16384
init_full: str = pool.alloc(init_full_len)
if init_full is not None:
written_v: t.CInt = viperlib.snprintf(init_full, init_full_len, "{ ")
pos_v: t.CSizeT = t.CSizeT(written_v)
if self.Gen.ClassGenVTable._vtable_name_needs_quote(vt_mangled) != 0:
viperlib.snprintf(vt_init_buf, vt_init_len, "{ i8* @\"%s\" }", vt_mangled)
written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, "i8* @\"%s\"", vt_mangled)
else:
viperlib.snprintf(vt_init_buf, vt_init_len, "{ i8* @%s }", vt_mangled)
stg_init_text = vt_init_buf
written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, "i8* @%s", vt_mangled)
pos_v += t.CSizeT(written_v)
fc_v: int = resolved_stg_entry.FieldCount
for fi_v in range(1, fc_v):
fe_v: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
resolved_stg_entry, fi_v)
if fe_v is None or fe_v.Ty is None:
continue
ty_buf_v: str = pool.alloc(128)
if ty_buf_v is None:
continue
llvmlite.TypePrint(ty_buf_v, 128, fe_v.Ty, pool)
zero_v: str = self._stg_field_zero_text(pool, fe_v.Ty, ty_buf_v)
if zero_v is None:
continue
written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, ", %s", zero_v)
pos_v += t.CSizeT(written_v)
viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, " }")
stg_init_text = init_full
stg_name_len: t.CSizeT = t.CSizeT(string.strlen(mangled_name)) + 8
stg_name_buf: str = pool.alloc(stg_name_len)
if stg_name_buf is not None: