From 1776dfa60abc5fe23be88f742a2fc56951535b5d Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 29 Sep 2026 23:58:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(LLVMCG):=20=E5=B0=BE=E9=83=A8=E5=AF=B9?= =?UTF-8?q?=E9=BD=90=E5=8A=A0=E3=80=8C=E5=89=8D=E7=BC=80=E6=95=B0=20=3D=3D?= =?UTF-8?q?=20=E7=88=B6=E7=B1=BB=20struct=20=E6=A7=BD=E6=95=B0=E3=80=8D?= =?UTF-8?q?=E5=89=8D=E7=BD=AE=E6=A0=A1=E9=AA=8C=EF=BC=8C=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20Generator.vp:136=20=E8=AF=AF=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类别:a 编译器缺陷(TPC 侧;修正 b06dac1d 引入的过宽判据) 现象:翻译 TransPyV/App/lib/core/Gen/Generator.vp 时 `SubTypeGen.Gen = self`(:136)报 「指针隐式转换已禁止(非基本类型):不能把 %"47382dc8277c9d28.Generator"* 隐式转为 %"6fbe68e8fca81223.TypeSpecArena"*」。 判据(事实链): · SubTypeGen 静态类型 = rawptr[TypeGenMixin.TypeGenMixin],Gen 字段声明在基类 TypeGenBase; 该 struct 41 槽:槽 0 = Generator*(Gen),槽 40 = TypeSpecArena*(Specs)。 · 抛错点 `_StoreWithCoerce` 用的是 **GEP 出来的槽类型**(TargetType = Ptr.type.pointee) ⇒ 报错里的 TypeSpecArena* 说明 "Gen 的偏移被算成了 40"(Specs 那一槽),而不是 0。 · 成因:b06dac1d 的「尾部对齐」在"成员表短于 body 字段区"时按 `len(elements) - len(表)` 求前缀数;TypeGenMixin 的表只有 ['Gen'] 一项(且其声明类型已退化成通用指针 ⇒ 类型自校验被放行),于是被锚到 body 末尾 = 槽 40。 修法:尾部对齐加**必需的前缀校验**——前缀数必须等于**父类 struct 的槽数**(展平前缀就是 父类整份布局,含其继承链);父类 struct 不可得(跨模块未加载 / opaque)时**不介入**。 TypeGenMixin:40 ≠ len(TypeGenBase)=41 ⇒ 不介入,落回下标法得 0(Generator*,赋值合法)。 (正面场景仍生效:AnnAssign 表仅 4 项自有字段、body 12 槽、父类 Stmt 8 槽 ⇒ 8 == 8。) 验证:冒烟两例——反例 TypeGenMixin.Gen → 0(修前 40);正例 AnnAssign 仅自有字段表仍得 target/annotation/value/simple = 8/9/10/11;FuncGen py_compile 通过。 --- lib/core/LLVMCG/FuncGen.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/core/LLVMCG/FuncGen.py b/lib/core/LLVMCG/FuncGen.py index 2238834..3919cf5 100644 --- a/lib/core/LLVMCG/FuncGen.py +++ b/lib/core/LLVMCG/FuncGen.py @@ -604,8 +604,23 @@ class FuncGenMixin: # _MemberSlotAccepts):表自洽(长度 == 字段区)时本路径不介入, # 对既有正确行为零变化;REnum 是 max-variant 镜像布局,不适用。 _FieldArea: int = len(_OffEls) - _BaseNow() + # 【前置校验·必需】尾部对齐只对"**缺父类前缀**"的表成立,判据是 + # 前缀数 == 父类 struct 的槽数(展平前缀就是父类整份布局,含其继承链)。 + # 缺了这条,一张**只含前若干字段**的残缺表会被锚到 body 末尾: + # 现场 `SubTypeGen.Gen = self`(Generator.vp:136)——TypeGenMixin 表 + # 仅 ['Gen'](且其声明类型是通用指针/未解析),body 41 槽 ⇒ 被锚到 + # 槽 40(= Specs,%TypeSpecArena*)⇒ 报"Generator* 不能隐式转 + # TypeSpecArena*"。父类 struct 不可得(跨模块未加载/opaque)时 + # **不介入**(保守落回配对 / 旧路径)。 + _ParentCls: str | None = self.class_parent.get(_ResolvedClass) + _ParentSt: Any = self.structs.get(_ParentCls) if _ParentCls else None + _ParentLen: int = -1 + if isinstance(_ParentSt, ir.IdentifiedStructType) and _ParentSt.elements is not None: + _ParentLen = len(_ParentSt.elements) if (len(_OffMembers) < _FieldArea - and not self._IsRenumLayoutClass(_ResolvedClass)): + and not self._IsRenumLayoutClass(_ResolvedClass) + and _ParentLen > 0 + and len(_OffEls) - len(_OffMembers) == _ParentLen): _TailBase: int = len(_OffEls) - len(_OffMembers) _TailOk: bool = _TailBase >= 0 _iT: int = 0