-
Notifications
You must be signed in to change notification settings - Fork 72
Description
Proposal
It has long been tradition to make compilers bootstrap themselves. This is a great stress test for the compiler and can allow finding deficiencies in a language that only show up when using them in practice. The original Rust compiler was written in OCaml, but later a new compiler was written in Rust itself which replaced the old bootstrap compiler in 2011. From that point on you needed an existing Rust compiler to build rustc and not just any Rust compiler, but a pretty new one. At first there were frequent bootstrap bumps, but in 2016 this was changed to bootstrapping from the previous release and this has been the status quo ever since.
While the current bootstrapping model has been working reasonably well, there are still some issues with it. The most well known is probably trusting trust attacks where the bootstrap compiler has a self-propagating backdoor that is invisible at the source level. A mitigation for this is John Hodge's mrustc which is an independent bootstrap compiler for Rust written in C++. It can currently only build up to rustc 1.74 however, so you still need 16 steps to bootstrap the latest stable release as of writing this blog. Furthermore bootstrapping for a new target currently requires cross-compiling from an already supported target, which can be non-trivial to setup. And finally distros need to build every single rustc version between the last one they ship and the rustc version they want to update to, which is both time consuming and may expose them to issues that have already been solved on newer rustc versions.
Traditionally during bootstrapping the first thing that happened was building the new standard library using the bootstrap compiler and then building the new rustc against the just compiled standard library. This required that the standard library could be compiled by both rustc versions despite using a lot of unstable features and implementation details of rustc. As such there were a lot of #[cfg(bootstrap)]
sprinkled everywhere at any given time. A couple of months ago this was reworked to instead build rustc against the standard library shipped with the bootstrap compiler and have any #[cfg(bootstrap)]
exclusively inside the rustc source and not in the standard library. Given that rustc uses a lot less unstable features than the standard library and barely (if at all) use internal implementation details, this makes it much easier to support compiling rustc with multiple bootstrap compiler versions. As such my proposal:
Stop bumping the bootstrap version on every rustc release and instead bump it when there is a good reason to like dependencies needing a newer rustc or to use new features. If the burden of this turns out to be too high, we revert back to bumping the bootstrap version on every rustc release.
I believe this to be a good tradeoff between reducing the bootstrap chain size on the one hand and minimizing the effect on the maintainability of rustc on the other hand.
To explore the feasibility of this proposal, I have been created a branch which bootstraps from earlier and earlier rustc versions in each commit. I've been updating this branch about every six weeks for a couple of months now. Each time the update took a couple of hours at most, with most time spent waiting for rustc to compile. Up to rustc 1.85 (which introduced the 2024 edition) the necessary changes are pretty modest. Mostly re-enabling stabilized feature gates, dealing with changed rustc internal lints and a bunch of usages of newer methods that could easily be polyfilled in the rustc_backports crate I added. When asking feedback on this proposal, it was suggested to not land those changes to reduce the bootstrap compiler version, but instead to just stop updating the minimum required bootstrap compiler.
We would still want to be able to bootstrap rustc from the previous release even if we allow bootstrapping from older releases. And for local development we probably want to use latest beta to benefit from performance improvements. As such we did need to add CI to check multiple bootstrap rustc versions. Should we support every release between the previous release and the minimum required release or should we only support those two versions? The latter would reduce the required amount of CI runners and probably make it easier to maintain, but would be a bit annoying for distros that have already updated to a version in between two supported bootstrap versions.
Mentors or Reviewers
If you have a reviewer or mentor in mind for this work, mention them here. You can put your own name here if you are planning to mentor the work.
Process
The main points of the Major Change Process are as follows:
- File an issue describing the proposal.
- A compiler team member who is knowledgeable in the area can second by writing
@rustbot second
or kickoff a team FCP with@rfcbot fcp $RESOLUTION
.- Refer to Proposals, Approvals and Stabilization docs for when a second is sufficient, or when a full team FCP is required.
- Once an MCP is seconded, the Final Comment Period begins.
- Final Comment Period lasts for 10 days after all outstanding concerns are solved.
- Outstanding concerns will block the Final Comment Period from finishing. Once all concerns are resolved, the 10 day countdown is restarted.
- If no concerns are raised after 10 days since the resolution of the last outstanding concern, the MCP is considered approved.
You can read more about Major Change Proposals on forge.