Skip to content

Reduce our MSRV as much as possible #554

@joshlf

Description

@joshlf

Our MSRV is currently 1.61, which is higher than the MSRVs of many crates. Here are MSRVs of the subset of the top 100 most-recently-downloaded crates that contain unsafe code:

Top 100 crates
Crate MSRV Unsafe
syn 1.56 search
bitflags 1.56 search
hashbrown 1.63 search
regex-syntax 1.65 search
proc-macro2 1.56 search
quote 1.56 search
base64 1.48 search
libc 1.13 search
unicode-ident 1.31 search
serde 1.31 search
cfg-if unknown search
rustix 1.63 search
rand_core unknown search
serde_derive 1.56 search
aho-corasick 1.60 search
indexmap 1.63 search
itoa 1.36 search
regex-automata 1.65 search
rand unknown search
getrandom 1.36 search

We should work to reduce our MSRV as much as possible so that more crates can replace unsafe code with zerocopy.

Mentoring instructions

  • Repeat the following steps as many times as possible:
    • Determine what is preventing our MSRV from being one version earlier
    • Determine whether there's a workaround for the same behavior that is compatible with an earlier MSRV

Conditional compilation problems

One problem with lowering our MSRV is that some features we want to use were introduced in more recent Rust versions. Naively, one might expect that this makes lowering our MSRV dead in the water. However, it's possible to work around this, albeit with a lot of machinery.

The core insight is that it's okay for zerocopy to provide certain features only when compiled with certain Rust versions. For example, imagine that a certain feature is only available on 1.60 and above. Downstream crates can be in one of two buckets:

  • Their MSRV is 1.60 or above. They will never compile with Rust <= 1.60, and so they will never compile zerocopy without support for this feature.
  • Their MSRV is below 1.60. They (hopefully) test their crate with their MSRV, and so are unable to publish code which makes use of this feature (unless they use their own conditional compilation logic, which just kicks the can to their downstream crates).

In both cases, it's consistent with semver rules for us to enable certain features only on more recent Rust versions.

This brings us to our first requirement: We need to support detecting the Rust toolchain version at compile time.


If we take this approach, it introduces a new problem: now zerocopy's behavior can differ by toolchain. If we continue to only test on MSRV, stable, and nightly toolchains, then there will be some toolchain versions which introduce different behavior relative to their parent, but on which we don't test. For example, if our MSRV is 1.56, and our pinned stable toolchain is 1.70, but we have a feature that is enabled on versions after 1.65, then it's possible that that feature is buggy on 1.65, 1.66, 1.67, 1.68, and 1.69. This implies that we also need to test on 1.65 (the first Rust version for which the feature is enabled). We need to do this for any Rust version for which we enable new behavior.

This brings us to our second requirement: In CI, we need to test on every Rust version which introduces new behavior.


This introduces another problem, though. How do we actually implement this? Naively, we could write our build.rs script to perform toolchain detection based on hard-coded toolchain versions, and then separately update our CI configuration to test on these toolchain versions. However, this risks bit rot: we could easily change the hard-coded versions in either place, but forget to update them in the other place. There would be no automatic way to detect this.

Instead, we should have one source of truth for the list of toolchain versions. This brings us to our third requirement: Both build.rs and our CI scripts should parse a single source of truth for the list of toolchain versions.


All three of these requirements are implemented in #843.

Metadata

Metadata

Assignees

No one assigned

    Labels

    experience-hardThis issue is hard, and requires a lot of experiencehelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions