Skip to content

Commit 800825c

Browse files
committed
msrv
1 parent b04866f commit 800825c

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

text/0000-min-rust-version.md

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
- Feature Name: min_rust_version
2+
- Start Date: 2018-06-28
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Add `rust` field to the package section of `Cargo.toml` which will be used to
10+
specify crate's Minimum Supported Rust Version (MSRV):
11+
```toml
12+
[package]
13+
name = "foo"
14+
version = "0.1.0"
15+
rust = "1.30"
16+
```
17+
18+
# Motivation
19+
[motivation]: #motivation
20+
21+
Currently crates have no way to formally specify MSRV. As a result users can't
22+
check if crate can be built on their toolchain without building it. It also
23+
leads to the debate on how to handle crate version change on bumping MSRV,
24+
conservative approach is to consider such changes as breaking ones, which can
25+
hinder adoption of new features across ecosystem or result in version number
26+
inflation, which makes it harder to keep downstream crates up-to-date. More
27+
relaxed approach on another hand can result in broken crates for user of older
28+
compiler versions.
29+
30+
# Guide-level explanation
31+
[guide-level-explanation]: #guide-level-explanation
32+
33+
`cargo init` will automatically create `Cargo.toml` with `rust` field equal to
34+
`rust="stable"` or `rust="nightly"` depending on the currently used toolcahin.
35+
On `cargo publish` cargo will take currently used Rust compiler version and
36+
will insert it before uploading the crate. In other words localy your `Cargo.toml`
37+
willl still have `rust="stable"`, but version sent to crates.io will have
38+
`rust="1.30"` if you've used Rust 1.30. This version will be used to determine if
39+
crate can be used with the crate user's toolchain and to select appropriate
40+
dependency versions. In case if you have `rust="stable"`, but execute
41+
`cargo publish` with Nigthly toolcahin you will get an error.
42+
43+
If you are sure that your crate supports older Rust versions (e.g. by using CI
44+
testing) you can change `rust` field accordingly. On `cargo publish` it will be
45+
checked that crate indeed can be built with the specified version. (though this
46+
check can be disabled with `--no-verify` option)
47+
48+
For example, lets imagine that your crate depends on crate `foo` with 10 published
49+
versions from `0.1.0` to `0.1.10`, in versions from `0.1.0` to `0.1.5` `rust`
50+
field in the `Cargo.toml` sent to crates.io equals to "1.30" and for others to
51+
"1.40". Now if you'll build your project with Rust 1.33 `cargo` will select
52+
`foo v0.1.5`, and `foo v0.1.10` if you'll build your project with Rust 1.30 or
53+
later. But if you'll try to build your project with Rust 1.29 cargo will issue an
54+
error. Although this check can be disabled with `--no-rust-check` option.
55+
56+
`rust` field should respect the following minimal requirements:
57+
- value should be equal to "stable", "nigthly" or to a version in semver format
58+
("1.50" is a valid value and implies "1.50.0")
59+
- version should not be bigger than the current stable toolchain
60+
- version should not be smaller than 1.27 (version in which `package.rust` field
61+
became a warning instead of an error)
62+
63+
`rust` will be a required field. For crates uploaded before introduction of this
64+
feature 2015 edition crates will imply `rust="1.0"` and 2018 ediiton will imply
65+
`rust = "1.30"`.
66+
67+
It will be an error to use `rust="1.27"` and `edition="2018"`, but `rust="1.40"` and `edition="2015"` is a valid combination.
68+
69+
# Reference-level explanation
70+
[reference-level-explanation]: #reference-level-explanation
71+
72+
The describe functionality can be introduced in several stages:
73+
74+
75+
## First stage: dumb field
76+
77+
At first the `rust` field can be simply a declarative optional field without any
78+
functionality behind it. The reason for it is to reduce implementation cost of
79+
the first stage to the minimum and ideally ship it as part of Rust 2018.
80+
It will also allow crate authors who care about MSRV to start mark their crates
81+
early.
82+
83+
## Second stage: versions resolution
84+
85+
`rust` field becomes required and cargo will add it as a constraint to dependency
86+
versions resolution. If user uses e.g. Rust 1.40 and uses crate `foo = "0.2"`, but
87+
all selected versions of `foo` specify MSRV e.g. equal 1.41 or bigger (or even
88+
nightly) `cargo` will issue an error.
89+
90+
`rust` field value will be checked as well, on crate build `cargo` will check if
91+
all upstream dependencies can be built with the specified MSRV. (i.e. it will
92+
check if there is exists solution for given crates and Rust versions constraints)
93+
94+
Yanked crates will be ignored in this process.
95+
96+
Implementing this functionality hopefully will allow to close the debate regarding
97+
MSRV handling in crate versions and will allow crate authors to feel less
98+
restrictive about bumping their crate's MSRV. (though it can be a usefull
99+
convention for post-1.0 crates to bump minor version on MSRV change to allow
100+
publishing backports which fix serious issues using patch version)
101+
102+
## Third stage: better crate checks
103+
104+
Here we introduce two-level check for crates. First level will check if all used
105+
items were stabilised before or on given MSRV using `#[stable(since=version)]`
106+
attribute, issuing compile errors otherwise.
107+
108+
Second level will try to build crate with the specified MSRV on `cargo publish`,
109+
i.e. words it will be required to install MSRV toolchain. (this check can be
110+
disabled using `--no-verify` option)
111+
112+
While these two checks will not replace proper CI testing, they will help to
113+
reduce number of improper MSRV configuration to the minimum.
114+
115+
Note that `rust` field must be equal to MSRV with default features for all
116+
supported targets.
117+
118+
## Extension: nightly versions
119+
120+
For some bleeding-edge crates which experience frequent breaks on Nightly updates
121+
(e.g. `rocket`) it can be useful to specify exact Nigthly version(s) on which
122+
crate can be built. One way to achieve this is by using the following syntax:
123+
- single version: rust = "nightly: 2018-01-01"
124+
- enumeration: "nightly: 2018-01-01, 2018-01-15"
125+
- (inclusive) range: "nightly: 2018-01-01..2018-01-15"
126+
- enumeration+range: "nightly: 2018-01-01, 2018-01-08..2018-01-15"
127+
128+
Such restrictions can be quite severe, but hopefully this functionality will be
129+
used only by handful of crates.
130+
131+
## Extension: cfg based MSRV
132+
133+
Some crates can have different MSRVs depending on target architecture or enabled
134+
features. In such cases it can be usefull to extend `rust` field, e.g. in the
135+
following way:
136+
```toml
137+
rust = "1.30"
138+
rust-cases = [
139+
{ cfg = "x86_64-pc-windows-gnu", version = "1.35" },
140+
{ cfg = 'cfg(feature = "foo")', version = "1.33" },
141+
]
142+
```
143+
144+
Version resolution will filter all cases with `cfg` equal to true and will take
145+
max `version` value from them as a MSRV. If all `cfg`s are false, value in the
146+
`rust` field will be used.
147+
148+
# Drawbacks
149+
[drawbacks]: #drawbacks
150+
151+
- Declaration of MSRV and describe checks does not guarantee that, only
152+
appropriate CI testing.
153+
- More complex dependency versions resolution algorithm.
154+
- MSRV selected by `cargo publish` can be overly conservative.
155+
- MSRV checks will make compiler more complex.
156+
157+
# Rationale and Alternatives
158+
[alternatives]: #alternatives
159+
160+
- Automatically calculate MSRV.
161+
- Do nothing and rely on [LTS releases](https://github.com/rust-lang/rfcs/pull/2483)
162+
for bumping crate MSRVs.
163+
164+
# Prior art
165+
[prior-art]: #prior-art
166+
167+
Previous proposals:
168+
- [RFC 1707](https://github.com/rust-lang/rfcs/pull/1707)
169+
- [RFC 1709](https://github.com/rust-lang/rfcs/pull/1709)
170+
- [RFC 1953](https://github.com/rust-lang/rfcs/pull/1953)
171+
- [RFC 2182](https://github.com/rust-lang/rfcs/pull/2128) (arguably this one got off-track)
172+
173+
# Unresolved questions
174+
[unresolved]: #unresolved-questions
175+
176+
- Name bike-shedding: `rust` vs `rustc` vs `min-rust-version`
177+
- Additional checks?
178+
- Better description of versions resolution algorithm.

0 commit comments

Comments
 (0)