定义端不再'整体移除' return 本帧存储的检查,而是按被调者 @life(ret(...)) 声明 放行/报错(§14.3.2 方案 A)。更新 NewLifetimeRetEscapeTest / NewLifetimeRetOkTest 的注释与 README 描述,去掉'已移除 fail-fast'的旧说法。
58 lines
2.2 KiB
Plaintext
58 lines
2.2 KiB
Plaintext
from stdint import *
|
||
|
||
|
||
# =============================================================================
|
||
# 负向工程(**应当编译失败**):A2 `@life(ret(frame))` —— 去向由**调用点**判定
|
||
#
|
||
# 定义端的判据是**声明感知**的(§14.3.2):`ret(frame)` / `ret(borrows=<该形参>)` 放行,
|
||
# 无声明或声明为非帧才报错 —— 因为定义端分不清"交出本帧"与"借出调用方的存储"
|
||
# (后者是 `return <借用形参>`,一律拦会误报)。于是"声明为 frame"之后,去向的判定
|
||
# 就落在**调用点**:谁把这个结果存进了长命存储,谁就报错。
|
||
#
|
||
# 本工程验:声明为 `frame` 的返回值被写进**长命存储**时必须被拒。
|
||
# 期望报错:LifetimeError(`a longer-lived field/element`)。
|
||
#
|
||
# 隔离性:FrameRet 的逃逸摘要为 0(`l` 不是形参,`return l` 不置任何逃逸位),
|
||
# 所以下面唯一的报错来源就是 `ret(frame)` → LIFE_FRAME。
|
||
#
|
||
# 本文件只保留**一条**会报错的语句:编译在第一个错误处终止,多条会掩盖顺序。
|
||
# 对照写法(`ret(borrows=x)` 的结果同样只在本帧)留作注释,见文末。
|
||
# =============================================================================
|
||
|
||
|
||
novirtual class Holder:
|
||
p: int*
|
||
|
||
|
||
@life(ret(frame))
|
||
def FrameRet() -> int*:
|
||
l: int* = new stack int
|
||
return l
|
||
|
||
|
||
# 唯一用例:ret(frame) 的结果存进**堆对象**字段 → 左值长命、右值本帧 → LifetimeError
|
||
def CaseFrame() -> int:
|
||
h: Holder* = new heap hlife Holder()
|
||
h.p = FrameRet() # ❌ 期望 LifetimeError
|
||
return 0
|
||
|
||
|
||
export def main() -> int:
|
||
CaseFrame()
|
||
return 0
|
||
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 对照用例(把 main 里的 CaseFrame() 换成本函数即可,一次只开一条):
|
||
#
|
||
# @life(noescape(x), ret(borrows=x))
|
||
# def IdentBorrow(x: int*) -> int*:
|
||
# return x
|
||
#
|
||
# def CaseBorrow() -> int:
|
||
# h: Holder* = new heap hlife Holder()
|
||
# l: int* = new stack int
|
||
# h.p = IdentBorrow(l) # ❌ 期望 LifetimeError(结果生命期 = l 的 = 本帧)
|
||
# return 0
|
||
# -----------------------------------------------------------------------------
|