From bb05a157a63e562726fa89951b0f32589dafb80f Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 28 Sep 2026 21:57:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(tpc):=20=E6=94=B6=E7=B4=A7=E3=80=8C?= =?UTF-8?q?=E6=9C=89=E7=B1=BB=E5=AE=9A=E4=B9=89=20=E2=87=92=20=E6=98=AF?= =?UTF-8?q?=E7=B1=BB=E3=80=8D=E5=88=A4=E6=8D=AE=EF=BC=9A=E6=8E=92=E9=99=A4?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E7=B1=BB=E5=9E=8B=E6=9C=AC=E8=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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)仍让位给类定义 —— 这正是 原修复要解决的那一类,不受影响。 --- lib/core/Handles/HandlesTypeMerge.py | 13 +++++++++++-- lib/core/LLVMCG/BaseGen.py | 11 +++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index ae8c0b3..42c8bb5 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -114,9 +114,18 @@ class HandlesTypeMerge(BaseHandle): # 查②后 BaseType=CStruct('Constant'),_get_or_create_struct 会按 # `_struct_sha1_map` 拼出 `".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 diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index 50f09fe..5652b37 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -493,9 +493,16 @@ class BaseGenMixin: # 结构体。否则此处返回 i32 ⇒ 上游 PtrCount=1 叠加后变成 i32*, # 与调用点实参 %".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: