fix(tpc): 收紧「有类定义 ⇒ 是类」判据:排除枚举类型本身

a 编译器缺陷(我上一轮 61f074ff / 3ca46c01 引入的过宽判据):判据用的
_struct_sha1_map 是 _build_struct_sha1_map 按 .vpi/.pyi 里**全部 ClassDef** 建的
⇒ **枚举类**(class ASTKind(t.CEnum)、class LogLevel 等)也在其中。于是
`x: ASTKind` 这类枚举注解被当成结构体建成 opaque struct,与「枚举宽度 = i32」
错位,现场表现为 i32 ↔ 结构体互换:
  AttributeError: IntType object has no attribute is_opaque
(llvmlite builder.store / LoadInstr 把 i32 值当指针用)。

收紧为判据分工(两处同口径):
· HandlesTypeMerge._GetCTypeInfoInternal 的 Name 分支:Entry.IsEnum ⇒ 枚举类型,
  不进「类定义」分支(走下方 IsEnum 分支,宽度 i32 等);
· BaseGen._get_or_create_struct:_known_class_name 追加 and not Entry.IsEnum。

「裸名被枚举**成员**占住」(Entry.IsEnumMember,如 ast/base.vp 的
Constant: t.State vs ast/exprs.vp 的 class Constant)仍让位给类定义 —— 这正是
原修复要解决的那一类,不受影响。
This commit is contained in:
TermiNexus committed 2026-09-28 21:57:21 +08:00
1 parent e6451a077e
commit bb05a157a6
2 files changed
+20 -4

No files matched your search

+11 -2
View File
@@ -114,9 +114,18 @@ 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)`):
# _struct_sha1_map 是按 .vpi 里全部 ClassDef 建的,枚举类也在其中;若一并
# 当结构体,`x: ASTKind` 这类枚举注解会被建成 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
_Gen = getattr(self.Trans, 'LlvmGen', None)
if _Gen and (TypeName in _Gen.structs
or TypeName in getattr(_Gen, '_struct_sha1_map', {})):
if _Gen and not _is_enum_type and (
TypeName in _Gen.structs
or TypeName in getattr(_Gen, '_struct_sha1_map', {})):
Result = CTypeInfo()
Result.BaseType = t.CStruct(name=TypeName)
Result.IsStruct = True
+9 -2
View File
@@ -493,9 +493,16 @@ 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(或裸名被成员占住)⇒ 成员,不是类型 ⇒ 让位给类定义。
_known_class_name: bool = (
clean_name in getattr(self, '_struct_sha1_map', {})
or clean_name in getattr(self, 'class_sha1_map', {}))
(clean_name in getattr(self, '_struct_sha1_map', {})
or clean_name in getattr(self, 'class_sha1_map', {}))
and not (Entry and Entry.IsEnum))
if Entry and Entry.IsTypedef:
resolved_str: str = self._resolve_typedef(clean_name)
if resolved_str != clean_name: