Skip to content

Raise MSRV to 1.85#15174

Open
alex wants to merge 5 commits into
mainfrom
claude/msrv-bump-1-85-13nu3v
Open

Raise MSRV to 1.85#15174
alex wants to merge 5 commits into
mainfrom
claude/msrv-bump-1-85-13nu3v

Conversation

@alex

@alex alex commented Jul 5, 2026

Copy link
Copy Markdown
Member

Raises the minimum supported Rust version from 1.83.0 to 1.85.0.

  • Cargo.toml: bump the workspace rust-version to 1.85.0.
  • .github/workflows/ci.yml: pin the three MSRV matrix builds (plain, AWS-LC, BoringSSL) to 1.85.0 and drop the now-satisfied "1.85: 2024 edition" line from the future-MSRV comment.
  • docs/installation.rst: document the new minimum version and update the distro notes — RHEL/CentOS now requires 9.7+ (9.6 ships Rust 1.84.1, 9.7 ships 1.88.0) and Alpine now requires 3.22+ (3.21 ships Rust 1.83, 3.22 ships 1.87). The Debian note is unchanged since trixie ships rustc 1.85.0, which meets the new MSRV.
  • CHANGELOG.rst: note the MSRV change in the unreleased 50.0.0 section.
  • noxfile.py: repair Rust coverage for proc-macro expanded functions (see below).

Coverage repair

The first CI run failed the combined-coverage gate with 124 missed statements, all of them proc-macro attribute lines (#[derive(...)], #[pyo3::pyclass], #[pyo3::pymethods]). Root cause, established by decoding the __llvm_covfun records and raw profiles of instrumented builds under 1.83.0/1.84.0/1.85.0/1.94.1:

Starting with Rust 1.84, a function consisting entirely of proc-macro expanded code gets a coverage mapping containing only a residual one-column region on the attribute line (the "visible macro" token span), wired to a non-entry counter that never fires. Under 1.83 the same functions got mappings wiring those regions to the entry counter, so the attribute line showed the function's execution count. Example, <TBSRequest as SimpleAsn1Writable>::data_length (runtime counters prove 8 executions in both builds):

toolchain covfun mapping line 7 result
1.83.0 3 regions, first wired to counter #0 (entry, =8) covered (8)
1.85.0 1 region wired to counter #1 (never fires, =0) "Unexecuted instantiation", 0

The 1.83.0 MSRV jobs were the last toolchain in the matrix producing entry-wired mappings, which is why the gate broke exactly when they moved to 1.85 (every ≥1.84 toolchain, including stable, emits the zero records). Disabling MIR inlining and codegen-units=1 were tested and ruled out as causes.

The fix repairs the lcov at collection time using the raw profile (llvm-profdata show --all-functions) as ground truth:

  • If the mapping computes 0 for a function whose raw profile count is >0, the mapping is defective — mark the function's start line executed with the true count.
  • If every function on a zero line is absent from the raw profile, the compiler emitted only "unused function" placeholder records for generated impls that were never codegen'd (e.g. an unused IntoPyObject impl); the line's executability is an artifact — drop it. Handwritten dead code is unaffected since codegen'd-but-uncalled functions register profile records (count 0) and keep their zero lines.

Unlike excluding attribute lines outright, this keeps genuine coverage semantics: attribute lines of executed generated impls count as executable and covered with real counts, and regressions there (generated code that stops running) remain visible.

🤖 Generated with Claude Code

https://claude.ai/code/session_01X4EZ7B8sU7cLxPP4qnHfAm

claude added 5 commits July 5, 2026 20:39
Updates the workspace rust-version, CI MSRV builds, installation docs
(RHEL 9.7 is now required for a sufficiently new packaged Rust), and
the changelog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X4EZ7B8sU7cLxPP4qnHfAm
Alpine 3.21 ships Rust 1.83; 3.22 is the first release with a
sufficiently new Rust.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X4EZ7B8sU7cLxPP4qnHfAm
rustc 1.84 changed how proc-macro expansions are attributed in
coverage maps: the attribute line (e.g. #[derive(...)],
#[pyo3::pyclass]) still gets a zero-count line record, but execution
of the generated code is no longer attributed to it. The combined
coverage gate previously stayed at 100% only because the Rust 1.83
MSRV jobs attributed hits to those lines; with the MSRV at 1.85 no
toolchain in the matrix can, so treat attribute lines as
non-executable when merging.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X4EZ7B8sU7cLxPP4qnHfAm
Starting with Rust 1.84, a function consisting entirely of proc-macro
expanded code (the impls generated by #[derive(...)], #[pyo3::pyclass],
#[pyo3::pymethods], ...) gets a coverage mapping containing only a
residual region on the attribute line, wired to a non-entry counter
that never fires. Two consequences corrupt line coverage:

- llvm-cov reports such a function as unexecuted even when the raw
  profile proves it ran, so the attribute line reads as a miss.
- Generated impls that are never codegen'd at all (e.g. an unused
  IntoPyObject impl) leave "unused function" placeholder records
  whose lone residual region marks the attribute line executable,
  and nothing can ever cover it.

Under Rust 1.83 these lines were covered because the mappings wired
the attribute-line regions to the entry counter; the 1.83 MSRV jobs
were the last toolchain in the matrix doing so, which is why the
combined coverage gate broke when they moved to 1.85.

Repair the lcov at collection time using the raw profile as ground
truth: trust the profile's function count when the mapping computes
zero for a function that ran, and drop attribute lines whose only
functions were never codegen'd. Handwritten dead code is unaffected:
it registers profile records (with count 0) and keeps its zero-count
lines.

This replaces the reverted approach of excluding all attribute lines
in the merge step, which discarded genuine coverage information.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X4EZ7B8sU7cLxPP4qnHfAm
@alex

alex commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

Blocked on rust-lang/rust#158833

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants