diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index fa4e0304d1a0f..92e2fd93df406 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -109,7 +109,7 @@ This does mean that indexed access to a Unicode codepoint inside a `str` value i * Most "character oriented" operations on text only work under very restricted language assumptions sets such as "ASCII-range codepoints only". Outside ASCII-range, you tend to have to use a complex (non-constant-time) algorithm for determining linguistic-unit (glyph, word, paragraph) boundaries anyways. We recommend using an "honest" linguistically-aware, Unicode-approved algorithm. * The `char` type is UCS4. If you honestly need to do a codepoint-at-a-time algorithm, it's trivial to write a `type wstr = [char]`, and unpack a `str` into it in a single pass, then work with the `wstr`. In other words: the fact that the language is not "decoding to UCS4 by default" shouldn't stop you from decoding (or re-encoding any other way) if you need to work with that encoding. -## Why are strings, vectors etc. built-in types rather than (say) special kinds of trait/impl? +## Why are `str`s, slices, arrays etc. built-in types rather than (say) special kinds of trait/impl? In each case there is one or more operator, literal constructor, overloaded use or integration with a built-in control structure that makes us think it would be awkward to phrase the type in terms of more-general type constructors. Same as, say, with numbers! But this is partly an aesthetic call, and we'd be willing to look at a worked-out proposal for eliminating or rephrasing these special cases. diff --git a/src/doc/reference.md b/src/doc/reference.md index 3918a558cb330..8103ce8f7f6cc 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2044,12 +2044,12 @@ A complete list of the built-in language items will be added in the future. ### Inline attributes -The inline attribute is used to suggest to the compiler to perform an inline -expansion and place a copy of the function or static in the caller rather than -generating code to call the function or access the static where it is defined. +The inline attribute suggests that the compiler should place a copy of +the function or static in the caller, rather than generating code to +call the function or access the static where it is defined. The compiler automatically inlines functions based on internal heuristics. -Incorrectly inlining functions can actually making the program slower, so it +Incorrectly inlining functions can actually make the program slower, so it should be used with care. Immutable statics are always considered inlineable unless marked with @@ -2057,8 +2057,8 @@ Immutable statics are always considered inlineable unless marked with have the same memory address. In other words, the compiler is free to collapse duplicate inlineable statics together. -`#[inline]` and `#[inline(always)]` always causes the function to be serialized -into crate metadata to allow cross-crate inlining. +`#[inline]` and `#[inline(always)]` always cause the function to be serialized +into the crate metadata to allow cross-crate inlining. There are three different types of inline attributes: diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index 119bbf7fb2a84..89f0db8dc56f3 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -40,6 +40,11 @@ want to dive in with a project, or ‘Syntax and Semantics’ if you prefer to start small, and learn a single concept thoroughly before moving onto the next. Copious cross-linking connects these parts together. +### Contributing + +The source files from which this book is generated can be found on Github: +[github.com/rust-lang/rust/tree/master/src/doc/trpl](https://github.com/rust-lang/rust/tree/master/src/doc/trpl) + ## A brief introduction to Rust Is Rust a language you might be interested in? Let’s examine a few small code diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index fb04b323cb05c..de7ded76280f6 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -27,7 +27,6 @@ * [References and Borrowing](references-and-borrowing.md) * [Lifetimes](lifetimes.md) * [Mutability](mutability.md) - * [Move semantics](move-semantics.md) * [Enums](enums.md) * [Match](match.md) * [Structs](structs.md) @@ -65,5 +64,6 @@ * [Benchmark Tests](benchmark-tests.md) * [Box Syntax and Patterns](box-syntax-and-patterns.md) * [Slice Patterns](slice-patterns.md) + * [Associated Constants](associated-constants.md) * [Glossary](glossary.md) * [Academic Research](academic-research.md) diff --git a/src/doc/trpl/associated-constants.md b/src/doc/trpl/associated-constants.md new file mode 100644 index 0000000000000..1c097be6d68a6 --- /dev/null +++ b/src/doc/trpl/associated-constants.md @@ -0,0 +1,79 @@ +% Associated Constants + +With the `associated_consts` feature, you can define constants like this: + +```rust +#![feature(associated_consts)] + +trait Foo { + const ID: i32; +} + +impl Foo for i32 { + const ID: i32 = 1; +} + +fn main() { + assert_eq!(1, i32::ID); +} +``` + +Any implementor of `Foo` will have to define `ID`. Without the definition: + +```rust,ignore +#![feature(associated_consts)] + +trait Foo { + const ID: i32; +} + +impl Foo for i32 { +} +``` + +gives + +```text +error: not all trait items implemented, missing: `ID` [E0046] + impl Foo for i32 { + } +``` + +A default value can be implemented as well: + +```rust +#![feature(associated_consts)] + +trait Foo { + const ID: i32 = 1; +} + +impl Foo for i32 { +} + +impl Foo for i64 { + const ID: i32 = 5; +} + +fn main() { + assert_eq!(1, i32::ID); + assert_eq!(5, i64::ID); +} +``` + +As you can see, when implementing `Foo`, you can leave it unimplemented, as +with `i32`. It will then use the default value. But, as in `i64`, we can also +add our own definition. + +Associated constants don’t have to be associated with a trait. An `impl` block +for a `struct` works fine too: + +```rust +#![feature(associated_consts)] + +struct Foo; + +impl Foo { + pub const FOO: u32 = 3; +} +``` diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index e261eb01dba3e..e4809214bd48e 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -252,7 +252,7 @@ struct Info { } fn write_info(info: &Info) -> io::Result<()> { - let mut file = File::open("my_best_friends.txt").unwrap(); + let mut file = File::create("my_best_friends.txt").unwrap(); if let Err(e) = writeln!(&mut file, "name: {}", info.name) { return Err(e) @@ -282,7 +282,7 @@ struct Info { } fn write_info(info: &Info) -> io::Result<()> { - let mut file = try!(File::open("my_best_friends.txt")); + let mut file = try!(File::create("my_best_friends.txt")); try!(writeln!(&mut file, "name: {}", info.name)); try!(writeln!(&mut file, "age: {}", info.age)); diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index d547451fccec2..cc8747d1fa7c1 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -5,7 +5,7 @@ projects. Cargo is currently in a pre-1.0 state, and so it is still a work in progress. However, it is already good enough to use for many Rust projects, and so it is assumed that Rust projects will use Cargo from the beginning. -[cratesio]: https://doc.crates.io +[cratesio]: http://doc.crates.io Cargo manages three things: building your code, downloading the dependencies your code needs, and building those dependencies. At first, your diff --git a/src/doc/trpl/if-let.md b/src/doc/trpl/if-let.md index 7173303e3b152..4872ed6a77347 100644 --- a/src/doc/trpl/if-let.md +++ b/src/doc/trpl/if-let.md @@ -65,7 +65,7 @@ loop as long as a value matches a certain pattern. It turns code like this: loop { match option { Some(x) => println!("{}", x), - _ => break, + _ => break, } } ``` diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index 58d9e57dc51cc..b8230f060e073 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -6,16 +6,16 @@ or a Mac, all you need to do is this (note that you don't need to type in the `$`s, they just indicate the start of each command): ```bash -$ curl -sf -L https://static.rust-lang.org/rustup.sh | sudo sh +$ curl -sf -L https://static.rust-lang.org/rustup.sh | sh ``` If you're concerned about the [potential insecurity][insecurity] of using `curl -| sudo sh`, please keep reading and see our disclaimer below. And feel free to +| sh`, please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: ```bash $ curl -f -L https://static.rust-lang.org/rustup.sh -O -$ sudo sh rustup.sh +$ sh rustup.sh ``` [insecurity]: http://curlpipesh.tumblr.com @@ -40,13 +40,11 @@ If you used the Windows installer, just re-run the `.msi` and it will give you an uninstall option. Some people, and somewhat rightfully so, get very upset when we tell you to -`curl | sudo sh`. Basically, when you do this, you are trusting that the good +`curl | sh`. Basically, when you do this, you are trusting that the good people who maintain Rust aren't going to hack your computer and do bad things. That's a good instinct! If you're one of those people, please check out the documentation on [building Rust from Source][from source], or [the official -binary downloads][install page]. And we promise that this method will not be -the way to install Rust forever: it's just the easiest way to keep people -updated while Rust is in its alpha state. +binary downloads][install page]. [from source]: https://github.com/rust-lang/rust#building-from-source [install page]: http://www.rust-lang.org/install.html diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index cfcd8c4ee155a..981286c82d798 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -1,3 +1,297 @@ % Lifetimes -Coming Soon! Until then, check out the [ownership](ownership.html) chapter. +This guide is one of three presenting Rust’s ownership system. This is one of +Rust’s most unique and compelling features, with which Rust developers should +become quite acquainted. Ownership is how Rust achieves its largest goal, +memory safety. There are a few distinct concepts, each with its own chapter: + +* [ownership][ownership], ownership, the key concept +* [borrowing][borrowing], and their associated feature ‘references’ +* lifetimes, which you’re reading now + +These three chapters are related, and in order. You’ll need all three to fully +understand the ownership system. + +[ownership]: ownership.html +[borrowing]: references-and-borrowing.html + +# Meta + +Before we get to the details, two important notes about the ownership system. + +Rust has a focus on safety and speed. It accomplishes these goals through many +‘zero-cost abstractions’, which means that in Rust, abstractions cost as little +as possible in order to make them work. The ownership system is a prime example +of a zero-cost abstraction. All of the analysis we’ll talk about in this guide +is _done at compile time_. You do not pay any run-time cost for any of these +features. + +However, this system does have a certain cost: learning curve. Many new users +to Rust experience something we like to call ‘fighting with the borrow +checker’, where the Rust compiler refuses to compile a program that the author +thinks is valid. This often happens because the programmer’s mental model of +how ownership should work doesn’t match the actual rules that Rust implements. +You probably will experience similar things at first. There is good news, +however: more experienced Rust developers report that once they work with the +rules of the ownership system for a period of time, they fight the borrow +checker less and less. + +With that in mind, let’s learn about lifetimes. + +# Lifetimes + +Lending out a reference to a resource that someone else owns can be +complicated, however. For example, imagine this set of operations: + +- I acquire a handle to some kind of resource. +- I lend you a reference to the resource. +- I decide I’m done with the resource, and deallocate it, while you still have + your reference. +- 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. + +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. + +When we have a function that takes a reference by argument, we can be implicit +or explicit about the lifetime of the reference: + +```rust +// implicit +fn foo(x: &i32) { +} + +// explicit +fn bar<'a>(x: &'a i32) { +} +``` + +The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime +associated with it, but the compiler lets you elide them in common cases. +Before we get to that, though, let’s break the explicit example down: + +```rust,ignore +fn bar<'a>(...) +``` + +This part declares our lifetimes. This says that `bar` has one lifetime, `'a`. +If we had two reference parameters, it would look like this: + +```rust,ignore +fn bar<'a, 'b>(...) +``` + +Then in our parameter list, we use the lifetimes we’ve named: + +```rust,ignore +...(x: &'a i32) +``` + +If we wanted an `&mut` reference, we’d do this: + +```rust,ignore +...(x: &'a mut i32) +``` + +If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s just that +the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut +i32` as ‘a mutable reference to an i32’ and `&'a mut i32` as ‘a mutable +reference to an `i32` with the lifetime `'a`’. + +You’ll also need explicit lifetimes when working with [`struct`][structs]s: + +```rust +struct Foo<'a> { + x: &'a i32, +} + +fn main() { + let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let f = Foo { x: y }; + + println!("{}", f.x); +} +``` + +[struct]: structs.html + +As you can see, `struct`s can also have lifetimes. In a similar way to functions, + +```rust +struct Foo<'a> { +# x: &'a i32, +# } +``` + +declares a lifetime, and + +```rust +# struct Foo<'a> { +x: &'a i32, +# } +``` + +uses it. So why do we need a lifetime here? We need to ensure that any reference +to a `Foo` cannot outlive the reference to an `i32` it contains. + +## Thinking in scopes + +A way to think about lifetimes is to visualize the scope that a reference is +valid for. For example: + +```rust +fn main() { + let y = &5; // -+ y goes into scope + // | + // stuff // | + // | +} // -+ y goes out of scope +``` + +Adding in our `Foo`: + +```rust +struct Foo<'a> { + x: &'a i32, +} + +fn main() { + let y = &5; // -+ y goes into scope + let f = Foo { x: y }; // -+ f goes into scope + // stuff // | + // | +} // -+ f and y go out of scope +``` + +Our `f` lives within the scope of `y`, so everything works. What if it didn’t? +This code won’t work: + +```rust,ignore +struct Foo<'a> { + x: &'a i32, +} + +fn main() { + let x; // -+ x goes into scope + // | + { // | + let y = &5; // ---+ y goes into scope + let f = Foo { x: y }; // ---+ f goes into scope + x = &f.x; // | | error here + } // ---+ f and y go out of scope + // | + println!("{}", x); // | +} // -+ x goes out of scope +``` + +Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope +of `x`. But when we do `x = &f.x`, we make `x` a reference to something that’s +about to go out of scope. + +Named lifetimes are a way of giving these scopes a name. Giving something a +name is the first step towards being able to talk about it. + +## 'static + +The lifetime named ‘static’ is a special lifetime. It signals that something +has the lifetime of the entire program. Most Rust programmers first come across +`'static` when dealing with strings: + +```rust +let x: &'static str = "Hello, world."; +``` + +String literals have the type `&'static str` because the reference is always +alive: they are baked into the data segment of the final binary. Another +example are globals: + +```rust +static FOO: i32 = 5; +let x: &'static i32 = &FOO; +``` + +This adds an `i32` to the data segment of the binary, and `x` is a reference +to it. + +## Lifetime Elision + +Rust supports powerful local type inference in function bodies, but it’s +forbidden in item signatures to allow reasoning about the types just based in +the item signature alone. However, for ergonomic reasons a very restricted +secondary inference algorithm called “lifetime elision” applies in function +signatures. It infers only based on the signature components themselves and not +based on the body of the function, only infers lifetime parameters, and does +this with only three easily memorizable and unambiguous rules. This makes +lifetime elision a shorthand for writing an item signature, while not hiding +away the actual types involved as full local inference would if applied to it. + +When talking about lifetime elision, we use the term *input lifetime* and +*output lifetime*. An *input lifetime* is a lifetime associated with a parameter +of a function, and an *output lifetime* is a lifetime associated with the return +value of a function. For example, this function has an input lifetime: + +```rust,ignore +fn foo<'a>(bar: &'a str) +``` + +This one has an output lifetime: + +```rust,ignore +fn foo<'a>() -> &'a str +``` + +This one has a lifetime in both positions: + +```rust,ignore +fn foo<'a>(bar: &'a str) -> &'a str +``` + +Here are the three rules: + +* Each elided lifetime in a function’s arguments becomes a distinct lifetime + parameter. + +* If there is exactly one input lifetime, elided or not, that lifetime is + assigned to all elided lifetimes in the return values of that function. + +* If there are multiple input lifetimes, but one of them is `&self` or `&mut + self`, the lifetime of `self` is assigned to all elided output lifetimes. + +Otherwise, it is an error to elide an output lifetime. + +### Examples + +Here are some examples of functions with elided lifetimes. We’ve paired each +example of an elided lifetime with its expanded form. + +```rust,ignore +fn print(s: &str); // elided +fn print<'a>(s: &'a str); // expanded + +fn debug(lvl: u32, s: &str); // elided +fn debug<'a>(lvl: u32, s: &'a str); // expanded + +// In the preceding example, `lvl` doesn’t need a lifetime because it’s not a +// reference (`&`). Only things relating to references (such as a `struct` +// which contains a reference) need lifetimes. + +fn substr(s: &str, until: u32) -> &str; // elided +fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded + +fn get_str() -> &str; // ILLEGAL, no inputs + +fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs +fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is unclear + +fn get_mut(&mut self) -> &mut T; // elided +fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded + +fn args(&mut self, args: &[T]) -> &mut Command // elided +fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded + +fn new(buf: &mut [u8]) -> BufWriter; // elided +fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded +``` diff --git a/src/doc/trpl/move-semantics.md b/src/doc/trpl/move-semantics.md deleted file mode 100644 index b5bd53e1d75a1..0000000000000 --- a/src/doc/trpl/move-semantics.md +++ /dev/null @@ -1,105 +0,0 @@ -% Move Semantics - -An important aspect of [ownership][ownership] is ‘move semantics’. Move -semantics control how and when ownership is transferred between bindings. - -[ownership]: ownership.html - -For example, consider a type like `Vec`, which owns its contents: - -```rust -let v = vec![1, 2, 3]; -``` - -I can assign this vector to another binding: - -```rust -let v = vec![1, 2, 3]; - -let v2 = v; -``` - -But, if we try to use `v` afterwards, we get an error: - -```rust,ignore -let v = vec![1, 2, 3]; - -let v2 = v; - -println!("v[0] is: {}", v[0]); -``` - -It looks like this: - -```text -error: use of moved value: `v` -println!("v[0] is: {}", v[0]); - ^ -``` - -A similar thing happens if we define a function which takes ownership, and -try to use something after we’ve passed it as an argument: - -```rust,ignore -fn take(v: Vec) { - // what happens here isn’t important. -} - -let v = vec![1, 2, 3]; - -take(v); - -println!("v[0] is: {}", v[0]); -``` - -Same error: “use of moved value.” When we transfer ownership to something else, -we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of -special annotation here, it’s the default thing that Rust does. - -# The details - -The reason that we cannot use a binding after we’ve moved it is subtle, but -important. When we write code like this: - -```rust -let v = vec![1, 2, 3]; - -let v2 = v; -``` - -The first line creates some data for the vector on the stack, `v`. The vector’s -data, however, is stored on the heap, and so it contains a pointer to that -data. When we move `v` to `v2`, it creates a copy of that data, for `v2`. Which -would mean two pointers to the contents of the vector on the heap. That would -be a problem: it would violate Rust’s safety guarantees by introducing a data -race. Therefore, Rust forbids using `v` after we’ve done the move. - -It’s also important to note that optimizations may remove the actual copy of -the bytes, depending on circumstances. So it may not be as inefficient as it -initially seems. - -# `Copy` types - -We’ve established that when ownership is transferred to another binding, you -cannot use the original binding. However, there’s a [trait][traits] that changes this -behavior, and it’s called `Copy`. We haven’t discussed traits yet, but for now, -you can think of them as an annotation to a particular type that adds extra -behavior. For example: - -```rust -let v = 1; - -let v2 = v; - -println!("v is: {}", v); -``` - -In this case, `v` is an `i32`, which implements the `Copy` trait. This means -that, just like a move, when we assign `v` to `v2`, a copy of the data is made. -But, unlike a move, we can still use `v` afterward. This is because an `i32` -has no pointers to data somewhere else, copying it is a full copy. - -We will discuss how to make your own types `Copy` in the [traits][traits] -section. - -[traits]: traits.html diff --git a/src/doc/trpl/nightly-rust.md b/src/doc/trpl/nightly-rust.md index 1cb62e8b2d3e9..2f3055deb04e0 100644 --- a/src/doc/trpl/nightly-rust.md +++ b/src/doc/trpl/nightly-rust.md @@ -9,16 +9,16 @@ process, see ‘[Stability as a deliverable][stability]’. To install nightly Rust, you can use `rustup.sh`: ```bash -$ curl -s https://static.rust-lang.org/rustup.sh | sudo sh -s -- --channel=nightly +$ curl -s https://static.rust-lang.org/rustup.sh | sh -s -- --channel=nightly ``` If you're concerned about the [potential insecurity][insecurity] of using `curl -| sudo sh`, please keep reading and see our disclaimer below. And feel free to +| sh`, please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: ```bash $ curl -f -L https://static.rust-lang.org/rustup.sh -O -$ sudo sh rustup.sh --channel=nightly +$ sh rustup.sh --channel=nightly ``` [insecurity]: http://curlpipesh.tumblr.com @@ -43,13 +43,11 @@ If you used the Windows installer, just re-run the `.msi` and it will give you an uninstall option. Some people, and somewhat rightfully so, get very upset when we tell you to -`curl | sudo sh`. Basically, when you do this, you are trusting that the good +`curl | sh`. Basically, when you do this, you are trusting that the good people who maintain Rust aren't going to hack your computer and do bad things. That's a good instinct! If you're one of those people, please check out the documentation on [building Rust from Source][from source], or [the official -binary downloads][install page]. And we promise that this method will not be -the way to install Rust forever: it's just the easiest way to keep people -updated while Rust is in its alpha state. +binary downloads][install page]. [from source]: https://github.com/rust-lang/rust#building-from-source [install page]: http://www.rust-lang.org/install.html diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 223085cc40b8e..3003156f875aa 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -1,555 +1,207 @@ % Ownership -This guide presents Rust's ownership system. This is one of Rust's most unique -and compelling features, with which Rust developers should become quite -acquainted. Ownership is how Rust achieves its largest goal, memory safety. -The ownership system has a few distinct concepts: *ownership*, *borrowing*, -and *lifetimes*. We'll talk about each one in turn. +This guide is one of three presenting Rust’s ownership system. This is one of +Rust’s most unique and compelling features, with which Rust developers should +become quite acquainted. Ownership is how Rust achieves its largest goal, +memory safety. The there are a few distinct concepts, each with its own +chapter: + +* ownership, which you’re reading now. +* [borrowing][borrowing], and their associated feature ‘references’ +* [lifetimes][lifetimes], an advanced concept of borrowing + +These three chapters are related, and in order. You’ll need all three to fully +understand the ownership system. + +[borrowing]: references-and-borrowing.html +[lifetimes]: lifetimes.html # Meta Before we get to the details, two important notes about the ownership system. Rust has a focus on safety and speed. It accomplishes these goals through many -*zero-cost abstractions*, which means that in Rust, abstractions cost as little +‘zero-cost abstractions’, which means that in Rust, abstractions cost as little as possible in order to make them work. The ownership system is a prime example -of a zero cost abstraction. All of the analysis we'll talk about in this guide +of a zero cost abstraction. All of the analysis we’ll talk about in this guide is _done at compile time_. You do not pay any run-time cost for any of these features. However, this system does have a certain cost: learning curve. Many new users -to Rust experience something we like to call "fighting with the borrow -checker," where the Rust compiler refuses to compile a program that the author -thinks is valid. This often happens because the programmer's mental model of -how ownership should work doesn't match the actual rules that Rust implements. +to Rust experience something we like to call ‘fighting with the borrow +checker’, where the Rust compiler refuses to compile a program that the author +thinks is valid. This often happens because the programmer’s mental model of +how ownership should work doesn’t match the actual rules that Rust implements. You probably will experience similar things at first. There is good news, however: more experienced Rust developers report that once they work with the rules of the ownership system for a period of time, they fight the borrow checker less and less. -With that in mind, let's learn about ownership. +With that in mind, let’s learn about ownership. # Ownership -At its core, ownership is about *resources*. For the purposes of the vast -majority of this guide, we will talk about a specific resource: memory. The -concept generalizes to any kind of resource, like a file handle, but to make it -more concrete, we'll focus on memory. - -When your program allocates some memory, it needs some way to deallocate that -memory. Imagine a function `foo` that allocates four bytes of memory, and then -never deallocates that memory. We call this problem *leaking* memory, because -each time we call `foo`, we're allocating another four bytes. Eventually, with -enough calls to `foo`, we will run our system out of memory. That's no good. So -we need some way for `foo` to deallocate those four bytes. It's also important -that we don't deallocate too many times, either. Without getting into the -details, attempting to deallocate memory multiple times can lead to problems. -In other words, any time some memory is allocated, we need to make sure that we -deallocate that memory once and only once. Too many times is bad, not enough -times is bad. The counts must match. - -There's one other important detail with regards to allocating memory. Whenever -we request some amount of memory, what we are given is a handle to that memory. -This handle (often called a *pointer*, when we're referring to memory) is how -we interact with the allocated memory. As long as we have that handle, we can -do something with the memory. Once we're done with the handle, we're also done -with the memory, as we can't do anything useful without a handle to it. - -Historically, systems programming languages require you to track these -allocations, deallocations, and handles yourself. For example, if we want some -memory from the heap in a language like C, we do this: - -```c -{ - int *x = malloc(sizeof(int)); - - // we can now do stuff with our handle x - *x = 5; - - free(x); -} -``` - -The call to `malloc` allocates some memory. The call to `free` deallocates the -memory. There's also bookkeeping about allocating the correct amount of memory. - -Rust combines these two aspects of allocating memory (and other resources) into -a concept called *ownership*. Whenever we request some memory, that handle we -receive is called the *owning handle*. Whenever that handle goes out of scope, -Rust knows that you cannot do anything with the memory anymore, and so -therefore deallocates the memory for you. Here's the equivalent example in -Rust: +[`Variable bindings`][bindings] have a property in Rust: they ‘have ownership’ +of what they’re bound to. This means that when a binding goes out of scope, the +resource that they’re bound to are freed. For example: ```rust -{ - let x = Box::new(5); -} -``` - -The `Box::new` function creates a `Box` (specifically `Box` in this -case) by allocating a small segment of memory on the heap with enough space to -fit an `i32`. But where in the code is the box deallocated? We said before that -we must have a deallocation for each allocation. Rust handles this for you. It -knows that our handle, `x`, is the owning reference to our box. Rust knows that -`x` will go out of scope at the end of the block, and so it inserts a call to -deallocate the memory at the end of the scope. Because the compiler does this -for us, it's impossible to forget. We always have exactly one deallocation - paired with each of our allocations. - -This is pretty straightforward, but what happens when we want to pass our box -to a function? Let's look at some code: - -```rust -fn main() { - let x = Box::new(5); - - add_one(x); -} - -fn add_one(mut num: Box) { - *num += 1; +fn foo() { + let v = vec![1, 2, 3]; } ``` -This code works, but it's not ideal. For example, let's add one more line of -code, where we print out the value of `x`: - -```{rust,ignore} -fn main() { - let x = Box::new(5); +When `v` comes into scope, a new [`Vec`][vect] is created. In this case, the +vector also allocates space on [the heap][heap], for the three elements. When +`v` goes out of scope at the end of `foo()`, Rust will clean up everything +related to the vector, even the heap-allocated memory. This happens +deterministically, at the end of the scope. - add_one(x); - - println!("{}", x); -} +[vect]: ../std/vec/struct.Vec.html +[heap]: the-stack-and-the-heap.html -fn add_one(mut num: Box) { - *num += 1; -} -``` +# Move semantics -This does not compile, and gives us an error: - -```text -error: use of moved value: `x` - println!("{}", x); - ^ -``` - -Remember, we need one deallocation for every allocation. When we try to pass -our box to `add_one`, we would have two handles to the memory: `x` in `main`, -and `num` in `add_one`. If we deallocated the memory when each handle went out -of scope, we would have two deallocations and one allocation, and that's wrong. -So when we call `add_one`, Rust defines `num` as the owner of the handle. And -so, now that we've given ownership to `num`, `x` is invalid. `x`'s value has -"moved" from `x` to `num`. Hence the error: use of moved value `x`. - -To fix this, we can have `add_one` give ownership back when it's done with the -box: +There’s some more subtlety here, though: Rust ensures that there is _exactly +one_ binding to any given resource. For example, if we have a vector, we can +assign it to another binding: ```rust -fn main() { - let x = Box::new(5); - - let y = add_one(x); - - println!("{}", y); -} - -fn add_one(mut num: Box) -> Box { - *num += 1; +let v = vec![1, 2, 3]; - num -} +let v2 = v; ``` -This code will compile and run just fine. Now, we return a `box`, and so the -ownership is transferred back to `y` in `main`. We only have ownership for the -duration of our function before giving it back. This pattern is very common, -and so Rust introduces a concept to describe a handle which temporarily refers -to something another handle owns. It's called *borrowing*, and it's done with -*references*, designated by the `&` symbol. - -# Borrowing +But, if we try to use `v` afterwards, we get an error: -Here's the current state of our `add_one` function: +```rust,ignore +let v = vec![1, 2, 3]; -```rust -fn add_one(mut num: Box) -> Box { - *num += 1; +let v2 = v; - num -} +println!("v[0] is: {}", v[0]); ``` -This function takes ownership, because it takes a `Box`, which owns its -contents. But then we give ownership right back. - -In the physical world, you can give one of your possessions to someone for a -short period of time. You still own your possession, you're just letting someone -else use it for a while. We call that *lending* something to someone, and that -person is said to be *borrowing* that something from you. - -Rust's ownership system also allows an owner to lend out a handle for a limited -period. This is also called *borrowing*. Here's a version of `add_one` which -borrows its argument rather than taking ownership: - -```rust -fn add_one(num: &mut i32) { - *num += 1; -} -``` - -This function borrows an `i32` from its caller, and then increments it. When -the function is over, and `num` goes out of scope, the borrow is over. - -We have to change our `main` a bit too: - -```rust -fn main() { - let mut x = 5; - - add_one(&mut x); +It looks like this: - println!("{}", x); -} - -fn add_one(num: &mut i32) { - *num += 1; -} -``` - -We don't need to assign the result of `add_one()` anymore, because it doesn't -return anything anymore. This is because we're not passing ownership back, -since we just borrow, not take ownership. - -# Lifetimes - -Lending out a reference to a resource that someone else owns can be -complicated, however. For example, imagine this set of operations: - -1. I acquire a handle to some kind of resource. -2. I lend you a reference to the resource. -3. I decide I'm done with the resource, and deallocate it, while you still have - your reference. -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. - -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. - -Remember the function that borrowed an `i32`? Let's look at it again. - -```rust -fn add_one(num: &mut i32) { - *num += 1; -} +```text +error: use of moved value: `v` +println!("v[0] is: {}", v[0]); + ^ ``` -Rust has a feature called *lifetime elision*, which allows you to not write -lifetime annotations in certain circumstances. This is one of them. We will -cover the others later. Without eliding the lifetimes, `add_one` looks like -this: +A similar thing happens if we define a function which takes ownership, and +try to use something after we’ve passed it as an argument: -```rust -fn add_one<'a>(num: &'a mut i32) { - *num += 1; +```rust,ignore +fn take(v: Vec) { + // what happens here isn’t important. } -``` - -The `'a` is called a *lifetime*. Most lifetimes are used in places where -short names like `'a`, `'b` and `'c` are clearest, but it's often useful to -have more descriptive names. Let's dig into the syntax in a bit more detail: -```{rust,ignore} -fn add_one<'a>(...) -``` +let v = vec![1, 2, 3]; -This part _declares_ our lifetimes. This says that `add_one` has one lifetime, -`'a`. If we had two, it would look like this: +take(v); -```{rust,ignore} -fn add_two<'a, 'b>(...) +println!("v[0] is: {}", v[0]); ``` -Then in our parameter list, we use the lifetimes we've named: - -```{rust,ignore} -...(num: &'a mut i32) -``` +Same error: “use of moved value.” When we transfer ownership to something else, +we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of +special annotation here, it’s the default thing that Rust does. -If you compare `&mut i32` to `&'a mut i32`, they're the same, it's just that the -lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut i32` as "a -mutable reference to an i32" and `&'a mut i32` as "a mutable reference to an i32 with the lifetime 'a.'" +## The details -Why do lifetimes matter? Well, for example, here's some code: +The reason that we cannot use a binding after we’ve moved it is subtle, but +important. When we write code like this: ```rust -struct Foo<'a> { - x: &'a i32, -} +let v = vec![1, 2, 3]; -fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y;` - let f = Foo { x: y }; - - println!("{}", f.x); -} +let v2 = v; ``` -As you can see, `struct`s can also have lifetimes. In a similar way to functions, - -```{rust} -struct Foo<'a> { -# x: &'a i32, -# } -``` +The first line creates some data for the vector on the [stack][sh], `v`. The +vector’s data, however, is stored on the [heap][sh], and so it contains a +pointer to that data. When we move `v` to `v2`, it creates a copy of that data, +for `v2`. Which would mean two pointers to the contents of the vector on the +heap. That would be a problem: it would violate Rust’s safety guarantees by +introducing a data race. Therefore, Rust forbids using `v` after we’ve done the +move. -declares a lifetime, and - -```rust -# struct Foo<'a> { -x: &'a i32, -# } -``` +[sh]: the-stack-and-the-heap.html -uses it. So why do we need a lifetime here? We need to ensure that any reference -to a `Foo` cannot outlive the reference to an `i32` it contains. +It’s also important to note that optimizations may remove the actual copy of +the bytes, depending on circumstances. So it may not be as inefficient as it +initially seems. -## Thinking in scopes +## `Copy` types -A way to think about lifetimes is to visualize the scope that a reference is -valid for. For example: +We’ve established that when ownership is transferred to another binding, you +cannot use the original binding. However, there’s a [trait][traits] that changes this +behavior, and it’s called `Copy`. We haven’t discussed traits yet, but for now, +you can think of them as an annotation to a particular type that adds extra +behavior. For example: ```rust -fn main() { - let y = &5; // -+ y goes into scope - // | - // stuff // | - // | -} // -+ y goes out of scope -``` - -Adding in our `Foo`: - -```rust -struct Foo<'a> { - x: &'a i32, -} - -fn main() { - let y = &5; // -+ y goes into scope - let f = Foo { x: y }; // -+ f goes into scope - // stuff // | - // | -} // -+ f and y go out of scope -``` +let v = 1; -Our `f` lives within the scope of `y`, so everything works. What if it didn't? -This code won't work: +let v2 = v; -```{rust,ignore} -struct Foo<'a> { - x: &'a i32, -} - -fn main() { - let x; // -+ x goes into scope - // | - { // | - let y = &5; // ---+ y goes into scope - let f = Foo { x: y }; // ---+ f goes into scope - x = &f.x; // | | error here - } // ---+ f and y go out of scope - // | - println!("{}", x); // | -} // -+ x goes out of scope +println!("v is: {}", v); ``` -Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope -of `x`. But when we do `x = &f.x`, we make `x` a reference to something that's -about to go out of scope. +In this case, `v` is an `i32`, which implements the `Copy` trait. This means +that, just like a move, when we assign `v` to `v2`, a copy of the data is made. +But, unlike a move, we can still use `v` afterward. This is because an `i32` +has no pointers to data somewhere else, copying it is a full copy. -Named lifetimes are a way of giving these scopes a name. Giving something a -name is the first step towards being able to talk about it. +We will discuss how to make your own types `Copy` in the [traits][traits] +section. -## 'static +[traits]: traits.html -The lifetime named *static* is a special lifetime. It signals that something -has the lifetime of the entire program. Most Rust programmers first come across -`'static` when dealing with strings: +# More than ownership -```rust -let x: &'static str = "Hello, world."; -``` - -String literals have the type `&'static str` because the reference is always -alive: they are baked into the data segment of the final binary. Another -example are globals: +Of course, if we had to hand ownership back with every function we wrote: ```rust -static FOO: i32 = 5; -let x: &'static i32 = &FOO; -``` - -This adds an `i32` to the data segment of the binary, and `x` is a reference -to it. +fn foo(v: Vec) -> Vec { + // do stuff with v -# Shared Ownership - -In all the examples we've considered so far, we've assumed that each handle has -a singular owner. But sometimes, this doesn't work. Consider a car. Cars have -four wheels. We would want a wheel to know which car it was attached to. But -this won't work: - -```{rust,ignore} -struct Car { - name: String, -} - -struct Wheel { - size: i32, - owner: Car, -} - -fn main() { - let car = Car { name: "DeLorean".to_string() }; - - for _ in 0..4 { - Wheel { size: 360, owner: car }; - } + // hand back ownership + v } ``` -We try to make four `Wheel`s, each with a `Car` that it's attached to. But the -compiler knows that on the second iteration of the loop, there's a problem: - -```text -error: use of moved value: `car` - Wheel { size: 360, owner: car }; - ^~~ -note: `car` moved here because it has type `Car`, which is non-copyable - Wheel { size: 360, owner: car }; - ^~~ -``` - -We need our `Car` to be pointed to by multiple `Wheel`s. We can't do that with -`Box`, because it has a single owner. We can do it with `Rc` instead: +This would get very tedius. It gets worse the more things we want to take ownership of: ```rust -use std::rc::Rc; +fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { + // do stuff with v1 and v2 -struct Car { - name: String, + // hand back ownership, and the result of our function + (v1, v2, 42) } -struct Wheel { - size: i32, - owner: Rc, -} +let v1 = vec![1, 2, 3]; +let v2 = vec![1, 2, 3]; -fn main() { - let car = Car { name: "DeLorean".to_string() }; - - let car_owner = Rc::new(car); - - for _ in 0..4 { - Wheel { size: 360, owner: car_owner.clone() }; - } -} +let (v1, v2, answer) = foo(v1, v2); ``` -We wrap our `Car` in an `Rc`, getting an `Rc`, and then use the -`clone()` method to make new references. We've also changed our `Wheel` to have -an `Rc` rather than just a `Car`. - -This is the simplest kind of multiple ownership possible. For example, there's -also `Arc`, which uses more expensive atomic instructions to be the -thread-safe counterpart of `Rc`. - -## Lifetime Elision - -Rust supports powerful local type inference in function bodies, but it’s -forbidden in item signatures to allow reasoning about the types just based in -the item signature alone. However, for ergonomic reasons a very restricted -secondary inference algorithm called “lifetime elision” applies in function -signatures. It infers only based on the signature components themselves and not -based on the body of the function, only infers lifetime parameters, and does -this with only three easily memorizable and unambiguous rules. This makes -lifetime elision a shorthand for writing an item signature, while not hiding -away the actual types involved as full local inference would if applied to it. - -When talking about lifetime elision, we use the term *input lifetime* and -*output lifetime*. An *input lifetime* is a lifetime associated with a parameter -of a function, and an *output lifetime* is a lifetime associated with the return -value of a function. For example, this function has an input lifetime: - -```{rust,ignore} -fn foo<'a>(bar: &'a str) -``` - -This one has an output lifetime: - -```{rust,ignore} -fn foo<'a>() -> &'a str -``` - -This one has a lifetime in both positions: - -```{rust,ignore} -fn foo<'a>(bar: &'a str) -> &'a str -``` +Ugh! The return type, return line, and calling the function gets way more +complicated. -Here are the three rules: +Luckily, Rust offers a feature, borrowing, which helps us solve this problem. +It’s the topic of the next section! -* Each elided lifetime in a function's arguments becomes a distinct lifetime - parameter. -* If there is exactly one input lifetime, elided or not, that lifetime is - assigned to all elided lifetimes in the return values of that function. -* If there are multiple input lifetimes, but one of them is `&self` or `&mut - self`, the lifetime of `self` is assigned to all elided output lifetimes. -Otherwise, it is an error to elide an output lifetime. -### Examples -Here are some examples of functions with elided lifetimes. We've paired each -example of an elided lifetime with its expanded form. -```{rust,ignore} -fn print(s: &str); // elided -fn print<'a>(s: &'a str); // expanded -fn debug(lvl: u32, s: &str); // elided -fn debug<'a>(lvl: u32, s: &'a str); // expanded -// In the preceding example, `lvl` doesn't need a lifetime because it's not a -// reference (`&`). Only things relating to references (such as a `struct` -// which contains a reference) need lifetimes. - -fn substr(s: &str, until: u32) -> &str; // elided -fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded - -fn get_str() -> &str; // ILLEGAL, no inputs - -fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs -fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is unclear - -fn get_mut(&mut self) -> &mut T; // elided -fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded - -fn args(&mut self, args: &[T]) -> &mut Command // elided -fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded - -fn new(buf: &mut [u8]) -> BufWriter; // elided -fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded -``` -# Related Resources -Coming Soon. diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index 0e13ea612645c..21feff73342ce 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -1,3 +1,336 @@ % References and Borrowing -Coming Soon! Until then, check out the [ownership](ownership.html) chapter. +This guide is one of three presenting Rust’s ownership system. This is one of +Rust’s most unique and compelling features, with which Rust developers should +become quite acquainted. Ownership is how Rust achieves its largest goal, +memory safety. The there are a few distinct concepts, each with its own +chapter: + +* [ownership][ownership], ownership, the key concept +* borrowing, which you’re reading now +* [lifetimes][lifetimes], an advanced concept of borrowing + +These three chapters are related, and in order. You’ll need all three to fully +understand the ownership system. + +[ownership]: ownership.html +[lifetimes]: lifetimes.html + +# Meta + +Before we get to the details, two important notes about the ownership system. + +Rust has a focus on safety and speed. It accomplishes these goals through many +‘zero-cost abstractions’, which means that in Rust, abstractions cost as little +as possible in order to make them work. The ownership system is a prime example +of a zero cost abstraction. All of the analysis we’ll talk about in this guide +is _done at compile time_. You do not pay any run-time cost for any of these +features. + +However, this system does have a certain cost: learning curve. Many new users +to Rust experience something we like to call ‘fighting with the borrow +checker’, where the Rust compiler refuses to compile a program that the author +thinks is valid. This often happens because the programmer’s mental model of +how ownership should work doesn’t match the actual rules that Rust implements. +You probably will experience similar things at first. There is good news, +however: more experienced Rust developers report that once they work with the +rules of the ownership system for a period of time, they fight the borrow +checker less and less. + +With that in mind, let’s learn about borrowing. + +# Borrowing + +At the end of the [ownership][ownership] section, we had a nasty function that looked +like this: + +```rust +fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { + // do stuff with v1 and v2 + + // hand back ownership, and the result of our function + (v1, v2, 42) +} + +let v1 = vec![1, 2, 3]; +let v2 = vec![1, 2, 3]; + +let (v1, v2, answer) = foo(v1, v2); +``` + +This is not idiomatic Rust, however, as it doesn’t take advantage of borrowing. Here’s +the first step: + +```rust +fn foo(v1: &Vec, v2: &Vec) -> i32 { + // do stuff with v1 and v2 + + // return the answer + 42 +} + +let v1 = vec![1, 2, 3]; +let v2 = vec![1, 2, 3]; + +let answer = foo(&v1, &v2); + +// we can use v1 and v2 here! +``` + +Instead of taking `Vec`s as our arguments, we take a reference: +`&Vec`. And instead of passing `v1` and `v2` directly, we pass `&v1` and +`&v2`. We call the `&T` type a ‘reference’, and rather than owning the resource, +it borrows ownership. A binding that borrows something does not deallocate the +resource when it goes out of scope. This means that after the call to `foo()`, +we can use our original bindings again. + +References are immutable, just like bindings. This means that inside of `foo()`, +the vectors can’t be changed at all: + +```rust,ignore +fn foo(v: &Vec) { + v.push(5); +} + +let v = vec![]; + +foo(&v); +``` + +errors with: + +```text +error: cannot borrow immutable borrowed content `*v` as mutable +v.push(5); +^ +``` + +Pushing a value mutates the vector, and so we aren’t allowed to do it. + +# &mut references + +There’s a second kind of reference: `&mut T`. A ‘mutable reference’ allows you +to mutate the resource you’re borrowing. For example: + +```rust +let mut x = 5; +{ + let y = &mut x; + *y += 1; +} +println!("{}", x); +``` + +This will print `6`. We make `y` a mutable reference to `x`, then add one to +the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well, +if it wasn’t, we couldn’t take a mutable borrow to an immutable value. + +Otherwise, `&mut` references are just like references. There _is_ a large +difference between the two, and how they interact, though. You can tell +something is fishy in the above example, because we need that extra scope, with +the `{` and `}`. If we remove them, we get an error: + +```text +error: cannot borrow `x` as immutable because it is also borrowed as mutable + println!("{}", x); + ^ +note: previous borrow of `x` occurs here; the mutable borrow prevents +subsequent moves, borrows, or modification of `x` until the borrow ends + let y = &mut x; + ^ +note: previous borrow ends here +fn main() { + +} +^ +``` + +As it turns out, there are rules. + +# The Rules + +Here’s the rules about borrowing in Rust: + +First, any borrow must last for a smaller scope than the owner. Second, you may +have one or the other of these two kinds of borrows, but not both at the same +time: + +* 0 to N references (`&T`) to a resource. +* exactly one mutable reference (`&mut T`) + + +You may notice that this is very similar, though not exactly the same as, +to the definition of a data race: + +> There is a ‘data race’ when two or more pointers access the same memory +> location at the same time, where at least one of them is writing, and the +> operations are not synchronized. + +With references, you may have as many as you’d like, since none of them are +writing. If you are writing, you need two or more pointers to the same memory, +and you can only have one `&mut` at a time. This is how Rust prevents data +races at compile time: we’ll get errors if we break the rules. + +With this in mind, let’s consider our example again. + +## Thinking in scopes + +Here’s the code: + +```rust,ignore +let mut x = 5; +let y = &mut x; + +*y += 1; + +println!("{}", x); +``` + +This code gives us this error: + +```text +error: cannot borrow `x` as immutable because it is also borrowed as mutable + println!("{}", x); + ^ +``` + +This is because we’ve violated the rules: we have a `&mut T` pointing to `x`, +and so we aren’t allowed to create any `&T`s. One or the other. The note +hints at how to think about this problem: + +```text +note: previous borrow ends here +fn main() { + +} +^ +``` + +In other words, the mutable borow is held through the rest of our example. What +we want is for the mutable borrow to end _before_ we try to call `println!` and +make an immutable borrow. In Rust, borrowing is tied to the scope that the +borrow is valid for. And our scopes look like this: + +```rust,ignore +let mut x = 5; + +let y = &mut x; // -+ &mut borrow of x starts here + // | +*y += 1; // | + // | +println!("{}", x); // -+ - try to borrow x here + // -+ &mut borrow of x ends here +``` + +The scopes conflict: we can’t make an `&x` while `y` is in scope. + +So when we add the curly braces: + +```rust +let mut x = 5; + +{ + let y = &mut x; // -+ &mut borrow starts here + *y += 1; // | +} // -+ ... and ends here + +println!("{}", x); // <- try to borrow x here +``` + +There’s no problem. Our mutable borrow goes out of scope before we create an +immutable one. But scope is the key to seeing how long a borrow lasts for. + +## Issues borrowing prevents + +Why have these restrictive rules? Well, as we noted, these rules prevent data +races. What kinds of issues do data races cause? Here’s a few. + +### Iterator invalidation + +One example is ‘iterator invalidation’, which happens when you try to mutate a +collection that you’re iterating over. Rust’s borrow checker prevents this from +happening: + +```rust +let mut v = vec![1, 2, 3]; + +for i in &v { + println!("{}", i); +} +``` + +This prints out one through three. As we iterate through the vectors, we’re +only given references to the elements. And `v` is itself borrowed as immutable, +which means we can’t change it while we’re iterating: + +```rust,ignore +let mut v = vec![1, 2, 3]; + +for i in &v { + println!("{}", i); + v.push(34); +} +``` + +Here’s the error: + +```text +error: cannot borrow `v` as mutable because it is also borrowed as immutable + v.push(34); + ^ +note: previous borrow of `v` occurs here; the immutable borrow prevents +subsequent moves or mutable borrows of `v` until the borrow ends +for i in &v { + ^ +note: previous borrow ends here +for i in &v { + println!(“{}”, i); + v.push(34); +} +^ +``` + +We can’t modify `v` because it’s borrowed by the loop. + +### use after free + +References must live as long as the resource they refer to. Rust will check the +scopes of your references to ensure that this is true. + +If Rust didn’t check that this property, we could accidentally use a reference +which was invalid. For example: + +```rust,ignore +let y: &i32; +{ + let x = 5; + y = &x; +} + +println!("{}", y); +``` + +We get this error: + +error: `x` does not live long enough + y = &x; + ^ +note: reference must be valid for the block suffix following statement 0 at +2:16... +let y: &i32; +{ + let x = 5; + y = &x; +} + +note: ...but borrowed value is only valid for the block suffix following +statement 0 at 4:18 + let x = 5; + y = &x; +} +``` + +In other words, `y` is only valid for the scope where `x` exists. As soon as +`x` goes away, it becomes invalid to refer to it. As such, the error says that +the borrow ‘doesn’t live long enough’ because it’s not valid for the right +amount of time. diff --git a/src/etc/extract_grammar.py b/src/etc/extract_grammar.py deleted file mode 100755 index a12c3298cb35b..0000000000000 --- a/src/etc/extract_grammar.py +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# This script is for extracting the grammar from the rust docs. - -import fileinput - -collections = {"gram": [], - "keyword": [], - "reserved": [], - "binop": [], - "unop": []} - - -in_coll = False -coll = "" - -for line in fileinput.input(openhook=fileinput.hook_encoded("utf-8")): - if in_coll: - if line.startswith("~~~~"): - in_coll = False - else: - if coll in ["keyword", "reserved", "binop", "unop"]: - for word in line.split(): - if word not in collections[coll]: - collections[coll].append(word) - else: - collections[coll].append(line) - - else: - if line.startswith("~~~~"): - for cname in collections: - if ("." + cname) in line: - coll = cname - in_coll = True - break - -# Define operator symbol-names here - -tokens = ["non_star", "non_slash", "non_eol", - "non_single_quote", "non_double_quote", "ident"] - -symnames = { - ".": "dot", - "+": "plus", - "-": "minus", - "/": "slash", - "*": "star", - "%": "percent", - - "~": "tilde", - "@": "at", - - "!": "not", - "&": "and", - "|": "or", - "^": "xor", - - "<<": "lsl", - ">>": "lsr", - ">>>": "asr", - - "&&": "andand", - "||": "oror", - - "<": "lt", - "<=": "le", - "==": "eqeq", - ">=": "ge", - ">": "gt", - - "=": "eq", - - "+=": "plusequal", - "-=": "minusequal", - "/=": "divequal", - "*=": "starequal", - "%=": "percentequal", - - "&=": "andequal", - "|=": "orequal", - "^=": "xorequal", - - ">>=": "lsrequal", - ">>>=": "asrequal", - "<<=": "lslequal", - - "::": "coloncolon", - - "->": "rightarrow", - "<-": "leftarrow", - "<->": "swaparrow", - - "//": "linecomment", - "/*": "openblockcomment", - "*/": "closeblockcomment", - "macro_rules": "macro_rules", - "=>": "eg", - "..": "dotdot", - ",": "comma" -} - -lines = [] - -for line in collections["gram"]: - line2 = "" - for word in line.split(): - # replace strings with keyword-names or symbol-names from table - if word.startswith("\""): - word = word[1:-1] - if word in symnames: - word = symnames[word] - else: - for ch in word: - if not ch.isalpha(): - raise Exception("non-alpha apparent keyword: " - + word) - if word not in tokens: - if (word in collections["keyword"] or - word in collections["reserved"]): - tokens.append(word) - else: - raise Exception("unknown keyword/reserved word: " - + word) - - line2 += " " + word - lines.append(line2) - - -for word in collections["keyword"] + collections["reserved"]: - if word not in tokens: - tokens.append(word) - -for sym in collections["unop"] + collections["binop"] + symnames.keys(): - word = symnames[sym] - if word not in tokens: - tokens.append(word) - - -print("%start parser, token;") -print("%%token %s ;" % ("\n\t, ".join(tokens))) -for coll in ["keyword", "reserved"]: - print("%s: %s ; " % (coll, "\n\t| ".join(collections[coll]))) -for coll in ["binop", "unop"]: - print("%s: %s ; " % (coll, "\n\t| ".join([symnames[x] - for x in collections[coll]]))) -print("\n".join(lines)) diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index d9151298a35e3..ba3e144e6287e 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -210,15 +210,13 @@ impl BitVec { assert_eq!(self.len(), other.len()); // This could theoretically be a `debug_assert!`. assert_eq!(self.storage.len(), other.storage.len()); - let mut changed = false; + let mut changed_bits = 0; for (a, b) in self.blocks_mut().zip(other.blocks()) { let w = op(*a, b); - if *a != w { - changed = true; - *a = w; - } + changed_bits |= *a ^ w; + *a = w; } - changed + changed_bits != 0 } /// Iterator over mutable refs to the underlying blocks of data. diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index db9f526a0f22e..38431ab5bf1b0 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -713,7 +713,7 @@ impl str { /// is skipped if empty. /// /// This method can be used for string data that is _terminated_, - /// rather than _seperated_ by a pattern. + /// rather than _separated_ by a pattern. /// /// # Iterator behavior /// @@ -760,7 +760,7 @@ impl str { /// skipped if empty. /// /// This method can be used for string data that is _terminated_, - /// rather than _seperated_ by a pattern. + /// rather than _separated_ by a pattern. /// /// # Iterator behavior /// diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index ad5ed1c89cdd9..3c668f7fe9bc6 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -757,7 +757,7 @@ impl FromUtf8Error { #[stable(feature = "rust1", since = "1.0.0")] pub fn into_bytes(self) -> Vec { self.bytes } - /// Accesss the underlying UTF8-error that was the cause of this error. + /// Access the underlying UTF8-error that was the cause of this error. #[stable(feature = "rust1", since = "1.0.0")] pub fn utf8_error(&self) -> Utf8Error { self.error } } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 33de6b7973672..a2be8b8121938 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -15,13 +15,13 @@ //! //! # Examples //! -//! Explicitly creating a `Vec` with `new()`: +//! You can explicitly create a `Vec` with `new()`: //! //! ``` //! let xs: Vec = Vec::new(); //! ``` //! -//! Using the `vec!` macro: +//! ...or by using the `vec!` macro: //! //! ``` //! let ys: Vec = vec![]; @@ -29,7 +29,7 @@ //! let zs = vec![1i32, 2, 3, 4, 5]; //! ``` //! -//! Push: +//! You can `push` values onto the end of a vector (which will grow the vector as needed): //! //! ``` //! let mut xs = vec![1i32, 2]; @@ -37,13 +37,21 @@ //! xs.push(3); //! ``` //! -//! And pop: +//! Popping values works in much the same way: //! //! ``` //! let mut xs = vec![1i32, 2]; //! //! let two = xs.pop(); //! ``` +//! +//! Vectors also support indexing (through the `Index` and `IndexMut` traits): +//! +//! ``` +//! let mut xs = vec![1i32, 2, 3]; +//! let three = xs[2]; +//! xs[1] = xs[1] + 5; +//! ``` #![stable(feature = "rust1", since = "1.0.0")] @@ -1777,6 +1785,11 @@ impl Iterator for IntoIter { let exact = diff / (if size == 0 {1} else {size}); (exact, Some(exact)) } + + #[inline] + fn count(self) -> usize { + self.size_hint().0 + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 8a8da0d9faaea..ac9cf198d6732 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -542,6 +542,11 @@ fn test_split_off() { assert_eq!(vec2, [5, 6]); } +#[test] +fn test_into_iter_count() { + assert_eq!(vec![1, 2, 3].into_iter().count(), 3); +} + #[bench] fn bench_new(b: &mut Bencher) { b.iter(|| { diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 9ff447a87f1fe..c717b608a246e 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -144,7 +144,7 @@ use clone::Clone; use cmp::PartialEq; use default::Default; -use marker::{Copy, Send, Sync}; +use marker::{Copy, Send, Sync, Sized}; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{None, Some}; @@ -266,9 +266,9 @@ impl PartialEq for Cell { /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] -pub struct RefCell { - value: UnsafeCell, +pub struct RefCell { borrow: Cell, + value: UnsafeCell, } /// An enumeration of values returned from the `state` method on a `RefCell`. @@ -328,7 +328,9 @@ impl RefCell { debug_assert!(self.borrow.get() == UNUSED); unsafe { self.value.into_inner() } } +} +impl RefCell { /// Query the current state of this `RefCell` /// /// The returned value can be dispatched on to determine if a call to @@ -449,7 +451,7 @@ impl RefCell { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for RefCell where T: Send {} +unsafe impl Send for RefCell where T: Send {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for RefCell { @@ -469,7 +471,7 @@ impl Default for RefCell { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for RefCell { +impl PartialEq for RefCell { #[inline] fn eq(&self, other: &RefCell) -> bool { *self.borrow() == *other.borrow() @@ -519,7 +521,7 @@ impl<'b> Clone for BorrowRef<'b> { /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Ref<'b, T:'b> { +pub struct Ref<'b, T: ?Sized + 'b> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref _value: &'b T, @@ -527,7 +529,7 @@ pub struct Ref<'b, T:'b> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T> Deref for Ref<'b, T> { +impl<'b, T: ?Sized> Deref for Ref<'b, T> { type Target = T; #[inline] @@ -582,7 +584,7 @@ impl<'b> BorrowRefMut<'b> { /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] -pub struct RefMut<'b, T:'b> { +pub struct RefMut<'b, T: ?Sized + 'b> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref _value: &'b mut T, @@ -590,7 +592,7 @@ pub struct RefMut<'b, T:'b> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T> Deref for RefMut<'b, T> { +impl<'b, T: ?Sized> Deref for RefMut<'b, T> { type Target = T; #[inline] @@ -600,7 +602,7 @@ impl<'b, T> Deref for RefMut<'b, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T> DerefMut for RefMut<'b, T> { +impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> { #[inline] fn deref_mut<'a>(&'a mut self) -> &'a mut T { self._value @@ -633,7 +635,7 @@ impl<'b, T> DerefMut for RefMut<'b, T> { /// recommended to access its fields directly, `get` should be used instead. #[lang="unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct UnsafeCell { +pub struct UnsafeCell { /// Wrapped value /// /// This field should not be accessed directly, it is made public for static @@ -642,7 +644,7 @@ pub struct UnsafeCell { pub value: T, } -impl !Sync for UnsafeCell {} +impl !Sync for UnsafeCell {} impl UnsafeCell { /// Constructs a new instance of `UnsafeCell` which will wrap the specified @@ -664,7 +666,12 @@ impl UnsafeCell { UnsafeCell { value: value } } - /// Gets a mutable pointer to the wrapped value. + /// Unwraps the value. + /// + /// # Unsafety + /// + /// This function is unsafe because there is no guarantee that this or other threads are + /// currently inspecting the inner value. /// /// # Examples /// @@ -673,22 +680,15 @@ impl UnsafeCell { /// /// let uc = UnsafeCell::new(5); /// - /// let five = uc.get(); + /// let five = unsafe { uc.into_inner() }; /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> *mut T { - // FIXME(#23542) Replace with type ascription. - #![allow(trivial_casts)] - &self.value as *const T as *mut T - } + pub unsafe fn into_inner(self) -> T { self.value } +} - /// Unwraps the value. - /// - /// # Unsafety - /// - /// This function is unsafe because there is no guarantee that this or other threads are - /// currently inspecting the inner value. +impl UnsafeCell { + /// Gets a mutable pointer to the wrapped value. /// /// # Examples /// @@ -697,9 +697,14 @@ impl UnsafeCell { /// /// let uc = UnsafeCell::new(5); /// - /// let five = unsafe { uc.into_inner() }; + /// let five = uc.get(); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn into_inner(self) -> T { self.value } + pub fn get(&self) -> *mut T { + // FIXME(#23542) Replace with type ascription. + #![allow(trivial_casts)] + &self.value as *const T as *mut T + } + } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 73778bfd03809..f8a1ef96bcc33 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1062,7 +1062,7 @@ impl Debug for Cell { } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for RefCell { +impl Debug for RefCell { fn fmt(&self, f: &mut Formatter) -> Result { match self.borrow_state() { BorrowState::Unused | BorrowState::Reading => { @@ -1074,14 +1074,14 @@ impl Debug for RefCell { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T: Debug> Debug for Ref<'b, T> { +impl<'b, T: ?Sized + Debug> Debug for Ref<'b, T> { fn fmt(&self, f: &mut Formatter) -> Result { Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, T: Debug> Debug for RefMut<'b, T> { +impl<'b, T: ?Sized + Debug> Debug for RefMut<'b, T> { fn fmt(&self, f: &mut Formatter) -> Result { Debug::fmt(&*(self.deref()), f) } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index be419e2cdadb0..a92b72e0f00fa 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -111,6 +111,7 @@ impl SipHasher { state } + #[inline] fn reset(&mut self) { self.length = 0; self.v0 = self.k0 ^ 0x736f6d6570736575; @@ -120,6 +121,7 @@ impl SipHasher { self.ntail = 0; } + #[inline] fn write(&mut self, msg: &[u8]) { let length = msg.len(); self.length += length; @@ -173,6 +175,7 @@ impl Hasher for SipHasher { self.write(msg) } + #[inline] fn finish(&self) -> u64 { let mut v0 = self.v0; let mut v1 = self.v1; diff --git a/src/libcore/option.rs b/src/libcore/option.rs index d1bc24bd9baa5..8da28094be3ae 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -161,7 +161,7 @@ use slice; // `Iterator` is an enumeration with one type parameter and two variants, // which basically means it must be `Option`. -/// The `Option` type. See [the module level documentation](../index.html) for more. +/// The `Option` type. See [the module level documentation](index.html) for more. #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4d343ea0f1e42..c9bbcba31e9de 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -136,6 +136,7 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8. +#[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { mem::transmute(v) @@ -420,7 +421,7 @@ macro_rules! derive_pattern_clone { /// wrapping an private internal one that makes use of the `Pattern` API. /// /// For all patterns `P: Pattern<'a>` the following items will be -/// generated (generics ommitted): +/// generated (generics omitted): /// /// struct $forward_iterator($internal_iterator); /// struct $reverse_iterator($internal_iterator); diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index 85dd10390038f..0bd0b66318f1b 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -159,3 +159,27 @@ fn refcell_default() { let cell: RefCell = Default::default(); assert_eq!(0, *cell.borrow()); } + +#[test] +fn unsafe_cell_unsized() { + let cell: &UnsafeCell<[i32]> = &UnsafeCell::new([1, 2, 3]); + { + let val: &mut [i32] = unsafe { &mut *cell.get() }; + val[0] = 4; + val[2] = 5; + } + let comp: &mut [i32] = &mut [4, 2, 5]; + assert_eq!(unsafe { &mut *cell.get() }, comp); +} + +#[test] +fn refcell_unsized() { + let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); + { + let b = &mut *cell.borrow_mut(); + b[0] = 4; + b[2] = 5; + } + let comp: &mut [i32] = &mut [4, 2, 5]; + assert_eq!(&*cell.borrow(), comp); +} diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 6cb39c39659e8..19d2df0b486cf 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -37,7 +37,7 @@ An example of an empty type is `enum Empty { }`. E0003: r##" Not-a-Number (NaN) values cannot be compared for equality and hence can never match the input to a match expression. To match against NaN values, you should -instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ... +instead use the `is_nan` method in a guard, as in: `x if x.is_nan() => ...` "##, E0004: r##" @@ -71,7 +71,7 @@ failure. E0007: r##" This error indicates that the bindings in a match arm would require a value to be moved into more than one location, thus violating unique ownership. Code like -the following is invalid as it requires the entire Option to be moved +the following is invalid as it requires the entire `Option` to be moved into a variable called `op_string` while simultaneously requiring the inner String to be moved into a variable called `s`. @@ -99,10 +99,10 @@ match Some("hi".to_string()) { } ``` -The variable `s` has type String, and its use in the guard is as a variable of -type String. The guard code effectively executes in a separate scope to the body -of the arm, so the value would be moved into this anonymous scope and therefore -become unavailable in the body of the arm. Although this example seems +The variable `s` has type `String`, and its use in the guard is as a variable of +type `String`. The guard code effectively executes in a separate scope to the +body of the arm, so the value would be moved into this anonymous scope and +therefore become unavailable in the body of the arm. Although this example seems innocuous, the problem is most clear when considering functions that take their argument by value. @@ -140,7 +140,8 @@ match x { ``` You have two solutions: -1. Bind the pattern's values the same way: + +Solution #1: Bind the pattern's values the same way. ``` struct X { x: (), } @@ -153,8 +154,9 @@ match x { } ``` -2. Implement the `Copy` trait for the X structure (however, please -keep in mind that the first solution should be preferred!): +Solution #2: Implement the `Copy` trait for the `X` structure. + +However, please keep in mind that the first solution should be preferred. ``` #[derive(Clone, Copy)] @@ -258,11 +260,13 @@ functions via FFI or marked as unsafe, is potentially dangerous and disallowed by safety checks. As such, those safety checks can be temporarily relaxed by wrapping the unsafe instructions inside an `unsafe` block. For instance: +``` unsafe fn f() { return; } fn main() { unsafe { f(); } } +``` See also http://doc.rust-lang.org/book/unsafe.html "##, @@ -313,8 +317,8 @@ it around as usual. E0162: r##" An if-let pattern attempts to match the pattern, and enters the body if the -match was succesful. If the match is irrefutable (when it cannot fail to match), -use a regular `let`-binding instead. For instance: +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding instead. For instance: ``` struct Irrefutable(i32); @@ -334,8 +338,8 @@ foo(x); E0165: r##" A while-let pattern attempts to match the pattern, and enters the body if the -match was succesful. If the match is irrefutable (when it cannot fail to match), -use a regular `let`-binding inside a `loop` instead. For instance: +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding inside a `loop` instead. For instance: ``` struct Irrefutable(i32); @@ -374,7 +378,7 @@ match m { ``` If you don't qualify the names, the code will bind new variables named "GET" and -"POST" instead. This behavior is likely not what you want, so rustc warns when +"POST" instead. This behavior is likely not what you want, so `rustc` warns when that happens. Qualified names are good practice, and most code works well with them. But if @@ -403,16 +407,16 @@ const Y: u32 = X; "##, E0267: r##" -This error indicates the use of loop keyword (break or continue) inside a -closure but outside of any loop. Break and continue can be used as normal -inside closures as long as they are also contained within a loop. To halt the -execution of a closure you should instead use a return statement. +This error indicates the use of a loop keyword (`break` or `continue`) inside a +closure but outside of any loop. Break and continue can be used as normal inside +closures as long as they are also contained within a loop. To halt the execution +of a closure you should instead use a return statement. "##, E0268: r##" -This error indicates the use of loop keyword (break or continue) outside of a -loop. Without a loop to break out of or continue in, no sensible action can be -taken. +This error indicates the use of a loop keyword (`break` or `continue`) outside +of a loop. Without a loop to break out of or continue in, no sensible action can +be taken. "##, E0296: r##" @@ -507,7 +511,7 @@ match Some("hi".to_string()) { } ``` -The `op_string_ref` binding has type &Option<&String> in both cases. +The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index f347d28b93c2b..b0940aa7ec0ac 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -461,7 +461,7 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { /// Constructs and returns a substitution that, for a given type /// scheme parameterized by `generics`, will replace every generic -/// parmeter in the type with a skolemized type/region (which one can +/// parameter in the type with a skolemized type/region (which one can /// think of as a "fresh constant", except at the type/region level of /// reasoning). /// diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 94071ff91903c..c80dba6d1fb31 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1908,7 +1908,7 @@ pub enum Predicate<'tcx> { } impl<'tcx> Predicate<'tcx> { - /// Performs a substituion suitable for going from a + /// Performs a substitution suitable for going from a /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal /// substitution in terms of what happens with bound regions. See diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 92c9549b37727..c59d317d8dfc1 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -1078,7 +1078,7 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) { sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| { match k { PathKind::Framework => { cmd.arg("-F").arg(path); } - _ => { cmd.arg("-L").arg(path); } + _ => { cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(path)); } } FileDoesntMatch }); diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 060dde02c2d12..84d464e8f0781 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -210,6 +210,7 @@ use trans::consts; use trans::datum::*; use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; use trans::expr::{self, Dest}; +use trans::monomorphize; use trans::tvec; use trans::type_of; use middle::ty::{self, Ty}; @@ -1076,9 +1077,39 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) { let repr = adt::represent_type(bcx.ccx(), left_ty); let arg_count = adt::num_args(&*repr, 0); - let field_vals: Vec = (0..arg_count).map(|ix| - adt::trans_field_ptr(bcx, &*repr, val, 0, ix) + let (arg_count, struct_val) = if type_is_sized(bcx.tcx(), left_ty) { + (arg_count, val) + } else { + // For an unsized ADT (i.e. DST struct), we need to treat + // the last field specially: instead of simply passing a + // ValueRef pointing to that field, as with all the others, + // we skip it and instead construct a 'fat ptr' below. + (arg_count - 1, Load(bcx, expr::get_dataptr(bcx, val))) + }; + let mut field_vals: Vec = (0..arg_count).map(|ix| + adt::trans_field_ptr(bcx, &*repr, struct_val, 0, ix) ).collect(); + + match left_ty.sty { + ty::ty_struct(def_id, substs) if !type_is_sized(bcx.tcx(), left_ty) => { + // The last field is technically unsized but + // since we can only ever match that field behind + // a reference we construct a fat ptr here. + let fields = ty::lookup_struct_fields(bcx.tcx(), def_id); + let unsized_ty = fields.iter().last().map(|field| { + let fty = ty::lookup_field_type(bcx.tcx(), def_id, field.id, substs); + monomorphize::normalize_associated_type(bcx.tcx(), &fty) + }).unwrap(); + let llty = type_of::type_of(bcx.ccx(), unsized_ty); + let scratch = alloca_no_lifetime(bcx, llty, "__struct_field_fat_ptr"); + let data = adt::trans_field_ptr(bcx, &*repr, struct_val, 0, arg_count); + let len = Load(bcx, expr::get_len(bcx, val)); + Store(bcx, data, expr::get_dataptr(bcx, scratch)); + Store(bcx, len, expr::get_len(bcx, scratch)); + field_vals.push(scratch); + } + _ => {} + } Some(field_vals) } else if any_uniq_pat(m, col) || any_region_pat(m, col) { Some(vec!(Load(bcx, val))) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 008ba1c6bf83e..8545e73c4f932 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -450,45 +450,57 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( let dtor_typescheme = ty::lookup_item_type(rcx.tcx(), impl_did); let dtor_generics = dtor_typescheme.generics; - let dtor_predicates = ty::lookup_predicates(rcx.tcx(), impl_did); - - let has_pred_of_interest = dtor_predicates.predicates.iter().any(|pred| { - // In `impl Drop where ...`, we automatically - // assume some predicate will be meaningful and thus - // represents a type through which we could reach - // borrowed data. However, there can be implicit - // predicates (namely for Sized), and so we still need - // to walk through and filter out those cases. - - let result = match *pred { - ty::Predicate::Trait(ty::Binder(ref t_pred)) => { - let def_id = t_pred.trait_ref.def_id; - match rcx.tcx().lang_items.to_builtin_kind(def_id) { - // Issue 24895: deliberately do not include `BoundCopy` here. - Some(ty::BoundSend) | - Some(ty::BoundSized) | - Some(ty::BoundSync) => false, - _ => true, + + let mut has_pred_of_interest = false; + + let mut seen_items = Vec::new(); + let mut items_to_inspect = vec![impl_did]; + 'items: while let Some(item_def_id) = items_to_inspect.pop() { + if seen_items.contains(&item_def_id) { + continue; + } + + for pred in ty::lookup_predicates(rcx.tcx(), item_def_id).predicates { + let result = match pred { + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::Projection(..) => { + // For now, assume all these where-clauses + // may give drop implementation capabilty + // to access borrowed data. + true } - } - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::Projection(..) => { - // we assume all of these where-clauses may - // give the drop implementation the capabilty - // to access borrowed data. - true - } - }; - if result { - debug!("typ: {} has interesting dtor due to generic preds, e.g. {}", - typ.repr(rcx.tcx()), pred.repr(rcx.tcx())); + ty::Predicate::Trait(ty::Binder(ref t_pred)) => { + let def_id = t_pred.trait_ref.def_id; + if ty::trait_items(rcx.tcx(), def_id).len() != 0 { + // If trait has items, assume it adds + // capability to access borrowed data. + true + } else { + // Trait without items is itself + // uninteresting from POV of dropck. + // + // However, may have parent w/ items; + // so schedule checking of predicates, + items_to_inspect.push(def_id); + // and say "no capability found" for now. + false + } + } + }; + + if result { + has_pred_of_interest = true; + debug!("typ: {} has interesting dtor due to generic preds, e.g. {}", + typ.repr(rcx.tcx()), pred.repr(rcx.tcx())); + break 'items; + } } - result - }); + seen_items.push(item_def_id); + } // In `impl<'a> Drop ...`, we automatically assume // `'a` is meaningful and thus represents a bound diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ec130e8233a74..eedda3cf4371a 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -212,8 +212,9 @@ fn test_resize_policy() { /// overridden with one of the constructors. /// /// It is required that the keys implement the `Eq` and `Hash` traits, although -/// this can frequently be achieved by using `#[derive(Eq, Hash)]`. If you -/// implement these yourself, it is important that the following property holds: +/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. +/// If you implement these yourself, it is important that the following +/// property holds: /// /// ```text /// k1 == k2 -> hash(k1) == hash(k2) @@ -250,26 +251,26 @@ fn test_resize_policy() { /// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); /// /// // check for a specific one. -/// if !book_reviews.contains_key(&("Les Misérables")) { +/// if !book_reviews.contains_key("Les Misérables") { /// println!("We've got {} reviews, but Les Misérables ain't one.", /// book_reviews.len()); /// } /// /// // oops, this review has a lot of spelling mistakes, let's delete it. -/// book_reviews.remove(&("The Adventures of Sherlock Holmes")); +/// book_reviews.remove("The Adventures of Sherlock Holmes"); /// /// // look up the values associated with some keys. /// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; -/// for book in to_find.iter() { +/// for book in &to_find { /// match book_reviews.get(book) { -/// Some(review) => println!("{}: {}", *book, *review), -/// None => println!("{} is unreviewed.", *book) +/// Some(review) => println!("{}: {}", book, review), +/// None => println!("{} is unreviewed.", book) /// } /// } /// /// // iterate over everything. -/// for (book, review) in book_reviews.iter() { -/// println!("{}: \"{}\"", *book, *review); +/// for (book, review) in &book_reviews { +/// println!("{}: \"{}\"", book, review); /// } /// ``` /// @@ -300,7 +301,7 @@ fn test_resize_policy() { /// vikings.insert(Viking::new("Harald", "Iceland"), 12); /// /// // Use derived implementation to print the status of the vikings. -/// for (viking, health) in vikings.iter() { +/// for (viking, health) in &vikings { /// println!("{:?} has {} hp", viking, health); /// } /// ``` @@ -1600,6 +1601,7 @@ impl RandomState { reason = "hashing an hash maps may be altered")] impl HashState for RandomState { type Hasher = SipHasher; + #[inline] fn hasher(&self) -> SipHasher { SipHasher::new_with_keys(self.k0, self.k1) } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index f7e43b38539f1..d6754f10335ca 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -31,10 +31,12 @@ use super::state::HashState; // to get rid of it properly. /// An implementation of a hash set using the underlying representation of a -/// HashMap where the value is (). As with the `HashMap` type, a `HashSet` -/// requires that the elements implement the `Eq` and `Hash` traits. This can -/// frequently be achieved by using `#[derive(Eq, Hash)]`. If you implement -/// these yourself, it is important that the following property holds: +/// HashMap where the value is (). +/// +/// As with the `HashMap` type, a `HashSet` requires that the elements +/// implement the `Eq` and `Hash` traits. This can frequently be achieved by +/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, +/// it is important that the following property holds: /// /// ```text /// k1 == k2 -> hash(k1) == hash(k2) @@ -64,17 +66,17 @@ use super::state::HashState; /// books.insert("The Great Gatsby"); /// /// // Check for a specific one. -/// if !books.contains(&("The Winds of Winter")) { +/// if !books.contains("The Winds of Winter") { /// println!("We have {} books, but The Winds of Winter ain't one.", /// books.len()); /// } /// /// // Remove a book. -/// books.remove(&"The Odyssey"); +/// books.remove("The Odyssey"); /// /// // Iterate over everything. -/// for book in books.iter() { -/// println!("{}", *book); +/// for book in &books { +/// println!("{}", book); /// } /// ``` /// @@ -98,7 +100,7 @@ use super::state::HashState; /// vikings.insert(Viking { name: "Harald", power: 8 }); /// /// // Use derived implementation to print the vikings. -/// for x in vikings.iter() { +/// for x in &vikings { /// println!("{:?}", x); /// } /// ``` diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index fcebe9c5e98d6..6a5e46e9ed062 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -152,12 +152,14 @@ macro_rules! try { /// thread::spawn(move|| { long_running_task(); tx1.send(()).unwrap(); }); /// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); }); /// -/// select! ( +/// select! { /// _ = rx1.recv() => println!("the long running task finished first"), /// answer = rx2.recv() => { /// println!("the answer was: {}", answer.unwrap()); /// } -/// ) +/// } +/// # drop(rx1.recv()); +/// # drop(rx2.recv()); /// ``` /// /// For more information about select, see the `std::sync::mpsc::Select` structure. @@ -434,7 +436,7 @@ pub mod builtin { /// Parse the current given file as an expression. /// - /// This is generally a bad idea, because it's going to behave unhygenically. + /// This is generally a bad idea, because it's going to behave unhygienically. /// /// # Examples /// diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 9fd69840f7f05..bc13d966a10b7 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -113,10 +113,13 @@ impl Ipv4Addr { /// Returns true if the address appears to be globally routable. /// - /// Non-globally-routable networks include the private networks (10.0.0.0/8, - /// 172.16.0.0/12 and 192.168.0.0/16), the loopback network (127.0.0.0/8), - /// the link-local network (169.254.0.0/16), the broadcast address (255.255.255.255/32) and - /// the test networks used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24). + /// The following return false: + /// + /// - private address (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) + /// - the loopback address (127.0.0.0/8) + /// - the link-local address (169.254.0.0/16) + /// - the broadcast address (255.255.255.255/32) + /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) pub fn is_global(&self) -> bool { !self.is_private() && !self.is_loopback() && !self.is_link_local() && !self.is_broadcast() && !self.is_documentation() @@ -139,7 +142,8 @@ impl Ipv4Addr { /// Returns true if this address is in a range designated for documentation. /// - /// This is defined in RFC 5737 + /// This is defined in RFC 5737: + /// /// - 192.0.2.0/24 (TEST-NET-1) /// - 198.51.100.0/24 (TEST-NET-2) /// - 203.0.113.0/24 (TEST-NET-3) @@ -171,7 +175,6 @@ impl Ipv4Addr { ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16, ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) } - } #[stable(feature = "rust1", since = "1.0.0")] @@ -244,6 +247,21 @@ impl FromInner for Ipv4Addr { } } +#[stable(feature = "ip_u32", since = "1.1.0")] +impl From for u32 { + fn from(ip: Ipv4Addr) -> u32 { + let ip = ip.octets(); + ((ip[0] as u32) << 24) + ((ip[1] as u32) << 16) + ((ip[2] as u32) << 8) + (ip[3] as u32) + } +} + +#[stable(feature = "ip_u32", since = "1.1.0")] +impl From for Ipv4Addr { + fn from(ip: u32) -> Ipv4Addr { + Ipv4Addr::new((ip >> 24) as u8, (ip >> 16) as u8, (ip >> 8) as u8, ip as u8) + } +} + impl Ipv6Addr { /// Creates a new IPv6 address from eight 16-bit segments. /// @@ -284,9 +302,11 @@ impl Ipv6Addr { /// Returns true if the address appears to be globally routable. /// - /// Non-globally-routable networks include the loopback address; the - /// link-local, site-local, and unique local unicast addresses; and the - /// interface-, link-, realm-, admin- and site-local multicast addresses. + /// The following return false: + /// + /// - the loopback address + /// - link-local, site-local, and unique local unicast addresses + /// - interface-, link-, realm-, admin- and site-local multicast addresses pub fn is_global(&self) -> bool { match self.multicast_scope() { Some(Ipv6MulticastScope::Global) => true, @@ -315,9 +335,12 @@ impl Ipv6Addr { /// Returns true if the address is a globally routable unicast address. /// - /// Non-globally-routable unicast addresses include the loopback address, - /// the link-local addresses, the deprecated site-local addresses and the - /// unique local addresses. + /// The following return false: + /// + /// - the loopback address + /// - the link-local addresses + /// - the (deprecated) site-local addresses + /// - unique local addresses pub fn is_unicast_global(&self) -> bool { !self.is_multicast() && !self.is_loopback() && !self.is_unicast_link_local() @@ -738,4 +761,16 @@ mod tests { let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); assert_eq!(Ok(vec![a]), tsa(a)); } + + #[test] + fn test_ipv4_to_int() { + let a = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(u32::from(a), 2130706433); + } + + #[test] + fn test_int_to_ipv4() { + let a = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(Ipv4Addr::from(2130706433), a); + } } diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 2e7c0a2c80e59..bf444ce671dfc 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -32,7 +32,7 @@ mod parser; /// Possible values which can be passed to the `shutdown` method of `TcpStream` /// and `UdpSocket`. -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Shutdown { /// Indicates that the reading portion of this stream/socket should be shut diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 130e1eee8f924..c0d880877b511 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -14,6 +14,7 @@ use prelude::v1::*; use io::prelude::*; +use fmt; use io; use net::{ToSocketAddrs, SocketAddr, Shutdown}; use sys_common::net2 as net_imp; @@ -167,6 +168,12 @@ impl FromInner for TcpStream { fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) } } +impl fmt::Debug for TcpStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + impl TcpListener { /// Creates a new `TcpListener` which will be bound to the specified /// address. @@ -239,6 +246,12 @@ impl FromInner for TcpListener { } } +impl fmt::Debug for TcpListener { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + #[cfg(test)] mod tests { use prelude::v1::*; @@ -248,6 +261,7 @@ mod tests { use net::*; use net::test::{next_test_ip4, next_test_ip6}; use sync::mpsc::channel; + use sys_common::AsInner; use thread; fn each_ip(f: &mut FnMut(SocketAddr)) { @@ -818,4 +832,27 @@ mod tests { rx.recv().unwrap(); }) } + + #[test] + fn debug() { + let name = if cfg!(windows) {"socket"} else {"fd"}; + let socket_addr = next_test_ip4(); + + let listener = t!(TcpListener::bind(&socket_addr)); + let listener_inner = listener.0.socket().as_inner(); + let compare = format!("TcpListener {{ addr: {:?}, {}: {:?} }}", + socket_addr, name, listener_inner); + assert_eq!(format!("{:?}", listener), compare); + + let mut stream = t!(TcpStream::connect(&("localhost", + socket_addr.port()))); + let stream_inner = stream.0.socket().as_inner(); + let compare = format!("TcpStream {{ addr: {:?}, \ + peer: {:?}, {}: {:?} }}", + stream.local_addr().unwrap(), + stream.peer_addr().unwrap(), + name, + stream_inner); + assert_eq!(format!("{:?}", stream), compare); + } } diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 0b04ecb1b7228..4360f62c1bf0f 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -13,6 +13,7 @@ use prelude::v1::*; +use fmt; use io::{self, Error, ErrorKind}; use net::{ToSocketAddrs, SocketAddr, IpAddr}; use sys_common::net2 as net_imp; @@ -136,6 +137,12 @@ impl FromInner for UdpSocket { fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) } } +impl fmt::Debug for UdpSocket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + #[cfg(test)] mod tests { use prelude::v1::*; @@ -144,6 +151,7 @@ mod tests { use net::*; use net::test::{next_test_ip4, next_test_ip6}; use sync::mpsc::channel; + use sys_common::AsInner; use thread; fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { @@ -301,4 +309,16 @@ mod tests { serv_rx.recv().unwrap(); }) } + + #[test] + fn debug() { + let name = if cfg!(windows) {"socket"} else {"fd"}; + let socket_addr = next_test_ip4(); + + let udpsock = t!(UdpSocket::bind(&socket_addr)); + let udpsock_inner = udpsock.0.socket().as_inner(); + let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", + socket_addr, name, udpsock_inner); + assert_eq!(format!("{:?}", udpsock), compare); + } } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 2ceb60cc3aa9f..8ccc387c90277 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -358,7 +358,7 @@ pub fn is_separator(c: char) -> bool { c.is_ascii() && is_sep_byte(c as u8) } -/// The primary sperator for the current platform +/// The primary separator for the current platform #[stable(feature = "rust1", since = "1.0.0")] pub const MAIN_SEPARATOR: char = platform::MAIN_SEP; diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 30c7407a96d97..222aff9188a6a 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -112,7 +112,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// *guard += 1; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct Mutex { +pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never // change (it can't be moved). This mutex type can be safely moved at any @@ -124,9 +124,9 @@ pub struct Mutex { // these are the only places where `T: Send` matters; all other // functionality works fine on a single thread. -unsafe impl Send for Mutex { } +unsafe impl Send for Mutex { } -unsafe impl Sync for Mutex { } +unsafe impl Sync for Mutex { } /// The static mutex type is provided to allow for static allocation of mutexes. /// @@ -164,7 +164,7 @@ pub struct StaticMutex { /// `Deref` and `DerefMut` implementations #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub struct MutexGuard<'a, T: 'a> { +pub struct MutexGuard<'a, T: ?Sized + 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). __lock: &'a StaticMutex, @@ -172,7 +172,7 @@ pub struct MutexGuard<'a, T: 'a> { __poison: poison::Guard, } -impl<'a, T> !marker::Send for MutexGuard<'a, T> {} +impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {} /// Static initialization of a mutex. This constant can be used to initialize /// other mutex constants. @@ -192,7 +192,9 @@ impl Mutex { data: UnsafeCell::new(t), } } +} +impl Mutex { /// Acquires a mutex, blocking the current task until it is able to do so. /// /// This function will block the local task until it is available to acquire @@ -245,7 +247,7 @@ impl Mutex { } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Mutex { +impl Drop for Mutex { fn drop(&mut self) { // This is actually safe b/c we know that there is no further usage of // this mutex (it's up to the user to arrange for a mutex to get @@ -255,12 +257,12 @@ impl Drop for Mutex { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Mutex { +impl fmt::Debug for Mutex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_lock() { - Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", *guard), + Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard), Err(TryLockError::Poisoned(err)) => { - write!(f, "Mutex {{ data: Poisoned({:?}) }}", **err.get_ref()) + write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) }, Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ }}") } @@ -310,7 +312,7 @@ impl StaticMutex { } } -impl<'mutex, T> MutexGuard<'mutex, T> { +impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell) -> LockResult> { @@ -325,7 +327,7 @@ impl<'mutex, T> MutexGuard<'mutex, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'mutex, T> Deref for MutexGuard<'mutex, T> { +impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> { type Target = T; fn deref<'a>(&'a self) -> &'a T { @@ -333,14 +335,14 @@ impl<'mutex, T> Deref for MutexGuard<'mutex, T> { } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'mutex, T> DerefMut for MutexGuard<'mutex, T> { +impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { fn deref_mut<'a>(&'a mut self) -> &'a mut T { unsafe { &mut *self.__data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Drop for MutexGuard<'a, T> { +impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { #[inline] fn drop(&mut self) { unsafe { @@ -350,11 +352,11 @@ impl<'a, T> Drop for MutexGuard<'a, T> { } } -pub fn guard_lock<'a, T>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { +pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { &guard.__lock.lock } -pub fn guard_poison<'a, T>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { +pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { &guard.__lock.poison } @@ -528,4 +530,16 @@ mod tests { let lock = arc.lock().unwrap(); assert_eq!(*lock, 2); } + + #[test] + fn test_mutex_unsized() { + let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); + { + let b = &mut *mutex.lock().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*mutex.lock().unwrap(), comp); + } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index a133bb01b610b..9294fb64783bd 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -60,13 +60,13 @@ use sys_common::rwlock as sys; /// } // write lock is dropped here /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLock { +pub struct RwLock { inner: Box, data: UnsafeCell, } -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} /// Structure representing a statically allocated RwLock. /// @@ -111,24 +111,24 @@ pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock { /// dropped. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLockReadGuard<'a, T: 'a> { +pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { __lock: &'a StaticRwLock, __data: &'a UnsafeCell, } -impl<'a, T> !marker::Send for RwLockReadGuard<'a, T> {} +impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLockWriteGuard<'a, T: 'a> { +pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { __lock: &'a StaticRwLock, __data: &'a UnsafeCell, __poison: poison::Guard, } -impl<'a, T> !marker::Send for RwLockWriteGuard<'a, T> {} +impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {} impl RwLock { /// Creates a new instance of an `RwLock` which is unlocked. @@ -144,7 +144,9 @@ impl RwLock { pub fn new(t: T) -> RwLock { RwLock { inner: box RW_LOCK_INIT, data: UnsafeCell::new(t) } } +} +impl RwLock { /// Locks this rwlock with shared read access, blocking the current thread /// until it can be acquired. /// @@ -250,19 +252,19 @@ impl RwLock { } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for RwLock { +impl Drop for RwLock { fn drop(&mut self) { unsafe { self.inner.lock.destroy() } } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for RwLock { +impl fmt::Debug for RwLock { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_read() { - Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", *guard), + Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard), Err(TryLockError::Poisoned(err)) => { - write!(f, "RwLock {{ data: Poisoned({:?}) }}", **err.get_ref()) + write!(f, "RwLock {{ data: Poisoned({:?}) }}", &**err.get_ref()) }, Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ }}") } @@ -341,8 +343,7 @@ impl StaticRwLock { } } -impl<'rwlock, T> RwLockReadGuard<'rwlock, T> { - +impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) -> LockResult> { poison::map_result(lock.poison.borrow(), |_| { @@ -353,8 +354,8 @@ impl<'rwlock, T> RwLockReadGuard<'rwlock, T> { }) } } -impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> { +impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { @@ -368,33 +369,35 @@ impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T> Deref for RwLockReadGuard<'rwlock, T> { +impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> { type Target = T; fn deref(&self) -> &T { unsafe { &*self.__data.get() } } } + #[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T> Deref for RwLockWriteGuard<'rwlock, T> { +impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> { type Target = T; fn deref(&self) -> &T { unsafe { &*self.__data.get() } } } + #[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T> DerefMut for RwLockWriteGuard<'rwlock, T> { +impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> { fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.__data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Drop for RwLockReadGuard<'a, T> { +impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> { fn drop(&mut self) { unsafe { self.__lock.lock.read_unlock(); } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Drop for RwLockWriteGuard<'a, T> { +impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> { fn drop(&mut self) { self.__lock.poison.done(&self.__poison); unsafe { self.__lock.lock.write_unlock(); } @@ -562,4 +565,16 @@ mod tests { let lock = arc.read().unwrap(); assert_eq!(*lock, 2); } + + #[test] + fn test_rwlock_unsized() { + let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + { + let b = &mut *rw.write().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*rw.read().unwrap(), comp); + } } diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs index 2b2c31d92edad..7da7071670ab6 100644 --- a/src/libstd/sys/common/net2.rs +++ b/src/libstd/sys/common/net2.rs @@ -11,6 +11,7 @@ use prelude::v1::*; use ffi::{CStr, CString}; +use fmt; use io::{self, Error, ErrorKind}; use libc::{self, c_int, c_char, c_void, socklen_t}; use mem; @@ -268,6 +269,24 @@ impl FromInner for TcpStream { } } +impl fmt::Debug for TcpStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut res = f.debug_struct("TcpStream"); + + if let Ok(addr) = self.socket_addr() { + res = res.field("addr", &addr); + } + + if let Ok(peer) = self.peer_addr() { + res = res.field("peer", &peer); + } + + let name = if cfg!(windows) {"socket"} else {"fd"}; + res = res.field(name, &self.inner.as_inner()); + res.finish() + } +} + //////////////////////////////////////////////////////////////////////////////// // TCP listeners //////////////////////////////////////////////////////////////////////////////// @@ -327,6 +346,20 @@ impl FromInner for TcpListener { } } +impl fmt::Debug for TcpListener { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut res = f.debug_struct("TcpListener"); + + if let Ok(addr) = self.socket_addr() { + res = res.field("addr", &addr); + } + + let name = if cfg!(windows) {"socket"} else {"fd"}; + res = res.field(name, &self.inner.as_inner()); + res.finish() + } +} + //////////////////////////////////////////////////////////////////////////////// // UDP //////////////////////////////////////////////////////////////////////////////// @@ -445,3 +478,17 @@ impl FromInner for UdpSocket { UdpSocket { inner: socket } } } + +impl fmt::Debug for UdpSocket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut res = f.debug_struct("UdpSocket"); + + if let Ok(addr) = self.socket_addr() { + res = res.field("addr", &addr); + } + + let name = if cfg!(windows) {"socket"} else {"fd"}; + res = res.field(name, &self.inner.as_inner()); + res.finish() + } +} diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 2e4ed38e50fe7..39910f509f9c2 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -138,11 +138,11 @@ impl Metadata { pub fn rdev(&self) -> raw::dev_t { self.0.raw().st_rdev as raw::dev_t } pub fn size(&self) -> raw::off_t { self.0.raw().st_size as raw::off_t } pub fn atime(&self) -> raw::time_t { self.0.raw().st_atime } - pub fn atime_nsec(&self) -> c_long { self.0.raw().st_atime } + pub fn atime_nsec(&self) -> c_long { self.0.raw().st_atime_nsec as c_long } pub fn mtime(&self) -> raw::time_t { self.0.raw().st_mtime } - pub fn mtime_nsec(&self) -> c_long { self.0.raw().st_mtime } + pub fn mtime_nsec(&self) -> c_long { self.0.raw().st_mtime_nsec as c_long } pub fn ctime(&self) -> raw::time_t { self.0.raw().st_ctime } - pub fn ctime_nsec(&self) -> c_long { self.0.raw().st_ctime } + pub fn ctime_nsec(&self) -> c_long { self.0.raw().st_ctime_nsec as c_long } pub fn blksize(&self) -> raw::blksize_t { self.0.raw().st_blksize as raw::blksize_t diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3b7bfb1043a35..e00cb82649b7b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -595,7 +595,7 @@ pub enum Pat_ { /// An associated const named using the qualified path `::CONST` or /// `::CONST`. Associated consts from inherent impls can be - /// refered to as simply `T::CONST`, in which case they will end up as + /// referred to as simply `T::CONST`, in which case they will end up as /// PatEnum, and the resolver will have to sort that out. PatQPath(QSelf, Path), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 87c164f7550f9..5c1f6cc12f59e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -903,10 +903,10 @@ impl<'a> State<'a> { try!(self.print_generics(params)); try!(self.end()); // end the inner ibox + try!(self.print_where_clause(¶ms.where_clause)); try!(space(&mut self.s)); try!(self.word_space("=")); try!(self.print_type(&**ty)); - try!(self.print_where_clause(¶ms.where_clause)); try!(word(&mut self.s, ";")); try!(self.end()); // end the outer ibox } diff --git a/src/test/auxiliary/issue-19163.rs b/src/test/auxiliary/issue-19163.rs new file mode 100644 index 0000000000000..76c5cdafd7cf1 --- /dev/null +++ b/src/test/auxiliary/issue-19163.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +#[macro_export] +macro_rules! mywrite { + ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) +} diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index fca74e457c21e..8c13ff7051531 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -8,14 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::RefCell; - trait Trait {} pub fn main() { let x: Vec = Vec::new(); //~^ ERROR the trait `core::marker::Sized` is not implemented //~^^ ERROR the trait `core::marker::Sized` is not implemented - let x: Vec>> = Vec::new(); - //~^ ERROR the trait `core::marker::Sized` is not implemented } diff --git a/src/test/compile-fail/issue-12511.rs b/src/test/compile-fail/issue-12511.rs new file mode 100644 index 0000000000000..35697e687341f --- /dev/null +++ b/src/test/compile-fail/issue-12511.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait t1 : t2 { +//~^ ERROR: unsupported cyclic reference between types/traits detected +} + +trait t2 : t1 { +//~^ ERROR: unsupported cyclic reference between types/traits detected +} + +fn main() { } diff --git a/src/test/compile-fail/issue-17959.rs b/src/test/compile-fail/issue-17959.rs new file mode 100644 index 0000000000000..56a66ecc8aa45 --- /dev/null +++ b/src/test/compile-fail/issue-17959.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate core; + +use core::ops::Drop; + +trait Bar {} + +struct G { + _ptr: *const T +} + +impl Drop for G { +//~^ ERROR: The requirement `T : core::marker::Sized` is added only by the Drop impl. [E0367] + fn drop(&mut self) { + if !self._ptr.is_null() { + } + } +} + +fn main() { + let x:G; +} diff --git a/src/test/compile-fail/issue-19109.rs b/src/test/compile-fail/issue-19109.rs new file mode 100644 index 0000000000000..1ffffa9fc748e --- /dev/null +++ b/src/test/compile-fail/issue-19109.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait { } + +fn function(t: &mut Trait) { + t as *mut Trait + //~^ ERROR: mismatched types: + //~| expected `()`, + //~| found `*mut Trait` + //~| (expected (), + //~| found *-ptr) [E0308] +} + +fn main() { } diff --git a/src/test/compile-fail/issue-19163.rs b/src/test/compile-fail/issue-19163.rs new file mode 100644 index 0000000000000..cd6f7c4fd8fc9 --- /dev/null +++ b/src/test/compile-fail/issue-19163.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-19163.rs + +#[macro_use] extern crate issue_19163; + +use std::io::Write; + +fn main() { + let mut v = vec![]; + mywrite!(&v, "Hello world"); + //~^ error: cannot borrow immutable borrowed content as mutable +} diff --git a/src/test/compile-fail/issue-19380.rs b/src/test/compile-fail/issue-19380.rs new file mode 100644 index 0000000000000..dbc0e410cf95c --- /dev/null +++ b/src/test/compile-fail/issue-19380.rs @@ -0,0 +1,28 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Qiz { + fn qiz(); +} + +struct Foo; +impl Qiz for Foo { + fn qiz() {} +} + +struct Bar { + foos: &'static [&'static (Qiz + 'static)] +} + +const FOO : Foo = Foo; +const BAR : Bar = Bar { foos: &[&FOO]}; +//~^ ERROR: cannot convert to a trait object because trait `Qiz` is not object-safe [E0038] + +fn main() { } diff --git a/src/test/compile-fail/issue-24805-dropck-child-has-items-via-parent.rs b/src/test/compile-fail/issue-24805-dropck-child-has-items-via-parent.rs new file mode 100644 index 0000000000000..37ef81e6866ef --- /dev/null +++ b/src/test/compile-fail/issue-24805-dropck-child-has-items-via-parent.rs @@ -0,0 +1,46 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that child trait who only has items via its *parent* trait +// does cause dropck to inject extra region constraints. + +#![allow(non_camel_case_types)] + +trait Parent { fn foo(&self); } +trait Child: Parent { } + +impl Parent for i32 { fn foo(&self) { } } +impl<'a> Parent for &'a D_Child { + fn foo(&self) { + println!("accessing child value: {}", self.0); + } +} + +impl Child for i32 { } +impl<'a> Child for &'a D_Child { } + +struct D_Child(T); +impl Drop for D_Child { fn drop(&mut self) { self.0.foo() } } + +fn f_child() { + // `_d` and `d1` are assigned the *same* lifetime by region inference ... + let (_d, d1); + + d1 = D_Child(1); + // ... we store a reference to `d1` within `_d` ... + _d = D_Child(&d1); //~ ERROR `d1` does not live long enough + + // ... dropck *should* complain, because Drop of _d could (and + // does) access the already dropped `d1` via the `foo` method. +} + +fn main() { + f_child(); +} diff --git a/src/test/compile-fail/issue-24805-dropck-trait-has-items.rs b/src/test/compile-fail/issue-24805-dropck-trait-has-items.rs new file mode 100644 index 0000000000000..0da1b9fc6e196 --- /dev/null +++ b/src/test/compile-fail/issue-24805-dropck-trait-has-items.rs @@ -0,0 +1,64 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that traits with various kinds of associated items cause +// dropck to inject extra region constraints. + +#![allow(non_camel_case_types)] + +trait HasSelfMethod { fn m1(&self) { } } +trait HasMethodWithSelfArg { fn m2(x: &Self) { } } +trait HasType { type Something; } + +impl HasSelfMethod for i32 { } +impl HasMethodWithSelfArg for i32 { } +impl HasType for i32 { type Something = (); } + +impl<'a,T> HasSelfMethod for &'a T { } +impl<'a,T> HasMethodWithSelfArg for &'a T { } +impl<'a,T> HasType for &'a T { type Something = (); } + +// e.g. `impl_drop!(Send, D_Send)` expands to: +// ```rust +// struct D_Send(T); +// impl Drop for D_Send { fn drop(&mut self) { } } +// ``` +macro_rules! impl_drop { + ($Bound:ident, $Id:ident) => { + struct $Id(T); + impl Drop for $Id { fn drop(&mut self) { } } + } +} + +impl_drop!{HasSelfMethod, D_HasSelfMethod} +impl_drop!{HasMethodWithSelfArg, D_HasMethodWithSelfArg} +impl_drop!{HasType, D_HasType} + +fn f_sm() { + let (_d, d1); + d1 = D_HasSelfMethod(1); + _d = D_HasSelfMethod(&d1); //~ ERROR `d1` does not live long enough +} +fn f_mwsa() { + let (_d, d1); + d1 = D_HasMethodWithSelfArg(1); + _d = D_HasMethodWithSelfArg(&d1); //~ ERROR `d1` does not live long enough +} +fn f_t() { + let (_d, d1); + d1 = D_HasType(1); + _d = D_HasType(&d1); //~ ERROR `d1` does not live long enough +} + +fn main() { + f_sm(); + f_mwsa(); + f_t(); +} diff --git a/src/test/pretty/issue-25031.rs b/src/test/pretty/issue-25031.rs new file mode 100644 index 0000000000000..6c5a847869e4c --- /dev/null +++ b/src/test/pretty/issue-25031.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Testing that type items with where clauses output correctly. + +// pp-exact + +fn main() { + type Foo where T: Copy = Box; +} diff --git a/src/test/run-make/issue-18943/Makefile b/src/test/run-make/issue-18943/Makefile new file mode 100644 index 0000000000000..bef70a0edaab9 --- /dev/null +++ b/src/test/run-make/issue-18943/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +# Regression test for ICE #18943 when compiling as lib + +all: + $(RUSTC) foo.rs --crate-type lib + $(call REMOVE_RLIBS,foo) && exit 0 || exit 1 diff --git a/src/test/run-make/issue-18943/foo.rs b/src/test/run-make/issue-18943/foo.rs new file mode 100644 index 0000000000000..aadf0f593e745 --- /dev/null +++ b/src/test/run-make/issue-18943/foo.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { } + +trait Bar { } + +impl<'a> Foo for Bar + 'a { } + diff --git a/src/test/run-pass/associated-types-impl-redirect.rs b/src/test/run-pass/associated-types-impl-redirect.rs index d9d11c95adbdc..4082580a123ff 100644 --- a/src/test/run-pass/associated-types-impl-redirect.rs +++ b/src/test/run-pass/associated-types-impl-redirect.rs @@ -14,8 +14,6 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -// ignore-pretty -- FIXME(#17362) - #![feature(lang_items, unboxed_closures)] #![no_implicit_prelude] diff --git a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs index 4152321cab813..082ad53d5593d 100644 --- a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs +++ b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs @@ -14,8 +14,6 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -// ignore-pretty -- FIXME(#17362) pretty prints with `<<` which lexes wrong - #![feature(lang_items, unboxed_closures)] #![no_implicit_prelude] diff --git a/src/test/run-pass/deriving-cmp-generic-struct-enum.rs b/src/test/run-pass/deriving-cmp-generic-struct-enum.rs index 14f7862ef21fc..f061b6cf4c1b3 100644 --- a/src/test/run-pass/deriving-cmp-generic-struct-enum.rs +++ b/src/test/run-pass/deriving-cmp-generic-struct-enum.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 - - #[derive(PartialEq, Eq, PartialOrd, Ord)] enum ES { ES1 { x: T }, diff --git a/src/test/run-pass/deriving-cmp-generic-struct.rs b/src/test/run-pass/deriving-cmp-generic-struct.rs index 5c7d806f519d1..d6c73f394acaa 100644 --- a/src/test/run-pass/deriving-cmp-generic-struct.rs +++ b/src/test/run-pass/deriving-cmp-generic-struct.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 - - #[derive(PartialEq, Eq, PartialOrd, Ord)] struct S { x: T, diff --git a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs index b7bfb91b278a0..fc256228507fa 100644 --- a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs +++ b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 - - #[derive(PartialEq, Eq, PartialOrd, Ord)] struct TS(T,T); diff --git a/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs b/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs index 7a0d35f6f499f..3fdf840d5963c 100644 --- a/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs +++ b/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test FIXME #11820: & is unreliable in deriving - use std::cmp::Ordering::{Less,Equal,Greater}; -#[derive(Eq,Ord)] +#[derive(PartialEq, Eq, PartialOrd, Ord)] struct A<'a> { x: &'a isize } diff --git a/src/test/run-pass/generic-recursive-tag.rs b/src/test/run-pass/generic-recursive-tag.rs index 863e0d7e33332..433bd7cd906ec 100644 --- a/src/test/run-pass/generic-recursive-tag.rs +++ b/src/test/run-pass/generic-recursive-tag.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty FIXME(#14193) - #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-14564.rs b/src/test/run-pass/issue-14564.rs new file mode 100644 index 0000000000000..a661437a44ccf --- /dev/null +++ b/src/test/run-pass/issue-14564.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod Foo { } +struct Foo; +impl Foo { } + +fn main() { } diff --git a/src/test/run-pass/issue-17170.rs b/src/test/run-pass/issue-17170.rs new file mode 100644 index 0000000000000..ef1345259278d --- /dev/null +++ b/src/test/run-pass/issue-17170.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(simd)] + +#[simd] +struct T(f64, f64, f64); + +static X: T = T(0.0, 0.0, 0.0); + +fn main() { + let _ = X; +} diff --git a/src/test/run-pass/issue-19081.rs b/src/test/run-pass/issue-19081.rs index 83ba322ba3013..8e2fa2b619715 100644 --- a/src/test/run-pass/issue-19081.rs +++ b/src/test/run-pass/issue-19081.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty -- FIXME(#17362) pretty prints as `Hash< or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type Foo where T: Copy = Box; + +fn main(){} diff --git a/src/test/run-pass/issue-23261.rs b/src/test/run-pass/issue-23261.rs new file mode 100644 index 0000000000000..fc806f5429a47 --- /dev/null +++ b/src/test/run-pass/issue-23261.rs @@ -0,0 +1,70 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Matching on a DST struct should not trigger an LLVM assertion. + +struct Foo { + a: i32, + inner: T +} + +trait Get { + fn get(&self) -> i32; +} + +impl Get for i32 { + fn get(&self) -> i32 { + *self + } +} + +fn check_val(val: &Foo<[u8]>) { + match *val { + Foo { a, .. } => { + assert_eq!(a, 32); + } + } +} + +fn check_dst_val(val: &Foo<[u8]>) { + match *val { + Foo { ref inner, .. } => { + assert_eq!(inner, [1, 2, 3]); + } + } +} + +fn check_both(val: &Foo<[u8]>) { + match *val { + Foo { a, ref inner } => { + assert_eq!(a, 32); + assert_eq!(inner, [1, 2, 3]); + } + } +} + +fn check_trait_obj(val: &Foo) { + match *val { + Foo { a, ref inner } => { + assert_eq!(a, 32); + assert_eq!(inner.get(), 32); + } + } +} + +fn main() { + let foo: &Foo<[u8]> = &Foo { a: 32, inner: [1, 2, 3] }; + check_val(foo); + check_dst_val(foo); + check_both(foo); + + let foo: &Foo = &Foo { a: 32, inner: 32 }; + check_trait_obj(foo); +} diff --git a/src/test/run-pass/issue-24805-dropck-itemless.rs b/src/test/run-pass/issue-24805-dropck-itemless.rs new file mode 100644 index 0000000000000..4512bcc2000bf --- /dev/null +++ b/src/test/run-pass/issue-24805-dropck-itemless.rs @@ -0,0 +1,81 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that item-less traits do not cause dropck to inject extra +// region constraints. + +#![allow(non_camel_case_types)] + +trait UserDefined { } + +impl UserDefined for i32 { } +impl<'a, T> UserDefined for &'a T { } + +// e.g. `impl_drop!(Send, D_Send)` expands to: +// ```rust +// struct D_Send(T); +// impl Drop for D_Send { fn drop(&mut self) { } } +// ``` +macro_rules! impl_drop { + ($Bound:ident, $Id:ident) => { + struct $Id(T); + impl Drop for $Id { fn drop(&mut self) { } } + } +} + +impl_drop!{Send, D_Send} +impl_drop!{Sized, D_Sized} + +// See note below regarding Issue 24895 +// impl_drop!{Copy, D_Copy} + +impl_drop!{Sync, D_Sync} +impl_drop!{UserDefined, D_UserDefined} + +macro_rules! body { + ($id:ident) => { { + // `_d` and `d1` are assigned the *same* lifetime by region inference ... + let (_d, d1); + + d1 = $id(1); + // ... we store a reference to `d1` within `_d` ... + _d = $id(&d1); + + // ... a *conservative* dropck will thus complain, because it + // thinks Drop of _d could access the already dropped `d1`. + } } +} + +fn f_send() { body!(D_Send) } +fn f_sized() { body!(D_Sized) } +fn f_sync() { body!(D_Sync) } + +// Issue 24895: Copy: Clone implies `impl Drop for ...` can +// access a user-defined clone() method, which causes this test case +// to fail. +// +// If 24895 is resolved by removing the `Copy: Clone` relationship, +// then this definition and the call below should be uncommented. If +// it is resolved by deciding to keep the `Copy: Clone` relationship, +// then this comment and the associated bits of code can all be +// removed. + +// fn f_copy() { body!(D_Copy) } + +fn f_userdefined() { body!(D_UserDefined) } + +fn main() { + f_send(); + f_sized(); + // See note above regarding Issue 24895. + // f_copy(); + f_sync(); + f_userdefined(); +} diff --git a/src/test/run-pass/last-use-in-cap-clause.rs b/src/test/run-pass/last-use-in-cap-clause.rs index f196899f69d68..867cb35f1f624 100644 --- a/src/test/run-pass/last-use-in-cap-clause.rs +++ b/src/test/run-pass/last-use-in-cap-clause.rs @@ -20,7 +20,6 @@ struct A { a: Box } fn foo() -> Box isize + 'static> { let k: Box<_> = box 22; let _u = A {a: k.clone()}; - // FIXME(#16640) suffix in `22` suffix shouldn't be necessary let result = || 22; // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Box::new(result) diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs index d90b88cbfd573..cff46f80cf4dc 100644 --- a/src/test/run-pass/out-of-stack.rs +++ b/src/test/run-pass/out-of-stack.rs @@ -9,6 +9,7 @@ // except according to those terms. // ignore-android: FIXME (#20004) +// ignore-musl #![feature(asm)] diff --git a/src/test/run-pass/ufcs-polymorphic-paths.rs b/src/test/run-pass/ufcs-polymorphic-paths.rs index eec852ae181c4..a8240dfbd1f8b 100644 --- a/src/test/run-pass/ufcs-polymorphic-paths.rs +++ b/src/test/run-pass/ufcs-polymorphic-paths.rs @@ -17,9 +17,6 @@ use std::default::Default; use std::iter::FromIterator; use std::ops::Add; use std::option::IntoIter as OptionIter; -// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent -// methods. -use std::vec::Vec; pub struct XorShiftRng; use XorShiftRng as DummyRng; @@ -81,11 +78,10 @@ tests! { Vec::map_in_place, fn(Vec, fn(u8) -> i8) -> Vec, (vec![b'f', b'o', b'o'], u8_as_i8); Vec::map_in_place:: i8>, fn(Vec, fn(u8) -> i8) -> Vec, (vec![b'f', b'o', b'o'], u8_as_i8); - // FIXME these break with "type parameter might not appear here pointing at ``. - // Vec::::map_in_place: fn(Vec, fn(u8) -> i8) -> Vec - // , (vec![b'f', b'o', b'o'], u8_as_i8); - // Vec::::map_in_place:: i8>: fn(Vec, fn(u8) -> i8) -> Vec - // , (vec![b'f', b'o', b'o'], u8_as_i8); + Vec::::map_in_place, fn(Vec, fn(u8) -> i8) -> Vec + , (vec![b'f', b'o', b'o'], u8_as_i8); + Vec::::map_in_place:: i8>, fn(Vec, fn(u8) -> i8) -> Vec + , (vec![b'f', b'o', b'o'], u8_as_i8); // Trait static methods. bool::size, fn() -> usize, (); diff --git a/src/test/run-pass/unfold-cross-crate.rs b/src/test/run-pass/unfold-cross-crate.rs index 5c699bf3044e6..938b5dc616729 100644 --- a/src/test/run-pass/unfold-cross-crate.rs +++ b/src/test/run-pass/unfold-cross-crate.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 - - #![feature(core)] use std::iter::Unfold; diff --git a/src/test/run-pass/utf8.rs b/src/test/run-pass/utf8.rs index 4782edf4e129a..ec1c6970ea0c9 100644 --- a/src/test/run-pass/utf8.rs +++ b/src/test/run-pass/utf8.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// -// no-pretty-expanded FIXME #15189 pub fn main() { let yen: char = '¥'; // 0xa5 diff --git a/src/test/run-pass/vec-fixed-length.rs b/src/test/run-pass/vec-fixed-length.rs index fbaba9b8a6191..befb27e6ccb00 100644 --- a/src/test/run-pass/vec-fixed-length.rs +++ b/src/test/run-pass/vec-fixed-length.rs @@ -11,7 +11,16 @@ use std::mem::size_of; -pub fn main() { +#[cfg(not(target_pointer_width = "64"))] +fn test_big_vec() {} + +#[cfg(target_pointer_width = "64")] +fn test_big_vec() +{ + assert_eq!(size_of::<[u8; (1 << 32)]>(), (1 << 32)); +} + +fn main() { let x: [isize; 4] = [1, 2, 3, 4]; assert_eq!(x[0], 1); assert_eq!(x[1], 2); @@ -19,10 +28,5 @@ pub fn main() { assert_eq!(x[3], 4); assert_eq!(size_of::<[u8; 4]>(), 4); - - // FIXME #10183 - // FIXME #18069 - //if cfg!(target_pointer_width = "64") { - // assert_eq!(size_of::<[u8; (1 << 32)]>(), (1 << 32)); - //} + test_big_vec(); }