# Modern C++ smoke probes (Phase 2.7)

Five small C++17 probes that exercise the language features most likely
to interact poorly with the W65816 backend's i32 / i16 / pointer-cast
codegen.  Each probe builds through the buildGno.sh recipe (clang++ -O2 +
crt0Gno + libcGno + libcxxabi + ExpressLoad OMF) and runs under real
GNO/ME inside MAME.  Success is verified by polling bank-2 memory for
the per-probe sentinel `0x0099` plus a small set of computed-value
anchors that pin down which surface area was exercised.

## Why these five

Each was picked from `docs/GAP_CLOSURE_PLAN.md` Phase 2.7 to maximise
the chance of catching an i32-codegen regression early:

| Probe              | Exercises                                         |
|--------------------|---------------------------------------------------|
| `rangeFor`         | range-based for over `etl::array`                 |
| `genericLambda`    | C++14 generic lambda + i32 capture-by-reference   |
| `variadicTpl`      | variadic template + initializer-list pack expand  |
| `structBind`       | C++17 structured bindings (aggregate + tuple proto) |
| `foldExpr`         | C++17 left/right/binary fold expressions          |

The `genericLambda` probe is the highest-value one: the i32-by-reference
capture path is where most recent codegen work has lived, so it's most
likely to regress.

## Build

```
bash tests/cxxSmoke/build.sh rangeFor       # build one probe
bash tests/cxxSmoke/runCxxSmoke.sh          # build + run all five under MAME
bash tests/cxxSmoke/runCxxSmoke.sh foldExpr # build + run one
```

Each MAME run takes roughly 3 minutes (GNO boot + login + shell + program
launch + marker poll), so the full sweep is ~15 minutes.

## What passes today (2026-06-01)

All five probes pass.  No XFAILs.

| Probe              | Build | Run under GNO | Notes                          |
|--------------------|-------|---------------|--------------------------------|
| `rangeFor`         | OK    | OK            | sum=15 via etl::array iterator |
| `genericLambda`    | OK    | OK            | i32 acc = 0x12445 (capture by &) |
| `variadicTpl`      | OK    | OK            | sum 0x10+0x20+0x30+0x18 = 0x78 |
| `structBind`       | OK    | OK            | aggregate + tuple-protocol both |
| `foldExpr`         | OK    | OK            | unary L/R + binary `,` folds   |

## Marker contract

Each probe writes a small set of u16 values to bank 2 (the same region
runInGno.sh polls).  The last write is always the success sentinel
`0x0099`; earlier writes are the computed values that anchor the check
to the right C++ surface.  See the per-probe `.cpp` headers for the
exact marker layout.

`runInGno.sh --check 0x025002=0099` (etc.) is the verification gate.
For headless-CI use, `runCxxSmoke.sh` wraps the build + check loop and
prints a `pass=N fail=M` summary at the end.

## Files

- `rangeFor.cpp`        — check 1
- `genericLambda.cpp`   — check 2
- `variadicTpl.cpp`     — check 3
- `structBind.cpp`      — check 4
- `foldExpr.cpp`        — check 5
- `build.sh`            — per-probe compile + link + OMF (mirrors demos/buildGno.sh)
- `runCxxSmoke.sh`      — full sweep harness
