test: prove --no-checks removes the bounds check
The bounds-no-checks cases emitted and built but never ran, so they only proved that --no-checks produces compilable C -- not that it removes the check, which is the entire point of the flag. A run case could not simply be appended. BOUNDS.FE returns the out-of-bounds element directly, so with checks removed its exit code is whatever sits past the array on the stack and there is no correct status to assert. Asserting on the generated C instead does not work either: emit_c.c defines fe_trap_bounds unconditionally and --no-checks only suppresses the call sites. Add NOCHK.FE, which reads one element past a [2]i32 and returns x - x. That is 0 for whatever garbage the unchecked read produced, so the same source has a defined outcome both ways: compiled with checks it must trap, compiled with --no-checks it must run to completion and exit 0. Register both halves and drop the two BOUNDS-N cases they supersede. Verified in DOSBox-X: 155 passed, including m3-nochk-trap failing as expected and m3-nochk-off-run succeeding. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BScg8CF1sAAM2zVHAu5zvW
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
unit m3_no_checks;
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
let a: [2]i32 = [1, 2];
|
||||||
|
let x: i32 = a[2];
|
||||||
|
return x - x;
|
||||||
|
}
|
||||||
@@ -146,10 +146,18 @@ CASES: list[Case] = [
|
|||||||
# These two must trap at runtime: the bounds check is the feature under test.
|
# These two must trap at runtime: the bounds check is the feature under test.
|
||||||
*_triple(3, "bounds", M3, run_suffix="trap", run_ok=False),
|
*_triple(3, "bounds", M3, run_suffix="trap", run_ok=False),
|
||||||
*_triple(3, "slcbound", M3, run_suffix="trap", run_ok=False),
|
*_triple(3, "slcbound", M3, run_suffix="trap", run_ok=False),
|
||||||
_case(3, "bounds-no-checks-emit",
|
# --no-checks is proved by a differential on one source. NOCHK.FE reads one
|
||||||
_emit(_fe(M3, "bounds"), f"{M3}\\BOUNDS-N.C", flags=("--no-checks",))),
|
# element past a [2]i32 and returns x - x, which is 0 whatever garbage the
|
||||||
_case(3, "bounds-no-checks-build",
|
# unchecked read produced: compiled with checks it must trap, compiled with
|
||||||
_wcl(f"{M3}\\BOUNDS-N.EXE", f"{M3}\\BOUNDS-N.C")),
|
# --no-checks it must run to completion. BOUNDS.FE cannot serve as the
|
||||||
|
# unchecked half because it returns the out-of-bounds value directly, so its
|
||||||
|
# exit code would be whatever happens to sit past the array on the stack.
|
||||||
|
*_triple(3, "nochk", M3, run_suffix="trap", run_ok=False),
|
||||||
|
_case(3, "nochk-off-emit",
|
||||||
|
_emit(_fe(M3, "nochk"), f"{M3}\\NOCHK-N.C", flags=("--no-checks",))),
|
||||||
|
_case(3, "nochk-off-build",
|
||||||
|
_wcl(f"{M3}\\NOCHK-N.EXE", f"{M3}\\NOCHK-N.C")),
|
||||||
|
_case(3, "nochk-off-run", f"{M3}\\NOCHK-N.EXE"),
|
||||||
*_rejects(3, M3, ("badfld", "badmat", "badarr", "badcycle", "badstr", "badchar",
|
*_rejects(3, M3, ("badfld", "badmat", "badarr", "badcycle", "badstr", "badchar",
|
||||||
"badfield", "badindex"), suffix="reject"),
|
"badfield", "badindex"), suffix="reject"),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user