From 62b3b40ade206830c502c394a9f547a300057ac0 Mon Sep 17 00:00:00 2001 From: Sandeep Datta Date: Thu, 11 Feb 2016 12:23:06 +0530 Subject: [PATCH 01/12] Clarified move semantics in "the details" section. --- src/doc/book/ownership.md | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index a62d31d362b14..585e337ccc2e6 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -124,19 +124,39 @@ special annotation here, it’s the default thing that Rust does. 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 x = 10; +``` + +Rust allocates memory for an integer [i32] on the [stack][sh], copies the bit +pattern representing the value of 10 to the allocated memory and binds the +variable name x to this memory region for future reference. + +Now consider the following code fragment: + ```rust let v = vec![1, 2, 3]; let v2 = v; ``` -The first line allocates memory for the vector object, `v`, and for the data it -contains. The vector object is stored on the [stack][sh] and contains a pointer -to the content (`[1, 2, 3]`) stored on the [heap][sh]. When we move `v` to `v2`, -it creates a copy of that pointer, for `v2`. Which means that there would be two -pointers to the content of the vector on the heap. It would violate Rust’s -safety guarantees by introducing a data race. Therefore, Rust forbids using `v` -after we’ve done the move. +The first line allocates memory for the vector object, `v`, on the stack like +it does for `x` above. But in addition to that it also allocates some memory +on on the [heap][sh] for the actual data `[1, 2, 3]`. Rust copies the address +of this heap allocation to an internal pointer part of the vector object +placed on the stack (let's call it the data pointer). It is worth pointing out +even at the risk of being redundant that the vector object and its data live +in separate memory regions instead of being a single contiguous memory +allocation (due to reasons we will not go into at this point of time). + +When we move `v` to `v2`, rust actually does a bitwise copy of the vector +object `v` into the stack allocation represented by `v2`. This shallow copy +does not create a copy of the heap allocation containing the actual data. +Which means that there would be two pointers to the contents of the vector +both pointing to the same memory allocation on the heap. It would violate +Rust’s safety guarantees by introducing a data race if one could access both +`v` and `v2` at the same time. Therefore, Rust forbids using `v` after we’ve +done the move (shallow copy). [sh]: the-stack-and-the-heap.html From 50d179e0624b74a68982d7002a497a7a3403d360 Mon Sep 17 00:00:00 2001 From: Sandeep Datta Date: Thu, 11 Feb 2016 19:40:19 +0530 Subject: [PATCH 02/12] Explained the data race with an example. --- src/doc/book/ownership.md | 40 +++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index 585e337ccc2e6..5c603582bfc67 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -122,7 +122,9 @@ 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: +important. + +When we write code like this: ```rust let x = 10; @@ -140,14 +142,18 @@ let v = vec![1, 2, 3]; let v2 = v; ``` -The first line allocates memory for the vector object, `v`, on the stack like +The first line allocates memory for the vector object `v` on the stack like it does for `x` above. But in addition to that it also allocates some memory -on on the [heap][sh] for the actual data `[1, 2, 3]`. Rust copies the address -of this heap allocation to an internal pointer part of the vector object -placed on the stack (let's call it the data pointer). It is worth pointing out -even at the risk of being redundant that the vector object and its data live -in separate memory regions instead of being a single contiguous memory -allocation (due to reasons we will not go into at this point of time). +on the [heap][sh] for the actual data (`[1, 2, 3]`). Rust copies the address +of this heap allocation to an internal pointer, which is part of the vector +object placed on the stack (let's call it the data pointer). + +It is worth pointing out (even at the risk of repeating things) that the vector +object and its data live in separate memory regions instead of being a single +contiguous memory allocation (due to reasons we will not go into at this point +of time). These two parts of the vector (the one on the stack and one on the +heap) must agree with each other at all times with regards to things like the +length, capacity etc. When we move `v` to `v2`, rust actually does a bitwise copy of the vector object `v` into the stack allocation represented by `v2`. This shallow copy @@ -155,8 +161,22 @@ does not create a copy of the heap allocation containing the actual data. Which means that there would be two pointers to the contents of the vector both pointing to the same memory allocation on the heap. It would violate Rust’s safety guarantees by introducing a data race if one could access both -`v` and `v2` at the same time. Therefore, Rust forbids using `v` after we’ve -done the move (shallow copy). +`v` and `v2` at the same time. + +For example if we truncated the vector to just two elements through `v2`: + +```rust +v2.truncate(2); +``` + +and `v1` were still accessible we'd end up with an invalid vector since it +would not know that the heap data has been truncated. Now, the part of the +vector `v1` on the stack does not agree with its corresponding part on the +heap. `v1` still thinks there are three elements in the vector and will +happily let us access the non existent element `v1[2]` but as you might +already know this is a recipe for disaster. + +This is why Rust forbids using `v` after we’ve done the move. [sh]: the-stack-and-the-heap.html From a8fd1bbd2f9511e9394fed1112c4ada186eb1b00 Mon Sep 17 00:00:00 2001 From: Sandeep Datta Date: Thu, 11 Feb 2016 19:44:33 +0530 Subject: [PATCH 03/12] Minor change. --- src/doc/book/ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index 5c603582bfc67..63c0671e6595e 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -171,10 +171,10 @@ v2.truncate(2); and `v1` were still accessible we'd end up with an invalid vector since it would not know that the heap data has been truncated. Now, the part of the -vector `v1` on the stack does not agree with its corresponding part on the +vector `v1` on the stack does not agree with the corresponding part on the heap. `v1` still thinks there are three elements in the vector and will happily let us access the non existent element `v1[2]` but as you might -already know this is a recipe for disaster. +already know this is a recipe for disaster (might lead to a segfault). This is why Rust forbids using `v` after we’ve done the move. From a6fedc85bfec568a404c4a78d9c7faef12937695 Mon Sep 17 00:00:00 2001 From: Sandeep Datta Date: Thu, 11 Feb 2016 19:55:45 +0530 Subject: [PATCH 04/12] Minor change. --- src/doc/book/ownership.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index 63c0671e6595e..cf6a43b1f1334 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -148,12 +148,12 @@ on the [heap][sh] for the actual data (`[1, 2, 3]`). Rust copies the address of this heap allocation to an internal pointer, which is part of the vector object placed on the stack (let's call it the data pointer). -It is worth pointing out (even at the risk of repeating things) that the vector -object and its data live in separate memory regions instead of being a single -contiguous memory allocation (due to reasons we will not go into at this point -of time). These two parts of the vector (the one on the stack and one on the -heap) must agree with each other at all times with regards to things like the -length, capacity etc. +It is worth pointing out (even at the risk of stating the obvious) that the +vector object and its data live in separate memory regions instead of being a +single contiguous memory allocation (due to reasons we will not go into at +this point of time). These two parts of the vector (the one on the stack and +one on the heap) must agree with each other at all times with regards to +things like the length, capacity etc. When we move `v` to `v2`, rust actually does a bitwise copy of the vector object `v` into the stack allocation represented by `v2`. This shallow copy @@ -169,7 +169,7 @@ For example if we truncated the vector to just two elements through `v2`: v2.truncate(2); ``` -and `v1` were still accessible we'd end up with an invalid vector since it +and `v1` were still accessible we'd end up with an invalid vector since `v1` would not know that the heap data has been truncated. Now, the part of the vector `v1` on the stack does not agree with the corresponding part on the heap. `v1` still thinks there are three elements in the vector and will From 37a952a672ca79bfcc41795e378a710c196a557a Mon Sep 17 00:00:00 2001 From: Sandeep Datta Date: Sat, 13 Feb 2016 18:40:24 +0530 Subject: [PATCH 05/12] Fixed build error as per steveklabnik's suggestion and expanded on the ills of doing out of bounds accesses. --- src/doc/book/ownership.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index cf6a43b1f1334..3d67e20388bcc 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -166,6 +166,8 @@ Rust’s safety guarantees by introducing a data race if one could access both For example if we truncated the vector to just two elements through `v2`: ```rust +# let v = vec![1, 2, 3]; +# let v2 = v; v2.truncate(2); ``` @@ -174,7 +176,9 @@ would not know that the heap data has been truncated. Now, the part of the vector `v1` on the stack does not agree with the corresponding part on the heap. `v1` still thinks there are three elements in the vector and will happily let us access the non existent element `v1[2]` but as you might -already know this is a recipe for disaster (might lead to a segfault). +already know this is a recipe for disaster. Especially because it might lead +to a segmentation fault or worse allow an unauthorized user to read from +memory to which they don't have access. This is why Rust forbids using `v` after we’ve done the move. From 1c8766761e6c2a264ed972ad70f506443184f51d Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 15 Feb 2016 17:57:21 +0100 Subject: [PATCH 06/12] Global error explanations improvements --- src/librustc/diagnostics.rs | 247 ++++++++++++++++++--------- src/librustc_borrowck/diagnostics.rs | 20 ++- src/librustc_privacy/diagnostics.rs | 10 +- src/librustc_resolve/diagnostics.rs | 82 ++++----- 4 files changed, 223 insertions(+), 136 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 8a9ef666b8384..92db527ef9803 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -20,8 +20,8 @@ This error suggests that the expression arm corresponding to the noted pattern will never be reached as for all possible values of the expression being matched, one of the preceding patterns will match. -This means that perhaps some of the preceding patterns are too general, this one -is too specific or the ordering is incorrect. +This means that perhaps some of the preceding patterns are too general, this +one is too specific or the ordering is incorrect. For example, the following `match` block has too many arms: @@ -104,28 +104,86 @@ E0004: r##" This error indicates that the compiler cannot guarantee a matching pattern for one or more possible inputs to a match expression. Guaranteed matches are required in order to assign values to match expressions, or alternatively, -determine the flow of execution. +determine the flow of execution. Erroneous code example: + +```compile_fail +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered + Terminator::TalkToMyHand => {} +} +``` If you encounter this error you must alter your patterns so that every possible value of the input type is matched. For types with a small number of variants (like enums) you should probably cover all cases explicitly. Alternatively, the underscore `_` wildcard pattern can be added after all other patterns to match -"anything else". +"anything else". Example: + +``` +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { + Terminator::TalkToMyHand => {} + Terminator::HastaLaVistaBaby => {} +} + +// or: + +match x { + Terminator::TalkToMyHand => {} + _ => {} +} +``` "##, E0005: r##" Patterns used to bind names must be irrefutable, that is, they must guarantee -that a name will be extracted in all cases. If you encounter this error you -probably need to use a `match` or `if let` to deal with the possibility of -failure. +that a name will be extracted in all cases. Erroneous code example: + +```compile_fail +let x = Some(1); +let Some(y) = x; +// error: refutable pattern in local binding: `None` not covered +``` + +If you encounter this error you probably need to use a `match` or `if let` to +deal with the possibility of failure. Example: + +```compile_fail +let x = Some(1); + +match x { + Some(y) => { + // do something + }, + None => {} +} + +// or: + +if let Some(y) = x { + // do something +} +``` "##, 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 -into a variable called `op_string` while simultaneously requiring the inner -String to be moved into a variable called `s`. +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 into a variable called `op_string` while simultaneously requiring the +inner `String` to be moved into a variable called `s`. ```compile_fail let x = Some("s".to_string()); @@ -180,7 +238,7 @@ by-ref. This limitation may be removed in a future version of Rust. -Wrong example: +Erroneous code example: ```compile_fail struct X { x: (), } @@ -264,7 +322,7 @@ trait Foo where Self: Sized { } ``` -we cannot create an object of type `Box` or `&Foo` since in this case +We cannot create an object of type `Box` or `&Foo` since in this case `Self` would not be `Sized`. Generally, `Self : Sized` is used to indicate that the trait should not be used @@ -294,7 +352,7 @@ impl Trait for u8 { ``` (Note that `&self` and `&mut self` are okay, it's additional `Self` types which -cause this problem) +cause this problem.) In such a case, the compiler cannot predict the return type of `foo()` in a situation like the following: @@ -573,15 +631,15 @@ type X = u32; // ok! "##, E0133: r##" -Using unsafe functionality, is potentially dangerous and disallowed -by safety checks. Examples: +Using unsafe functionality is potentially dangerous and disallowed by safety +checks. Examples: -- Dereferencing raw pointers -- Calling functions via FFI -- Calling functions marked unsafe +* Dereferencing raw pointers +* Calling functions via FFI +* Calling functions marked unsafe -These safety checks can be relaxed for a section of the code -by wrapping the unsafe instructions with an `unsafe` block. For instance: +These safety checks can be relaxed for a section of the code by wrapping the +unsafe instructions with an `unsafe` block. For instance: ``` unsafe fn f() { return; } @@ -1039,14 +1097,16 @@ let y = match x { println!("{}", y); ``` -In the previous example, the print statement was never reached when the wildcard -match arm was hit, so we were okay with `foo()` not returning an integer that we -could set to `y`. But in this example, `foo()` actually does return control, so -the print statement will be executed with an uninitialized value. +In the previous example, the print statement was never reached when the +wildcard match arm was hit, so we were okay with `foo()` not returning an +integer that we could set to `y`. But in this example, `foo()` actually does +return control, so the print statement will be executed with an uninitialized +value. Obviously we cannot have functions which are allowed to be used in such positions and yet can return control. So, if you are defining a function that -returns `!`, make sure that there is no way for it to actually finish executing. +returns `!`, make sure that there is no way for it to actually finish +executing. "##, E0271: r##" @@ -1206,19 +1266,19 @@ trait Index { ... } foo(true); // `bool` does not implement `Index` ``` -there will be an error about `bool` not implementing `Index`, followed by a +There will be an error about `bool` not implementing `Index`, followed by a note saying "the type `bool` cannot be indexed by `u8`". -As you can see, you can specify type parameters in curly braces for substitution -with the actual types (using the regular format string syntax) in a given -situation. Furthermore, `{Self}` will substitute to the type (in this case, -`bool`) that we tried to use. +As you can see, you can specify type parameters in curly braces for +substitution with the actual types (using the regular format string syntax) in +a given situation. Furthermore, `{Self}` will substitute to the type (in this +case, `bool`) that we tried to use. This error appears when the curly braces contain an identifier which doesn't -match with any of the type parameters or the string `Self`. This might happen if -you misspelled a type parameter, or if you intended to use literal curly braces. -If it is the latter, escape the curly braces with a second curly brace of the -same type; e.g. a literal `{` is `{{` +match with any of the type parameters or the string `Self`. This might happen +if you misspelled a type parameter, or if you intended to use literal curly +braces. If it is the latter, escape the curly braces with a second curly brace +of the same type; e.g. a literal `{` is `{{`. "##, E0273: r##" @@ -1239,10 +1299,10 @@ foo(true); // `bool` does not implement `Index` there will be an error about `bool` not implementing `Index`, followed by a note saying "the type `bool` cannot be indexed by `u8`". -As you can see, you can specify type parameters in curly braces for substitution -with the actual types (using the regular format string syntax) in a given -situation. Furthermore, `{Self}` will substitute to the type (in this case, -`bool`) that we tried to use. +As you can see, you can specify type parameters in curly braces for +substitution with the actual types (using the regular format string syntax) in +a given situation. Furthermore, `{Self}` will substitute to the type (in this +case, `bool`) that we tried to use. This error appears when the curly braces do not contain an identifier. Please add one of the same name as a type parameter. If you intended to use literal @@ -1274,8 +1334,8 @@ trait. E0275: r##" This error occurs when there was a recursive trait requirement that overflowed -before it could be evaluated. Often this means that there is unbounded recursion -in resolving some type bounds. +before it could be evaluated. Often this means that there is unbounded +recursion in resolving some type bounds. For example, in the following code: @@ -1288,9 +1348,9 @@ impl Foo for T where Bar: Foo {} ``` To determine if a `T` is `Foo`, we need to check if `Bar` is `Foo`. However, -to do this check, we need to determine that `Bar>` is `Foo`. To determine -this, we check if `Bar>>` is `Foo`, and so on. This is clearly a -recursive requirement that can't be resolved directly. +to do this check, we need to determine that `Bar>` is `Foo`. To +determine this, we check if `Bar>>` is `Foo`, and so on. This is +clearly a recursive requirement that can't be resolved directly. Consider changing your trait bounds so that they're less self-referential. "##, @@ -1336,7 +1396,7 @@ fn main() { // we now call the method with the i32 type, which doesn't implement // the Foo trait some_func(5i32); // error: the trait `Foo` is not implemented for the - // type `i32` + // type `i32` } ``` @@ -1564,7 +1624,9 @@ borrows were allowed: ```compile_fail match Some(()) { None => { }, - option if option.take().is_none() => { /* impossible, option is `Some` */ }, + option if option.take().is_none() => { + /* impossible, option is `Some` */ + }, Some(_) => { } // When the previous match failed, the option became `None`. } ``` @@ -1615,12 +1677,29 @@ See also https://github.com/rust-lang/rust/issues/14587 E0306: r##" In an array literal `[x; N]`, `N` is the number of elements in the array. This -number cannot be negative. +must be an unsigned integer. Erroneous code example: + +```compile_fail +let x = [0i32; true]; // error: expected positive integer for repeat count, + // found boolean +``` + +Working example: + +``` +let x = [0i32; 2]; +``` "##, E0307: r##" -The length of an array is part of its type. For this reason, this length must be -a compile-time constant. +The length of an array is part of its type. For this reason, this length must +be a compile-time constant. Erroneous code example: + +```compile_fail + let len = 10; + let x = [0i32; len]; // error: expected constant integer for repeat count, + // found variable +``` "##, E0308: r##" @@ -1713,24 +1792,22 @@ struct Foo { "##, E0398: r##" -In Rust 1.3, the default object lifetime bounds are expected to -change, as described in RFC #1156 [1]. You are getting a warning -because the compiler thinks it is possible that this change will cause -a compilation error in your code. It is possible, though unlikely, -that this is a false alarm. - -The heart of the change is that where `&'a Box` used to -default to `&'a Box`, it now defaults to `&'a -Box` (here, `SomeTrait` is the name of some trait -type). Note that the only types which are affected are references to -boxes, like `&Box` or `&[Box]`. More common -types like `&SomeTrait` or `Box` are unaffected. - -To silence this warning, edit your code to use an explicit bound. -Most of the time, this means that you will want to change the -signature of a function that you are calling. For example, if -the error is reported on a call like `foo(x)`, and `foo` is -defined as follows: +In Rust 1.3, the default object lifetime bounds are expected to change, as +described in RFC #1156 [1]. You are getting a warning because the compiler +thinks it is possible that this change will cause a compilation error in your +code. It is possible, though unlikely, that this is a false alarm. + +The heart of the change is that where `&'a Box` used to default to +`&'a Box`, it now defaults to `&'a Box` (here, +`SomeTrait` is the name of some trait type). Note that the only types which are +affected are references to boxes, like `&Box` or +`&[Box]`. More common types like `&SomeTrait` or `Box` +are unaffected. + +To silence this warning, edit your code to use an explicit bound. Most of the +time, this means that you will want to change the signature of a function that +you are calling. For example, if the error is reported on a call like `foo(x)`, +and `foo` is defined as follows: ```ignore fn foo(arg: &Box) { ... } @@ -1742,8 +1819,8 @@ You might change it to: fn foo<'a>(arg: &Box) { ... } ``` -This explicitly states that you expect the trait object `SomeTrait` to -contain references (with a maximum lifetime of `'a`). +This explicitly states that you expect the trait object `SomeTrait` to contain +references (with a maximum lifetime of `'a`). [1]: https://github.com/rust-lang/rfcs/pull/1156 "##, @@ -1812,8 +1889,8 @@ Also, for now, it is not possible to write deprecation messages either. "##, E0517: r##" -This error indicates that a `#[repr(..)]` attribute was placed on an unsupported -item. +This error indicates that a `#[repr(..)]` attribute was placed on an +unsupported item. Examples of erroneous code: @@ -1829,29 +1906,29 @@ struct Foo {bar: bool, baz: bool} #[repr(C)] impl Foo { - ... + // ... } ``` - - The `#[repr(C)]` attribute can only be placed on structs and enums - - The `#[repr(packed)]` and `#[repr(simd)]` attributes only work on structs - - The `#[repr(u8)]`, `#[repr(i16)]`, etc attributes only work on enums +* The `#[repr(C)]` attribute can only be placed on structs and enums. +* The `#[repr(packed)]` and `#[repr(simd)]` attributes only work on structs. +* The `#[repr(u8)]`, `#[repr(i16)]`, etc attributes only work on enums. These attributes do not work on typedefs, since typedefs are just aliases. Representations like `#[repr(u8)]`, `#[repr(i64)]` are for selecting the -discriminant size for C-like enums (when there is no associated data, e.g. `enum -Color {Red, Blue, Green}`), effectively setting the size of the enum to the size -of the provided type. Such an enum can be cast to a value of the same type as -well. In short, `#[repr(u8)]` makes the enum behave like an integer with a -constrained set of allowed values. +discriminant size for C-like enums (when there is no associated data, e.g. +`enum Color {Red, Blue, Green}`), effectively setting the size of the enum to +the size of the provided type. Such an enum can be cast to a value of the same +type as well. In short, `#[repr(u8)]` makes the enum behave like an integer +with a constrained set of allowed values. Only C-like enums can be cast to numerical primitives, so this attribute will not apply to structs. `#[repr(packed)]` reduces padding to make the struct size smaller. The -representation of enums isn't strictly defined in Rust, and this attribute won't -work on enums. +representation of enums isn't strictly defined in Rust, and this attribute +won't work on enums. `#[repr(simd)]` will give a struct consisting of a homogenous series of machine types (i.e. `u8`, `i32`, etc) a representation that permits vectorization via @@ -1860,8 +1937,8 @@ single list of data. "##, E0518: r##" -This error indicates that an `#[inline(..)]` attribute was incorrectly placed on -something other than a function or method. +This error indicates that an `#[inline(..)]` attribute was incorrectly placed +on something other than a function or method. Examples of erroneous code: @@ -1871,7 +1948,7 @@ struct Foo; #[inline(never)] impl Foo { - ... + // ... } ``` diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 29944aaf3673d..7f6fd9de3d294 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -26,7 +26,8 @@ fn foo() -> Box u32> { Notice that `x` is stack-allocated by `foo()`. By default, Rust captures closed-over data by reference. This means that once `foo()` returns, `x` no -longer exists. An attempt to access `x` within the closure would thus be unsafe. +longer exists. An attempt to access `x` within the closure would thus be +unsafe. Another situation where this might be encountered is when spawning threads: @@ -73,7 +74,14 @@ fn main() { ``` To fix this, ensure that any declared variables are initialized before being -used. +used. Example: + +``` +fn main() { + let x: i32 = 0; + let y = x; // ok! +} +``` "##, E0382: r##" @@ -210,8 +218,8 @@ let mut y: Box<_> = Box::new(&mut x); **y = 2; ``` -It can also be fixed by using a type with interior mutability, such as `Cell` or -`RefCell`: +It can also be fixed by using a type with interior mutability, such as `Cell` +or `RefCell`: ``` use std::cell::Cell; @@ -259,8 +267,8 @@ fn foo(f: F) { } ``` Alternatively, we can consider using the `Cell` and `RefCell` types to achieve -interior mutability through a shared reference. Our example's `mutable` function -could be redefined as below: +interior mutability through a shared reference. Our example's `mutable` +function could be redefined as below: ``` use std::cell::Cell; diff --git a/src/librustc_privacy/diagnostics.rs b/src/librustc_privacy/diagnostics.rs index d124ead5091d3..36ba3d0ca7363 100644 --- a/src/librustc_privacy/diagnostics.rs +++ b/src/librustc_privacy/diagnostics.rs @@ -27,8 +27,8 @@ pub fn foo (t: T) {} // same error ``` To solve this error, please ensure that the trait is also public. The trait -can be made inaccessible if necessary by placing it into a private inner module, -but it still has to be marked with `pub`. Example: +can be made inaccessible if necessary by placing it into a private inner +module, but it still has to be marked with `pub`. Example: ```ignore pub trait Foo { // we set the Foo trait public @@ -55,8 +55,8 @@ mod Foo { ``` To solve this error, please ensure that the type is also public. The type -can be made inaccessible if necessary by placing it into a private inner module, -but it still has to be marked with `pub`. +can be made inaccessible if necessary by placing it into a private inner +module, but it still has to be marked with `pub`. Example: ``` @@ -165,7 +165,7 @@ let f = Bar::Foo(0); // error: cannot invoke tuple struct constructor with ``` To solve this issue, please ensure that all of the fields of the tuple struct -are public. Alternatively, provide a new() method to the tuple struct to +are public. Alternatively, provide a `new()` method to the tuple struct to construct it from a given inner value. Example: ``` diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 99c29bbb8ef72..dee2727c16316 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -94,8 +94,8 @@ mod bar { "##, E0253: r##" -Attempt was made to import an unimportable value. This can happen when -trying to import a method from a trait. An example of this error: +Attempt was made to import an unimportable value. This can happen when trying +to import a method from a trait. An example of this error: ```compile_fail mod foo { @@ -149,10 +149,10 @@ fn main() {} "##, E0259: r##" -The name chosen for an external crate conflicts with another external crate that -has been imported into the current module. +The name chosen for an external crate conflicts with another external crate +that has been imported into the current module. -Wrong example: +Erroneous code example: ```compile_fail extern crate a; @@ -251,8 +251,8 @@ https://doc.rust-lang.org/reference.html#types "##, E0364: r##" -Private items cannot be publicly re-exported. This error indicates that -you attempted to `pub use` a type or value that was not itself public. +Private items cannot be publicly re-exported. This error indicates that you +attempted to `pub use` a type or value that was not itself public. Here is an example that demonstrates the error: @@ -275,15 +275,15 @@ mod foo { pub use foo::X; ``` -See the 'Use Declarations' section of the reference for more information -on this topic: +See the 'Use Declarations' section of the reference for more information on +this topic: https://doc.rust-lang.org/reference.html#use-declarations "##, E0365: r##" -Private modules cannot be publicly re-exported. This error indicates -that you attempted to `pub use` a module that was not itself public. +Private modules cannot be publicly re-exported. This error indicates that you +attempted to `pub use` a module that was not itself public. Here is an example that demonstrates the error: @@ -313,8 +313,8 @@ https://doc.rust-lang.org/reference.html#use-declarations "##, E0401: r##" -Inner items do not inherit type parameters from the functions they are -embedded in. For example, this will not compile: +Inner items do not inherit type parameters from the functions they are embedded +in. For example, this will not compile: ```compile_fail fn foo(x: T) { @@ -543,16 +543,15 @@ impl Bar { "##, E0411: r##" -The `Self` keyword was used outside an impl or a trait. Erroneous -code example: +The `Self` keyword was used outside an impl or a trait. Erroneous code example: ```compile_fail ::foo; // error: use of `Self` outside of an impl or trait ``` -The `Self` keyword represents the current type, which explains why it -can only be used inside an impl or a trait. It gives access to the -associated items of a type: +The `Self` keyword represents the current type, which explains why it can only +be used inside an impl or a trait. It gives access to the associated items of a +type: ``` trait Foo { @@ -564,7 +563,7 @@ trait Baz : Foo { } ``` -However, be careful when two types has a common associated type: +However, be careful when two types have a common associated type: ```compile_fail trait Foo { @@ -581,8 +580,8 @@ trait Baz : Foo + Foo2 { } ``` -This problem can be solved by specifying from which trait we want -to use the `Bar` type: +This problem can be solved by specifying from which trait we want to use the +`Bar` type: ``` trait Foo { @@ -604,16 +603,20 @@ An undeclared type name was used. Example of erroneous codes: ```compile_fail impl Something {} // error: use of undeclared type name `Something` + // or: + trait Foo { fn bar(N); // error: use of undeclared type name `N` } + // or: + fn foo(x: T) {} // error: use of undeclared type name `T` ``` -To fix this error, please verify you didn't misspell the type name, -you did declare it or imported it into the scope. Examples: +To fix this error, please verify you didn't misspell the type name, you did +declare it or imported it into the scope. Examples: ``` struct Something; @@ -635,8 +638,8 @@ fn foo(x: T) {} // ok! "##, E0413: r##" -A declaration shadows an enum variant or unit-like struct in scope. -Example of erroneous code: +A declaration shadows an enum variant or unit-like struct in scope. Example of +erroneous code: ```compile_fail struct Foo; @@ -666,8 +669,7 @@ The goal here is to avoid a conflict of names. "##, E0415: r##" -More than one function parameter have the same name. Example of erroneous -code: +More than one function parameter have the same name. Example of erroneous code: ```compile_fail fn foo(f: i32, f: i32) {} // error: identifier `f` is bound more than @@ -682,8 +684,7 @@ fn foo(f: i32, g: i32) {} // ok! "##, E0416: r##" -An identifier is bound more than once in a pattern. Example of erroneous -code: +An identifier is bound more than once in a pattern. Example of erroneous code: ```compile_fail match (1, 2) { @@ -739,8 +740,7 @@ match 0 { "##, E0419: r##" -An unknown enum variant, struct or const was used. Example of -erroneous code: +An unknown enum variant, struct or const was used. Example of erroneous code: ```compile_fail match 0 { @@ -766,8 +766,8 @@ match Something::NotFoo { "##, E0422: r##" -You are trying to use an identifier that is either undefined or not a -struct. For instance: +You are trying to use an identifier that is either undefined or not a struct. +For instance: ``` compile_fail fn main () { @@ -785,13 +785,13 @@ fn main () { } ``` -In this case, `foo` is defined, but is not a struct, so Rust can't use -it as one. +In this case, `foo` is defined, but is not a struct, so Rust can't use it as +one. "##, E0423: r##" -A `struct` variant name was used like a function name. Example of -erroneous code: +A `struct` variant name was used like a function name. Example of erroneous +code: ```compile_fail struct Foo { a: bool}; @@ -801,8 +801,8 @@ let f = Foo(); // it like a function name ``` -Please verify you didn't misspell the name of what you actually wanted -to use here. Example: +Please verify you didn't misspell the name of what you actually wanted to use +here. Example: ``` fn Foo() -> u32 { 0 } @@ -851,6 +851,7 @@ something_that_doesnt_exist::foo; // error: unresolved name `something_that_doesnt_exist::foo` // or: + trait Foo { fn bar() { Self; // error: unresolved name `Self` @@ -858,6 +859,7 @@ trait Foo { } // or: + let x = unknown_variable; // error: unresolved name `unknown_variable` ``` @@ -941,7 +943,7 @@ use something::self; // ok! "##, E0431: r##" -`self` import was made. Erroneous code example: +An invalid `self` import was made. Erroneous code example: ```compile_fail use {self}; // error: `self` import can only appear in an import list with a From 071b4b6f7b162e92711677846dcfb1736f3b9440 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Mon, 15 Feb 2016 20:18:16 -0500 Subject: [PATCH 07/12] correct the primitive char doc's use of bytes and code points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the docs suggested that '❤️' doesn't fit in a char because it's 6 bytes. But that's misleading. 'a̚' also doesn't fit in a char, even though it's only 3 bytes. The important thing is the number of code points, not the number of bytes. Clarify the primitive char docs around this. --- src/libstd/primitive_docs.rs | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index ad93fe0094ae4..b840e51873e3f 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -50,18 +50,21 @@ mod prim_bool { } /// [`String`]: string/struct.String.html /// /// As always, remember that a human intuition for 'character' may not map to -/// Unicode's definitions. For example, emoji symbols such as '❤️' are more than -/// one byte; ❤️ in particular is six: +/// Unicode's definitions. For example, emoji symbols such as '❤️' can be more +/// than one Unicode code point; this ❤️ in particular is two: /// /// ``` /// let s = String::from("❤️"); /// -/// // six bytes times one byte for each element -/// assert_eq!(6, s.len() * std::mem::size_of::()); +/// // we get two chars out of a single ❤️ +/// let mut iter = s.chars(); +/// assert_eq!(Some('\u{2764}'), iter.next()); +/// assert_eq!(Some('\u{fe0f}'), iter.next()); +/// assert_eq!(None, iter.next()); /// ``` /// -/// This also means it won't fit into a `char`, and so trying to create a -/// literal with `let heart = '❤️';` gives an error: +/// This means it won't fit into a `char`. Trying to create a literal with +/// `let heart = '❤️';` gives an error: /// /// ```text /// error: character literal may only contain one codepoint: '❤ @@ -69,8 +72,8 @@ mod prim_bool { } /// ^~ /// ``` /// -/// Another implication of this is that if you want to do per-`char`acter -/// processing, it can end up using a lot more memory: +/// Another implication of the 4-byte fixed size of a `char`, is that +/// per-`char`acter processing can end up using a lot more memory: /// /// ``` /// let s = String::from("love: ❤️"); @@ -79,19 +82,6 @@ mod prim_bool { } /// assert_eq!(12, s.len() * std::mem::size_of::()); /// assert_eq!(32, v.len() * std::mem::size_of::()); /// ``` -/// -/// Or may give you results you may not expect: -/// -/// ``` -/// let s = String::from("❤️"); -/// -/// let mut iter = s.chars(); -/// -/// // we get two chars out of a single ❤️ -/// assert_eq!(Some('\u{2764}'), iter.next()); -/// assert_eq!(Some('\u{fe0f}'), iter.next()); -/// assert_eq!(None, iter.next()); -/// ``` mod prim_char { } #[doc(primitive = "unit")] From 2cac9d7bd3f26072e101ccabcb4913ef05f46d7c Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Sat, 30 Jan 2016 13:44:45 -0500 Subject: [PATCH 08/12] clarify how insert() doesn't update keys The first time I read the docs for `insert()`, I thought it was saying it didn't update existing *values*, and I was confused. Reword the docs to make it clear that `insert()` does update values. --- src/libcollections/btree/map.rs | 7 ++++--- src/libstd/collections/hash/map.rs | 7 ++++--- src/libstd/collections/mod.rs | 9 ++++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 0ced4e1952aa5..7207e7b151c1e 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -375,9 +375,10 @@ impl BTreeMap { /// /// If the map did not have this key present, `None` is returned. /// - /// If the map did have this key present, the key is not updated, the - /// value is updated and the old value is returned. - /// See the [module-level documentation] for more. + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [module-level + /// documentation] for more. /// /// [module-level documentation]: index.html#insert-and-complex-keys /// diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 586fafc2b4a75..7220690469c2a 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1157,9 +1157,10 @@ impl HashMap /// /// If the map did not have this key present, `None` is returned. /// - /// If the map did have this key present, the key is not updated, the - /// value is updated and the old value is returned. - /// See the [module-level documentation] for more. + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [module-level + /// documentation] for more. /// /// [module-level documentation]: index.html#insert-and-complex-keys /// diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 417261cf4c304..06c14157606b2 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -397,12 +397,15 @@ //! } //! //! let mut map = BTreeMap::new(); -//! map.insert(Foo { a: 1, b: "baz" }, ()); +//! map.insert(Foo { a: 1, b: "baz" }, 99); //! //! // We already have a Foo with an a of 1, so this will be updating the value. -//! map.insert(Foo { a: 1, b: "xyz" }, ()); +//! map.insert(Foo { a: 1, b: "xyz" }, 100); //! -//! // ... but the key hasn't changed. b is still "baz", not "xyz" +//! // The value has been updated... +//! assert_eq!(map.values().next().unwrap(), &100); +//! +//! // ...but the key hasn't changed. b is still "baz", not "xyz". //! assert_eq!(map.keys().next().unwrap().b, "baz"); //! ``` From 4a1ddff1c1fbf444a8a688efc34466ab4fc14ae5 Mon Sep 17 00:00:00 2001 From: Wangshan Lu Date: Tue, 16 Feb 2016 19:40:06 +0800 Subject: [PATCH 09/12] Fix links in release notes 1.7.0 --- RELEASES.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 5ff06f2f81075..a247eb2e9555c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -94,11 +94,11 @@ Misc the `-Z unstable-options` flag. * [When running tests with `--test`, rustdoc will pass `--cfg` arguments to the compiler][1.7dt]. -* [The compiler is built with RPATH information by default][1.7rp]. +* [The compiler is built with RPATH information by default][1.7rpa]. This means that it will be possible to run `rustc` when installed in unusual configurations without configuring the dynamic linker search path explicitly. -* [`rustc` passes `--enable-new-dtags` to GNU ld][1.7dt]. This makes +* [`rustc` passes `--enable-new-dtags` to GNU ld][1.7dta]. This makes any RPATH entries (emitted with `-C rpath`) *not* take precedence over `LD_LIBRARY_PATH`. @@ -132,7 +132,7 @@ Compatibility Notes [1.7cp]: https://github.com/rust-lang/cargo/pull/2224 [1.7d]: https://github.com/rust-lang/rust/pull/30724 [1.7dt]: https://github.com/rust-lang/rust/pull/30372 -[1.7dt]: https://github.com/rust-lang/rust/pull/30394 +[1.7dta]: https://github.com/rust-lang/rust/pull/30394 [1.7f]: https://github.com/rust-lang/rust/pull/30672 [1.7h]: https://github.com/rust-lang/rust/pull/30818 [1.7j]: https://github.com/rust-lang/rust/pull/30711 @@ -140,7 +140,7 @@ Compatibility Notes [1.7m]: https://github.com/rust-lang/rust/pull/30381 [1.7p]: https://github.com/rust-lang/rust/pull/30681 [1.7rp]: https://github.com/rust-lang/rust/pull/29498 -[1.7rp]: https://github.com/rust-lang/rust/pull/30353 +[1.7rpa]: https://github.com/rust-lang/rust/pull/30353 [1.7rr]: https://github.com/rust-lang/cargo/pull/2279 [1.7sf]: https://github.com/rust-lang/rust/pull/30389 [1.7utf8]: https://github.com/rust-lang/rust/pull/30740 From 8f13f8752f925e376b26cb32382fe25acd2a8241 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 16 Feb 2016 21:43:49 -0500 Subject: [PATCH 10/12] Improve 'std::mem::transmute_copy' doc example. Prior to this commit, it was a trivial example that did not demonstrate the effects of using the function. Fixes https://github.com/rust-lang/rust/issues/31094 --- src/libcore/mem.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index a521700b84bd8..c36ad592ad3b5 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -571,9 +571,25 @@ pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize; /// ``` /// use std::mem; /// -/// let one = unsafe { mem::transmute_copy(&1) }; +/// #[repr(packed)] +/// struct Foo { +/// bar: u8, +/// } +/// +/// let foo_slice = [10u8]; +/// +/// unsafe { +/// // Copy the data from 'foo_slice' and treat it as a 'Foo' +/// let mut foo_struct: Foo = mem::transmute_copy(&foo_slice); +/// assert_eq!(foo_struct.bar, 10); +/// +/// // Modify the copied data +/// foo_struct.bar = 20; +/// assert_eq!(foo_struct.bar, 20); +/// } /// -/// assert_eq!(1, one); +/// // The contents of 'foo_slice' should not have changed +/// assert_eq!(foo_slice, [10]); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 1536195ce66dcf764782e1f36ced4aa5eefef321 Mon Sep 17 00:00:00 2001 From: Sandeep Datta Date: Wed, 17 Feb 2016 20:47:24 +0530 Subject: [PATCH 11/12] Made v2 mutable so that we can actually truncate it. --- src/doc/book/ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index 3d67e20388bcc..ac6184013ee23 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -139,7 +139,7 @@ Now consider the following code fragment: ```rust let v = vec![1, 2, 3]; -let v2 = v; +let mut v2 = v; ``` The first line allocates memory for the vector object `v` on the stack like @@ -167,7 +167,7 @@ For example if we truncated the vector to just two elements through `v2`: ```rust # let v = vec![1, 2, 3]; -# let v2 = v; +# let mut v2 = v; v2.truncate(2); ``` From f82c984764c6f97dccac6a78b421954a64f3e6e0 Mon Sep 17 00:00:00 2001 From: Gleb Kozyrev Date: Wed, 17 Feb 2016 20:13:59 +0200 Subject: [PATCH 12/12] Update `Path::strip_prefix` doc --- src/libstd/path.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 10ecaed3aefd6..3798fb76ad6a5 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1582,8 +1582,10 @@ impl Path { /// Returns a path that, when joined onto `base`, yields `self`. /// + /// # Errors + /// /// If `base` is not a prefix of `self` (i.e. `starts_with` - /// returns false), then `relative_from` returns `None`. + /// returns `false`), returns `Err`. #[stable(since = "1.7.0", feature = "path_strip_prefix")] pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P) -> Result<&'a Path, StripPrefixError>