Skip to content

Commit ec1a4b7

Browse files
committed
draft
1 parent bdbe73d commit ec1a4b7

File tree

1 file changed

+273
-0
lines changed

1 file changed

+273
-0
lines changed

text/0000-rustc-bug-fix-procedure.md

+273
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
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

Comments
 (0)