fix(tpv): REnum 别名表去指针化(class 槽位改 perm_pool 字符串 + strcmp 内容比较)

- _register_renum_field_alias: class_name strcpy 到 perm_pool,去重检查改 strcmp

- _lookup_renum_field_alias/_lookup_renum_field_alias_ty/_lookup_renum_member_ty: 指针值比较改 strcmp 内容比较

- 删除 _update_renum_alias_class_ptr 及调用点(去指针化后无需指针统一)

- 根治 'LLVMType 字段 Pointee 未找到' 反复报错(注册 AST 指针 vs 查找 entry.Name 池拷贝指针恒不等)
This commit is contained in:
TermiNexus committed 2026-08-28 15:00:50 +08:00
1 parent a8eb7fe5fe
commit 27ba74c720
2 files changed
+29 -41

No files matched your search

+1 -2
View File
@@ -801,8 +801,7 @@ class AssignGenMixin:
if scope_type == 1:
# global 变量
target_alloca = self.Gen.VarGen.lookup_module_var(
trans.SymTab, nm.id)
target_alloca = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id)
if target_alloca is not None:
if target_alloca.Ty is None:
# fail-fast: 变量类型信息缺失,禁止兜底 i32
+28 -39
View File
@@ -775,14 +775,6 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
VLogger.error(f"failed to register {class_name}", "RENUM")
return 0
# 修复 class_name 指针不匹配:
# 别名注册时用 class_name(= cd.name,AST 原始指针),
# 但查找时用 entry.Name(register_struct 通过 pool.alloc+strcpy 复制的副本指针)。
# 两者是不同指针,CSizeT 指针值比较会失败。
# 调用辅助函数将已注册别名的 class_name 统一更新为 entry.Name。
if entry.Name is not None:
self._update_renum_alias_class_ptr(t.CSizeT(class_name), t.CSizeT(entry.Name))
# 添加 __tag 字段(位置 0,i32)
self.Gen.StructGen.add_field(pool, entry, "__tag", i32_ty, None, None)
@@ -973,23 +965,29 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
if self.RenumAliasCount >= RENUM_ALIAS_MAX:
return
# 检查是否已注册(避免重复)— class 用 CSizeT 指针值比较(契约不变),
# field 槽位是 perm_pool 拷贝、key 是原指针,指针比较恒不相等 → 改 strcmp
cls_key: t.CSizeT = t.CSizeT(class_name)
# 去重检查(去指针化):class 槽位存 perm_pool 字符串拷贝,用 strcmp
# 内容比较——不再依赖指针值统一("LLVMType 字段 Pointee 未找到"四次
# 依旧根因:注册用 AST 指针、查找用 entry.Name 池拷贝,指针恒不等)。
for i in range(self.RenumAliasCount):
cls_existing: t.CSizeT = self.RenumAliasClass[i]
if cls_existing == cls_key:
cls_existing_ptr: str = (str | t.CPtr)(
t.CVoid(self.RenumAliasClass[i], t.CPtr))
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
fld_existing_ptr: str = (str | t.CPtr)(
t.CVoid(self.RenumAliasField[i], t.CPtr))
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
return
idx: int = self.RenumAliasCount
self.RenumAliasClass[idx] = cls_key
# class_name 同样 strcpy 到 perm_pool(去指针化:查找方任何来源的
# class_name 字符串都可用 strcmp 命中,无需 _update_renum_alias_class_ptr)
cls_len_rfa: t.CSizeT = string.strlen(class_name)
cls_buf_rfa: str = CompilerFactory.factory.PermPool.alloc(cls_len_rfa + 1)
if cls_buf_rfa is None:
return
string.strcpy(cls_buf_rfa, class_name)
self.RenumAliasClass[idx] = t.CSizeT(cls_buf_rfa)
# field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias
# 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。
# class_name 槽位保持原指针:_update_renum_alias_class_ptr 会统一为
# entry.Name(perm_pool 拷贝),指针值比较契约不变。
fn_len_rfa: t.CSizeT = string.strlen(field_name)
fn_buf_rfa: str = CompilerFactory.factory.PermPool.alloc(fn_len_rfa + 1)
if fn_buf_rfa is None:
@@ -1014,27 +1012,18 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
string.strcpy(vn_buf_rfa, variant_name)
self.RenumAliasVariant[idx] = t.CSizeT(vn_buf_rfa)
self.RenumAliasCount = idx + 1
def _update_renum_alias_class_ptr(self, old_ptr: t.CSizeT, new_ptr: t.CSizeT):
"""更新别名表中的 class_name 指针,从 old_ptr 更新为 new_ptr"""
if old_ptr == new_ptr:
return
if self.RenumAliasClass is None:
return
for i in range(self.RenumAliasCount):
if self.RenumAliasClass[i] == old_ptr:
self.RenumAliasClass[i] = new_ptr
def _lookup_renum_field_alias(self, class_name: str, field_name: str) -> int:
"""查找 REnum 变体字段名的 payload 索引,返回索引或 -1
class_name: 用 CSizeT 指针值比较(_update_renum_alias_class_ptr 已统一指针)
field_name: 用 strcmp 内容比较(注册时 vnm.id 与查找时 at.attr 是不同指针)
class_name/field_name 均用 strcmp 内容比较(去指针化:槽位存 perm_pool
字符串拷贝,任何来源的 class_name 字符串都可命中)
"""
if class_name is None or field_name is None or self.RenumAliasClass is None:
return -1
cls_key: t.CSizeT = t.CSizeT(class_name)
for i in range(self.RenumAliasCount):
cls_existing: t.CSizeT = self.RenumAliasClass[i]
if cls_existing == cls_key:
cls_existing_ptr: str = (str | t.CPtr)(
t.CVoid(self.RenumAliasClass[i], t.CPtr))
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
# field_name 用 strcmp 内容比较(指针不同但内容相同)
fld_existing_ptr: str = (str | t.CPtr)(
t.CVoid(self.RenumAliasField[i], t.CPtr))
@@ -1045,15 +1034,15 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
field_name: str) -> llvmlite.LLVMType | t.CPtr:
"""查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None
与 _lookup_renum_field_alias 同表同键(class 指针值比较 + field strcmp)。
与 _lookup_renum_field_alias 同表同键(class/field 均 strcmp 内容比较)。
注册期未解析成功(自引用类型等)槽位为 0 → 返回 None,绑定回退槽位类型。
"""
if class_name is None or field_name is None or self.RenumAliasTy is None:
return None
cls_key: t.CSizeT = t.CSizeT(class_name)
for i in range(self.RenumAliasCount):
cls_existing: t.CSizeT = self.RenumAliasClass[i]
if cls_existing == cls_key:
cls_existing_ptr: str = (str | t.CPtr)(
t.CVoid(self.RenumAliasClass[i], t.CPtr))
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
fld_existing_ptr: str = (str | t.CPtr)(
t.CVoid(self.RenumAliasField[i], t.CPtr))
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
@@ -1068,17 +1057,17 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
"""按 (class, 变体名, payload 位置) 查找变体成员的实际 LLVM 类型
match 绑定用:同一 payload 位置跨变体类型不同(Int.Bits=i32 vs
Struct.Fields=Ptr),必须带变体名定位。class 指针值比较 + 变体/位置
内容比较。返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。
Struct.Fields=Ptr),必须带变体名定位。class/变体均 strcmp 内容比较。
返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。
"""
if class_name is None or variant_name is None or self.RenumAliasVariant is None:
return None
if payload_idx < 1:
return None
cls_key: t.CSizeT = t.CSizeT(class_name)
for i in range(self.RenumAliasCount):
cls_existing: t.CSizeT = self.RenumAliasClass[i]
if cls_existing != cls_key:
cls_existing_ptr: str = (str | t.CPtr)(
t.CVoid(self.RenumAliasClass[i], t.CPtr))
if cls_existing_ptr is None or string.strcmp(cls_existing_ptr, class_name) != 0:
continue
if self.RenumAliasVariant[i] == 0:
continue