fix(tpc): 同名枚举成员不得遮蔽类定义(_get_or_create_struct 的 i32 出口)

a 编译器缺陷:类型注解语境下枚举**成员**从不是类型,判据只能是「该名是否有类
定义」。但 _get_or_create_struct 的两个枚举出口(Entry.IsEnum 分支、Entry.BaseType
为 CEnum 分支)没有这条判据:当平坦符号表条目被**同名枚举成员**占住时(ast/base.vp
的 `Constant: t.State` 与 ast/exprs.vp 的 `class Constant` 同名,谁后插入谁占住裸名),
返回 i32;上游 PtrCount=1 叠加后即 i32*,与调用点实参 %"<sha1>.Constant"* 分裂 ——
现场 `constant_get_str_val` 形参 i32*(上一轮 61f074ff 只修了上游 TypeMerge 的 Name
分支,这里是真正吐出 i32 的那一步)。

判据与既有规则源统一(_struct_sha1_map / class_sha1_map 已登记该名为类 ⇒ 是类):
与 TypeConvert._type_str_to_llvm_base 的 `type_str in self.structs or type_str in
self._struct_sha1_map`、HandlesTypeMerge 的 Name/Attribute 分支、
DeclarationGenerator 的 `attr_name in struct_names` 同一条。

修后落到下方正常结构体创建路径,按 _struct_sha1_map 拼出 `"<sha1>.Constant"`,
与实参/声明端同一结构体对象。
This commit is contained in:
TermiNexus committed 2026-09-28 21:46:15 +08:00
1 parent 61f074ffa4
commit 3ca46c01cf
1 file changed
+16 -2
+16 -2
View File
@@ -483,6 +483,19 @@ class BaseGenMixin:
return ir.IntType(8)
if self.SymbolTable:
Entry: _CTypeInfo | None = self.SymbolTable.lookup(clean_name)
# 「有类定义 ⇒ 是类」的唯一判据(与 TypeConvert._type_str_to_llvm_base
# 的 `type_str in self.structs or type_str in self._struct_sha1_map`、
# HandlesTypeMerge 的 Name/Attribute 分支、DeclarationGenerator 的
# `attr_name in struct_names` 同一条规则源):
# _struct_sha1_map / class_sha1_map 已登记该名为**类**时,即便平坦符号表
# 条目是**同名枚举成员**(如 ast/base.vp 的 `Constant: t.State` 与
# ast/exprs.vp 的 `class Constant` 同名;谁后插入谁占住裸名),也必须建成
# 结构体。否则此处返回 i32 ⇒ 上游 PtrCount=1 叠加后变成 i32*,
# 与调用点实参 %"<sha1>.Constant"* 分裂(现场:constant_get_str_val 的
# 形参 i32*)。类型注解语境下枚举**成员**从不是类型,判据只能是"是否有类定义"。
_known_class_name: bool = (
clean_name in getattr(self, '_struct_sha1_map', {})
or clean_name in getattr(self, 'class_sha1_map', {}))
if Entry and Entry.IsTypedef:
resolved_str: str = self._resolve_typedef(clean_name)
if resolved_str != clean_name:
@@ -499,7 +512,8 @@ class BaseGenMixin:
# 需要继续到下方正常结构体创建路径,创建 opaque 结构体。
# 这对自引用 REnum(如 LLVMType 包含 LLVMType*)至关重要:
# _parse_llvm_type 先通过此路径创建 opaque 结构体,_TryLoadStructFromStub 再 set_body。
elif Entry and Entry.IsEnum and clean_name not in self.class_methods:
elif (Entry and Entry.IsEnum and clean_name not in self.class_methods
and not _known_class_name):
# CEnum 存储宽度 = 最宽成员类型(登记在 Entry.enum_width;未登记
# → 默认 i32)。此前此处恒 i32,与同文件 _enum_int_type 的常量/
# 注解宽度分裂(宽成员枚举的类型与常量不同宽)。
@@ -516,7 +530,7 @@ class BaseGenMixin:
return ir.PointerType(ir.IntType(8))
if Entry and Entry.IsVariable and not _is_class_name:
return ir.PointerType(ir.IntType(8))
if Entry and Entry.BaseType:
if Entry and Entry.BaseType and not _known_class_name:
if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum):
return self._enum_int_type(clean_name, Entry)
if Entry.BaseType is _t.CEnum: