fix(cast): 显式指针 cast 一律放行(按 bitcast 重解释)+ MemoryOps 改用 vast 解析器模块

① 新增 _IsExplicitPtrCastNode:值节点是写明的指针转换调用(t.CPtr(x)/CPtr(x)/c.CPtr(x)/rawptr[T](x)/t.CPtr[T](x)/(T*)x/T*(x))时,_ClassifyPtrImplicitConvert 直接放行(用户规则「显式转换都可以」),调用方按既有 bitcast 重解释;非 cast 调用(MemBuddy(x)/list[X](x)/foo(x))不受影响。

根因:includes/_list.vp:60 的 elem_ptr: T | t.CPtr = t.CPtr(地址) 在 list[X*] 特化下 T|t.CPtr = X**(T 本身是指针),而 t.CPtr(...) 的值是 i8* ⇒ 被判「层数不同」,与报错自己给的「如需转换请显式 cast(如 t.CPtr(...))」建议自相矛盾(ExprGenFstr.vp 编译失败的 2 条 elem_ptr 报错)。

② MemoryOps.py 的 import ast 是标准库 —— 但 TPC 全部源码由 vast 解析,节点类为 lib.vast.Nodes.*,与标准库 ast 互不兼容 ⇒ 该文件所有节点类型判据对 Viper 源码静默失效(_value_node_of 子表达式下沉、_CtorCallStructType 构造物化豁免、以及新增的 cast 判据都不生效)。改为 import vast as ast,一并修复。
This commit is contained in:
TermiNexus committed 2026-09-28 16:48:52 +08:00
1 parent 5d1620505e
commit 49ff1b995f
3 files changed
+50 -5

No files matched your search

+1 -1
View File
@@ -917,7 +917,7 @@ class AnnAssignHandle(BaseHandle):
elif isinstance(InitValue.type, ir.PointerType) and isinstance(VarType, ir.PointerType):
Allowed: bool
Reason: str
Allowed, Reason = Gen._ClassifyPtrImplicitConvert(InitValue.type, VarType)
Allowed, Reason = Gen._ClassifyPtrImplicitConvert(InitValue.type, VarType, Node.value)
if not Allowed:
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
+1 -1
View File
@@ -1568,7 +1568,7 @@ class AssignHandle(BaseHandle):
# 被指类型无损时放行,非基本/有损/层数不同 fail-fast。
Allowed: bool
Reason: str
Allowed, Reason = Gen._ClassifyPtrImplicitConvert(Value.type, TargetType)
Allowed, Reason = Gen._ClassifyPtrImplicitConvert(Value.type, TargetType, Node)
if not Allowed:
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
+48 -3
View File
@@ -1,6 +1,11 @@
from __future__ import annotations
from typing import Any
import ast
# 必须用 TPC 自己的解析器模块(vast),**不是**标准库 ast:TPC 全部源码
# (.vp 与 .py)都由 vast 解析,产出的是 lib.vast.Nodes.* 节点,与标准库
# ast 的节点类互不兼容(isinstance 恒 False)。此前误用标准库 ast,使本文件
# 全部节点类型判据对 Viper 源码静默失效(_value_node_of 的子表达式下沉、
# _CtorCallStructType 的构造物化豁免、指针 cast 判据都不生效)。
import vast as ast
import llvmlite.ir as ir
@@ -265,7 +270,40 @@ class MemoryOpsMixin:
return True
return False
def _ClassifyPtrImplicitConvert(self, Src: Any, Dst: Any) -> tuple[bool, str]:
def _IsExplicitPtrCastNode(self, Node: Any) -> bool:
"""值节点是否为「显式指针 cast」调用(用户规则:显式转换一律放行)。
形式(TPC 解析产物的共同点 = ast.Call 且 func 是**指针类型表达式**):
- `t.CPtr(x)` / 别名 `CPtr(x)` / `c.CPtr(x)`
- `rawptr[T](x)` / `t.CPtr[T](x)` / 裸名 `CPtr[T](x)`
- `(T*)x` / `(T*)(x)` / `T*(x)`(含 `**` 两层;ExprParser 把三种写法统一
产成 Call(func = `T | t.CPtr`))
- 裸 `rawptr(x)`(≡ t.CPtr)
非 cast 调用(构造函数 / 普通函数,如 `MemBuddy(x)`、`list[X](...)`)不命中
⇒ 仍按隐式转换规则判定。只判 func 节点形状,不做类型解析(不与 Gen 耦合)。
必要性:`includes/_list.vp:60` 的 `elem_ptr: T | t.CPtr = t.CPtr(地址)` 在
`list[X*]` 特化下 T | t.CPtr = `X**`(T 本身是指针),而 `t.CPtr(...)` 的值是
`i8*`——层数不同被判"隐式转换已禁止",与报错自己给的"如需转换请显式 cast
(如 t.CPtr(...))"建议自相矛盾。显式 cast 一律放行后按 bitcast 重解释。
"""
if not isinstance(Node, ast.Call):
return False
Func: Any = Node.func
from lib.core.SymbolUtils import (IsCPtrNode, IsPtrSubscriptNode,
AnnotationContainsName)
if IsCPtrNode(Func) or IsPtrSubscriptNode(Func):
return True
if isinstance(Func, ast.Attribute) and Func.attr == 'CPtr':
return True
if isinstance(Func, ast.Name) and Func.id in ('CPtr', 'rawptr'):
return True
if isinstance(Func, ast.BinOp) and isinstance(Func.op, ast.BitOr):
return AnnotationContainsName(Func, 'CPtr')
return False
def _ClassifyPtrImplicitConvert(self, Src: Any, Dst: Any,
Node: Any = None) -> tuple[bool, str]:
"""隐式转换判据:返回 (Allowed, Reason)。
规则(用户决定,与 TransPyV 同口径):
@@ -280,8 +318,15 @@ class MemoryOpsMixin:
**唯一例外**是「构造物化」——该豁免需 AST 层判据,故在 coerce 调用点
由 _CtorCallStructType 单独放行(本判据只给出「禁」的结论)。
④ 完全相同类型不算转换 ⇒ 放行。
⑤ **显式 cast 一律放行**(用户规则「显式转换都可以」):值侧节点本身是写明的
指针转换调用(t.CPtr(x) / rawptr[T](x) / (T*)x ...,见
_IsExplicitPtrCastNode)⇒ 目标类型即程序员指定的转换目标,调用方按
bitcast 重解释,不做层数/被指类型判定。
Reason 供报文说明「哪一级不允许 + 原因(非基本类型/有损/层数不同)」。
"""
# ⑤ 显式 cast:先于一切判据放行(Node 缺省 None ⇒ 不适用,等价既有行为)
if self._IsExplicitPtrCastNode(Node):
return (True, '显式 cast(按 bitcast 重解释)')
if Src == Dst:
return (True, '同类型(不构成转换)')
s_ptr: bool = isinstance(Src, ir.PointerType)
@@ -507,7 +552,7 @@ class MemoryOpsMixin:
# 被指类型无损时放行,非基本类型/有损/层数不同一律 fail-fast。
Allowed: bool
Reason: str
Allowed, Reason = self._ClassifyPtrImplicitConvert(val.type, target_type)
Allowed, Reason = self._ClassifyPtrImplicitConvert(val.type, target_type, Node)
if not Allowed:
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(