From a18ca4da3b6a83aa7a2132339baa88104a6808d2 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 09:59:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(ExprAttr):=20=E5=B5=8C=E5=A5=97=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E8=AF=BB=E7=9A=84=E6=AF=8F=E4=B8=AA=20silent=20return?= =?UTF-8?q?=20=E9=83=BD=E7=95=99=E7=97=95=EF=BC=88=E5=90=AB=E5=86=85?= =?UTF-8?q?=E5=B1=82=E5=A4=B1=E8=B4=A5=E5=8E=9F=E5=9B=A0=E9=93=BE=EF=BC=89?= =?UTF-8?q?=EF=BC=8CRepl.vp:802=20=E7=B1=BB=E9=94=99=E8=AF=AF=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E5=8F=AA=E8=83=BD=E7=9C=8B=E5=88=B0"=E5=9F=BA?= =?UTF-8?q?=E5=BA=A7=E5=BD=A2=E6=80=81"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类别:a 编译器缺陷(可观测性补齐:报错点与真因相隔数层) 现象:TPC 编译 TransPyV/App/lib/core/Repl.vp:802 `ct_names: list[str]* = GenApi._g_gen.TypeGenCType.CTypedefNames` 报「带注解赋值表达式 …(Attribute 形态)编译期求值为空(表达式未解析出目标、无值可存)… 赋值将被跳过」,报文里只有「基座形态=Attribute(.TypeGenCType←Attribute(._g_gen←Name(GenApi)))」, 看不出是三级链的哪一级失败、为什么失败。 判据:`_handle_attr_nested`(多级属性读)里有 7 处 `return None` 是**静默**的,而 `Gen._LastAttrNone`(`_NoteAttrNone` 记账,供 `_DescribeAttrBase` 回显"读取侧原因")只在 `_handle_attr_name`/`_gep_and_Load_member` 一侧登记 ⇒ 本函数的失败在报文里完全没有原因。 且嵌套读取时**内层**的记账会被外层覆盖,即使内层登记了也回显不出来。 修法(纯记账,不改任何判定/IR): 1. `_handle_attr_nested` 的每处静默 return 都调 `_NoteAttrNone` 记下**具体事实**: · 基座求值为空/非指针 → 附 type + **内层链的失败原因**(把 `_LastAttrNone` 里"字段名不同" 的那条记录串进来,形成原因链); · 类名提示未命中 Gen.structs 键(报 structs 键数); · struct 实例类型异常; · body 仍 opaque 且无泛型特化成员; · **字段在类中取不到偏移**(报成员表项数 / body 槽数 —— 跨模块成员表缺失或漂移的关键判据); · 槽是 void 占位; · 结构体分支 pointee 未匹配任何类(报 structs 键数)。 2. `_DescribeAttrBase` 的回显键是 (字段名, 类名),本次登记与报错节点一致 ⇒ 下次同类报错将 直接给出"读取侧原因=…",一轮定位到级与因。 验证:py_compile EXIT=0。真因证据(同一现场、另一侧):`TypeGenCType` 类体一个字段都没声明, 5 个字段全靠方法体裸 `self.x = ...`;其 .vpi(temp/05d515186a7c3668.vpi)里确实没有 CTypedefNames —— 跨模块成员表缺该字段即本次链断之处,已在 TransPyV 侧按"跨模块可见字段 必须在类体声明"补上(见另一仓 commit)。 --- lib/core/Handles/HandlesExprAttr.py | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py index 2bec0c1..706d320 100644 --- a/lib/core/Handles/HandlesExprAttr.py +++ b/lib/core/Handles/HandlesExprAttr.py @@ -834,6 +834,18 @@ class ExprAttrHandle(BaseHandle): return cdefine_result ObjVal: Any = self.HandleExprLlvm(Node.value) if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + # 取证(纯记账):基座求值为空/非指针时,把**内层链的失败原因**一并挂上—— + # 嵌套读取的内层记录随后会被本节点的记录覆盖,报错点(本节点)与真因(内层某级) + # 相隔数层的可读性问题由此解决(现场:`GenApi._g_gen.TypeGenCType.CTypedefNames`)。 + _prev_an: Any = getattr(Gen, '_LastAttrNone', None) + _chain_an: str = '' + if (isinstance(_prev_an, tuple) and len(_prev_an) >= 3 and _prev_an[2] + and _prev_an[1] and _prev_an[1] != Node.attr): + _chain_an = f";内层字段 '{_prev_an[1]}' 的失败原因:{_prev_an[2]}" + self._NoteAttrNone( + Gen, None, Node.attr, + f"基座 {self._ExprShape(Node.value)} 求值为空或非指针" + f"(type={getattr(ObjVal, 'type', None)}){_chain_an}") return None pointee: Any = ObjVal.type.pointee @@ -887,25 +899,41 @@ class ExprAttrHandle(BaseHandle): or getattr(Gen, 'global_struct_class', {}).get(_mva.attr)) ResolvedKey: str | None = self._find_struct_key_for_class_hint(Gen, AttrClassName) if ResolvedKey is None or ResolvedKey not in Gen.structs: + self._NoteAttrNone( + Gen, AttrClassName, Node.attr, + f"基座字段的所属类未能在 Gen.structs 命中键(类名提示={AttrClassName!r}," + f"structs 键数={len(Gen.structs)})") return None st: Any ok: bool st, ok = self._try_Load_struct_from_stub(Gen, ResolvedKey) if not isinstance(st, ir.IdentifiedStructType): + self._NoteAttrNone(Gen, ResolvedKey, Node.attr, + f"类 '{ResolvedKey}' 的 struct 实例类型异常({type(st).__name__})") return None if st.elements is None: # stub 仍 opaque(如跨模块泛型仅声明):走泛型特化候选访问 spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st, Node, ResolvedKey, AttrClassName) if spec_val is not None: return spec_val + self._NoteAttrNone( + Gen, ResolvedKey, Node.attr, + f"类 '{ResolvedKey}' 的 body 仍为 opaque(elements=None),且无泛型特化成员可访问") return None CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{ResolvedKey}") if Node.attr in Gen.class_member_bitoffsets.get(ResolvedKey, {}): return self._load_bitfield_member(CastedObj, ResolvedKey, Node.attr) offset: int | None = Gen._get_member_offset(Node.attr, ResolvedKey) if offset is None: + self._NoteAttrNone( + Gen, ResolvedKey, Node.attr, + f"字段 '{Node.attr}' 在类 '{ResolvedKey}' 中取不到偏移" + f"(成员表 {len(Gen.class_members.get(ResolvedKey) or [])} 项 / body {len(st.elements)} 槽)") return None if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType): + self._NoteAttrNone( + Gen, ResolvedKey, Node.attr, + f"字段 '{Node.attr}' 的槽 {offset} 是 void(占位槽:类型信息缺失)") return None return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, ResolvedKey, st) @@ -934,6 +962,11 @@ class ExprAttrHandle(BaseHandle): return self._load_bitfield_member(ObjVal, CN, Node.attr) offset = Gen._get_member_offset(Node.attr, CN) if offset is None: + self._NoteAttrNone( + Gen, CN, Node.attr, + f"字段 '{Node.attr}' 在类 '{CN}' 中取不到偏移" + f"(成员表 {len(Gen.class_members.get(CN) or [])} 项 / " + f"body {len(st.elements) if isinstance(st, ir.IdentifiedStructType) and st.elements is not None else 'opaque'} 槽)") break # 泛型基础类型字段特化(根本修复): # 当字段声明为特化泛型(如 GSList[BasicBlock])时,基础类型(GSList)的 @@ -965,6 +998,12 @@ class ExprAttrHandle(BaseHandle): return self._gep_and_Load_member(Gen, _casted, _off2, Node.attr, CN2, ST2) break return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) + # 结构体分支未命中任何类:pointee 与 Gen.structs 全部键都不等(同名类双实例 / + # 该类未注册)——这是"基座类型已知却读不到字段"的最后一种来源,必须留痕。 + self._NoteAttrNone( + Gen, None, Node.attr, + f"基座 pointee {pointee} 未匹配 Gen.structs 中任何 struct(键数={len(Gen.structs)})" + f";基座形态={self._ExprShape(Node.value)}") return None def _handle_attr_call_result(self, Node: ast.Attribute) -> ir.Value | None: