fix(TPC): 跨模块多继承布局统一 - 字段整体前置/方法表合并/父类防重复
1. 定义模块多继承字段展平 prepend(反序) 改 append(正序),与 DeclarationGenerator stub 一致,修复 ASan 定位的 Generator 字段运行时错位(0xbe)。2. 跨模块加载 class_members 已含子类自身字段,父类字段必须整体前置(prepend),否则 Value.Next 命中 FloatVal(double) 导致 store 类型错乱。3. 跨模块补充与定义模块一致的方法合并(父类槽位前置、子类覆盖放父类位置),修复 vtable 槽错位(MemBuddy.alloc→_fl_find_and_remove)。4. 父类前置按字段名过滤已存在字段,防 _EmitExternalClassDeclLlvm 多加载路径重复调用导致 class_members 重复(BasicBlock:[Next,Next,...])。
This commit is contained in:
1 parent
bb0f7049ce
commit
2129430446
2 files changed
+84
-17
No files matched your search
@@ -613,26 +613,34 @@ class ClassHandle(BaseHandle):
|
||||
Gen.class_parents[ClassName] = ParentClasses
|
||||
if ParentClasses:
|
||||
# ============================================================
|
||||
# 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明父类优先),
|
||||
# 多继承字段展平:遍历所有父类(声明顺序),字段名**不去重**,
|
||||
# __vtable__ 跳过(vtable 指针由 _generate_structs 按 class_vtable 统一添加)。
|
||||
# 布局: [父类1字段..., 父类2字段..., 子类字段...]
|
||||
# 布局: [父类1字段..., 父类2字段..., 子类字段...](MRO 正序,与
|
||||
# DeclarationGenerator stub / TPV 参考实现一致)。
|
||||
#
|
||||
# 关键修复(2026-08-10):原实现用 `inherited + class_members`(prepend)
|
||||
# 产出 MRO 反序布局,且按字段名去重(如多个 Mixin 各自声明的 TempDir
|
||||
# 被剔除)——导致定义模块 struct 与跨模块 stub 布局不一致,所有多继承
|
||||
# 类字段运行时错位(ASan 下读到 0xbe 填充崩溃)。Mixin 方法体以自身
|
||||
# 局部索引独立编译,调用侧 this_adjust + 块内索引依赖"展平块与 Mixin
|
||||
# 自身逐字段一致",因此跨父类不能去重。菱形继承(A→D, B→D)会让 D
|
||||
# 字段重复——当前项目 Mixin 为兄弟无共享祖先;若未来出现真菱形需改为
|
||||
# "按继承源去重"而非"按字段名去重"。
|
||||
# ============================================================
|
||||
for ParentClass in ParentClasses:
|
||||
if ParentClass not in class_graph and ParentClass not in Gen.class_members:
|
||||
continue
|
||||
parent_members: list = list(Gen.class_members.get(ParentClass, []))
|
||||
parent_defaults: dict = dict(Gen.class_member_defaults.get(ParentClass, {}))
|
||||
existing_names: set = {m[0] for m in Gen.class_members[ClassName]}
|
||||
inherited: list[tuple] = []
|
||||
for pm_name, pm_type in parent_members:
|
||||
if pm_name == '__vtable__':
|
||||
continue
|
||||
if pm_name not in existing_names:
|
||||
inherited.append((pm_name, pm_type))
|
||||
if pm_name in parent_defaults:
|
||||
Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name]
|
||||
inherited.append((pm_name, pm_type))
|
||||
if pm_name in parent_defaults:
|
||||
Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name]
|
||||
if inherited:
|
||||
Gen.class_members[ClassName] = inherited + Gen.class_members[ClassName]
|
||||
Gen.class_members[ClassName] = Gen.class_members[ClassName] + inherited
|
||||
# ============================================================
|
||||
# 多继承方法合并:遍历所有父类(声明顺序)收集方法(短名去重,先声明父类优先),
|
||||
# vtable 槽/方法名用"实际定义类.方法"(如 B.get_b,与 TPV 一致),
|
||||
|
||||
@@ -1852,6 +1852,7 @@ class ImportHandle(BaseHandle):
|
||||
# 避免 struct body 从不完整 class_members 生成导致 GEP 越界。
|
||||
# 同时处理父类 class_members 全为占位符的情况(清除后重新加载)。
|
||||
_any_parent_loaded: bool = False
|
||||
_all_inherited: list[tuple] = []
|
||||
for _ParentClass in _ParentClasses:
|
||||
if not _ParentClass:
|
||||
continue
|
||||
@@ -1882,18 +1883,30 @@ class ImportHandle(BaseHandle):
|
||||
if _ParentClass in Gen.class_members:
|
||||
_parent_members: list = list(Gen.class_members[_ParentClass])
|
||||
_parent_defaults: dict = dict(Gen.class_member_defaults.get(_ParentClass, {}))
|
||||
_existing_names: set = {m[0] for m in Gen.class_members[ClassName]}
|
||||
_inherited: list[tuple] = []
|
||||
# 跨父类不去重(与 HandlesClassDef 展平、DeclarationGenerator stub 一致):
|
||||
# 多继承展平必须保留每个父类全部字段(含重名如多个 Mixin 的 TempDir),
|
||||
# 否则 Mixin 方法体 this_adjust + 块内局部索引寻址与全量布局错位。
|
||||
for _pm_name, _pm_type in _parent_members:
|
||||
if _pm_name == '__vtable__':
|
||||
continue
|
||||
if _pm_name not in _existing_names:
|
||||
_inherited.append((_pm_name, _pm_type))
|
||||
if _pm_name in _parent_defaults:
|
||||
Gen.class_member_defaults[ClassName][_pm_name] = _parent_defaults[_pm_name]
|
||||
if _inherited:
|
||||
Gen.class_members[ClassName] = _inherited + Gen.class_members[ClassName]
|
||||
_any_parent_loaded = True
|
||||
_all_inherited.append((_pm_name, _pm_type))
|
||||
if _pm_name in _parent_defaults:
|
||||
Gen.class_member_defaults[ClassName][_pm_name] = _parent_defaults[_pm_name]
|
||||
if _all_inherited:
|
||||
# 防重复注册(2026-08-10):_EmitExternalClassDeclLlvm 可能被多个模块
|
||||
# 加载路径重复调用(_LoadModuleDeclarationsFromFile / _LoadDeclarationsFromStubLlvm
|
||||
# / _TryLoadClassMembersFromPyi 懒加载),此前调用已前置的父类字段会被再次
|
||||
# 前置 → class_members 出现重复字段(如 BasicBlock: [Next, Next, Name, ...])
|
||||
# → 与 struct elements 数量不匹配 → 属性偏移错乱。按字段名过滤已存在的
|
||||
# 父类字段;跨父类重名字段(不同父类各自声明)仍全部保留。
|
||||
_cur_member_names_pre: set = {n for n, _ in Gen.class_members.get(ClassName, [])}
|
||||
_filtered_inherited: list[tuple] = [
|
||||
(nm2, tp2) for nm2, tp2 in _all_inherited if nm2 not in _cur_member_names_pre
|
||||
]
|
||||
if _filtered_inherited:
|
||||
Gen.class_members[ClassName] = _filtered_inherited + Gen.class_members[ClassName]
|
||||
# 父类字段已处理(可能此前已前置),跳过占位符路径避免叠加
|
||||
_any_parent_loaded = True
|
||||
if not _any_parent_loaded and _ParentClasses:
|
||||
# 父类未加载到 class_members(常见于泛型特化基类如 GSListNode[Value],
|
||||
# 其特化不在 .pyi 中)。用 struct body 元素数推断继承字段数。
|
||||
@@ -1910,7 +1923,53 @@ class ImportHandle(BaseHandle):
|
||||
if _num_elements > _num_members:
|
||||
_num_inherited = _num_elements - _num_members
|
||||
_inherited_ph: list[tuple] = [(f'__inherited_{i}', _st.elements[i]) for i in range(_num_inherited)]
|
||||
# 占位符路径同样整体前置(继承字段在 struct 头部),与主路径保持一致
|
||||
Gen.class_members[ClassName] = _inherited_ph + Gen.class_members[ClassName]
|
||||
# ============================================================
|
||||
# 跨模块 vtable 槽布局与定义模块一致:父类方法在前(子类覆盖放父类槽位),
|
||||
# 子类新增方法在后。定义模块(HandlesClassDef)已按此合并,跨模块若只
|
||||
# 注册自身方法(_has_methods_prescan),vtable 槽位会错位 →
|
||||
# 虚分派调用错误函数(如 MemBuddy.alloc 被解析到槽 13=_fl_find_and_remove
|
||||
# → 返回 None → "Generator alloc failed")。
|
||||
# ============================================================
|
||||
if _ParentClasses:
|
||||
_all_parent_methods: list[str] = []
|
||||
_parent_method_names_seen: set[str] = set()
|
||||
for _pcls in _ParentClasses:
|
||||
for _pm in list(Gen.class_methods.get(_pcls, [])):
|
||||
_pm_name: str = _pm.split('.')[-1] if '.' in _pm else _pm
|
||||
if _pm_name in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
if _pm_name in _parent_method_names_seen:
|
||||
continue
|
||||
_parent_method_names_seen.add(_pm_name)
|
||||
_all_parent_methods.append(_pm)
|
||||
if _all_parent_methods:
|
||||
_child_method_map: dict[str, str] = {}
|
||||
for _m in Gen.class_methods.get(ClassName, []):
|
||||
_mn: str = _m.split('.')[-1] if '.' in _m else _m
|
||||
_child_method_map[_mn] = _m
|
||||
# 从 .vpi 的 FunctionDef 补充子类方法映射(覆盖方法可能尚未注册)
|
||||
for _item_m in getattr(Node, 'body', []):
|
||||
if isinstance(_item_m, ast.FunctionDef):
|
||||
_mn2: str = _item_m.name
|
||||
if _mn2 in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
_child_method_map[_mn2] = f"{ClassName}.{_mn2}"
|
||||
_new_methods: list[str] = []
|
||||
_covered_names: set[str] = set()
|
||||
for _pm2 in _all_parent_methods:
|
||||
_mname2: str = _pm2.split('.')[-1] if '.' in _pm2 else _pm2
|
||||
if _mname2 in _child_method_map:
|
||||
_new_methods.append(_child_method_map[_mname2])
|
||||
else:
|
||||
_new_methods.append(_pm2)
|
||||
_covered_names.add(_mname2)
|
||||
for _m3 in list(Gen.class_methods.get(ClassName, [])):
|
||||
_mn3: str = _m3.split('.')[-1] if '.' in _m3 else _m3
|
||||
if _mn3 not in _covered_names:
|
||||
_new_methods.append(_m3)
|
||||
Gen.class_methods[ClassName] = _new_methods
|
||||
if has_methods:
|
||||
if IsCVTable:
|
||||
Gen._cross_module_vtable_classes.add(ClassName)
|
||||
|
||||
Reference in new issue
Block a user