From e2c4c7645ef8dec5f933cd78fbb2233919014886 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 28 Sep 2026 15:29:42 +0800 Subject: [PATCH] =?UTF-8?q?fix(cast):=20=E8=A1=A5=E7=BB=A7=E6=89=BF?= =?UTF-8?q?=E4=B8=8A=E8=BD=AC=E8=B1=81=E5=85=8D=EF=BC=88Derived*=E2=86=92B?= =?UTF-8?q?ase*=20=E6=94=BE=E8=A1=8C=EF=BC=89=EF=BC=8C=E4=B8=8E=20TPC=20?= =?UTF-8?q?=E5=90=8C=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 _class_name_of_ptr_pointee(复用 StructGen.get_class_name_by_type)与 _is_inheritance_upcast(复用 StructGen.get_mro_chain:目标类名命中源类 MRO 链自身之后的祖先即放行,含多级) 在 _pointee_convert_reason 落入“非基本类型”分支前插入上转豁免;其余规则(通用指针通配/层数不同即禁/完全相同放行/None 任意/构造物化豁免/标量无损)未动;Base*→Derived* 与无关结构体仍禁 注:本提交顺带带入 App/main.vp 的既有版本号改动(0.0.5-dev.479,非本次会话产出) --- App/lib/core/Gen/Expr/ExprGenBase.vp | 52 +++++++++++++++++++++++++++- App/main.vp | 4 +-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/App/lib/core/Gen/Expr/ExprGenBase.vp b/App/lib/core/Gen/Expr/ExprGenBase.vp index 3278241..1efca31 100644 --- a/App/lib/core/Gen/Expr/ExprGenBase.vp +++ b/App/lib/core/Gen/Expr/ExprGenBase.vp @@ -574,9 +574,56 @@ novirtual class ExprGenBase: return PC_LOSSY return PC_OK # ============================================================ + # _class_name_of_ptr_pointee - 指针被指类型 → 已注册类名 + # + # 复用 StructGen.get_class_name_by_type(内部即 find_struct_by_type 首注册 + # 优先匹配 + 按名/后缀回退),把 LLVM 被指类型映射到类名;非结构体/未注册 + # 返回 None。不新造表。 + # ============================================================ + def _class_name_of_ptr_pointee(self, pool: memhub.MemBuddy*, + pt: llvmlite.LLVMType*) -> str: + """指针被指类型映射到已注册类名;失败返回 None""" + if pt is None: + return None + return self.Gen.StructGen.get_class_name_by_type(pool, pt) + # ============================================================ + # _is_inheritance_upcast - 继承上转判据(Derived* → Base*,含多级) + # + # 规则 2 的豁免:两侧被指类型都解析到已注册类时,若**目标类名出现在源类名 + # 的 MRO 链「自身之后」**(即目标为源的基类/祖先)⇒ 允许隐式上转。 + # 复用既有继承判据(StructGen.get_class_name_by_type + get_mro_chain), + # 不引入新表。下转(Base* → Derived*:派生类不在基类 MRO 链里)与无关 + # 类型(Foo* ↔ Bar*)都不命中 ⇒ 返回 0,仍按规则 2/3 禁止。 + # ============================================================ + def _is_inheritance_upcast(self, pool: memhub.MemBuddy*, + src_pt: llvmlite.LLVMType*, + dst_pt: llvmlite.LLVMType*) -> int: + """派生类指针 → 基类指针(含多级):1=允许上转 / 0=否""" + src_name: str = self._class_name_of_ptr_pointee(pool, src_pt) + if src_name is None: + return 0 + dst_name: str = self._class_name_of_ptr_pointee(pool, dst_pt) + if dst_name is None: + return 0 + if string.strcmp(src_name, dst_name) == 0: + return 0 + chain: sizet* = self.Gen.StructGen.get_mro_chain(pool, src_name) + if chain is None: + return 0 + # chain[0] = 自身;父类/祖先在后,遇 0 终止。只查「自身之后」的祖先。 + i: int = 1 + while chain[i] != 0: + anc: str = (str | t.CPtr)(chain[i]) + if anc is not None and string.strcmp(anc, dst_name) == 0: + return 1 + i += 1 + return 0 + # ============================================================ # _pointee_convert_reason - 被指类型 src_pt → dst_pt(T*→U* 的 T→U 关系)判定码 # # 规则 2:T* → U*(T、U 都非通用指针)允许 ⇔ 被指类型 T → U 无损。 + # 豁免:T、U 都是已注册类且 U 是 T 的基类(含多级)时,Derived* → Base* + # 继承上转允许(见 _is_inheritance_upcast)。 # 规则 3:非基本类型 T 与其指针 T* 之间(值/指针互换)一律禁止——此处体现为 # 被指类型一侧是「非基本值类型」、另一侧是「其指针(或其它的基本/非基本类型)」 # 时一律不匹配 ⇒ PC_NONBASIC。 @@ -596,8 +643,11 @@ novirtual class ExprGenBase: return PC_NONBASIC # 两侧都是指针:递归 return self._ptr_cast_reason(pool, src_pt, dst_pt) - # 一侧是非基本类型(结构体/类/联合/数组/函数)→ 一律禁止 + # 一侧是非基本类型(结构体/类/联合/数组/函数)→ 一般禁止 if self._is_basic_scalar_ty(src_pt) == 0 or self._is_basic_scalar_ty(dst_pt) == 0: + # 豁免:Derived* → Base* 继承上转(含多级)允许(C++/GCC 同口径) + if self._is_inheritance_upcast(pool, src_pt, dst_pt) != 0: + return PC_OK return PC_NONBASIC return self._scalar_convert_reason(src_pt, dst_pt) # ============================================================ diff --git a/App/main.vp b/App/main.vp index e50cc3b..475b062 100644 --- a/App/main.vp +++ b/App/main.vp @@ -41,8 +41,8 @@ define CODE_PAGE = 65001 # Source code buffer size (1MB) define SRC_BUF_SIZE = 1048576 # Version (dev/beta/rc) -V_TPV_VERSION: __attribute__(section(".PRVERSN")) []char = "0.0.3-dev.428" -define V_VIPER_VERSION = "1.0.4-dev.579 2026-09-27 Non-LTS" +V_TPV_VERSION: __attribute__(section(".PRVERSN")) []char = "0.0.5-dev.479" +define V_VIPER_VERSION = "1.0.5-dev.970 2026-09-28 Non-LTS" define V_RUNTIME_VERSION = "0.2.3+19-Non-LTS" define V_TPC_COMMIT = "e376b949c9" define V_TPV_COMMIT = "ab0f37e1a8"