新增 3 个工程(均登记进 regression_test.py / SequentialRegressionTest.py / run_lifetime_negative_tests.py 的 escape/负向清单): - NewLifetimeRetOkTest(正向):ret(heap)/ret(static)/ret(borrows=none) 的结果 可存进堆对象字段;ret(frame)/ret(borrows=x) 的结果只在本帧内使用; 同模块契约表与跨模块 .vpi(escr=) 两条取用路径都覆盖 → 编译通过 + 退出码 0。 - NewLifetimeRetEscapeTest(负向):同模块 @life(ret(frame)) 的返回值写进堆对象 字段 → LifetimeError(隔离性:FrameRet 摘要为 0,唯一报错源是 ret 契约)。 - NewLifetimeRetXmodTest(负向):跨模块 @life(noescape(x), ret(borrows=x)) 的结果 写进堆对象字段 → LifetimeError(契约经对方 .vpi 的 escr= 传来;noescape 清掉了 实参逃逸路径,判据收敛到 ret 契约)。 README.md 的 escape 测试表与负向清单同步。
25 lines
1.1 KiB
Plaintext
25 lines
1.1 KiB
Plaintext
from stdint import *
|
|
|
|
|
|
# =============================================================================
|
|
# A2 跨模块负例的**被调方**:契约(逃逸掩码 + 返回值生命期)只能经本模块 .vpi
|
|
# 行尾 `# esc=… escn=… escr=…` 传到调用点 —— 本文件与 main.vp 不同模块,
|
|
# 调用点的本地契约表按文件重置、必然查不到,命中
|
|
# CallGenBase.lookup_ret_kind_via_vpi → VpiReader 的 escr= 缓存这条回退路径。
|
|
# =============================================================================
|
|
|
|
|
|
# ret(borrows=x):返回值借用形参 x —— 调用点把结果当 x 的生命期。
|
|
# 配 `noescape(x)`:本函数只**借出** x、不把它存进长命存储 → 形参 x 不算逃逸,
|
|
# 于是调用点上"实参逃逸"那条路径不会先报错,判据收敛到 ret 契约本身。
|
|
@life(noescape(x), ret(borrows=x))
|
|
def IdentBorrow(x: int*) -> int*:
|
|
return x
|
|
|
|
|
|
# 对照:`ret(frame)`(把 main 的用例换成 CaseFrame 时用)。返回值指向本帧存储。
|
|
@life(ret(frame))
|
|
def FrameRet() -> int*:
|
|
l: int* = new stack int
|
|
return l
|