diff --git a/App/lib/core/Gen/Expr/ExprGenAttr.vp b/App/lib/core/Gen/Expr/ExprGenAttr.vp index 13844a2..e445c2e 100644 --- a/App/lib/core/Gen/Expr/ExprGenAttr.vp +++ b/App/lib/core/Gen/Expr/ExprGenAttr.vp @@ -832,6 +832,11 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase): # Mod.g,如 GenApi._g_gen)——缺此则 Mod.g.Field[.Field] 的 # 接收者类解析不出(末跳 lookup_field 必然失败)。 base_class = self._resolve_attr_field_class(pool, trans, at.value, 1) + elif at.value.kind() == ast.ASTKind.Call: + # 指针强转基座(`(ast.Call*(x)).IsVolatile`):`T*(x)` 的结果 + # 类型是联合简化后的 i8*,须从强转注解提类名,详见 + # _base_class_from_cast_base 头注释 + base_class = self._base_class_from_cast_base(pool, trans, at.value) if base_class is not None: cur_sha1: str = trans.ModuleSha1 field_info = self.Gen.StructGen.lookup_field_by_class(base_class, at.attr, cur_sha1, at, trans._from_imports) @@ -1020,6 +1025,10 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase): parent_class = self.Gen.VarGen.var_annot_class_name(var_entry) elif at.value.kind() == ast.ASTKind.Attribute: parent_class = self._resolve_attr_field_class(pool, trans, at.value, allow_module_global) + elif at.value.kind() == ast.ASTKind.Call: + # 指针强转基座(`(T*(x)).f.g` 的递归父节点):从强转注解提取类名, + # 详见 _base_class_from_cast_base 头注释 + parent_class = self._base_class_from_cast_base(pool, trans, at.value) else: return None if parent_class is None: return None # 在父类中查 at.attr 字段,返回其注解类名 @@ -1031,6 +1040,58 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase): if fe is None: return None return self.Gen.StructGen.get_field_annot_class_name(fe) + # ============================================================ + # _base_class_from_cast_base - 指针强转基座 `T*(x)` 的类名 + # + # `T*(x)` 被 parser 的 _consume_ptr_suffix_call 解析成 `(T | t.CPtr)(x)` + # 强转调用(与手写 `(T | t.CPtr)(x)` 逐字同形),与 `t.CPtr` 取联合后结果 + # 的 LLVM 类型是**简化后的 i8***。于是 `(ast.Call*(vinner)).IsVolatile` + # 这类强转基座的字段访问/写入里 lookup_field(i8, ...) 必然失败。 + # + # 此函数从强转注解 func(BinOp)提取类名,交给既有的「按需过滤」分支 + # bitcast 回真实结构体类型后查字段——与 Name 变量注解、Attribute 字段注解 + # 两条路径同口径(见 _resolve_attr_field_class 头注释)。 + # + # 只认 func 是 BinOp 的形态:BinOp 作 callee 只可能是类型注解 + # (见 CallGenMixin 的联合强转分支),普通函数调用不会命中,故无误伤。 + # + # **取裸类名**(`ast.Call` → `"Call"`)而非 TypeGenResolve + # .extract_class_name_from_annotation 的模块限定名:后者对 `ast.Call` + # 返回 "ast.Call",而 lookup_field_by_class 的模块限定分支对「模块段可解析、 + # 但类注册在子模块」的形态会 fail-fast(模块段取到包名 "ast" 的 sha1,类 + # entry 的 ModuleSha1 却是子模块 exprs 的,find_struct_by_module 必失败)。 + # 裸名走「按类名查找第一个」回退,与 TPC _extract_union_base_class 同口径。 + # ============================================================ + def _base_class_from_cast_base(self, pool: memhub.MemBuddy*, + trans: HT.Translator*, + node: ast.AST*) -> str: + """`T*(x)` 强转基座的裸类名;非该形态返回 None""" + if node is None or trans is None: + return None + if node.kind() != ast.ASTKind.Call: + return None + cl_cb: ast.Call* = ast.Call*(node) + if cl_cb.func is None or cl_cb.func.kind() != ast.ASTKind.BinOp: + return None + bo_cb: ast.BinOp* = ast.BinOp*(cl_cb.func) + if bo_cb.op != ast.OpKind.BitOr: + return None + # 联合一侧是 t.CPtr 标记(`T | t.CPtr` / `T**` 展开的嵌套联合)时取另一侧; + # 否则(手写 `X | Y`)取左侧——与 parser 的 _make_ptr_type 产物一致。 + tgt_cb: ast.AST* = bo_cb.left + if self.Gen.TypeGenResolve._is_cptr_marker(bo_cb.left, trans._imported_modules) != 0: + tgt_cb = bo_cb.right + if tgt_cb is None: + return None + k_cb: int = tgt_cb.kind() + if k_cb == ast.ASTKind.Attribute: + at_cb: ast.Attribute* = ast.Attribute*(tgt_cb) + return at_cb.attr + if k_cb == ast.ASTKind.Name: + nm_cb: ast.Name* = ast.Name*(tgt_cb) + return nm_cb.id + return None + # ============================================================ # _resolve_module_global_class_name - 「模块名.全局变量」Mod.g 的结构体类名 # @@ -1328,6 +1389,11 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase): # allow_module_global=1:同 translate_attribute(基座可为 # 「模块名.全局变量」,如 GenApi._g_gen.TypeGenCDef) base_class = self._resolve_attr_field_class(pool, trans, at.value, 1) + elif at.value.kind() == ast.ASTKind.Call: + # 指针强转基座(`(ast.Call*(vinner)).IsVolatile = 1`): + # `T*(x)` 的结果类型是联合简化后的 i8*,须从强转注解提类名, + # 详见 _base_class_from_cast_base 头注释 + base_class = self._base_class_from_cast_base(pool, trans, at.value) if base_class is not None: cur_sha1: str = None lfi_gp: str = None