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:
1 parent
81ad712475
commit
7c6a497111
1 file changed
+65
@@ -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]]:
|
||||
|
||||
Reference in new issue
Block a user