You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix UI test runner flag handling and recursive provenance resolution (#126)
This PR rewrites the UI test runner to actually respect `//@
compile-flags:` directives (previously silently ignored), and fixes a
panic in provenance type resolution that crashed on nested struct
fields.
- Rewrite `run_ui_tests.sh`: flag-based CLI, build-once-then-invoke
(eliminates cargo freshness overhead per test), arch-aware skip logic,
optional `--save-debug-output` for failure triage
- Add `extract_test_flags()` to both runners: parses `//@
compile-flags:`, `//@ edition:`, and `//@ rustc-env:` directives from
test files
- Fix `get_prov_ty` to recursively walk nested struct/tuple fields
instead of requiring an exact byte-offset match at the top level
- Replace panicking unwraps in `get_prov_ty` with graceful fallbacks
UI test results: 19 failing -> 2 failing, 2871 passing -> 2888 passing.
## What was wrong
Two independent problems, both surfaced by investigating the 19 UI test
failures on the `master` branch.
### 1. Test runner ignoring compile-flags directives
The UI test runners (`run_ui_tests.sh`, `remake_ui_tests.sh`) never
extracted `//@ compile-flags:`, `//@ edition:`, or `//@ rustc-env:`
directives from test files. Every test ran with bare `-Zno-codegen`
regardless of what the test required. 17 of the 19 failures were
compilation errors caused by missing flags (e.g., `--edition 2021`,
`--test`, `-Zunstable-options`, `-Ccodegen-units=1`).
These tests were "failing" for the wrong reason: they weren't testing
stable-mir-json at all, just failing to compile.
### 2. Provenance type resolution panicking on nested structs
`get_prov_ty` used `field_for_offset` (exact byte-offset match) to find
which field a provenance pointer belongs to, then returned that field's
type directly. This works when the pointer sits at the start of a
top-level field, but breaks on nested structs.
Concrete example: `TestDescAndFn` has fields at offsets 0 (`TestDesc`)
and 128 (`TestFn`). A pointer at byte offset 56 sits inside `TestDesc`
(which itself has a `&str` field at relative offset 56). The old code
looked for a field starting at exactly offset 56 in the top-level
struct, found nothing, and panicked.
The fix adds `field_containing_offset` (range-based: finds the field
with the largest start offset <= target) and makes the struct and tuple
branches recurse into the containing field with a relative offset,
walking down through the field hierarchy until reaching the actual
pointer type.
## Test runner changes
The rewritten `run_ui_tests.sh`:
- **Flag-based CLI**: `--verbose`, `--save-generated-output`,
`--save-debug-output` replace positional args and env vars
- **Build once**: runs `cargo build` upfront, then invokes the binary
directly with proper `DYLD_LIBRARY_PATH`/`LD_LIBRARY_PATH` setup (cuts
~2-3s of cargo freshness checking per test)
- **Arch filtering**: skips tests gated on foreign architectures via
path matching and `//@ only-<arch>` directive parsing
- **Flag extraction**: `extract_test_flags()` parses `//@
compile-flags:`, `//@ edition:`, and `//@ rustc-env:` directives
- **Debug output**: `--save-debug-output` captures stderr on failure to
`tests/ui/debug/<test_name>.stderr` and prints a 4-line snippet inline
`remake_ui_tests.sh` gets the same `extract_test_flags()` function so
regeneration respects directives too.
## Remaining failures
| Test | Exit | Root cause |
|------|------|------------|
| `tests/ui/issues/issue-26641.rs` | 101 | rustc internal panic
("escaping bound vars"); not a stable-mir-json bug |
| `tests/ui/sanitizer/cfi/drop-in-place.rs` | 101 | Missing
`-Ccodegen-units=1` in the test file's `//@ compile-flags:` directive;
every sibling CFI test has it, this one doesn't. Upstream test bug, not
ours. |
## Test plan
- [x] `cargo build` clean
- [x] Full UI test suite on Linux: 2888 passing, 2 failing (both known,
neither ours)
- [x] `make integration-test`
Copy file name to clipboardExpand all lines: CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,10 +27,15 @@ retroactive best-effort summary; earlier changes were not formally tracked.
27
27
- Restructured `printer.rs` into a declarative 3-phase pipeline: `collect_items` -> `collect_and_analyze_items` -> `assemble_smir`, with `CollectedCrate`/`DerivedInfo` interface types enforcing the boundary between collection and assembly
28
28
- Added `AllocMap` with debug-mode coherence checking (`verify_coherence`): asserts that every `AllocId` in stored bodies exists in the alloc map and that no body is walked twice; zero cost in release builds
29
29
- Removed dead static-item fixup from `assemble_smir` (violated the phase boundary, misclassified statics as functions; never triggered in integration tests)
30
+
- Rewrote `run_ui_tests.sh`: flag-based CLI (`--verbose`, `--save-generated-output`, `--save-debug-output`), build-once-then-invoke (eliminates per-test cargo overhead), arch-aware skip logic for cross-platform test lists
31
+
- UI test runners now extract and pass `//@ compile-flags:`, `//@ edition:`, and `//@ rustc-env:` directives from test files (previously silently ignored)
30
32
- Switched from compiler build to `rustup`-managed toolchain ([#33])
31
33
- Removed forked rust dependency ([#19])
32
34
33
35
### Fixed
36
+
- Fixed `get_prov_ty` to recursively walk nested struct/tuple fields when resolving provenance types; previously used exact byte-offset matching which panicked on pointers inside nested structs (e.g., `&str` at offset 56 inside `TestDesc` inside `TestDescAndFn`)
37
+
- Removed incorrect `builtin_deref` assertions from VTable and Static allocation collection that rejected valid non-pointer types (raw `*const ()` vtable pointers, non-pointer statics)
38
+
- Replaced panicking `unwrap`/`assert` calls in `get_prov_ty` with graceful fallbacks for layout failures, non-rigid types, and unexpected offsets
34
39
- Fixed early `return` in `BodyAnalyzer::visit_terminator` that skipped `super_terminator()`, causing alloc/type/span collection to miss everything inside `Call` terminators with non-`ZeroSized` function operands (const-evaluated function pointers); bug present since [`aff2dd0`](https://github.com/runtimeverification/stable-mir-json/commit/aff2dd0)
35
40
- Avoided duplicate `inst.body()` calls that were reallocating `AllocId`s ([#120])
36
41
- Prevented svg/png generation when `dot` is unavailable ([#117])
0 commit comments