diff --git a/lib/core/LLVMCG/MemoryOps.py b/lib/core/LLVMCG/MemoryOps.py index 920a4a0..1047a2d 100644 --- a/lib/core/LLVMCG/MemoryOps.py +++ b/lib/core/LLVMCG/MemoryOps.py @@ -222,14 +222,58 @@ class MemoryOpsMixin: return False return False - @staticmethod - def _ClassifyPtrImplicitConvert(Src: Any, Dst: Any) -> tuple[bool, str]: + def _ClassNameOfPointee(self, Pointee: Any) -> str | None: + """把 LLVM 被指类型映射到已注册类名(复用本仓既有 find_struct_by_pointee; + 身份比较失败时按短名(去 sha1 前缀)回退匹配 Gen.structs,与 HandlesAssign + 既有回退同口径)。非结构体 / 未注册 → None。不新造表。 + """ + if Pointee is None: + return None + Found: Any = self.find_struct_by_pointee(Pointee) + if Found: + return Found[0] + if isinstance(Pointee, ir.IdentifiedStructType): + PShort: str = self._extract_short_name(Pointee.name) + if PShort: + for CN, ST in self.structs.items(): + if isinstance(ST, ir.IdentifiedStructType) and \ + self._extract_short_name(ST.name) == PShort: + return CN + return None + + def _IsInheritanceUpcastPointee(self, SrcPointee: Any, DstPointee: Any) -> bool: + """继承上转判据:SrcPointee → DstPointee 是否为「派生类 → 基类」(含多级)。 + + 复用本仓既有继承判据:_ClassNameOfPointee(→ find_struct_by_pointee)取 + 类名,Gen._get_mro_chain 取 MRO 线性化(含自身,父类在后)。目标类名落在 + 源类名 MRO 链「自身之后」⇒ 允许上转(Derived* → Base*,C++/GCC 同口径); + 下转(Base* → Derived*)与无关类型(Foo* ↔ Bar*)不命中 ⇒ False。 + """ + SrcName: str | None = self._ClassNameOfPointee(SrcPointee) + if not SrcName: + return False + DstName: str | None = self._ClassNameOfPointee(DstPointee) + if not DstName: + return False + SrcShort: str = self._extract_short_name(SrcName) + DstShort: str = self._extract_short_name(DstName) + if SrcShort == DstShort: + return False + Chain: list[str] = self._get_mro_chain(SrcName) + for Anc in Chain[1:]: + if self._extract_short_name(Anc) == DstShort: + return True + return False + + def _ClassifyPtrImplicitConvert(self, Src: Any, Dst: Any) -> tuple[bool, str]: """隐式转换判据:返回 (Allowed, Reason)。 规则(用户决定,与 TransPyV 同口径): ① 通用指针(t.CPtr/i8*)为通配:与任何 T* **双向**互转放行(须同级)。 ② T* → U*(皆非通用):允许 ⇔ 被指类型 T → U 无损;非基本类型 - (结构体/类/联合)一律不允许 ⇒ Foo*→Bar* 禁止。 + (结构体/类/联合)一律不允许 ⇒ Foo*→Bar* 禁止;**唯一例外**是 + 继承上转 Derived* → Base*(目标被指类型是源被指类型的基类,含多级) + ——见 _IsInheritanceUpcastPointee。下转 Base* → Derived* 仍禁止。 ③ 非基本类型 T 与 T* 之间的隐式转换(Foo ↔ Foo*)一律禁止(层数不同); **唯一例外**是「构造物化」——该豁免需 AST 层判据,故在 coerce 调用点 由 _CtorCallStructType 单独放行(本判据只给出「禁」的结论)。 @@ -253,6 +297,10 @@ class MemoryOpsMixin: if MemoryOpsMixin._ScalarConvertLossless(sp, dp): return (True, '被指类型无损') return (False, '被指类型有损') + # 豁免:Derived* → Base* 继承上转(目标被指类型是源被指类型的基类, + # 含多级)允许(C++/GCC 同口径);下转/无关类型不命中,仍禁止。 + if self._IsInheritanceUpcastPointee(sp, dp): + return (True, '继承上转(派生类指针 → 基类指针)') return (False, '非基本类型(结构体/类/联合)') if not s_ptr and not d_ptr: return (True, '非指针间(本判据不裁决)')