fix(DeclarationGenerator): 按自有字段展平时补齐祖先 vtable 指针

_FlattenInheritedDecl 递归只取类自有字段,而原 _get_inherited_members 返回完整 struct 天然含 vtable。改造后 Module(AST CVTable) 等子类 struct 缺 vtable 指针 → 字段错位 → 编译报 'cannot store i8* to %AST**'(写 vtable 到 parent 槽位)。新增 _ShouldEmitOwnVtablePtr 判定,递归各祖先类时在自有字段前补齐 vtable。
This commit is contained in:
TermiNexus committed 2026-08-18 13:19:51 +08:00
1 parent 81ad712475
commit 7c6a497111
1 file changed
+65
+65
View File
@@ -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]]: