Skip to content

Commit 0d37e78

Browse files
committed
lots more felix fixes
1 parent 5789106 commit 0d37e78

12 files changed

+104
-74
lines changed

src/doc/tarpl/casts.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ Note that lengths are not adjusted when casting raw slices -
4141
half of the original memory.
4242

4343
Casting is not transitive, that is, even if `e as U1 as U2` is a valid
44-
expression, `e as U2` is not necessarily so (in fact it will only be valid if
45-
`U1` coerces to `U2`).
44+
expression, `e as U2` is not necessarily so.
4645

4746
For numeric casts, there are quite a few cases to consider:
4847

@@ -53,15 +52,20 @@ For numeric casts, there are quite a few cases to consider:
5352
* zero-extend if the source is unsigned
5453
* sign-extend if the source is signed
5554
* casting from a float to an integer will round the float towards zero
56-
* **NOTE: currently this will cause Undefined Behaviour if the rounded
57-
value cannot be represented by the target integer type**. This includes
58-
Inf and NaN. This is a bug and will be fixed.
55+
* **[NOTE: currently this will cause Undefined Behaviour if the rounded
56+
value cannot be represented by the target integer type][float-int]**.
57+
This includes Inf and NaN. This is a bug and will be fixed.
5958
* casting from an integer to float will produce the floating point
6059
representation of the integer, rounded if necessary (rounding strategy
6160
unspecified)
6261
* casting from an f32 to an f64 is perfect and lossless
6362
* casting from an f64 to an f32 will produce the closest possible value
6463
(rounding strategy unspecified)
65-
* **NOTE: currently this will cause Undefined Behaviour if the value
64+
* **[NOTE: currently this will cause Undefined Behaviour if the value
6665
is finite but larger or smaller than the largest or smallest finite
67-
value representable by f32**. This is a bug and will be fixed.
66+
value representable by f32][float-float]**. This is a bug and will
67+
be fixed.
68+
69+
70+
[float-int]: https://github.com/rust-lang/rust/issues/10184
71+
[float-float]: https://github.com/rust-lang/rust/issues/15536

src/doc/tarpl/checked-uninit.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,14 @@ fn main() {
104104
```
105105

106106
However reassigning `y` in this example *would* require `y` to be marked as
107-
mutable, as a Safe Rust program could observe that the value of `y` changed.
108-
Otherwise the variable is exactly like new.
107+
mutable, as a Safe Rust program could observe that the value of `y` changed:
108+
109+
```rust
110+
fn main() {
111+
let mut y = Box::new(0);
112+
let z = y; // y is now logically uninitialized because Box isn't Copy
113+
y = Box::new(1); // reinitialize y
114+
}
115+
```
116+
117+
Otherwise it's like `y` is a brand new variable.

src/doc/tarpl/coercions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ only implemented automatically, and enables the following transformations:
2727
* `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
2828
* `T: Unsize<U>`
2929
* `Foo` is a struct
30-
* Only the last field has type `T`
30+
* Only the last field of `Foo` has type `T`
3131
* `T` is not part of the type of any other fields
3232

3333
Coercions occur at a *coercion site*. Any location that is explicitly typed

src/doc/tarpl/drop-flags.md

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,42 @@
22

33
The examples in the previous section introduce an interesting problem for Rust.
44
We have seen that's possible to conditionally initialize, deinitialize, and
5-
*reinitialize* locations of memory totally safely. For Copy types, this isn't
5+
reinitialize locations of memory totally safely. For Copy types, this isn't
66
particularly notable since they're just a random pile of bits. However types
77
with destructors are a different story: Rust needs to know whether to call a
88
destructor whenever a variable is assigned to, or a variable goes out of scope.
99
How can it do this with conditional initialization?
1010

11+
Note that this is not a problem that all assignments need worry about. In
12+
particular, assigning through a dereference unconditionally drops, and assigning
13+
in a `let` unconditionally *doesn't* drop:
14+
15+
```
16+
let mut x = Box::new(0); // let makes a fresh variable, so never need to drop
17+
let y = &mut x;
18+
*y = Box::new(1); // Deref assumes the referent is initialized, so always drops
19+
```
20+
21+
This is only a problem when overwriting a previously initialized variable or
22+
one of its subfields.
23+
1124
It turns out that Rust actually tracks whether a type should be dropped or not
1225
*at runtime*. As a variable becomes initialized and uninitialized, a *drop flag*
1326
for that variable is toggled. When a variable *might* need to be dropped, this
1427
flag is evaluated to determine if it *should* be dropped.
1528

1629
Of course, it is *often* the case that a value's initialization state can be
1730
*statically* known at every point in the program. If this is the case, then the
18-
compiler can theoretically generate more effecient code! For instance, straight-
31+
compiler can theoretically generate more efficient code! For instance, straight-
1932
line code has such *static drop semantics*:
2033

2134
```rust
2235
let mut x = Box::new(0); // x was uninit; just overwrite.
2336
let mut y = x; // y was uninit; just overwrite and make x uninit.
2437
x = Box::new(0); // x was uninit; just overwrite.
2538
y = x; // y was init; Drop y, overwrite it, and make x uninit!
26-
// y was init; Drop y!
27-
// x was uninit; do nothing.
39+
// y goes out of scope; y was init; Drop y!
40+
// x goes out of scope; x was uninit; do nothing.
2841
```
2942

3043
And even branched code where all branches have the same behaviour with respect
@@ -40,7 +53,7 @@ if condition {
4053
drop(x) // x gets moved out; make x uninit.
4154
}
4255
x = Box::new(0); // x was uninit; just overwrite.
43-
// x was init; Drop x!
56+
// x goes out of scope; x was init; Drop x!
4457
```
4558

4659
However code like this *requires* runtime information to correctly Drop:
@@ -52,7 +65,8 @@ if condition {
5265
x = Box::new(0); // x was uninit; just overwrite.
5366
println!("{}", x);
5467
}
55-
// x *might* be uninit; check the flag!
68+
// x goes out of scope; x *might* be uninit;
69+
// check the flag!
5670
```
5771

5872
Of course, in this case it's trivial to retrieve static drop semantics:
@@ -66,10 +80,10 @@ if condition {
6680
```
6781

6882
As of Rust 1.0, the drop flags are actually not-so-secretly stashed in a hidden
69-
field of any type that implements Drop. Rust sets the drop flag by
70-
overwriting the *entire* value with a particular byte. This is pretty obviously
71-
Not The Fastest and causes a bunch of trouble with optimizing code. It's legacy
72-
from a time when you could do much more complex conditional initialization.
83+
field of any type that implements Drop. Rust sets the drop flag by overwriting
84+
the *entire* value with a particular bit pattern. This is pretty obviously Not
85+
The Fastest and causes a bunch of trouble with optimizing code. It's legacy from
86+
a time when you could do much more complex conditional initialization.
7387

7488
As such work is currently under way to move the flags out onto the stack frame
7589
where they more reasonably belong. Unfortunately, this work will take some time

src/doc/tarpl/dropck.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ accidentally make dangling pointers. Consider the following simple program:
4949
struct Inspector<'a>(&'a u8);
5050

5151
fn main() {
52-
let (days, inspector);
52+
let (inspector, days);
5353
days = Box::new(1);
5454
inspector = Inspector(&days);
5555
}
@@ -71,7 +71,7 @@ impl<'a> Drop for Inspector<'a> {
7171
}
7272
7373
fn main() {
74-
let (days, inspector);
74+
let (inspector, days);
7575
days = Box::new(1);
7676
inspector = Inspector(&days);
7777
// Let's say `days` happens to get dropped first.
@@ -85,14 +85,14 @@ fn main() {
8585
^~~~
8686
<anon>:9:11: 15:2 note: reference must be valid for the block at 9:10...
8787
<anon>:9 fn main() {
88-
<anon>:10 let (days, inspector);
88+
<anon>:10 let (inspector, days);
8989
<anon>:11 days = Box::new(1);
9090
<anon>:12 inspector = Inspector(&days);
9191
<anon>:13 // Let's say `days` happens to get dropped first.
9292
<anon>:14 // Then when Inspector is dropped, it will try to read free'd memory!
9393
...
9494
<anon>:10:27: 15:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 10:26
95-
<anon>:10 let (days, inspector);
95+
<anon>:10 let (inspector, days);
9696
<anon>:11 days = Box::new(1);
9797
<anon>:12 inspector = Inspector(&days);
9898
<anon>:13 // Let's say `days` happens to get dropped first.
@@ -112,8 +112,8 @@ of the finer details of how the drop checker validates types is totally up in
112112
the air. However The Big Rule is the subtlety that we have focused on this whole
113113
section:
114114

115-
**For a generic type to soundly implement drop, it must strictly outlive all of
116-
its generic arguments.**
115+
**For a generic type to soundly implement drop, its generics arguments must
116+
strictly outlive it.**
117117

118118
This rule is sufficient but not necessary to satisfy the drop checker. That is,
119119
if your type obeys this rule then it's *definitely* sound to drop. However

src/doc/tarpl/exception-safety.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ needs to be careful and consider exception safety.
3737
## Vec::push_all
3838

3939
`Vec::push_all` is a temporary hack to get extending a Vec by a slice reliably
40-
effecient without specialization. Here's a simple implementation:
40+
efficient without specialization. Here's a simple implementation:
4141

4242
```rust,ignore
4343
impl<T: Clone> Vec<T> {

src/doc/tarpl/hrtb.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
% Higher-Rank Trait Bounds (HRTBs)
22

3-
Rust's Fn traits are a little bit magic. For instance, we can write the
3+
Rust's `Fn` traits are a little bit magic. For instance, we can write the
44
following code:
55

66
```rust
@@ -52,21 +52,22 @@ fn main() {
5252
}
5353
```
5454

55-
How on earth are we supposed to express the lifetimes on F's trait bound? We need
56-
to provide some lifetime there, but the lifetime we care about can't be named until
57-
we enter the body of `call`! Also, that isn't some fixed lifetime; call works with
58-
*any* lifetime `&self` happens to have at that point.
55+
How on earth are we supposed to express the lifetimes on `F`'s trait bound? We
56+
need to provide some lifetime there, but the lifetime we care about can't be
57+
named until we enter the body of `call`! Also, that isn't some fixed lifetime;
58+
call works with *any* lifetime `&self` happens to have at that point.
5959

60-
This job requires The Magic of Higher-Rank Trait Bounds. The way we desugar
61-
this is as follows:
60+
This job requires The Magic of Higher-Rank Trait Bounds (HRTBs). The way we
61+
desugar this is as follows:
6262

6363
```rust,ignore
6464
where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8,
6565
```
6666

67-
(Where `Fn(a, b, c) -> d` is itself just sugar for the unstable *real* Fn trait)
67+
(Where `Fn(a, b, c) -> d` is itself just sugar for the unstable *real* `Fn`
68+
trait)
6869

6970
`for<'a>` can be read as "for all choices of `'a`", and basically produces an
70-
*inifinite list* of trait bounds that F must satisfy. Intense. There aren't many
71-
places outside of the Fn traits where we encounter HRTBs, and even for those we
72-
have a nice magic sugar for the common cases.
71+
*infinite list* of trait bounds that F must satisfy. Intense. There aren't many
72+
places outside of the `Fn` traits where we encounter HRTBs, and even for
73+
those we have a nice magic sugar for the common cases.

src/doc/tarpl/lifetime-splitting.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,17 @@ In order to "teach" borrowck that what we're doing is ok, we need to drop down
5252
to unsafe code. For instance, mutable slices expose a `split_at_mut` function
5353
that consumes the slice and returns *two* mutable slices. One for everything to
5454
the left of the index, and one for everything to the right. Intuitively we know
55-
this is safe because the slices don't alias. However the implementation requires
56-
some unsafety:
55+
this is safe because the slices don't overlap, and therefore alias. However
56+
the implementation requires some unsafety:
5757

5858
```rust,ignore
5959
fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
60+
let len = self.len();
61+
let ptr = self.as_mut_ptr();
62+
assert!(mid <= len);
6063
unsafe {
61-
let self2: &mut [T] = mem::transmute_copy(&self);
62-
63-
(ops::IndexMut::index_mut(self, ops::RangeTo { end: mid } ),
64-
ops::IndexMut::index_mut(self2, ops::RangeFrom { start: mid } ))
64+
(from_raw_parts_mut(ptr, mid),
65+
from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
6566
}
6667
}
6768
```

src/doc/tarpl/lifetimes.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,21 @@ the scope it's valid for.
77

88
Within a function body, Rust generally doesn't let you explicitly name the
99
lifetimes involved. This is because it's generally not really *necessary*
10-
to talk about lifetimes in a local context; rust has all the information and
11-
can work out everything. It's also a good thing because the scope of a borrow
12-
is often significantly smaller than the scope its referent is *actually* valid
13-
for. Rust will introduce *many* anonymous scopes and temporaries to make your
14-
code *just work*.
10+
to talk about lifetimes in a local context; Rust has all the information and
11+
can work out everything as optimally as possible. Many anonymous scopes and
12+
temporaries that you would otherwise have to write are often introduced to
13+
make your code *just work*.
1514

1615
However once you cross the function boundary, you need to start talking about
1716
lifetimes. Lifetimes are denoted with an apostrophe: `'a`, `'static`. To dip
1817
our toes with lifetimes, we're going to pretend that we're actually allowed
1918
to label scopes with lifetimes, and desugar the examples from the start of
2019
this chapter.
2120

22-
Originally, our examples made use of *aggressive* sugar -- high fructose corn syrup even --
23-
around scopes and lifetimes, because writing everything out explicitly is
24-
*extremely noisy*. All Rust code relies on aggressive inference and elision of
25-
"obvious" things.
21+
Originally, our examples made use of *aggressive* sugar -- high fructose corn
22+
syrup even -- around scopes and lifetimes, because writing everything out
23+
explicitly is *extremely noisy*. All Rust code relies on aggressive inference
24+
and elision of "obvious" things.
2625

2726
One particularly interesting piece of sugar is that each `let` statement implicitly
2827
introduces a scope. For the most part, this doesn't really matter. However it

src/doc/tarpl/safe-unsafe-meaning.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ unsafe impl UnsafeOrd for MyType {
125125
But it's probably not the implementation you want.
126126

127127
Rust has traditionally avoided making traits unsafe because it makes Unsafe
128-
pervasive, which is not desirable. Send and Sync are unsafe is because
129-
thread safety is a *fundamental property* that Unsafe cannot possibly hope to
130-
defend against in the same way it would defend against a bad Ord implementation.
131-
The only way to possibly defend against thread-unsafety would be to *not use
132-
threading at all*. Making every operation atomic isn't even sufficient, because
133-
it's possible for complex invariants to exist between disjoint locations in
134-
memory. For instance, the pointer and capacity of a Vec must be in sync.
128+
pervasive, which is not desirable. Send and Sync are unsafe is because thread
129+
safety is a *fundamental property* that Unsafe cannot possibly hope to defend
130+
against in the same way it would defend against a bad Ord implementation. The
131+
only way to possibly defend against thread-unsafety would be to *not use
132+
threading at all*. Making every load and store atomic isn't even sufficient,
133+
because it's possible for complex invariants to exist between disjoint locations
134+
in memory. For instance, the pointer and capacity of a Vec must be in sync.
135135

136136
Even concurrent paradigms that are traditionally regarded as Totally Safe like
137137
message passing implicitly rely on some notion of thread safety -- are you

src/doc/tarpl/subtyping.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Variance is where things get a bit complicated.
3333
Variance is a property that *type constructors* have with respect to their
3434
arguments. A type constructor in Rust is a generic type with unbound arguments.
3535
For instance `Vec` is a type constructor that takes a `T` and returns a
36-
`Vec<T>`. `&` and `&mut` are type constructors that take a two types: a
36+
`Vec<T>`. `&` and `&mut` are type constructors that take two inputs: a
3737
lifetime, and a type to point to.
3838

3939
A type constructor's *variance* is how the subtyping of its inputs affects the
@@ -54,7 +54,8 @@ Some important variances:
5454
* `&'a T` is variant over `'a` and `T` (as is `*const T` by metaphor)
5555
* `&'a mut T` is variant with over `'a` but invariant over `T`
5656
* `Fn(T) -> U` is invariant over `T`, but variant over `U`
57-
* `Box`, `Vec`, and all other collections are variant over their contents
57+
* `Box`, `Vec`, and all other collections are variant over the types of
58+
their contents
5859
* `UnsafeCell<T>`, `Cell<T>`, `RefCell<T>`, `Mutex<T>` and all other
5960
interior mutability types are invariant over T (as is `*mut T` by metaphor)
6061

@@ -71,7 +72,7 @@ to be able to pass `&&'static str` where an `&&'a str` is expected. The
7172
additional level of indirection does not change the desire to be able to pass
7273
longer lived things where shorted lived things are expected.
7374

74-
However this logic *does not* apply to see why `&mut`. To see why &mut should
75+
However this logic *does not* apply to `&mut`. To see why `&mut` should
7576
be invariant over T, consider the following code:
7677

7778
```rust,ignore
@@ -117,8 +118,9 @@ in them *via a mutable reference*! The mutable reference makes the whole type
117118
invariant, and therefore prevents you from smuggling a short-lived type into
118119
them.
119120

120-
Being variant *does* allows them to be weakened when shared immutably.
121-
So you can pass a `&Box<&'static str>` where a `&Box<&'a str>` is expected.
121+
Being variant *does* allows `Box` and `Vec` to be weakened when shared
122+
immutably. So you can pass a `&Box<&'static str>` where a `&Box<&'a str>` is
123+
expected.
122124

123125
However what should happen when passing *by-value* is less obvious. It turns out
124126
that, yes, you can use subtyping when passing by-value. That is, this works:
@@ -178,7 +180,7 @@ fn foo(usize) -> &'static str;
178180
in its place. Therefore functions *are* variant over their return type.
179181

180182
`*const` has the exact same semantics as `&`, so variance follows. `*mut` on the
181-
other hand can dereference to an &mut whether shared or not, so it is marked
183+
other hand can dereference to an `&mut` whether shared or not, so it is marked
182184
as invariant just like cells.
183185

184186
This is all well and good for the types the standard library provides, but

0 commit comments

Comments
 (0)