|
| 1 | +- Feature Name: N/A |
| 2 | +- Start Date: 2016-04-22 |
| 3 | +- RFC PR: (leave this empty) |
| 4 | +- Rust Issue: (leave this empty) |
| 5 | + |
| 6 | +# Summary |
| 7 | +[summary]: #summary |
| 8 | + |
| 9 | +Defines a best practices procedure for making bug fixes or soundness |
| 10 | +corrections in the compiler that can cause existing code to stop |
| 11 | +compiling. |
| 12 | + |
| 13 | +# Motivation |
| 14 | +[motivation]: #motivation |
| 15 | + |
| 16 | +From time to time, we encounter the need to make a bug fix, soundness |
| 17 | +correction, or other change in the compiler which will cause existing |
| 18 | +code to stop compiling. When this happens, it is important that we |
| 19 | +handle the change in a way that gives users of Rust a smooth |
| 20 | +transition. What we want to avoid is that existing programs suddenly |
| 21 | +stop compiling with opaque error messages: we would prefer to have a |
| 22 | +gradual period of warnings, with clear guidance as to what the problem |
| 23 | +is, how to fix it, and why the change was made. This RFC describes the |
| 24 | +procedure that we have been developing for handling breaking changes |
| 25 | +that aims to achieve that kind of smooth transition. |
| 26 | + |
| 27 | +One of the key points of this policy is that (a) warnings should be |
| 28 | +issued initially rather than hard errors if at all possible and (b) |
| 29 | +every change that causes existing code to stop compiling will have an |
| 30 | +associated tracking issue. This issue provides a point to collect |
| 31 | +feedback on the results of that change. Sometimes changes have |
| 32 | +unexpectedly large consequences or there may be a way to avoid the |
| 33 | +change that was not considered. In those cases, we may decide to |
| 34 | +change course and roll back the change, or find another solution (if |
| 35 | +warnings are being used, this is particularly easy to do). |
| 36 | + |
| 37 | +### What qualifies as a bug fix? |
| 38 | + |
| 39 | +Note that this RFC does not try to define when a breaking change is |
| 40 | +permitted. That is already covered under [RFC 1122][]. This document |
| 41 | +assumes that the change being made is in accordance with those |
| 42 | +policies. Here is a summary of the conditions from RFC 1122: |
| 43 | + |
| 44 | +- **Soundness changes:** Fixes to holes uncovered in the type system. |
| 45 | +- **Compiler bugs:** Places where the compiler is not implementing the |
| 46 | + specified semantics found in an RFC or lang-team decision. |
| 47 | +- **Underspecified language semantics:** Clarifications to grey areas |
| 48 | + where the compiler behaves inconsistently and no formal behavior had |
| 49 | + been previously decided. |
| 50 | + |
| 51 | +Please see [the RFC][RFC 1122] for full details! |
| 52 | + |
| 53 | +# Detailed design |
| 54 | +[design]: #detailed-design |
| 55 | + |
| 56 | +The procedure for making a breaking change is as follows (each of |
| 57 | +these steps is described in more detail below): |
| 58 | + |
| 59 | +0. Do a **crater run** to assess the impact of the change. |
| 60 | +1. Make a **special tracking issue** dedicated to the change. |
| 61 | +2. Do not report an error right away. Instead, **issue |
| 62 | + forwards-compatibility lint warnings**. |
| 63 | + - Sometimes this is not straightforward. See the text below for |
| 64 | + suggestions on different techniques we have employed in the past. |
| 65 | + - For cases where warnings are infeasible: |
| 66 | + - Report errors, but make every effort to give a targeted error |
| 67 | + message that directs users to the tracking issue |
| 68 | + - Submit PRs to all known affected crates that fix the issue |
| 69 | + - or, at minimum, alert the owners of those crates to the problem |
| 70 | + and direct them to the tracking issue |
| 71 | +3. Once the change has been in the wild for at least one cycle, we can |
| 72 | + **stabilize the change**, converting those warnings into errors. |
| 73 | + |
| 74 | +Finally, for changes to libsyntax that will affect plugins, the |
| 75 | +general policy is to batch these changes. That is discussed below in |
| 76 | +more detail. |
| 77 | + |
| 78 | +### Tracking issue |
| 79 | + |
| 80 | +Every breaking change should be accompanied by a **dedicated tracking |
| 81 | +issue** for that change. The main text of this issue should describe |
| 82 | +the change being made, with a focus on what users must do to fix their |
| 83 | +code. The issue should be approachable and practical; it may make |
| 84 | +sense to direct users to an RFC or some other issue for the full |
| 85 | +details. The issue also serves as a place where users can comment with |
| 86 | +questions or other concerns. |
| 87 | + |
| 88 | +A template for these breaking-change tracking issues can be found |
| 89 | +below. An example of how such an issue should look can be |
| 90 | +[found here][breaking-change-issue]. |
| 91 | + |
| 92 | +The issue should be tagged with (at least) `B-unstable` and |
| 93 | +`T-compiler`. |
| 94 | + |
| 95 | +### Tracking issue template |
| 96 | + |
| 97 | +What follows is a template for tracking issues. |
| 98 | + |
| 99 | +--------------------------------------------------------------------------- |
| 100 | + |
| 101 | +This is the **summary issue** for the `YOUR_LINT_NAME_HERE` |
| 102 | +future-compatibility warning and other related errors. The goal of |
| 103 | +this page is describe why this change was made and how you can fix |
| 104 | +code that is affected by it. It also provides a place to ask questions |
| 105 | +or register a complaint if you feel the change should not be made. For |
| 106 | +more information on the policy around future-compatibility warnings, |
| 107 | +see our [breaking change policy guidelines][guidelines]. |
| 108 | + |
| 109 | +[guidelines]: LINK_TO_THIS_RFC |
| 110 | + |
| 111 | +#### What is the warning for? |
| 112 | + |
| 113 | +*Describe the conditions that trigger the warning and how they can be |
| 114 | +fixed. Also explain why the change was made.** |
| 115 | + |
| 116 | +#### When will this warning become a hard error? |
| 117 | + |
| 118 | +At the beginning of each 6-week release cycle, the Rust compiler team |
| 119 | +will review the set of outstanding future compatibility warnings and |
| 120 | +nominate some of them for **Final Comment Period**. Toward the end of |
| 121 | +the cycle, we will review any comments and make a final determination |
| 122 | +whether to convert the warning into a hard error or remove it |
| 123 | +entirely. |
| 124 | + |
| 125 | +--------------------------------------------------------------------------- |
| 126 | + |
| 127 | +### Issuing future compatibility warnings |
| 128 | + |
| 129 | +The best way to handle a breaking change is to begin by issuing |
| 130 | +future-compatibility warnings. These are a special category of lint |
| 131 | +warning. Adding a new future-compatibility warning can be done as |
| 132 | +follows. |
| 133 | + |
| 134 | +```rust |
| 135 | +// 1. Define the lint in `src/librustc/lint/builtin.rs`: |
| 136 | +declare_lint! { |
| 137 | + pub YOUR_ERROR_HERE, |
| 138 | + Warn, |
| 139 | + "illegal use of foo bar baz" |
| 140 | +} |
| 141 | + |
| 142 | +// 2. Add to the list of HardwiredLints in the same file: |
| 143 | +impl LintPass for HardwiredLints { |
| 144 | + fn get_lints(&self) -> LintArray { |
| 145 | + lint_array!( |
| 146 | + .., |
| 147 | + YOUR_ERROR_HERE |
| 148 | + ) |
| 149 | + } |
| 150 | +} |
| 151 | + |
| 152 | +// 3. Register the lint in `src/librustc_lint/lib.rs`: |
| 153 | +store.register_future_incompatible(sess, vec![ |
| 154 | + ..., |
| 155 | + FutureIncompatibleInfo { |
| 156 | + id: LintId::of(YOUR_ERROR_HERE), |
| 157 | + reference: "issue #1234", // your tracking issue here! |
| 158 | + }, |
| 159 | +]); |
| 160 | + |
| 161 | +// 4. Report the lint: |
| 162 | +tcx.sess.add_lint( |
| 163 | + lint::builtin::YOUR_ERROR_HERE, |
| 164 | + path_id, |
| 165 | + binding.span, |
| 166 | + format!("some helper message here")); |
| 167 | +``` |
| 168 | + |
| 169 | +#### Helpful techniques |
| 170 | + |
| 171 | +It can often be challenging to filter out new warnings from older, |
| 172 | +pre-existing errors. One technique that has been used in the past is |
| 173 | +to run the older code unchanged and collect the errors it would have |
| 174 | +reported. You can then issue warnings for any errors you would give |
| 175 | +which do not appear in that original set. Another option is to abort |
| 176 | +compilation after the original code completes if errors are reported: |
| 177 | +then you know that your new code will only execute when there were no |
| 178 | +errors before. |
| 179 | + |
| 180 | +#### Crater and crates.io |
| 181 | + |
| 182 | +We should always do a crater run to assess impact. It is polite and |
| 183 | +considerate to at least notify the authors of affected crates the |
| 184 | +breaking change. If we can submit PRs to fix the problem, so much the |
| 185 | +better. |
| 186 | + |
| 187 | +#### What if issuing a warning is too hard? |
| 188 | + |
| 189 | +It does happen from time to time that it is nigh impossible to isolate |
| 190 | +the breaking change so that you can issue warnings. In such cases, the best |
| 191 | +strategy is to mitigate: |
| 192 | + |
| 193 | +1. Issue warnings for subparts of the problem, and reserve the new errors for |
| 194 | + the smallest set of cases you can. |
| 195 | +2. Try to give a very precise error message that suggests how to fix |
| 196 | + the problem and directs users to the tracking issue. |
| 197 | +3. It may also make sense to layer the fix: |
| 198 | + - First, add warnings where possible and let those land before proceeding |
| 199 | + to issue errors. |
| 200 | + - Work with authors of affected crates to ensure that corrected |
| 201 | + versions are available *before* the fix lands, so that downstream |
| 202 | + users can use them. |
| 203 | + |
| 204 | +If you will be issuing a new hard warning, then it is mandatory to at |
| 205 | +least notify authors of affected crates which we know |
| 206 | +about. Submitting PRs to fix the problem is strongly recommended. If |
| 207 | +the impact is too large to make that practical, then we should try |
| 208 | +harder to issue warnings or find a way to avoid making the change at |
| 209 | +all. |
| 210 | + |
| 211 | +### Stabilization |
| 212 | + |
| 213 | +After a change is made, we will **stabilize** the change using the same |
| 214 | +process that we use for unstable features: |
| 215 | + |
| 216 | +- After a new release is made, we will go through the outstanding tracking |
| 217 | + issues corresponding to breaking changes and nominate some of them for |
| 218 | + **final comment period** (FCP). |
| 219 | +- The FCP for such issues lasts for one cycle. In the final week or two of the cycle, |
| 220 | + we will review comments and make a final determination: |
| 221 | + - Convert to error: the change should be made into a hard error. |
| 222 | + - Revert: we should remove the warning and continue to allow the older code to compile. |
| 223 | + - Defer: can't decide yet, wait longer, or try other strategies. |
| 224 | + |
| 225 | +### Batching breaking changes to libsyntax |
| 226 | + |
| 227 | +Due to the lack of stable plugins, making changes to libsyntax can |
| 228 | +currently be quite disruptive to the ecosystem that relies on plugins. |
| 229 | +In an effort to ease this pain, we generally try to batch up such |
| 230 | +changes so that they occur all at once, rather than occuring in a |
| 231 | +piecemeal fashion. In practice, this means that you should add: |
| 232 | + |
| 233 | + cc #31645 @Manishearth |
| 234 | + |
| 235 | +to the PR and avoid directly merging it. In the future we may develop |
| 236 | +a more polished procedure here, but the hope is that this is a |
| 237 | +relatively temporary state of affairs. |
| 238 | + |
| 239 | +# Drawbacks |
| 240 | +[drawbacks]: #drawbacks |
| 241 | + |
| 242 | +Following this policy can require substantial effort and slows the |
| 243 | +time it takes for a change to become final. However, this is far |
| 244 | +outweighed by the benefits of avoiding sharp disruptions in the |
| 245 | +ecosystem. |
| 246 | + |
| 247 | +# Alternatives |
| 248 | +[alternatives]: #alternatives |
| 249 | + |
| 250 | +There are obviously many points that we could tweak in this policy: |
| 251 | + |
| 252 | +- Eliminate the tracking issue. |
| 253 | +- Change the stabilization schedule. |
| 254 | +- |
| 255 | + |
| 256 | +Two other obvious (and rather extreme) alternatives are not having a |
| 257 | +policy and not making any sort of breaking change at all: |
| 258 | + |
| 259 | +- Not having a policy at all (as is the case today) encourages |
| 260 | + inconsistent treatment of issues. |
| 261 | +- Not making any sorts of breaking changes would mean that Rust simply |
| 262 | + has to stop evolving, or else would issue new major versions quite |
| 263 | + frequently, causing undue disruption. |
| 264 | + |
| 265 | +# Unresolved questions |
| 266 | +[unresolved]: #unresolved-questions |
| 267 | + |
| 268 | +N/A |
| 269 | + |
| 270 | +<!-- -Links--------------------------------------------------------------------- --> |
| 271 | + |
| 272 | +[RFC 1122]: https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md |
| 273 | +[breaking-change-issue]: https://gist.github.com/nikomatsakis/631ec8b4af9a18b5d062d9d9b7d3d967 |
0 commit comments