From 3ca46c01cf7601a44ea058497c890355e67a38d6 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 28 Sep 2026 21:46:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(tpc):=20=E5=90=8C=E5=90=8D=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE=E6=88=90=E5=91=98=E4=B8=8D=E5=BE=97=E9=81=AE=E8=94=BD?= =?UTF-8?q?=E7=B1=BB=E5=AE=9A=E4=B9=89=EF=BC=88=5Fget=5For=5Fcreate=5Fstru?= =?UTF-8?q?ct=20=E7=9A=84=20i32=20=E5=87=BA=E5=8F=A3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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*,与调用点实参 %".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 拼出 `".Constant"`, 与实参/声明端同一结构体对象。 --- lib/core/LLVMCG/BaseGen.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index f05d4d2..50f09fe 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -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*, + # 与调用点实参 %".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: