fix(tpc): 修正枚举判据——按 IsEnumMember 区分成员/类型(bb05a157 判反了)

a 编译器缺陷:bb05a157 用 `not Entry.IsEnum` 排除"枚举类型",但现场实测枚举
**成员**条目的标志组合是
    IsEnum=True + IsEnumMember=True + BaseType=CEnum
(成员的 IsEnum 也被置真)⇒ 成员被误判成枚举类型,`rawptr[Constant]` 落 i32*,
`constant_get_str_val` 形参再次退化成 i32*。

正确判据(两处同源):
  枚举**类型** = IsEnum and not IsEnumMember ⇒ 走枚举分支(宽度 i32 等)
  枚举**成员**(IsEnumMember)⇒ 不是类型 ⇒ 让位给类定义("有类定义 ⇒ 是类")

现场证据(51de3b6d 的 [DIAG-decl] 报文,随 Traceback 输出):
  实参类=5df907d3a02a0bac.Constant | structs=有 |
  _struct_sha1_map=5df907d3a02a0bac | class_sha1_map=5df907d3a02a0bac |
  symtab[IsStruct=False, IsEnum=True, IsEnumMember=True, Base=CEnum] |
  声明函数类型=i8* (i32*) | 声明来源=..._EmitExternalFuncDeclLlvm <- _get_or_declare_function

修后 `ResolveAnnotationType(rawptr[Constant])` 得 CStruct/1 ⇒ _ctype_to_llvm 取
structs['Constant'] ⇒ 声明变为 i8* (%"5df907d3a02a0bac.Constant"*),与实参同型。
This commit is contained in:
TermiNexus committed 2026-09-28 22:44:20 +08:00
1 parent 51de3b6dcf
commit 1c1f78e7b3
2 files changed
+21 -13

No files matched your search

+11 -6
View File
@@ -114,14 +114,19 @@ class HandlesTypeMerge(BaseHandle):
# 查②后 BaseType=CStruct('Constant'),_get_or_create_struct 会按
# `_struct_sha1_map` 拼出 `"<sha1>.Constant"`(BaseGen.py:527-528),
# 与声明端/实参同一结构体对象。
# 但必须排除**枚举类型本身**(`Entry.IsEnum`,如 `class ASTKind(t.CEnum)`):
# 但必须排除**枚举类型本身**(如 `class ASTKind(t.CEnum)` 的注解 `x: ASTKind`):
# _struct_sha1_map 是按 .vpi 里全部 ClassDef 建的,枚举类也在其中;若一并
# 当结构体,`x: ASTKind` 这类枚举注解会被建成 opaque struct,与 i32 错位
# 当结构体,枚举注解会被建成 opaque struct,与 i32 错位
# (现场:'IntType' object has no attribute 'is_opaque')。
# 判据分工:Entry.IsEnum ⇒ 枚举类型(走下方 IsEnum 分支,宽度=i32 等);
# 裸名被枚举**成员**占住(Entry.IsEnumMember / 空标记)⇒ 成员不是类型
# ⇒ 让位给类定义。
_is_enum_type: bool = isinstance(Entry, CTypeInfo) and Entry.IsEnum
# 判据必须按 **IsEnumMember** 区分(现场实测):枚举**成员**条目的标志组合是
# IsEnum=True + IsEnumMember=True + BaseType=CEnum
# (即成员的 IsEnum 也被置真),只判 IsEnum 会把成员误当枚举类型 ⇒ 落 i32*;
# 而枚举**类型**条目是 IsEnum=True + IsEnumMember=False。
# 故:枚举类型 = IsEnum and not IsEnumMember ⇒ 走下方 IsEnum 分支;
# 成员(IsEnumMember)⇒ 不是类型 ⇒ 让位给类定义。
_is_enum_type: bool = (
isinstance(Entry, CTypeInfo) and Entry.IsEnum
and not getattr(Entry, 'IsEnumMember', False))
_Gen = getattr(self.Trans, 'LlvmGen', None)
if _Gen and not _is_enum_type and (
TypeName in _Gen.structs
+10 -7
View File
@@ -493,16 +493,19 @@ class BaseGenMixin:
# 结构体。否则此处返回 i32 ⇒ 上游 PtrCount=1 叠加后变成 i32*,
# 与调用点实参 %"<sha1>.Constant"* 分裂(现场:constant_get_str_val 的
# 形参 i32*)。类型注解语境下枚举**成员**从不是类型,判据只能是"是否有类定义"。
# 必须排除**枚举类型本身**(`Entry.IsEnum`,如 `class ASTKind(t.CEnum)`):
# _struct_sha1_map 是按 .vpi 里全部 ClassDef 建的,枚举类也在其中 ——
# 若一并当结构体,枚举注解(kind() 返回值等)会被建为 opaque struct,
# 引发 i32 ↔ 结构体错位('IntType' object has no attribute 'is_opaque' 现场)。
# 判据分工:Entry.IsEnum ⇒ 枚举类型(走下方枚举分支,宽度=i32 等);
# Entry.IsEnumMember(或裸名被成员占住)⇒ 成员,不是类型 ⇒ 让位给类定义。
# 必须排除**枚举类型本身**(如 `class ASTKind(t.CEnum)`):_struct_sha1_map
# 是按 .vpi 里全部 ClassDef 建的,枚举类也在其中 —— 若一并当结构体,枚举
# 注解(kind() 返回值等)会被建为 opaque struct,引发 i32 ↔ 结构体错位
# ('IntType' object has no attribute 'is_opaque' 现场)。
# 判据必须按 **IsEnumMember** 区分(现场实测标志组合):
# 枚举**成员** = IsEnum=True + IsEnumMember=True + BaseType=CEnum
# 枚举**类型** = IsEnum=True + IsEnumMember=False
# 只判 IsEnum 会把成员误当枚举类型 ⇒ 返回 i32 ⇒ 上游 PtrCount=1 ⇒ i32*。
_known_class_name: bool = (
(clean_name in getattr(self, '_struct_sha1_map', {})
or clean_name in getattr(self, 'class_sha1_map', {}))
and not (Entry and Entry.IsEnum))
and not (Entry and Entry.IsEnum
and not getattr(Entry, 'IsEnumMember', False)))
if Entry and Entry.IsTypedef:
resolved_str: str = self._resolve_typedef(clean_name)
if resolved_str != clean_name: