Skip to content

In-compiler invariants (check-invariants.patch, rustc-verify13) and invariant-sweep; findings 56-57 - #41

Merged
zmaril merged 1 commit into
mainfrom
mirth/invariants
Oct 10, 2026
Merged

zmaril merged 1 commit into
mainfrom
mirth/invariants

Conversation

@zmaril

@zmaril zmaril commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Step 2 of leaning on mirth more: invariants checked inside rustc on every compilation.

The patch

docs/hunt/check-invariants.patch is applied last on the verify-reuse stack and is built into ~/mirth-work/rustc-verify13.

# (properties.md) Check What upstream had
18 A query result contains no inference variables. Checked on each provider's typed result, dispatched on the value's type (autoref specialization over TypeVisitable, EarlyBinder, references, Option/Result, canonical responses, typeck node types, borrowck hidden types, clauses, impl headers, layouts). 99 of the ~200 query kinds a small program runs are checked. nothing
14 A compile that emitted no error has no error types: typeck results (tainted, node types), type_of, fn_sig. nothing
24 Local symbols are distinct from upstream crates' exported symbols. within a session only (fatal SymbolAlreadyDefined)
15 Each metadata table entry is written once. nothing
9 LLVM's ABI size of a lowered type equals the layout size. rustc's expensive layout sanity checks also run in release. debug builds only
1 Argument lists fit the generics (debug_assert_args_compatible and the alias variant); violations are reported instead of raising a bug. debug builds only
7 Encoded spans: lo <= hi, and lo is inside its file. debug_assert! only

rustc/regen-patches.sh regenerates the new patch alongside the others; its embedded Python is replaced by sed. Checked by regenerating the stack:

  • "0 files differ";
  • verify-reuse.patch is identical apart from the length of the abbreviated index hashes.

The sweep

mirth-lab invariant-sweep compiles each standalone UI test with the variable set (codegen for tests that build). An ICE that happens only with the variable set counts as a finding.

Results:

  • UI tests: 18,624 tests (7,408 compile, 11,198 fail as expected, 17 ICE without the checks too, 1 timeout). 315 have findings, all property 15. There is nothing for 18, 14, 24, 9, 1 or 7.
  • gate-mutate: 12,000 mutants with the variable set gave no new ICE signatures.

Findings (docs/hunt/metadata-written-twice.md, facts only):

  • 56: the crate root's module children are encoded twice in every library with a public item (encode_def_ids calls encode_info_for_mod(CRATE_DEF_ID), then reaches the root again in its loop).
  • 57: coroutine layouts are encoded twice (encode_mir records mir_coroutine_witnesses inside if encode_opt and again at the end of the loop).
  • Cost: low, in bytes only. A compiler with both removed saves 2,164 bytes of std's 8.0 MB .rmeta, 1,384 of core's, and 226 of a 16.5 KB async library's. With the fix, the invariant reports nothing.
  • Versions: both are present since at least 1.80.0. Nothing was found upstream.

Findings 56–57 may need renumbering if other branches merge first.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QXiEXbESemwqMLYKaWLDbT

…S: query results without inference variables, no error types in an error-free compile, symbols distinct from upstream exports, metadata records written once, LLVM vs layout sizes and rustc's layout sanity checks in release, argument lists against generics, valid spans), built as rustc-verify13; mirth-lab invariant-sweep; findings 56-57 (metadata written twice); regen-patches.sh regenerates the new patch, without Python

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QXiEXbESemwqMLYKaWLDbT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant