Skip to content

Commit 8583740

Browse files
authored
Merge pull request #5 from rust-lang/feat/code-considerations
Initial code considerations and other sections
2 parents 80ea37f + 4024cdf commit 8583740

30 files changed

+626
-1
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ cache:
88
- book/linkcheck/
99
before_install:
1010
- shopt -s globstar
11-
- MAX_LINE_LENGTH=100 bash ci/check_line_lengths.sh src/**/*.md
1211
install:
1312
- source ~/.cargo/env || true
1413
- cargo install mdbook --version '^0.4.5'

src/SUMMARY.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
11
# Summary
22

33
[About this guide](./about-this-guide.md)
4+
5+
[Getting started](./getting-started.md)
6+
7+
[Reviewer checklist](./reviewer-checklist.md)
8+
9+
---
10+
11+
- [The feature lifecycle](./feature-lifecycle/summary.md)
12+
- [Landing new features](./feature-lifecycle/new-unstable-features.md)
13+
- [Using tracking issues](./feature-lifecycle/tracking-issues.md)
14+
- [Stabilizing features](./feature-lifecycle/stabilization.md)
15+
- [Deprecating features](./feature-lifecycle/deprecation.md)
16+
17+
---
18+
19+
- [Code considerations](./code-considerations/summary.md)
20+
- [Design](./code-considerations/design/summary.md)
21+
- [Public APIs](./code-considerations/design/public-apis.md)
22+
- [Breaking changes](./code-considerations/breaking-changes/summary.md)
23+
- [Breakage from changing behavior](./code-considerations/breaking-changes/behavior.md)
24+
- [Breakage from new trait impls](./code-considerations/breaking-changes/new-trait-impls.md)
25+
- [`#[fundamental]` types](./code-considerations/breaking-changes/fundamental.md)
26+
- [Safety and soundness](./code-considerations/safety-and-soundness/summary.md)
27+
- [Generics and unsafe](./code-considerations/safety-and-soundness/generics-and-unsafe.md)
28+
- [Drop and `#[may_dangle]`](./code-considerations/safety-and-soundness/may-dangle.md)
29+
- [`std::mem` and exclusive references](./code-considerations/safety-and-soundness/mem-and-exclusive-refs.md)
30+
- [Using unstable language features](./code-considerations/using-unstable-lang/summary.md)
31+
- [Const generics](./code-considerations/using-unstable-lang/const-generics.md)
32+
- [Specialization](./code-considerations/using-unstable-lang/specialization.md)
33+
- [Performance](./code-considerations/performance/summary.md)
34+
- [When to `#[inline]`](./code-considerations/performance/inline.md)
35+
36+
---
37+
38+
- [Tools and bots](./tools-and-bots/summary.md)
39+
- [`@bors`](./tools-and-bots/bors.md)
40+
- [`@rust-timer`](./tools-and-bots/timer.md)
41+
- [`@craterbot`](./tools-and-bots/crater.md)

src/about-this-guide.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# About this guide
22

3+
**Status:** Stub
4+
35
This guide is for contributors and reviewers to Rust's standard library.
46

57
## Other places to find information
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Breakage from changing behavior
2+
3+
Breaking changes aren't just limited to compilation failures. Behavioral changes to stable functions generally can't be accepted. See [the `home_dir` issue](https://github.com/rust-lang/rust/pull/46799) for an example.
4+
5+
An exception is when a behavior is specified in an RFC (such as IETF specifications for IP addresses). If a behavioral change fixes non-conformance then it can be considered a bug fix. In these cases, `@rust-lang/libs` should still be pinged for input.
6+
7+
## For reviewers
8+
9+
Look out for changes in existing implementations for stable functions, especially if assertions in test cases have been changed.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# `#[fundamental]` types
2+
3+
**Status:** Stub
4+
5+
Type annotated with the `#[fundamental]` attribute have different coherence rules. See [RFC 1023](https://rust-lang.github.io/rfcs/1023-rebalancing-coherence.html) for details. That includes:
6+
7+
- `&T`
8+
- `&mut T`
9+
- `Box<T>`
10+
- `Pin<T>`
11+
12+
Typically, the scope of [breakage in new trait impls](./reviewing-code/breakage/new-trait-impls.md) is limited to inference and deref-coercion. New trait impls on `#[fundamental]` types may overlap with downstream impls and cause other kinds of breakage.
13+
14+
[RFC 1023]: https://rust-lang.github.io/rfcs/1023-rebalancing-coherence.html
15+
16+
## For reviewers
17+
18+
Look out for blanket trait implementations for fundamental types, like:
19+
20+
```rust
21+
impl<'a, T> PublicTrait for &'a T
22+
where
23+
T: SomeBound,
24+
{
25+
26+
}
27+
```
28+
29+
unless the blanket implementation is being stabilized along with `PublicTrait`. In cases where we really want to do this, a [crater] run can help estimate the scope of the breakage.
30+
31+
[crater]: ../../tools-and-bots/crater.md
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Breakage from new trait impls
2+
3+
A lot of PRs to the standard library are adding new impls for already stable traits, which can break consumers in many weird and wonderful ways. The following sections gives some examples of breakage from new trait impls that may not be obvious just from the change made to the standard library.
4+
5+
Also see [`#[fundamental]` types](./fundamental.md) for special considerations for types like `&T`, `&mut T`, `Box<T>`, and other core smart pointers.
6+
7+
## Inference breaks when a second generic impl is introduced
8+
9+
Rust will use the fact that there's only a single impl for a generic trait during inference. This breaks once a second impl makes the type of that generic ambiguous. Say we have:
10+
11+
```rust
12+
// in `std`
13+
impl From<&str> for Arc<str> { .. }
14+
```
15+
16+
```rust
17+
// in an external `lib`
18+
let b = Arc::from("a");
19+
```
20+
21+
then we add:
22+
23+
```diff
24+
impl From<&str> for Arc<str> { .. }
25+
+ impl From<&str> for Arc<String> { .. }
26+
```
27+
28+
then
29+
30+
```rust
31+
let b = Arc::from("a");
32+
```
33+
34+
will no longer compile, because we've previously been relying on inference to figure out the `T` in `Box<T>`.
35+
36+
This kind of breakage can be ok, but a [crater] run should estimate the scope.
37+
38+
## Deref coercion breaks when a new impl is introduced
39+
40+
Rust will use deref coercion to find a valid trait impl if the arguments don't type check directly. This only seems to occur if there's a single impl so introducing a new one may break consumers relying on deref coercion. Say we have:
41+
42+
```rust
43+
// in `std`
44+
impl Add<&str> for String { .. }
45+
46+
impl Deref for String { type Target = str; .. }
47+
```
48+
49+
```rust
50+
// in an external `lib`
51+
let a = String::from("a");
52+
let b = String::from("b");
53+
54+
let c = a + &b;
55+
```
56+
57+
then we add:
58+
59+
```diff
60+
impl Add<&str> for String { .. }
61+
+ impl Add<char> for String { .. }
62+
```
63+
64+
then
65+
66+
```rust
67+
let c = a + &b;
68+
```
69+
70+
will no longer compile, because we won't attempt to use deref to coerce the `&String` into `&str`.
71+
72+
This kind of breakage can be ok, but a [crater](../../tools-and-bots/crater.md) run should estimate the scope.
73+
74+
## For reviewers
75+
76+
Look out for new `#[stable]` trait implementations for existing stable traits.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Breaking changes
2+
3+
Breaking changes should be avoided when possible. [RFC 1105](https://rust-lang.github.io/rfcs/1105-api-evolution.html) lays the foundations for what constitutes a breaking change. Breakage may be deemed acceptable or not based on its actual impact, which can be approximated with a [crater](../../tools-and-bots/crater.md) run.
4+
5+
There are strategies for mitigating breakage depending on the impact.
6+
7+
For changes where the value is high and the impact is high too:
8+
9+
- Using compiler lints to try phase out broken behavior.
10+
11+
If the impact isn't too high:
12+
13+
- Looping in maintainers of broken crates and submitting PRs to fix them.
14+
15+
## For reviewers
16+
17+
Look out for changes to documented behavior and new trait impls for existing stable traits.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Public API design
2+
3+
**Status:** Stub
4+
5+
Standard library APIs typically follow the [API Guidelines](https://rust-lang.github.io/api-guidelines/), which were originally spawned from the standard library itself.
6+
7+
## For reviewers
8+
9+
For new unstable features, look for any prior discussion of the proposed API to see what options and tradeoffs have already been considered. If in doubt, ping `@rust-lang/libs` for input.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Design
2+
3+
**Status:** Stub
4+
5+
Most of the considerations in this guide are quality in some sense. This section has some general advice on maintaining code quality in the standard library.
6+
7+
## For reviewers
8+
9+
Think about how you would implement a feature and whether your approach would differ from what's being proposed. What trade-offs are being made? Is the weighting of those trade-offs the most appropriate?
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# When to `#[inline]`
2+
3+
Inlining is a trade-off between potential execution speed, compile time and code size. There's some discussion about it in [this PR to the `hashbrown` crate](https://github.com/rust-lang/hashbrown/pull/119). From the thread:
4+
5+
> `#[inline]` is very different than simply just an inline hint. As I mentioned before, there's no equivalent in C++ for what `#[inline]` does. In debug mode rustc basically ignores `#[inline]`, pretending you didn't even write it. In release mode the compiler will, by default, codegen an `#[inline]` function into every single referencing codegen unit, and then it will also add `inlinehint`. This means that if you have 16 CGUs and they all reference an item, every single one is getting the entire item's implementation inlined into it.
6+
7+
You can add `#[inline]`:
8+
9+
- To public, small, non-generic functions.
10+
11+
You shouldn't need `#[inline]`:
12+
13+
- On methods that have any generics in scope.
14+
- On methods on traits that don't have a default implementation.
15+
16+
`#[inline]` can always be introduced later, so if you're in doubt they can just be removed.
17+
18+
## What about `#[inline(always)]`?
19+
20+
You should just about never need `#[inline(always)]`. It may be beneficial for private helper methods that are used in a limited number of places or for trivial operators. A micro benchmark should justify the attribute.
21+
22+
## For reviewers
23+
24+
`#[inline]` can always be added later, so if there's any debate about whether it's appropriate feel free to defer it by removing the annotations for a start.

0 commit comments

Comments
 (0)