diff --git a/lib/core/LLVMCG/StructGen.py b/lib/core/LLVMCG/StructGen.py index 15b74d2..9f1f1d8 100644 --- a/lib/core/LLVMCG/StructGen.py +++ b/lib/core/LLVMCG/StructGen.py @@ -319,6 +319,35 @@ class StructGenMixin: # 判据不可用(缺上下文)时保守放行,避免误清已正确的布局。 return True + def _IsRenumLayoutClass(self, ClassName: str | None) -> bool: + """该类是否属 **REnum 布局**(主 REnum 自身,或其变体嵌套结构体 `_`)。 + + REnum 的 struct body 是 **max-variant 镜像布局**:`class_members` 里那些名字是 + *变体*(不是字段),变体嵌套结构体也必须逐字镜像主结构体。因此**一律不得**用 + class_members 的"声明类型"去改写或校验它们的布局 —— 否则跨模块 GEP 偏移与 + 定义端失配(变体载荷槽本就允许与 max-variant 槽类型不同,取值处靠 bitcast)。 + """ + if not ClassName: + return False + _tbl: Any = getattr(self, 'SymbolTable', None) + if _tbl is None: + return False + try: + _e: Any = _tbl.lookup(ClassName) + except Exception: + return False + if _e is not None and getattr(_e, 'IsRenum', False): + return True + if '_' in ClassName: + _prefix: str = ClassName.rsplit('_', 1)[0] + try: + _pe: Any = _tbl.lookup(_prefix) + except Exception: + _pe = None + if _pe is not None and getattr(_pe, 'IsRenum', False): + return True + return False + def _SyncStructBodyTypes(self, ClassName: str | None) -> None: """把 struct body 中与 `class_members` 声明**不兼容**的槽改回声明类型(就地修复)。 @@ -339,6 +368,10 @@ class StructGenMixin: """ if not ClassName: return + # REnum 布局(主 REnum 及其变体嵌套结构体)是 max-variant 镜像布局,声明成员 + # 不是字段 —— 一律不参与本修复,避免改写其布局导致跨模块偏移失配。 + if self._IsRenumLayoutClass(ClassName): + return _st: Any = self.structs.get(ClassName) if not isinstance(_st, ir.IdentifiedStructType) or _st.elements is None: return @@ -358,8 +391,21 @@ class StructGenMixin: _changed = True if not _changed: return + _backup: list = list(_st.elements) _st._elements = None - _st.set_body(*_elems) + try: + _st.set_body(*_elems) + except Exception as _e: + # 回滚到原布局(直接写回私有字段,不再经 set_body),再响亮失败:把 llvmlite + # 那句含糊的 " is already defined" 变成带类名/元素数/原异常的错误, + # 且保证不留下被改坏的中间状态。 + _st._elements = _backup + from lib.core.LLVMCG.FuncGen import FailFastError + raise FailFastError( + f"struct body 就地修复失败(类 '{ClassName}',struct='{_st}'):" + f"{type(_e).__name__}: {_e};元素数={len(_backup)} → 目标元素数={len(_elems)}," + f"已回滚原布局" + ) from _e def _generate_structs(self) -> None: all_classes: set[str] = set(self.class_methods.keys()) | set(self.class_members.keys()) @@ -548,7 +594,10 @@ class StructGenMixin: # 声明类型**能隐式写进该槽**才算一致 —— 通用指针槽(i8*)照旧放行,不误清。 _slot_types_ok: bool = True _members_pre: list = self.class_members.get(ClassName, []) - if _members_pre: + # REnum 布局(主 REnum 及变体嵌套结构体)是 max-variant 镜像布局, + # class_members 里是*变体*不是字段 ⇒ 不参与逐元素类型校验(见 + # _IsRenumLayoutClass)。 + if _members_pre and not self._IsRenumLayoutClass(ClassName): _base_pre: int = 1 if _has_vtable_precheck else 0 _elems_pre: list = list(existing_st.elements) for _i_pre, _item_pre in enumerate(_members_pre):