Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 10 pull requests #37170

Merged
merged 22 commits into from
Oct 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
00098bd
Add missing urls for hash modules
GuillaumeGomez Oct 4, 2016
6a89b8f
rustdoc: color the question mark operator
est31 Oct 12, 2016
96a8bae
add missing urls for BufWriter and BufReader
GuillaumeGomez Oct 12, 2016
1eb36b8
book: remove backticks in Type Aliases header
durka Oct 12, 2016
6a738c6
run rustfmt on liblog
srinivasreddy Oct 12, 2016
5457c35
run rustfmt on libcore/num folder
srinivasreddy Oct 12, 2016
87cbfb4
Change color and make ? bold
est31 Oct 12, 2016
595b754
Changed error message E0408 to new format
faebser Sep 6, 2016
cb90723
Explain motivation behind lifetimes
Rantanen Sep 26, 2016
cd314ab
Updated RwLock Docs
omern1 Oct 13, 2016
b491ddd
Update
omern1 Oct 13, 2016
2ebef83
add (missing) tar to list of packages to get under mingw
cthulhua Oct 14, 2016
cd0c70f
Rollup merge of #36307 - faebser:E0408_new_error_format, r=GuillaumeG…
Oct 14, 2016
71a183f
Rollup merge of #36755 - Rantanen:master, r=GuillaumeGomez
Oct 14, 2016
ad40a42
Rollup merge of #36961 - GuillaumeGomez:hash_doc, r=frewsxcv
Oct 14, 2016
3da9ddb
Rollup merge of #37102 - est31:rustdoc_question_mark, r=GuillaumeGomez
Oct 14, 2016
67aaddd
Rollup merge of #37115 - GuillaumeGomez:buf_reader_urls, r=kmcallister
Oct 14, 2016
6822769
Rollup merge of #37119 - durka:patch-31, r=steveklabnik
Oct 14, 2016
72a9dcf
Rollup merge of #37122 - srinivasreddy:liblog, r=alexcrichton
Oct 14, 2016
886d47c
Rollup merge of #37123 - srinivasreddy:libcore_num, r=erickt
Oct 14, 2016
dd25442
Rollup merge of #37141 - nabeelomer:master, r=sfackler
Oct 14, 2016
881f0f8
Rollup merge of #37159 - cthulhua:readme-mingw-tar, r=alexcrichton
Oct 14, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ build.
$ pacman -S git \
make \
diffutils \
tar \
mingw-w64-x86_64-python2 \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-gcc
Expand Down
90 changes: 76 additions & 14 deletions src/doc/book/lifetimes.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,78 @@ complicated. For example, imagine this set of operations:
4. You decide to use the resource.

Uh oh! Your reference is pointing to an invalid resource. This is called a
dangling pointer or ‘use after free’, when the resource is memory.
dangling pointer or ‘use after free’, when the resource is memory. A small
example of such a situation would be:

```rust,compile_fail
let r; // Introduce reference: r
{
let i = 1; // Introduce scoped value: i
r = &i; // Store reference of i in r
} // i goes out of scope and is dropped.

println!("{}", r); // r still refers to i
```

To fix this, we have to make sure that step four never happens after step
three. The ownership system in Rust does this through a concept called
lifetimes, which describe the scope that a reference is valid for.
three. In the small example above the Rust compiler is able to report the issue
as it can see the lifetimes of the various values in the function.

When we have a function that takes arguments by reference the situation becomes
more complex. Consider the following example:

```rust,compile_fail,E0106
fn skip_prefix(line: &str, prefix: &str) -> &str {
// ...
# line
}

let line = "lang:en=Hello World!";
let lang = "en";

let v;
{
let p = format!("lang:{}=", lang); // -+ p goes into scope
v = skip_prefix(line, p.as_str()); // |
} // -+ p goes out of scope
println!("{}", v);
```

Here we have a function `skip_prefix` which takes two `&str` references
as parameters and returns a single `&str` reference. We call it
by passing in references to `line` and `p`: Two variables with different
lifetimes. Now the safety of the `println!`-line depends on whether the
reference returned by `skip_prefix` function references the still living
`line` or the already dropped `p` string.

Because of the above ambiguity, Rust will refuse to compile the example
code. To get it to compile we need to tell the compiler more about the
lifetimes of the references. This can be done by making the lifetimes
explicit in the function declaration:

```rust
fn skip_prefix<'a, 'b>(line: &'a str, prefix: &'b str) -> &'a str {
// ...
# line
}
```

Let's examine the changes without going too deep into the syntax for now -
we'll get to that later. The first change was adding the `<'a, 'b>` after the
method name. This introduces two lifetime parameters: `'a` and `'b`. Next each
reference in the function signature was associated with one of the lifetime
parameters by adding the lifetime name after the `&`. This tells the compiler
how the lifetimes between different references are related.

As a result the compiler is now able to deduce that the return value of
`skip_prefix` has the same lifetime as the `line` parameter, which makes the `v`
reference safe to use even after the `p` goes out of scope in the original
example.

In addition to the compiler being able to validate the usage of `skip_prefix`
return value, it can also ensure that the implementation follows the contract
established by the function declaration. This is useful especially when you are
implementing traits that are introduced [later in the book][traits].

**Note** It's important to understand that lifetime annotations are
_descriptive_, not _prescriptive_. This means that how long a reference is valid
Expand All @@ -63,20 +130,14 @@ give information about lifetimes to the compiler that uses them to check the
validity of references. The compiler can do so without annotations in simple
cases, but needs the programmers support in complex scenarios.

```rust
// implicit
fn foo(x: &i32) {
}
[traits]: traits.html

// explicit
fn bar<'a>(x: &'a i32) {
}
```
# Syntax

The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime
associated with it, but the compiler lets you elide (i.e. omit, see
["Lifetime Elision"][lifetime-elision] below) them in common cases.
Before we get to that, though, let’s break the explicit example down:
["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we
get to that, though, let’s look at a short example with explicit lifetimes:

[lifetime-elision]: #lifetime-elision

Expand All @@ -94,7 +155,8 @@ focus on the lifetimes aspect.
[generics]: generics.html

We use `<>` to declare our lifetimes. This says that `bar` has one lifetime,
`'a`. If we had two reference parameters, it would look like this:
`'a`. If we had two reference parameters with different lifetimes, it would
look like this:


```rust,ignore
Expand Down
2 changes: 1 addition & 1 deletion src/doc/book/type-aliases.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
% `type` Aliases
% Type Aliases

The `type` keyword lets you declare an alias of another type:

Expand Down
37 changes: 22 additions & 15 deletions src/libcore/hash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@
//! ```
//!
//! If you need more control over how a value is hashed, you need to implement
//! the `Hash` trait:
//! the [`Hash`] trait:
//!
//! [`Hash`]: trait.Hash.html
//!
//! ```rust
//! use std::hash::{Hash, Hasher, SipHasher};
Expand Down Expand Up @@ -90,21 +92,21 @@ mod sip;
/// The `H` type parameter is an abstract hash state that is used by the `Hash`
/// to compute the hash.
///
/// If you are also implementing `Eq`, there is an additional property that
/// If you are also implementing [`Eq`], there is an additional property that
/// is important:
///
/// ```text
/// k1 == k2 -> hash(k1) == hash(k2)
/// ```
///
/// In other words, if two keys are equal, their hashes should also be equal.
/// `HashMap` and `HashSet` both rely on this behavior.
/// [`HashMap`] and [`HashSet`] both rely on this behavior.
///
/// ## Derivable
///
/// This trait can be used with `#[derive]` if all fields implement `Hash`.
/// When `derive`d, the resulting hash will be the combination of the values
/// from calling `.hash()` on each field.
/// from calling [`.hash()`] on each field.
///
/// ## How can I implement `Hash`?
///
Expand All @@ -127,6 +129,11 @@ mod sip;
/// }
/// }
/// ```
///
/// [`Eq`]: ../../std/cmp/trait.Eq.html
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
/// [`.hash()`]: #tymethod.hash
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Hash {
/// Feeds this value into the state given, updating the hasher as necessary.
Expand All @@ -151,35 +158,35 @@ pub trait Hasher {
#[stable(feature = "rust1", since = "1.0.0")]
fn finish(&self) -> u64;

/// Writes some data into this `Hasher`
/// Writes some data into this `Hasher`.
#[stable(feature = "rust1", since = "1.0.0")]
fn write(&mut self, bytes: &[u8]);

/// Write a single `u8` into this hasher
/// Write a single `u8` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u8(&mut self, i: u8) {
self.write(&[i])
}
/// Write a single `u16` into this hasher.
/// Writes a single `u16` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u16(&mut self, i: u16) {
self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) })
}
/// Write a single `u32` into this hasher.
/// Writes a single `u32` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u32(&mut self, i: u32) {
self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) })
}
/// Write a single `u64` into this hasher.
/// Writes a single `u64` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u64(&mut self, i: u64) {
self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) })
}
/// Write a single `usize` into this hasher.
/// Writes a single `usize` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_usize(&mut self, i: usize) {
Expand All @@ -189,31 +196,31 @@ pub trait Hasher {
self.write(bytes);
}

/// Write a single `i8` into this hasher.
/// Writes a single `i8` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i8(&mut self, i: i8) {
self.write_u8(i as u8)
}
/// Write a single `i16` into this hasher.
/// Writes a single `i16` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i16(&mut self, i: i16) {
self.write_u16(i as u16)
}
/// Write a single `i32` into this hasher.
/// Writes a single `i32` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i32(&mut self, i: i32) {
self.write_u32(i as u32)
}
/// Write a single `i64` into this hasher.
/// Writes a single `i64` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i64(&mut self, i: i64) {
self.write_u64(i as u64)
}
/// Write a single `isize` into this hasher.
/// Writes a single `isize` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_isize(&mut self, i: isize) {
Expand Down
17 changes: 8 additions & 9 deletions src/libcore/num/bignum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,22 @@ use intrinsics;
pub trait FullOps: Sized {
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
/// where `W` is the number of bits in `Self`.
fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
fn full_add(self, other: Self, carry: bool) -> (bool /* carry */, Self);

/// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
/// where `W` is the number of bits in `Self`.
fn full_mul(self, other: Self, carry: Self) -> (Self /*carry*/, Self);
fn full_mul(self, other: Self, carry: Self) -> (Self /* carry */, Self);

/// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
/// where `W` is the number of bits in `Self`.
fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /*carry*/, Self);
fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self);

/// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem`
/// and `0 <= rem < other`, where `W` is the number of bits in `Self`.
fn full_div_rem(self, other: Self, borrow: Self) -> (Self /*quotient*/, Self /*remainder*/);
fn full_div_rem(self,
other: Self,
borrow: Self)
-> (Self /* quotient */, Self /* remainder */);
}

macro_rules! impl_full_ops {
Expand Down Expand Up @@ -100,11 +103,7 @@ impl_full_ops! {

/// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value
/// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`.
const SMALL_POW5: [(u64, usize); 3] = [
(125, 3),
(15625, 6),
(1_220_703_125, 13),
];
const SMALL_POW5: [(u64, usize); 3] = [(125, 3), (15625, 6), (1_220_703_125, 13)];

macro_rules! define_bignum {
($name:ident: type=$ty:ty, n=$n:expr) => (
Expand Down
35 changes: 28 additions & 7 deletions src/libcore/num/diy_float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,30 @@ impl Fp {
pub fn normalize(&self) -> Fp {
let mut f = self.f;
let mut e = self.e;
if f >> (64 - 32) == 0 { f <<= 32; e -= 32; }
if f >> (64 - 16) == 0 { f <<= 16; e -= 16; }
if f >> (64 - 8) == 0 { f <<= 8; e -= 8; }
if f >> (64 - 4) == 0 { f <<= 4; e -= 4; }
if f >> (64 - 2) == 0 { f <<= 2; e -= 2; }
if f >> (64 - 1) == 0 { f <<= 1; e -= 1; }
if f >> (64 - 32) == 0 {
f <<= 32;
e -= 32;
}
if f >> (64 - 16) == 0 {
f <<= 16;
e -= 16;
}
if f >> (64 - 8) == 0 {
f <<= 8;
e -= 8;
}
if f >> (64 - 4) == 0 {
f <<= 4;
e -= 4;
}
if f >> (64 - 2) == 0 {
f <<= 2;
e -= 2;
}
if f >> (64 - 1) == 0 {
f <<= 1;
e -= 1;
}
debug_assert!(f >= (1 >> 63));
Fp { f: f, e: e }
}
Expand All @@ -66,6 +84,9 @@ impl Fp {
assert!(edelta >= 0);
let edelta = edelta as usize;
assert_eq!(self.f << edelta >> edelta, self.f);
Fp { f: self.f << edelta, e: e }
Fp {
f: self.f << edelta,
e: e,
}
}
}
Loading