test(lifetime): 补齐 A2 @life(ret(...)) 的正/负向回归工程
新增 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 测试表与负向清单同步。
This commit is contained in:
1 parent
9307b34af6
commit
66ebd75dec
12 files changed
+344
-12
No files matched your search
@@ -0,0 +1,56 @@
|
||||
from stdint import *
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 负向工程(**应当编译失败**):A2 `@life(ret(frame))` —— 去向由**调用点**判定
|
||||
#
|
||||
# A2 移除了定义端对 `return <本帧地址>` 的 fail-fast:定义端无法区分"交出本帧"
|
||||
# 与"借出调用方的存储"(后者是 `return <借用形参>`,一律拦会误报)。取而代之:
|
||||
# 被调者用 `@life(ret(...))` 声明返回值生命期,**调用点**按声明判去向。
|
||||
#
|
||||
# 本工程验:声明为 `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
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "NewLifetimeRetEscapeTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32"],
|
||||
"output": "NewLifetimeRetEscapeTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
from stdint import *
|
||||
import stdio
|
||||
import retdep
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 正向工程:A2 `@life(ret(...))` 契约**不得误报**(编译必须成功、运行退出码 0)
|
||||
#
|
||||
# 对照负向工程:
|
||||
# · NewLifetimeRetEscapeTest —— 同模块 `ret(frame)` 的结果存进长命存储 → 必须报;
|
||||
# · NewLifetimeRetXmodTest —— 跨模块 `ret(borrows=x)`(经 .vpi 的 escr=)→ 必须报。
|
||||
#
|
||||
# 本工程覆盖:
|
||||
# (1) 非帧契约(heap / static / borrows=none)→ 结果可存进**堆对象字段**(长命左值);
|
||||
# (2) ret(frame) → 结果只在本帧内使用 → 合法(不是"无害",而是调用点按声明**放行**);
|
||||
# (3) ret(borrows=x) → 结果的生命期 = 实参 x 的生命期(本帧实参 → 帧内使用合法);
|
||||
# (4) 同模块(本文件契约表)与跨模块(retdep.vp,经 .vpi 的 escr=)两条取用路径都走一遍。
|
||||
#
|
||||
# 注意:本文件**不得**把 `ret(frame)` / `ret(borrows=x)` 的结果写进堆对象字段
|
||||
# (`h.p = …`)——那是负向工程负责证明会被拒的写法。
|
||||
# =============================================================================
|
||||
|
||||
|
||||
novirtual class Holder:
|
||||
p: int*
|
||||
c: char*
|
||||
|
||||
|
||||
# ---- 同模块契约(走本文件 EscDirTable,不经 .vpi)----
|
||||
|
||||
@life(ret(heap))
|
||||
def LocalHeap() -> int*:
|
||||
return new heap hlife int
|
||||
|
||||
|
||||
@life(ret(frame))
|
||||
def LocalFrame() -> int*:
|
||||
l: int* = new stack int
|
||||
return l
|
||||
|
||||
|
||||
export def main() -> int:
|
||||
h: Holder* = new heap hlife Holder()
|
||||
|
||||
# (1) 非帧契约 → 存进堆对象字段(左值长命、右值非帧)→ 放行
|
||||
h.p = retdep.MkHeap() # 跨模块 ret(heap)
|
||||
h.c = retdep.MkStatic() # 跨模块 ret(static)
|
||||
h.p = retdep.Fresh() # 跨模块 ret(borrows=none)
|
||||
h.p = LocalHeap() # 同模块 ret(heap)
|
||||
|
||||
# (2) ret(frame):结果只在本帧内使用 → 放行
|
||||
pf: int* = retdep.FrameRet() # 跨模块 ret(frame)
|
||||
pl: int* = LocalFrame() # 同模块 ret(frame)
|
||||
|
||||
# (3) ret(borrows=x):结果生命期 = 实参生命期;实参在本帧 → 结果只在本帧用 → 放行
|
||||
base: int* = new stack int
|
||||
pb: int* = retdep.IdentBorrow(base)
|
||||
|
||||
if pf is None: return 1
|
||||
if pl is None: return 2
|
||||
if pb is None: return 3
|
||||
|
||||
stdio.printf("RetOkTest OK: @life(ret(...)) contracts accepted\n")
|
||||
return 0
|
||||
@@ -0,0 +1,45 @@
|
||||
from stdint import *
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# A2(§14)`@life(ret(...))` 的被调方:五种返回值生命期契约各一条。
|
||||
#
|
||||
# 调用点(main.vp)**跨模块**取用 → 本文件的契约只能经 .vpi 行尾
|
||||
# `# esc=… escn=… escr=…` 传递(本地契约表按文件重置,调用点必然查不到)。
|
||||
# 设计与编码见 Debugger/ownership-and-new.md §14.3 / §14.3.1(GenApi.RET_KIND_*)。
|
||||
# =============================================================================
|
||||
|
||||
|
||||
# ret(heap):自由生命期 → 结果可自由存进长命存储
|
||||
@life(ret(heap))
|
||||
def MkHeap() -> int*:
|
||||
return new heap hlife int
|
||||
|
||||
|
||||
# ret(static):指向静态存储(字符串常量)
|
||||
@life(ret(static))
|
||||
def MkStatic() -> char*:
|
||||
return "static-lit"
|
||||
|
||||
|
||||
# ret(borrows=none):返回值**不借用任何形参** → 非本帧
|
||||
@life(ret(borrows=none))
|
||||
def Fresh() -> int*:
|
||||
return new heap hlife int
|
||||
|
||||
|
||||
# ret(frame):返回值可能指向**本帧**存储 → 去向由调用点负责
|
||||
# (A2 已移除定义端对 `return <本帧地址>` 的 fail-fast:定义端无法区分
|
||||
# "交出本帧"与"借出调用方的存储",一律拦会误报 `return <借用形参>`。)
|
||||
@life(ret(frame))
|
||||
def FrameRet() -> int*:
|
||||
l: int* = new stack int
|
||||
return l
|
||||
|
||||
|
||||
# ret(borrows=x):返回值借用形参 x —— 调用点把结果当 x 的生命期。
|
||||
# 配 `noescape(x)`:本函数只**借出** x、不把它存进长命存储,故形参 x 不算逃逸;
|
||||
# 否则调用点会先在"实参逃逸"那条路径上拦下来,掩盖 ret 契约本身。
|
||||
@life(noescape(x), ret(borrows=x))
|
||||
def IdentBorrow(x: int*) -> int*:
|
||||
return x
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "NewLifetimeRetOkTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32"],
|
||||
"output": "NewLifetimeRetOkTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
from stdint import *
|
||||
import retdep2
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 负向工程(**应当编译失败**):A2 **跨模块** `@life(ret(...))` —— 契约经 .vpi 的 `escr=`
|
||||
#
|
||||
# 被调者定义在 retdep2.vp,契约(含 ret_kind)只能经对方 .vpi 行尾的 `escr=` 传来;
|
||||
# 本文件里它的本地契约表必然为空 → 命中跨模块回退路径。
|
||||
#
|
||||
# 本工程验:跨模块声明为 `borrows=x` 的返回值(生命期 = 实参 = 本帧)被写进长命存储
|
||||
# 时必须被拒。期望报错:LifetimeError(`a longer-lived field/element`)。
|
||||
#
|
||||
# 隔离性:IdentBorrow 带 `@life(noescape(x))`,"实参逃逸"那条路径被清掉,
|
||||
# 故唯一的报错来源是 .vpi 的 `escr=` → ret(borrows=x) → 结果 LIFE_FRAME。
|
||||
# =============================================================================
|
||||
|
||||
|
||||
novirtual class Holder:
|
||||
p: int*
|
||||
|
||||
|
||||
# 唯一用例:跨模块 ret(borrows=x) 的结果存进**堆对象**字段 → 左值长命、右值本帧
|
||||
def CaseBorrow() -> int:
|
||||
h: Holder* = new heap hlife Holder()
|
||||
l: int* = new stack int
|
||||
h.p = retdep2.IdentBorrow(l) # ❌ 期望 LifetimeError
|
||||
return 0
|
||||
|
||||
|
||||
export def main() -> int:
|
||||
CaseBorrow()
|
||||
return 0
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 对照用例(把 main 里的 CaseBorrow() 换成本函数即可,一次只开一条):
|
||||
#
|
||||
# def CaseFrame() -> int:
|
||||
# h: Holder* = new heap hlife Holder()
|
||||
# h.p = retdep2.FrameRet() # ❌ 期望 LifetimeError
|
||||
# return 0
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -0,0 +1,24 @@
|
||||
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
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "NewLifetimeRetXmodTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32"],
|
||||
"output": "NewLifetimeRetXmodTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,9 @@
|
||||
## 一·附、生命期 / 逃逸(escape)相关测试
|
||||
|
||||
验证 M1–M3 的生命期检查(栈地址逃逸、借用传播、函数逃逸摘要)、`new` 描述符分配,
|
||||
以及 `new heap slife` 的 RAII 自动释放(M3)。因历史原因前 4 个位于**仓库根**(不在 `Test/` 下):
|
||||
`new heap slife` 的 RAII 自动释放(M3),以及 `@life(...)` 标注面(P2 `willFree`、
|
||||
§14 `escape/stores`、`noescape/borrows`、A2 `ret(...)`:返回值生命期契约,声明优先于推断)。
|
||||
因历史原因前 4 个位于**仓库根**(不在 `Test/` 下):
|
||||
|
||||
| 项目 | 位置 | 期望结果 |
|
||||
|---|---|---|
|
||||
@@ -142,6 +144,9 @@
|
||||
| NewLifetimeWillFreeAddrTest | [Test/NewLifetimeWillFreeAddrTest/](NewLifetimeWillFreeAddrTest/App/main.vp) | **编译失败**:P2 **取地址**路径 —— `stdlib.free(p)` 之后取 `&p` → `LifetimeError`(与读取同一口径) |
|
||||
| NewLifetimeFieldEscapeTest | [Test/NewLifetimeFieldEscapeTest/](NewLifetimeFieldEscapeTest/App/main.vp) | **编译失败**:P3 —— `h.p = &local`(堆对象字段收下本帧栈地址)→ `LifetimeError` |
|
||||
| NewLifetimeAnnFieldEscapeTest | [Test/NewLifetimeAnnFieldEscapeTest/](NewLifetimeAnnFieldEscapeTest/App/main.vp) | **编译失败**:P3 **注解形态** —— `h.p: int* = &local`(AnnAssign 属性目标,同一条规则;也守住"非 Name 目标不得被静默丢弃")→ `LifetimeError` |
|
||||
| NewLifetimeRetOkTest | [Test/NewLifetimeRetOkTest/](NewLifetimeRetOkTest/App/main.vp) | **编译成功 + 退出码 0**:A2(§14)`@life(ret(...))` 契约**不得误报** —— `ret(heap)`/`ret(static)`/`ret(borrows=none)` 的结果存进堆对象字段;`ret(frame)`/`ret(borrows=x)` 的结果只在本帧内使用;同模块(契约表)与跨模块(`retdep.vp`,经 `.vpi` 的 `escr=`)两条取用路径都走一遍 |
|
||||
| NewLifetimeRetEscapeTest | [Test/NewLifetimeRetEscapeTest/](NewLifetimeRetEscapeTest/App/main.vp) | **编译失败**:A2 —— 同模块 `@life(ret(frame))` 的返回值被写进**堆对象字段**(长命左值)→ `LifetimeError`(A2 已移除定义端 `return <本帧地址>` 的 fail-fast,去向改由调用点按契约判定) |
|
||||
| NewLifetimeRetXmodTest | [Test/NewLifetimeRetXmodTest/](NewLifetimeRetXmodTest/App/main.vp) | **编译失败**:A2 **跨模块** —— 被调者(`retdep2.vp`)声明 `@life(noescape(x), ret(borrows=x))`,结果(生命期 = 实参 = 本帧)写进堆对象字段 → `LifetimeError`(契约经对方 `.vpi` 的 `escr=` 传来) |
|
||||
|
||||
单独运行(`regression_test.py` 与 `SequentialRegressionTest.py` 都支持):
|
||||
|
||||
@@ -166,7 +171,7 @@ python Test/run_lifetime_negative_tests.py --exe .\TransPyV\output\TransPyV.exe
|
||||
python Test/run_lifetime_negative_tests.py --exe .\TransPyV\output\TransPyV.exe --only EscapeMethodTest
|
||||
```
|
||||
|
||||
> 默认跑 `EscapeTest` / `EscapeMethodTest` / `EscapeXmodTest` / `NewLifetimeFreeTest` / `NewLifetimeAsyncTest` / `NewLifetimeWillFreeTest` / `NewLifetimeUseAfterFreeTest` / `NewLifetimeWillFreeKwargTest` / `NewLifetimeWillFreeMethodTest` / `NewLifetimeWillFreeAddrTest` / `NewLifetimeFieldEscapeTest` / `NewLifetimeAnnFieldEscapeTest`:断言**编译失败且输出含 `LifetimeError`**;编译成功 = 漏检(FAIL),报错但方向不符 = SKIP。
|
||||
> 默认跑 `EscapeTest` / `EscapeMethodTest` / `EscapeXmodTest` / `NewLifetimeFreeTest` / `NewLifetimeAsyncTest` / `NewLifetimeWillFreeTest` / `NewLifetimeUseAfterFreeTest` / `NewLifetimeWillFreeKwargTest` / `NewLifetimeWillFreeMethodTest` / `NewLifetimeWillFreeAddrTest` / `NewLifetimeFieldEscapeTest` / `NewLifetimeAnnFieldEscapeTest` / `NewLifetimeRetEscapeTest` / `NewLifetimeRetXmodTest`:断言**编译失败且输出含 `LifetimeError`**;编译成功 = 漏检(FAIL),报错但方向不符 = SKIP。
|
||||
|
||||
负向项目在 `SequentialRegressionTest.py` 里是**反向判定**(`NEGATIVE_PROJECTS`):编译失败且输出含 `LifetimeError` 才算通过,且**不再进入运行阶段**;编译成功 = 漏检,直接终止。`regression_test.py --escape` 会**剔除**这些项目(该脚本要求"编译成功 + 能跑"),负向断言请用 `SequentialRegressionTest.py --escape` 或上面的 `run_lifetime_negative_tests.py`。
|
||||
|
||||
|
||||
@@ -36,12 +36,13 @@ OVERVIEW = os.path.join(TEST_DIR, "README.md")
|
||||
# ============================================================
|
||||
# 单独运行支持:--escape / --only
|
||||
# ============================================================
|
||||
# escape 相关项目(生命期/逃逸检查 + M2.4 new 描述符 + M3 owned slife RAII + §3.6 析构 + P2 willFree):
|
||||
# Test/ 下:NewTest、NewLifetimeTest、NewLifetimeWillFreeOkTest(正向)、
|
||||
# escape 相关项目(生命期/逃逸检查 + M2.4 new 描述符 + M3 owned slife RAII + §3.6 析构 +
|
||||
# P2 willFree + A2 @life(ret(...))):
|
||||
# Test/ 下:NewTest、NewLifetimeTest、NewLifetimeWillFreeOkTest、NewLifetimeRetOkTest(正向)、
|
||||
# NewLifetimeFreeTest / NewLifetimeAsyncTest / NewLifetimeWillFreeTest /
|
||||
# NewLifetimeUseAfterFreeTest(负向);
|
||||
# NewLifetimeUseAfterFreeTest / NewLifetimeRetEscapeTest / NewLifetimeRetXmodTest(负向);
|
||||
# 仓库根下:EscapeTest/EscapeOkTest/EscapeMethodTest/EscapeXmodTest
|
||||
ESCAPE_PROJECTS = ["EscapeTest", "EscapeOkTest", "EscapeMethodTest", "EscapeXmodTest", "NewTest", "NewLifetimeTest", "NewLifetimeWillFreeOkTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest", "NewLifetimeWillFreeMethodTest", "NewLifetimeWillFreeAddrTest", "NewLifetimeFieldEscapeTest", "NewLifetimeAnnFieldEscapeTest"]
|
||||
ESCAPE_PROJECTS = ["EscapeTest", "EscapeOkTest", "EscapeMethodTest", "EscapeXmodTest", "NewTest", "NewLifetimeTest", "NewLifetimeWillFreeOkTest", "NewLifetimeRetOkTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest", "NewLifetimeWillFreeMethodTest", "NewLifetimeWillFreeAddrTest", "NewLifetimeFieldEscapeTest", "NewLifetimeAnnFieldEscapeTest", "NewLifetimeRetEscapeTest", "NewLifetimeRetXmodTest"]
|
||||
|
||||
# 负向项目:**期望编译失败**且输出含指定关键字(反向判定,且不运行可执行文件)。
|
||||
# 这些项目里的用例故意交出本帧栈地址(或跨模块摘要路径),必须被 M1–M2.3 的
|
||||
@@ -69,6 +70,10 @@ NEGATIVE_PROJECTS = {
|
||||
"NewLifetimeFieldEscapeTest": "LifetimeError",
|
||||
# P3:obj.f: T = &local(注解形态的属性目标,同一条规则;防"非 Name 目标被静默丢弃")
|
||||
"NewLifetimeAnnFieldEscapeTest": "LifetimeError",
|
||||
# A2(§14):@life(ret(frame)) 的结果存进堆对象字段(同模块契约表 EscDirTable)
|
||||
"NewLifetimeRetEscapeTest": "LifetimeError",
|
||||
# A2(§14):@life(ret(borrows=x)) 的结果存进堆对象字段(跨模块,经 .vpi 的 escr=)
|
||||
"NewLifetimeRetXmodTest": "LifetimeError",
|
||||
}
|
||||
|
||||
# IR 断言:项目名 → 生成 IR 中**必须出现**的子串。
|
||||
|
||||
+6
-5
@@ -85,17 +85,18 @@ def find_test_projects():
|
||||
# ============================================================
|
||||
# 单独运行支持:--escape / --only
|
||||
# ============================================================
|
||||
# escape 相关项目(生命期/逃逸检查 + M2.4 new 描述符 + M3 owned slife RAII + §3.6 析构 + P2 willFree):
|
||||
# Test/ 下:NewTest、NewLifetimeTest、NewLifetimeWillFreeOkTest(正向)、
|
||||
# escape 相关项目(生命期/逃逸检查 + M2.4 new 描述符 + M3 owned slife RAII + §3.6 析构 +
|
||||
# P2 willFree + A2 @life(ret(...))):
|
||||
# Test/ 下:NewTest、NewLifetimeTest、NewLifetimeWillFreeOkTest、NewLifetimeRetOkTest(正向)、
|
||||
# NewLifetimeFreeTest / NewLifetimeAsyncTest / NewLifetimeWillFreeTest /
|
||||
# NewLifetimeUseAfterFreeTest(负向);
|
||||
# NewLifetimeUseAfterFreeTest / NewLifetimeRetEscapeTest / NewLifetimeRetXmodTest(负向);
|
||||
# 仓库根下:EscapeTest/EscapeOkTest/EscapeMethodTest/EscapeXmodTest
|
||||
ESCAPE_PROJECTS = ["EscapeTest", "EscapeOkTest", "EscapeMethodTest", "EscapeXmodTest", "NewTest", "NewLifetimeTest", "NewLifetimeWillFreeOkTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest", "NewLifetimeWillFreeMethodTest", "NewLifetimeWillFreeAddrTest", "NewLifetimeFieldEscapeTest", "NewLifetimeAnnFieldEscapeTest"]
|
||||
ESCAPE_PROJECTS = ["EscapeTest", "EscapeOkTest", "EscapeMethodTest", "EscapeXmodTest", "NewTest", "NewLifetimeTest", "NewLifetimeWillFreeOkTest", "NewLifetimeRetOkTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest", "NewLifetimeWillFreeMethodTest", "NewLifetimeWillFreeAddrTest", "NewLifetimeFieldEscapeTest", "NewLifetimeAnnFieldEscapeTest", "NewLifetimeRetEscapeTest", "NewLifetimeRetXmodTest"]
|
||||
|
||||
# 负向项目(**期望编译失败**,见 SequentialRegressionTest.NEGATIVE_PROJECTS):
|
||||
# 本脚本按"编译必须成功 + 能跑"判定,纳入会误报,故 --escape 时剔除;
|
||||
# 负向断言请用 SequentialRegressionTest(反向判定)或 run_lifetime_negative_tests.py。
|
||||
NEGATIVE_PROJECT_NAMES = {"EscapeTest", "EscapeMethodTest", "EscapeXmodTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest", "NewLifetimeWillFreeMethodTest", "NewLifetimeWillFreeAddrTest", "NewLifetimeFieldEscapeTest", "NewLifetimeAnnFieldEscapeTest"}
|
||||
NEGATIVE_PROJECT_NAMES = {"EscapeTest", "EscapeMethodTest", "EscapeXmodTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest", "NewLifetimeWillFreeMethodTest", "NewLifetimeWillFreeAddrTest", "NewLifetimeFieldEscapeTest", "NewLifetimeAnnFieldEscapeTest", "NewLifetimeRetEscapeTest", "NewLifetimeRetXmodTest"}
|
||||
|
||||
|
||||
def find_project_file(proj_dir):
|
||||
|
||||
@@ -34,7 +34,9 @@ PROJECT_ROOT = os.path.dirname(TEST_DIR)
|
||||
# NewLifetimeAsyncTest:M3 §4.2(协程体里的 `new heap slife` → 释放点无法确定,fail-fast)。
|
||||
# NewLifetimeWillFreeTest / NewLifetimeUseAfterFreeTest:P2(@life(willFree(p)) 标注驱动——
|
||||
# 二次释放 / 释放后使用,对应正向工程 NewLifetimeWillFreeOkTest)。
|
||||
NEGATIVE_PROJECTS = ["EscapeTest", "EscapeMethodTest", "EscapeXmodTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest", "NewLifetimeWillFreeMethodTest", "NewLifetimeWillFreeAddrTest", "NewLifetimeFieldEscapeTest", "NewLifetimeAnnFieldEscapeTest"]
|
||||
# NewLifetimeRetEscapeTest / NewLifetimeRetXmodTest:A2(§14)`@life(ret(...))`——
|
||||
# 声明为 frame / borrows=x 的返回值被写进长命存储(同模块契约表 / 跨模块 .vpi 的 escr=)。
|
||||
NEGATIVE_PROJECTS = ["EscapeTest", "EscapeMethodTest", "EscapeXmodTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest", "NewLifetimeWillFreeMethodTest", "NewLifetimeWillFreeAddrTest", "NewLifetimeFieldEscapeTest", "NewLifetimeAnnFieldEscapeTest", "NewLifetimeRetEscapeTest", "NewLifetimeRetXmodTest"]
|
||||
EXPECT_KEYWORD = "LifetimeError"
|
||||
COMPILE_TIMEOUT = 300
|
||||
|
||||
|
||||
Reference in new issue
Block a user