lots more felix fixes

pull/10/head
Alexis Beingessner 9 years ago committed by Manish Goregaokar
parent fadf50dc7d
commit 36d7b94c89

@ -41,8 +41,7 @@ Note that lengths are not adjusted when casting raw slices -
half of the original memory. half of the original memory.
Casting is not transitive, that is, even if `e as U1 as U2` is a valid Casting is not transitive, that is, even if `e as U1 as U2` is a valid
expression, `e as U2` is not necessarily so (in fact it will only be valid if expression, `e as U2` is not necessarily so.
`U1` coerces to `U2`).
For numeric casts, there are quite a few cases to consider: For numeric casts, there are quite a few cases to consider:
@ -53,15 +52,20 @@ For numeric casts, there are quite a few cases to consider:
* zero-extend if the source is unsigned * zero-extend if the source is unsigned
* sign-extend if the source is signed * sign-extend if the source is signed
* casting from a float to an integer will round the float towards zero * casting from a float to an integer will round the float towards zero
* **NOTE: currently this will cause Undefined Behaviour if the rounded * **[NOTE: currently this will cause Undefined Behaviour if the rounded
value cannot be represented by the target integer type**. This includes value cannot be represented by the target integer type][float-int]**.
Inf and NaN. This is a bug and will be fixed. This includes Inf and NaN. This is a bug and will be fixed.
* casting from an integer to float will produce the floating point * casting from an integer to float will produce the floating point
representation of the integer, rounded if necessary (rounding strategy representation of the integer, rounded if necessary (rounding strategy
unspecified) unspecified)
* casting from an f32 to an f64 is perfect and lossless * casting from an f32 to an f64 is perfect and lossless
* casting from an f64 to an f32 will produce the closest possible value * casting from an f64 to an f32 will produce the closest possible value
(rounding strategy unspecified) (rounding strategy unspecified)
* **NOTE: currently this will cause Undefined Behaviour if the value * **[NOTE: currently this will cause Undefined Behaviour if the value
is finite but larger or smaller than the largest or smallest finite is finite but larger or smaller than the largest or smallest finite
value representable by f32**. This is a bug and will be fixed. value representable by f32][float-float]**. This is a bug and will
be fixed.
[float-int]: https://github.com/rust-lang/rust/issues/10184
[float-float]: https://github.com/rust-lang/rust/issues/15536

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

@ -27,7 +27,7 @@ only implemented automatically, and enables the following transformations:
* `Foo<..., T, ...>` => `Foo<..., U, ...>` where: * `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
* `T: Unsize<U>` * `T: Unsize<U>`
* `Foo` is a struct * `Foo` is a struct
* Only the last field has type `T` * Only the last field of `Foo` has type `T`
* `T` is not part of the type of any other fields * `T` is not part of the type of any other fields
Coercions occur at a *coercion site*. Any location that is explicitly typed Coercions occur at a *coercion site*. Any location that is explicitly typed

@ -2,12 +2,25 @@
The examples in the previous section introduce an interesting problem for Rust. The examples in the previous section introduce an interesting problem for Rust.
We have seen that's possible to conditionally initialize, deinitialize, and We have seen that's possible to conditionally initialize, deinitialize, and
*reinitialize* locations of memory totally safely. For Copy types, this isn't reinitialize locations of memory totally safely. For Copy types, this isn't
particularly notable since they're just a random pile of bits. However types particularly notable since they're just a random pile of bits. However types
with destructors are a different story: Rust needs to know whether to call a with destructors are a different story: Rust needs to know whether to call a
destructor whenever a variable is assigned to, or a variable goes out of scope. destructor whenever a variable is assigned to, or a variable goes out of scope.
How can it do this with conditional initialization? How can it do this with conditional initialization?
Note that this is not a problem that all assignments need worry about. In
particular, assigning through a dereference unconditionally drops, and assigning
in a `let` unconditionally *doesn't* drop:
```
let mut x = Box::new(0); // let makes a fresh variable, so never need to drop
let y = &mut x;
*y = Box::new(1); // Deref assumes the referent is initialized, so always drops
```
This is only a problem when overwriting a previously initialized variable or
one of its subfields.
It turns out that Rust actually tracks whether a type should be dropped or not It turns out that Rust actually tracks whether a type should be dropped or not
*at runtime*. As a variable becomes initialized and uninitialized, a *drop flag* *at runtime*. As a variable becomes initialized and uninitialized, a *drop flag*
for that variable is toggled. When a variable *might* need to be dropped, this for that variable is toggled. When a variable *might* need to be dropped, this
@ -15,7 +28,7 @@ flag is evaluated to determine if it *should* be dropped.
Of course, it is *often* the case that a value's initialization state can be Of course, it is *often* the case that a value's initialization state can be
*statically* known at every point in the program. If this is the case, then the *statically* known at every point in the program. If this is the case, then the
compiler can theoretically generate more effecient code! For instance, straight- compiler can theoretically generate more efficient code! For instance, straight-
line code has such *static drop semantics*: line code has such *static drop semantics*:
```rust ```rust
@ -23,8 +36,8 @@ let mut x = Box::new(0); // x was uninit; just overwrite.
let mut y = x; // y was uninit; just overwrite and make x uninit. let mut y = x; // y was uninit; just overwrite and make x uninit.
x = Box::new(0); // x was uninit; just overwrite. x = Box::new(0); // x was uninit; just overwrite.
y = x; // y was init; Drop y, overwrite it, and make x uninit! y = x; // y was init; Drop y, overwrite it, and make x uninit!
// y was init; Drop y! // y goes out of scope; y was init; Drop y!
// x was uninit; do nothing. // x goes out of scope; x was uninit; do nothing.
``` ```
And even branched code where all branches have the same behaviour with respect And even branched code where all branches have the same behaviour with respect
@ -40,7 +53,7 @@ if condition {
drop(x) // x gets moved out; make x uninit. drop(x) // x gets moved out; make x uninit.
} }
x = Box::new(0); // x was uninit; just overwrite. x = Box::new(0); // x was uninit; just overwrite.
// x was init; Drop x! // x goes out of scope; x was init; Drop x!
``` ```
However code like this *requires* runtime information to correctly Drop: However code like this *requires* runtime information to correctly Drop:
@ -52,7 +65,8 @@ if condition {
x = Box::new(0); // x was uninit; just overwrite. x = Box::new(0); // x was uninit; just overwrite.
println!("{}", x); println!("{}", x);
} }
// x *might* be uninit; check the flag! // x goes out of scope; x *might* be uninit;
// check the flag!
``` ```
Of course, in this case it's trivial to retrieve static drop semantics: Of course, in this case it's trivial to retrieve static drop semantics:
@ -66,10 +80,10 @@ if condition {
``` ```
As of Rust 1.0, the drop flags are actually not-so-secretly stashed in a hidden As of Rust 1.0, the drop flags are actually not-so-secretly stashed in a hidden
field of any type that implements Drop. Rust sets the drop flag by field of any type that implements Drop. Rust sets the drop flag by overwriting
overwriting the *entire* value with a particular byte. This is pretty obviously the *entire* value with a particular bit pattern. This is pretty obviously Not
Not The Fastest and causes a bunch of trouble with optimizing code. It's legacy The Fastest and causes a bunch of trouble with optimizing code. It's legacy from
from a time when you could do much more complex conditional initialization. a time when you could do much more complex conditional initialization.
As such work is currently under way to move the flags out onto the stack frame As such work is currently under way to move the flags out onto the stack frame
where they more reasonably belong. Unfortunately, this work will take some time where they more reasonably belong. Unfortunately, this work will take some time

@ -49,7 +49,7 @@ accidentally make dangling pointers. Consider the following simple program:
struct Inspector<'a>(&'a u8); struct Inspector<'a>(&'a u8);
fn main() { fn main() {
let (days, inspector); let (inspector, days);
days = Box::new(1); days = Box::new(1);
inspector = Inspector(&days); inspector = Inspector(&days);
} }
@ -71,7 +71,7 @@ impl<'a> Drop for Inspector<'a> {
} }
fn main() { fn main() {
let (days, inspector); let (inspector, days);
days = Box::new(1); days = Box::new(1);
inspector = Inspector(&days); inspector = Inspector(&days);
// Let's say `days` happens to get dropped first. // Let's say `days` happens to get dropped first.
@ -85,14 +85,14 @@ fn main() {
^~~~ ^~~~
<anon>:9:11: 15:2 note: reference must be valid for the block at 9:10... <anon>:9:11: 15:2 note: reference must be valid for the block at 9:10...
<anon>:9 fn main() { <anon>:9 fn main() {
<anon>:10 let (days, inspector); <anon>:10 let (inspector, days);
<anon>:11 days = Box::new(1); <anon>:11 days = Box::new(1);
<anon>:12 inspector = Inspector(&days); <anon>:12 inspector = Inspector(&days);
<anon>:13 // Let's say `days` happens to get dropped first. <anon>:13 // Let's say `days` happens to get dropped first.
<anon>:14 // Then when Inspector is dropped, it will try to read free'd memory! <anon>:14 // Then when Inspector is dropped, it will try to read free'd memory!
... ...
<anon>:10:27: 15:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 10:26 <anon>:10:27: 15:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 10:26
<anon>:10 let (days, inspector); <anon>:10 let (inspector, days);
<anon>:11 days = Box::new(1); <anon>:11 days = Box::new(1);
<anon>:12 inspector = Inspector(&days); <anon>:12 inspector = Inspector(&days);
<anon>:13 // Let's say `days` happens to get dropped first. <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
the air. However The Big Rule is the subtlety that we have focused on this whole the air. However The Big Rule is the subtlety that we have focused on this whole
section: section:
**For a generic type to soundly implement drop, it must strictly outlive all of **For a generic type to soundly implement drop, its generics arguments must
its generic arguments.** strictly outlive it.**
This rule is sufficient but not necessary to satisfy the drop checker. That is, This rule is sufficient but not necessary to satisfy the drop checker. That is,
if your type obeys this rule then it's *definitely* sound to drop. However if your type obeys this rule then it's *definitely* sound to drop. However

@ -37,7 +37,7 @@ needs to be careful and consider exception safety.
## Vec::push_all ## Vec::push_all
`Vec::push_all` is a temporary hack to get extending a Vec by a slice reliably `Vec::push_all` is a temporary hack to get extending a Vec by a slice reliably
effecient without specialization. Here's a simple implementation: efficient without specialization. Here's a simple implementation:
```rust,ignore ```rust,ignore
impl<T: Clone> Vec<T> { impl<T: Clone> Vec<T> {

@ -1,6 +1,6 @@
% Higher-Rank Trait Bounds (HRTBs) % Higher-Rank Trait Bounds (HRTBs)
Rust's Fn traits are a little bit magic. For instance, we can write the Rust's `Fn` traits are a little bit magic. For instance, we can write the
following code: following code:
```rust ```rust
@ -52,21 +52,22 @@ fn main() {
} }
``` ```
How on earth are we supposed to express the lifetimes on F's trait bound? We need How on earth are we supposed to express the lifetimes on `F`'s trait bound? We
to provide some lifetime there, but the lifetime we care about can't be named until need to provide some lifetime there, but the lifetime we care about can't be
we enter the body of `call`! Also, that isn't some fixed lifetime; call works with named until we enter the body of `call`! Also, that isn't some fixed lifetime;
*any* lifetime `&self` happens to have at that point. call works with *any* lifetime `&self` happens to have at that point.
This job requires The Magic of Higher-Rank Trait Bounds. The way we desugar This job requires The Magic of Higher-Rank Trait Bounds (HRTBs). The way we
this is as follows: desugar this is as follows:
```rust,ignore ```rust,ignore
where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8,
``` ```
(Where `Fn(a, b, c) -> d` is itself just sugar for the unstable *real* Fn trait) (Where `Fn(a, b, c) -> d` is itself just sugar for the unstable *real* `Fn`
trait)
`for<'a>` can be read as "for all choices of `'a`", and basically produces an `for<'a>` can be read as "for all choices of `'a`", and basically produces an
*inifinite list* of trait bounds that F must satisfy. Intense. There aren't many *infinite list* of trait bounds that F must satisfy. Intense. There aren't many
places outside of the Fn traits where we encounter HRTBs, and even for those we places outside of the `Fn` traits where we encounter HRTBs, and even for
have a nice magic sugar for the common cases. those we have a nice magic sugar for the common cases.

@ -52,16 +52,17 @@ In order to "teach" borrowck that what we're doing is ok, we need to drop down
to unsafe code. For instance, mutable slices expose a `split_at_mut` function to unsafe code. For instance, mutable slices expose a `split_at_mut` function
that consumes the slice and returns *two* mutable slices. One for everything to that consumes the slice and returns *two* mutable slices. One for everything to
the left of the index, and one for everything to the right. Intuitively we know the left of the index, and one for everything to the right. Intuitively we know
this is safe because the slices don't alias. However the implementation requires this is safe because the slices don't overlap, and therefore alias. However
some unsafety: the implementation requires some unsafety:
```rust,ignore ```rust,ignore
fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
let len = self.len();
let ptr = self.as_mut_ptr();
assert!(mid <= len);
unsafe { unsafe {
let self2: &mut [T] = mem::transmute_copy(&self); (from_raw_parts_mut(ptr, mid),
from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
(ops::IndexMut::index_mut(self, ops::RangeTo { end: mid } ),
ops::IndexMut::index_mut(self2, ops::RangeFrom { start: mid } ))
} }
} }
``` ```

@ -7,11 +7,10 @@ the scope it's valid for.
Within a function body, Rust generally doesn't let you explicitly name the Within a function body, Rust generally doesn't let you explicitly name the
lifetimes involved. This is because it's generally not really *necessary* lifetimes involved. This is because it's generally not really *necessary*
to talk about lifetimes in a local context; rust has all the information and to talk about lifetimes in a local context; Rust has all the information and
can work out everything. It's also a good thing because the scope of a borrow can work out everything as optimally as possible. Many anonymous scopes and
is often significantly smaller than the scope its referent is *actually* valid temporaries that you would otherwise have to write are often introduced to
for. Rust will introduce *many* anonymous scopes and temporaries to make your make your code *just work*.
code *just work*.
However once you cross the function boundary, you need to start talking about However once you cross the function boundary, you need to start talking about
lifetimes. Lifetimes are denoted with an apostrophe: `'a`, `'static`. To dip lifetimes. Lifetimes are denoted with an apostrophe: `'a`, `'static`. To dip
@ -19,10 +18,10 @@ our toes with lifetimes, we're going to pretend that we're actually allowed
to label scopes with lifetimes, and desugar the examples from the start of to label scopes with lifetimes, and desugar the examples from the start of
this chapter. this chapter.
Originally, our examples made use of *aggressive* sugar -- high fructose corn syrup even -- Originally, our examples made use of *aggressive* sugar -- high fructose corn
around scopes and lifetimes, because writing everything out explicitly is syrup even -- around scopes and lifetimes, because writing everything out
*extremely noisy*. All Rust code relies on aggressive inference and elision of explicitly is *extremely noisy*. All Rust code relies on aggressive inference
"obvious" things. and elision of "obvious" things.
One particularly interesting piece of sugar is that each `let` statement implicitly One particularly interesting piece of sugar is that each `let` statement implicitly
introduces a scope. For the most part, this doesn't really matter. However it introduces a scope. For the most part, this doesn't really matter. However it

@ -125,13 +125,13 @@ unsafe impl UnsafeOrd for MyType {
But it's probably not the implementation you want. But it's probably not the implementation you want.
Rust has traditionally avoided making traits unsafe because it makes Unsafe Rust has traditionally avoided making traits unsafe because it makes Unsafe
pervasive, which is not desirable. Send and Sync are unsafe is because pervasive, which is not desirable. Send and Sync are unsafe is because thread
thread safety is a *fundamental property* that Unsafe cannot possibly hope to safety is a *fundamental property* that Unsafe cannot possibly hope to defend
defend against in the same way it would defend against a bad Ord implementation. against in the same way it would defend against a bad Ord implementation. The
The only way to possibly defend against thread-unsafety would be to *not use only way to possibly defend against thread-unsafety would be to *not use
threading at all*. Making every operation atomic isn't even sufficient, because threading at all*. Making every load and store atomic isn't even sufficient,
it's possible for complex invariants to exist between disjoint locations in because it's possible for complex invariants to exist between disjoint locations
memory. For instance, the pointer and capacity of a Vec must be in sync. in memory. For instance, the pointer and capacity of a Vec must be in sync.
Even concurrent paradigms that are traditionally regarded as Totally Safe like Even concurrent paradigms that are traditionally regarded as Totally Safe like
message passing implicitly rely on some notion of thread safety -- are you message passing implicitly rely on some notion of thread safety -- are you

@ -33,7 +33,7 @@ Variance is where things get a bit complicated.
Variance is a property that *type constructors* have with respect to their Variance is a property that *type constructors* have with respect to their
arguments. A type constructor in Rust is a generic type with unbound arguments. arguments. A type constructor in Rust is a generic type with unbound arguments.
For instance `Vec` is a type constructor that takes a `T` and returns a For instance `Vec` is a type constructor that takes a `T` and returns a
`Vec<T>`. `&` and `&mut` are type constructors that take a two types: a `Vec<T>`. `&` and `&mut` are type constructors that take two inputs: a
lifetime, and a type to point to. lifetime, and a type to point to.
A type constructor's *variance* is how the subtyping of its inputs affects the A type constructor's *variance* is how the subtyping of its inputs affects the
@ -54,7 +54,8 @@ Some important variances:
* `&'a T` is variant over `'a` and `T` (as is `*const T` by metaphor) * `&'a T` is variant over `'a` and `T` (as is `*const T` by metaphor)
* `&'a mut T` is variant with over `'a` but invariant over `T` * `&'a mut T` is variant with over `'a` but invariant over `T`
* `Fn(T) -> U` is invariant over `T`, but variant over `U` * `Fn(T) -> U` is invariant over `T`, but variant over `U`
* `Box`, `Vec`, and all other collections are variant over their contents * `Box`, `Vec`, and all other collections are variant over the types of
their contents
* `UnsafeCell<T>`, `Cell<T>`, `RefCell<T>`, `Mutex<T>` and all other * `UnsafeCell<T>`, `Cell<T>`, `RefCell<T>`, `Mutex<T>` and all other
interior mutability types are invariant over T (as is `*mut T` by metaphor) interior mutability types are invariant over T (as is `*mut T` by metaphor)
@ -71,7 +72,7 @@ to be able to pass `&&'static str` where an `&&'a str` is expected. The
additional level of indirection does not change the desire to be able to pass additional level of indirection does not change the desire to be able to pass
longer lived things where shorted lived things are expected. longer lived things where shorted lived things are expected.
However this logic *does not* apply to see why `&mut`. To see why &mut should However this logic *does not* apply to `&mut`. To see why `&mut` should
be invariant over T, consider the following code: be invariant over T, consider the following code:
```rust,ignore ```rust,ignore
@ -117,8 +118,9 @@ in them *via a mutable reference*! The mutable reference makes the whole type
invariant, and therefore prevents you from smuggling a short-lived type into invariant, and therefore prevents you from smuggling a short-lived type into
them. them.
Being variant *does* allows them to be weakened when shared immutably. Being variant *does* allows `Box` and `Vec` to be weakened when shared
So you can pass a `&Box<&'static str>` where a `&Box<&'a str>` is expected. immutably. So you can pass a `&Box<&'static str>` where a `&Box<&'a str>` is
expected.
However what should happen when passing *by-value* is less obvious. It turns out However what should happen when passing *by-value* is less obvious. It turns out
that, yes, you can use subtyping when passing by-value. That is, this works: that, yes, you can use subtyping when passing by-value. That is, this works:
@ -178,7 +180,7 @@ fn foo(usize) -> &'static str;
in its place. Therefore functions *are* variant over their return type. in its place. Therefore functions *are* variant over their return type.
`*const` has the exact same semantics as `&`, so variance follows. `*mut` on the `*const` has the exact same semantics as `&`, so variance follows. `*mut` on the
other hand can dereference to an &mut whether shared or not, so it is marked other hand can dereference to an `&mut` whether shared or not, so it is marked
as invariant just like cells. as invariant just like cells.
This is all well and good for the types the standard library provides, but This is all well and good for the types the standard library provides, but

@ -26,7 +26,7 @@ returns a pointer to uninitialized memory.
To handle this, we must use the `ptr` module. In particular, it provides To handle this, we must use the `ptr` module. In particular, it provides
three functions that allow us to assign bytes to a location in memory without three functions that allow us to assign bytes to a location in memory without
evaluating the old value: `write`, `copy`, and `copy_nonoverlapping`. dropping the old value: `write`, `copy`, and `copy_nonoverlapping`.
* `ptr::write(ptr, val)` takes a `val` and moves it into the address pointed * `ptr::write(ptr, val)` takes a `val` and moves it into the address pointed
to by `ptr`. to by `ptr`.
@ -35,7 +35,7 @@ evaluating the old value: `write`, `copy`, and `copy_nonoverlapping`.
order is reversed!) order is reversed!)
* `ptr::copy_nonoverlapping(src, dest, count)` does what `copy` does, but a * `ptr::copy_nonoverlapping(src, dest, count)` does what `copy` does, but a
little faster on the assumption that the two ranges of memory don't overlap. little faster on the assumption that the two ranges of memory don't overlap.
(this is equivalent to memcopy -- note that the argument order is reversed!) (this is equivalent to memcpy -- note that the argument order is reversed!)
It should go without saying that these functions, if misused, will cause serious It should go without saying that these functions, if misused, will cause serious
havoc or just straight up Undefined Behaviour. The only things that these havoc or just straight up Undefined Behaviour. The only things that these
@ -68,14 +68,14 @@ unsafe {
println!("{:?}", x); println!("{:?}", x);
``` ```
It's worth noting that you don't need to worry about ptr::write-style It's worth noting that you don't need to worry about `ptr::write`-style
shenanigans with types which don't implement Drop or shenanigans with types which don't implement `Drop` or contain `Drop` types,
contain Drop types, because Rust knows not to try to Drop them. Similarly you because Rust knows not to try to drop them. Similarly you should be able to
should be able to assign to fields of partially initialized structs assign to fields of partially initialized structs directly if those fields don't
directly if those fields don't contain any Drop types. contain any `Drop` types.
However when working with uninitialized memory you need to be ever-vigilant for However when working with uninitialized memory you need to be ever-vigilant for
Rust trying to Drop values you make like this before they're fully initialized. Rust trying to drop values you make like this before they're fully initialized.
Every control path through that variable's scope must initialize the value Every control path through that variable's scope must initialize the value
before it ends, if has a destructor. before it ends, if has a destructor.
*[This includes code panicking](unwinding.html)*. *[This includes code panicking](unwinding.html)*.

Loading…
Cancel
Save