From 7c6a497111450e5835d7b99a1afad3475dcbdd89 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 18 Aug 2026 13:19:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(DeclarationGenerator):=20=E6=8C=89=E8=87=AA?= =?UTF-8?q?=E6=9C=89=E5=AD=97=E6=AE=B5=E5=B1=95=E5=B9=B3=E6=97=B6=E8=A1=A5?= =?UTF-8?q?=E9=BD=90=E7=A5=96=E5=85=88=20vtable=20=E6=8C=87=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _FlattenInheritedDecl 递归只取类自有字段,而原 _get_inherited_members 返回完整 struct 天然含 vtable。改造后 Module(AST CVTable) 等子类 struct 缺 vtable 指针 → 字段错位 → 编译报 'cannot store i8* to %AST**'(写 vtable 到 parent 槽位)。新增 _ShouldEmitOwnVtablePtr 判定,递归各祖先类时在自有字段前补齐 vtable。 --- lib/Projectrans/DeclarationGenerator.py | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/lib/Projectrans/DeclarationGenerator.py b/lib/Projectrans/DeclarationGenerator.py index b38844a..e36bbc1 100644 --- a/lib/Projectrans/DeclarationGenerator.py +++ b/lib/Projectrans/DeclarationGenerator.py @@ -794,6 +794,67 @@ class DeclarationGenerator: member_types.append('i32') return member_types, has_bitfield, total_bits + def _ShouldEmitOwnVtablePtr(self, node: ast.ClassDef) -> bool: + """类自身是否需要 vtable 指针(复刻 _generate_class_decl 的判定)。 + + 仅"有方法 + CVTable 且父类无 vtable + 非 NoVTable"的类在 struct 最前 + 放 vtable 指针。继承 vtable 父类的子类不重复添加。_FlattenInheritedDecl + 递归时用此判定补齐各祖先类的 vtable 指针(原 _get_inherited_members + 走 _generate_class_decl 完整 struct 天然包含;改按自有字段后必须补上)。 + """ + has_methods: bool = any(isinstance(item, ast.FunctionDef) for item in node.body) + is_cvtable: bool = False + is_cpython_object: bool = False + is_novtable: bool = False + if hasattr(node, 'decorator_list') and node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Attribute): + if getattr(decorator.value, 'id', None) == 't': + if decorator.attr == 'CVTable': + is_cvtable = True + elif decorator.attr == 'Object': + is_cpython_object = True + elif decorator.attr == 'NoVTable': + is_novtable = True + elif isinstance(decorator, ast.Name): + if decorator.id == 'CVTable': + is_cvtable = True + elif decorator.id == 'Object': + is_cpython_object = True + elif decorator.id == 'NoVTable': + is_novtable = True + if has_methods and not is_cpython_object: + is_cpython_object = True + base_has_vtable: bool = False + for base in node.bases: + base_name: str | None = None + if isinstance(base, ast.Attribute): + base_name = base.attr + elif isinstance(base, ast.Name): + base_name = base.id + elif isinstance(base, ast.Subscript): + if isinstance(base.value, ast.Attribute): + base_name = base.value.attr + elif isinstance(base.value, ast.Name): + base_name = base.value.id + if base_name and not self._is_marker_base(base_name): + _base_node: ast.ClassDef | None = None + for n in ast.iter_child_nodes(self._pyi_tree): + if isinstance(n, ast.ClassDef) and n.name == base_name: + _base_node = n + break + if _base_node is None: + _base_node = self._cross_module_class_defs.get(base_name) + if _base_node is not None and hasattr(_base_node, 'decorator_list') and _base_node.decorator_list: + for dec in _base_node.decorator_list: + if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable': + base_has_vtable = True + elif isinstance(dec, ast.Name) and dec.id == 'CVTable': + base_has_vtable = True + if base_has_vtable: + break + return has_methods and is_cvtable and not base_has_vtable and not is_novtable + def _FlattenInheritedDecl(self, cls_name: str, seen_cls: set, member_types: list[str], type_args: list[str] | None = None) -> None: """按继承源去重递归展平:继承树每个类只处理一次,每类只贡献自有字段。 @@ -845,6 +906,10 @@ class DeclarationGenerator: own, _hbf, _tbits = self._CollectOwnMemberTypes(cls_node) if type_args: own = self._specialize_member_types(own, type_args) + # 该类的 vtable 指针(若有)放在自有字段最前(与 _generate_class_decl + # L485 一致;递归时各祖先类的 vtable 也按此补齐) + if self._ShouldEmitOwnVtablePtr(cls_node): + member_types.append('i8*') member_types.extend(own) def _get_inherited_members(self, base_name: str) -> tuple[list[str], set[str]]: