From e74397e932c21eab707d8506c29c6397dfe18758 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 8 Oct 2026 21:40:22 +0800 Subject: [PATCH] =?UTF-8?q?test(lifetime):=20=E6=96=B0=E5=A2=9E=E5=85=B3?= =?UTF-8?q?=E9=94=AE=E5=AD=97=E5=AE=9E=E5=8F=82=E8=B7=AF=E5=BE=84=E7=9A=84?= =?UTF-8?q?=20willFree=20=E8=B4=9F=E5=90=91=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NewLifetimeWillFreeKwargTest:stdlib.free(p = p) 之后再用 p 必须报 LifetimeError,覆盖 P2 的关键字实参标记路径;同步注册到 SequentialRegressionTest / regression_test / run_lifetime_negative_tests 与 README。 --- NewLifetimeWillFreeKwargTest/App/main.vp | 26 ++++++++++++++++++++ NewLifetimeWillFreeKwargTest/project.json | 29 +++++++++++++++++++++++ README.md | 3 ++- SequentialRegressionTest.py | 4 +++- regression_test.py | 4 ++-- run_lifetime_negative_tests.py | 2 +- 6 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 NewLifetimeWillFreeKwargTest/App/main.vp create mode 100644 NewLifetimeWillFreeKwargTest/project.json diff --git a/NewLifetimeWillFreeKwargTest/App/main.vp b/NewLifetimeWillFreeKwargTest/App/main.vp new file mode 100644 index 0000000..b0a1c93 --- /dev/null +++ b/NewLifetimeWillFreeKwargTest/App/main.vp @@ -0,0 +1,26 @@ +from stdint import * +import stdlib + + +# ============================================================================= +# 负向工程(**应当编译失败**):P2 willFree 的**关键字实参**路径 +# +# 模块级调用的实参可以是关键字形式(`stdlib.free(p = x)`)。标注驱动的失效标记 +# 必须同样覆盖这条路径:被标注的形参位按"关键字名 → 形参名"映射到实参后标记。 +# 本工程:关键字传参后继续使用该变量 → 必须报 LifetimeError。 +# +# 另两条路径(手工验证用,语法依赖较多故不建独立工程): +# · 方法调用:在类方法上 `@life(willFree(p))`,`obj.Release(x)` 后使用 x → LifetimeError +# · 取地址:`stdlib.free(p)` 之后 `&p` → LifetimeError +# ============================================================================= + + +def Use(x: rawptr) -> int: + return 0 + + +export def main() -> int: + p: rawptr = stdlib.malloc(8) + stdlib.free(p = p) # 关键字实参:p 在此之后失效 + Use(p) # ← 必须被拒:使用已释放变量(关键字实参路径) + return 0 diff --git a/NewLifetimeWillFreeKwargTest/project.json b/NewLifetimeWillFreeKwargTest/project.json new file mode 100644 index 0000000..5225968 --- /dev/null +++ b/NewLifetimeWillFreeKwargTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "NewLifetimeWillFreeKwargTest", + "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": "NewLifetimeWillFreeKwargTest.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 + } +} diff --git a/README.md b/README.md index 4ca7b3b..8e12b42 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,7 @@ | NewLifetimeWillFreeTest | [Test/NewLifetimeWillFreeTest/](NewLifetimeWillFreeTest/App/main.vp) | **编译失败**:P2 `@life(willFree(p))` 标注驱动 —— `free(p)` 之后再 `free(p)` → `LifetimeError`(二次释放) | | NewLifetimeUseAfterFreeTest | [Test/NewLifetimeUseAfterFreeTest/](NewLifetimeUseAfterFreeTest/App/main.vp) | **编译失败**:P2 —— `free(p)` 之后读/传 `p` → `LifetimeError`(使用已释放变量) | | NewLifetimeWillFreeOkTest | [Test/NewLifetimeWillFreeOkTest/](NewLifetimeWillFreeOkTest/App/main.vp) | **编译成功 + 退出码 0**:P2 合法用法 —— 首次 `free` 本身合法;同名变量**重新赋值**会清除失效态,其后可再用、再 `free`(防误报) | +| NewLifetimeWillFreeKwargTest | [Test/NewLifetimeWillFreeKwargTest/](NewLifetimeWillFreeKwargTest/App/main.vp) | **编译失败**:P2 **关键字实参**路径 —— `stdlib.free(p = p)` 之后再用 `p` → `LifetimeError` | 单独运行(`regression_test.py` 与 `SequentialRegressionTest.py` 都支持): @@ -161,7 +162,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`:断言**编译失败且输出含 `LifetimeError`**;编译成功 = 漏检(FAIL),报错但方向不符 = SKIP。 +> 默认跑 `EscapeTest` / `EscapeMethodTest` / `EscapeXmodTest` / `NewLifetimeFreeTest` / `NewLifetimeAsyncTest` / `NewLifetimeWillFreeTest` / `NewLifetimeUseAfterFreeTest` / `NewLifetimeWillFreeKwargTest`:断言**编译失败且输出含 `LifetimeError`**;编译成功 = 漏检(FAIL),报错但方向不符 = SKIP。 负向项目在 `SequentialRegressionTest.py` 里是**反向判定**(`NEGATIVE_PROJECTS`):编译失败且输出含 `LifetimeError` 才算通过,且**不再进入运行阶段**;编译成功 = 漏检,直接终止。`regression_test.py --escape` 会**剔除**这些项目(该脚本要求"编译成功 + 能跑"),负向断言请用 `SequentialRegressionTest.py --escape` 或上面的 `run_lifetime_negative_tests.py`。 diff --git a/SequentialRegressionTest.py b/SequentialRegressionTest.py index 74fb916..65e65c9 100644 --- a/SequentialRegressionTest.py +++ b/SequentialRegressionTest.py @@ -41,7 +41,7 @@ OVERVIEW = os.path.join(TEST_DIR, "README.md") # NewLifetimeFreeTest / NewLifetimeAsyncTest / NewLifetimeWillFreeTest / # NewLifetimeUseAfterFreeTest(负向); # 仓库根下:EscapeTest/EscapeOkTest/EscapeMethodTest/EscapeXmodTest -ESCAPE_PROJECTS = ["EscapeTest", "EscapeOkTest", "EscapeMethodTest", "EscapeXmodTest", "NewTest", "NewLifetimeTest", "NewLifetimeWillFreeOkTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest"] +ESCAPE_PROJECTS = ["EscapeTest", "EscapeOkTest", "EscapeMethodTest", "EscapeXmodTest", "NewTest", "NewLifetimeTest", "NewLifetimeWillFreeOkTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest"] # 负向项目:**期望编译失败**且输出含指定关键字(反向判定,且不运行可执行文件)。 # 这些项目里的用例故意交出本帧栈地址(或跨模块摘要路径),必须被 M1–M2.3 的 @@ -59,6 +59,8 @@ NEGATIVE_PROJECTS = { # P2 willFree:`stdlib.free` 带 @life(willFree(p)),二次释放/释放后使用 → LifetimeError "NewLifetimeWillFreeTest": "LifetimeError", "NewLifetimeUseAfterFreeTest": "LifetimeError", + # P2:关键字实参路径(stdlib.free(p = p) 之后再用 p) + "NewLifetimeWillFreeKwargTest": "LifetimeError", } # IR 断言:项目名 → 生成 IR 中**必须出现**的子串。 diff --git a/regression_test.py b/regression_test.py index 8adc6e6..c36a4a2 100644 --- a/regression_test.py +++ b/regression_test.py @@ -90,12 +90,12 @@ def find_test_projects(): # NewLifetimeFreeTest / NewLifetimeAsyncTest / NewLifetimeWillFreeTest / # NewLifetimeUseAfterFreeTest(负向); # 仓库根下:EscapeTest/EscapeOkTest/EscapeMethodTest/EscapeXmodTest -ESCAPE_PROJECTS = ["EscapeTest", "EscapeOkTest", "EscapeMethodTest", "EscapeXmodTest", "NewTest", "NewLifetimeTest", "NewLifetimeWillFreeOkTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest"] +ESCAPE_PROJECTS = ["EscapeTest", "EscapeOkTest", "EscapeMethodTest", "EscapeXmodTest", "NewTest", "NewLifetimeTest", "NewLifetimeWillFreeOkTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest"] # 负向项目(**期望编译失败**,见 SequentialRegressionTest.NEGATIVE_PROJECTS): # 本脚本按"编译必须成功 + 能跑"判定,纳入会误报,故 --escape 时剔除; # 负向断言请用 SequentialRegressionTest(反向判定)或 run_lifetime_negative_tests.py。 -NEGATIVE_PROJECT_NAMES = {"EscapeTest", "EscapeMethodTest", "EscapeXmodTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest"} +NEGATIVE_PROJECT_NAMES = {"EscapeTest", "EscapeMethodTest", "EscapeXmodTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest"} def find_project_file(proj_dir): diff --git a/run_lifetime_negative_tests.py b/run_lifetime_negative_tests.py index 4611dcc..5e0d44c 100644 --- a/run_lifetime_negative_tests.py +++ b/run_lifetime_negative_tests.py @@ -34,7 +34,7 @@ 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"] +NEGATIVE_PROJECTS = ["EscapeTest", "EscapeMethodTest", "EscapeXmodTest", "NewLifetimeFreeTest", "NewLifetimeAsyncTest", "NewLifetimeWillFreeTest", "NewLifetimeUseAfterFreeTest", "NewLifetimeWillFreeKwargTest"] EXPECT_KEYWORD = "LifetimeError" COMPILE_TIMEOUT = 300