]> git.proxmox.com Git - rustc.git/blame - src/doc/rustc-dev-guide/src/bug-fix-procedure.md
New upstream version 1.44.1+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / bug-fix-procedure.md
CommitLineData
dfeec247
XL
1# Rustc Bug Fix Procedure
2This page defines the best practices procedure for making bug fixes or soundness
3corrections in the compiler that can cause existing code to stop compiling. This
4text is based on
5[RFC 1589](https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md).
6
7# Motivation
8
9[motivation]: #motivation
10
11From time to time, we encounter the need to make a bug fix, soundness
12correction, or other change in the compiler which will cause existing code to
13stop compiling. When this happens, it is important that we handle the change in
14a way that gives users of Rust a smooth transition. What we want to avoid is
15that existing programs suddenly stop compiling with opaque error messages: we
16would prefer to have a gradual period of warnings, with clear guidance as to
17what the problem is, how to fix it, and why the change was made. This RFC
18describes the procedure that we have been developing for handling breaking
19changes that aims to achieve that kind of smooth transition.
20
21One of the key points of this policy is that (a) warnings should be issued
22initially rather than hard errors if at all possible and (b) every change that
23causes existing code to stop compiling will have an associated tracking issue.
24This issue provides a point to collect feedback on the results of that change.
25Sometimes changes have unexpectedly large consequences or there may be a way to
26avoid the change that was not considered. In those cases, we may decide to
27change course and roll back the change, or find another solution (if warnings
28are being used, this is particularly easy to do).
29
30### What qualifies as a bug fix?
31
32Note that this RFC does not try to define when a breaking change is permitted.
33That is already covered under [RFC 1122][]. This document assumes that the
34change being made is in accordance with those policies. Here is a summary of the
35conditions from RFC 1122:
36
37- **Soundness changes:** Fixes to holes uncovered in the type system.
38- **Compiler bugs:** Places where the compiler is not implementing the specified
39 semantics found in an RFC or lang-team decision.
40- **Underspecified language semantics:** Clarifications to grey areas where the
41 compiler behaves inconsistently and no formal behavior had been previously
42 decided.
43
44Please see [the RFC][rfc 1122] for full details!
45
46# Detailed design
47
48[design]: #detailed-design
49
50The procedure for making a breaking change is as follows (each of these steps is
51described in more detail below):
52
530. Do a **crater run** to assess the impact of the change.
541. Make a **special tracking issue** dedicated to the change.
551. Do not report an error right away. Instead, **issue forwards-compatibility
56 lint warnings**.
57 - Sometimes this is not straightforward. See the text below for suggestions
58 on different techniques we have employed in the past.
59 - For cases where warnings are infeasible:
60 - Report errors, but make every effort to give a targeted error message
61 that directs users to the tracking issue
62 - Submit PRs to all known affected crates that fix the issue
63 - or, at minimum, alert the owners of those crates to the problem and
64 direct them to the tracking issue
651. Once the change has been in the wild for at least one cycle, we can
66 **stabilize the change**, converting those warnings into errors.
67
74b04a01 68Finally, for changes to `librustc_ast` that will affect plugins, the general policy
dfeec247
XL
69is to batch these changes. That is discussed below in more detail.
70
71### Tracking issue
72
73Every breaking change should be accompanied by a **dedicated tracking issue**
74for that change. The main text of this issue should describe the change being
75made, with a focus on what users must do to fix their code. The issue should be
76approachable and practical; it may make sense to direct users to an RFC or some
77other issue for the full details. The issue also serves as a place where users
78can comment with questions or other concerns.
79
80A template for these breaking-change tracking issues can be found below. An
81example of how such an issue should look can be [found
82here][breaking-change-issue].
83
84The issue should be tagged with (at least) `B-unstable` and `T-compiler`.
85
86### Tracking issue template
87
88This is a template to use for tracking issues:
89
90```
91This is the **summary issue** for the `YOUR_LINT_NAME_HERE`
92future-compatibility warning and other related errors. The goal of
93this page is describe why this change was made and how you can fix
94code that is affected by it. It also provides a place to ask questions
95or register a complaint if you feel the change should not be made. For
96more information on the policy around future-compatibility warnings,
97see our [breaking change policy guidelines][guidelines].
98
99[guidelines]: LINK_TO_THIS_RFC
100
101#### What is the warning for?
102
103*Describe the conditions that trigger the warning and how they can be
104fixed. Also explain why the change was made.**
105
106#### When will this warning become a hard error?
107
108At the beginning of each 6-week release cycle, the Rust compiler team
109will review the set of outstanding future compatibility warnings and
110nominate some of them for **Final Comment Period**. Toward the end of
111the cycle, we will review any comments and make a final determination
112whether to convert the warning into a hard error or remove it
113entirely.
114```
115
116### Issuing future compatibility warnings
117
118The best way to handle a breaking change is to begin by issuing
119future-compatibility warnings. These are a special category of lint warning.
120Adding a new future-compatibility warning can be done as follows.
121
122```rust
123// 1. Define the lint in `src/librustc/lint/builtin.rs`:
124declare_lint! {
125 pub YOUR_ERROR_HERE,
126 Warn,
127 "illegal use of foo bar baz"
128}
129
130// 2. Add to the list of HardwiredLints in the same file:
131impl LintPass for HardwiredLints {
132 fn get_lints(&self) -> LintArray {
133 lint_array!(
134 ..,
135 YOUR_ERROR_HERE
136 )
137 }
138}
139
140// 3. Register the lint in `src/librustc_lint/lib.rs`:
141store.register_future_incompatible(sess, vec![
142 ...,
143 FutureIncompatibleInfo {
144 id: LintId::of(YOUR_ERROR_HERE),
145 reference: "issue #1234", // your tracking issue here!
146 },
147]);
148
149// 4. Report the lint:
150tcx.lint_node(
151 lint::builtin::YOUR_ERROR_HERE,
152 path_id,
153 binding.span,
154 format!("some helper message here"));
155```
156
157#### Helpful techniques
158
159It can often be challenging to filter out new warnings from older, pre-existing
160errors. One technique that has been used in the past is to run the older code
161unchanged and collect the errors it would have reported. You can then issue
162warnings for any errors you would give which do not appear in that original set.
163Another option is to abort compilation after the original code completes if
164errors are reported: then you know that your new code will only execute when
165there were no errors before.
166
167#### Crater and crates.io
168
169We should always do a crater run to assess impact. It is polite and considerate
170to at least notify the authors of affected crates the breaking change. If we can
171submit PRs to fix the problem, so much the better.
172
173#### Is it ever acceptable to go directly to issuing errors?
174
175Changes that are believed to have negligible impact can go directly to issuing
176an error. One rule of thumb would be to check against `crates.io`: if fewer than
17710 **total** affected projects are found (**not** root errors), we can move
178straight to an error. In such cases, we should still make the "breaking change"
179page as before, and we should ensure that the error directs users to this page.
180In other words, everything should be the same except that users are getting an
181error, and not a warning. Moreover, we should submit PRs to the affected
182projects (ideally before the PR implementing the change lands in rustc).
183
184If the impact is not believed to be negligible (e.g., more than 10 crates are
185affected), then warnings are required (unless the compiler team agrees to grant
186a special exemption in some particular case). If implementing warnings is not
187feasible, then we should make an aggressive strategy of migrating crates before
188we land the change so as to lower the number of affected crates. Here are some
189techniques for approaching this scenario:
190
1911. Issue warnings for subparts of the problem, and reserve the new errors for
192 the smallest set of cases you can.
1932. Try to give a very precise error message that suggests how to fix the problem
194 and directs users to the tracking issue.
1953. It may also make sense to layer the fix:
196 - First, add warnings where possible and let those land before proceeding to
197 issue errors.
198 - Work with authors of affected crates to ensure that corrected versions are
199 available _before_ the fix lands, so that downstream users can use them.
200
201### Stabilization
202
203After a change is made, we will **stabilize** the change using the same process
204that we use for unstable features:
205
206- After a new release is made, we will go through the outstanding tracking
207 issues corresponding to breaking changes and nominate some of them for **final
208 comment period** (FCP).
209- The FCP for such issues lasts for one cycle. In the final week or two of the
210 cycle, we will review comments and make a final determination:
211
212 - Convert to error: the change should be made into a hard error.
213 - Revert: we should remove the warning and continue to allow the older code to
214 compile.
215 - Defer: can't decide yet, wait longer, or try other strategies.
216
217Ideally, breaking changes should have landed on the **stable branch** of the
218compiler before they are finalized.
219
220<a name="guide">
221
222### Removing a lint
223
224Once we have decided to make a "future warning" into a hard error, we need a PR
225that removes the custom lint. As an example, here are the steps required to
226remove the `overlapping_inherent_impls` compatibility lint. First, convert the
227name of the lint to uppercase (`OVERLAPPING_INHERENT_IMPLS`) ripgrep through the
228source for that string. We will basically by converting each place where this
229lint name is mentioned (in the compiler, we use the upper-case name, and a macro
230automatically generates the lower-case string; so searching for
231`overlapping_inherent_impls` would not find much).
232
ba9703b0
XL
233> NOTE: these exact files don't exist anymore, but the procedure is still the same.
234
dfeec247
XL
235#### Remove the lint.
236
237The first reference you will likely find is the lint definition [in
238`librustc/lint/builtin.rs` that resembles this][defsource]:
239
240[defsource]: https://github.com/rust-lang/rust/blob/085d71c3efe453863739c1fb68fd9bd1beff214f/src/librustc/lint/builtin.rs#L171-L175
241
242```rust
243declare_lint! {
244 pub OVERLAPPING_INHERENT_IMPLS,
245 Deny, // this may also say Warning
246 "two overlapping inherent impls define an item with the same name were erroneously allowed"
247}
248```
249
250This `declare_lint!` macro creates the relevant data structures. Remove it. You
251will also find that there is a mention of `OVERLAPPING_INHERENT_IMPLS` later in
252the file as [part of a `lint_array!`][lintarraysource]; remove it too,
253
254[lintarraysource]: https://github.com/rust-lang/rust/blob/085d71c3efe453863739c1fb68fd9bd1beff214f/src/librustc/lint/builtin.rs#L252-L290
255
256Next, you see see [a reference to `OVERLAPPING_INHERENT_IMPLS` in
257`librustc_lint/lib.rs`][futuresource]. This defining the lint as a "future
258compatibility lint":
259
260```rust
261FutureIncompatibleInfo {
262 id: LintId::of(OVERLAPPING_INHERENT_IMPLS),
263 reference: "issue #36889 <https://github.com/rust-lang/rust/issues/36889>",
264},
265```
266
267Remove this too.
268
269#### Add the lint to the list of removed lists.
270
271In `src/librustc_lint/lib.rs` there is a list of "renamed and removed lints".
272You can add this lint to the list:
273
274```rust
275store.register_removed("overlapping_inherent_impls", "converted into hard error, see #36889");
276```
277
278where `#36889` is the tracking issue for your lint.
279
280#### Update the places that issue the lint
281
282Finally, the last class of references you will see are the places that actually
283**trigger** the lint itself (i.e., what causes the warnings to appear). These
284you do not want to delete. Instead, you want to convert them into errors. In
285this case, the [`add_lint` call][addlintsource] looks like this:
286
287```rust
288self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
289 node_id,
290 self.tcx.span_of_impl(item1).unwrap(),
291 msg);
292```
293
ba9703b0
XL
294We want to convert this into an error. In some cases, there may be an
295existing error for this scenario. In others, we will need to allocate a
296fresh diagnostic code. [Instructions for allocating a fresh diagnostic
297code can be found here.](./diagnostics/diagnostic-codes.md) You may want
298to mention in the extended description that the compiler behavior
299changed on this point, and include a reference to the tracking issue for
300the change.
dfeec247
XL
301
302Let's say that we've adopted `E0592` as our code. Then we can change the
303`add_lint()` call above to something like:
304
305```rust
306struct_span_err!(self.tcx.sess, self.tcx.span_of_impl(item1).unwrap(), msg)
307 .emit();
308```
309
310#### Update tests
311
312Finally, run the test suite. These should be some tests that used to reference
313the `overlapping_inherent_impls` lint, those will need to be updated. In
314general, if the test used to have `#[deny(overlapping_inherent_impls)]`, that
315can just be removed.
316
317```
318./x.py test
319```
320
321#### All done!
322
323Open a PR. =)
324
325[addlintsource]: https://github.com/rust-lang/rust/blob/085d71c3efe453863739c1fb68fd9bd1beff214f/src/librustc_typeck/coherence/inherent.rs#L300-L303
326[futuresource]: https://github.com/rust-lang/rust/blob/085d71c3efe453863739c1fb68fd9bd1beff214f/src/librustc_lint/lib.rs#L202-L205
327
328<!-- -Links--------------------------------------------------------------------- -->
329
330[rfc 1122]: https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md
331[breaking-change-issue]: https://gist.github.com/nikomatsakis/631ec8b4af9a18b5d062d9d9b7d3d967