fix(cast): 补继承上转豁免(Derived*→Base* 放行),与 TPC 同口径

新增 _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,非本次会话产出)
This commit is contained in:
TermiNexus committed 2026-09-28 15:29:42 +08:00
1 parent f03aea15c7
commit e2c4c7645e
2 files changed
+53 -3

No files matched your search

+51 -1
View File
@@ -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)
# ============================================================
+2 -2
View File
@@ -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"