Auto merge of #33742 - Manishearth:rollup, r=Manishearth
Rollup of 10 pull requests - Successful merges: #33353, #33611, #33696, #33698, #33705, #33708, #33712, #33720, #33721, #33730 - Failed merges:
This commit is contained in:
commit
764ef92ae7
@ -12,7 +12,7 @@ the `link_args` attribute. This attribute is applied to `extern` blocks and
|
|||||||
specifies raw flags which need to get passed to the linker when producing an
|
specifies raw flags which need to get passed to the linker when producing an
|
||||||
artifact. An example usage would be:
|
artifact. An example usage would be:
|
||||||
|
|
||||||
``` no_run
|
```rust,no_run
|
||||||
#![feature(link_args)]
|
#![feature(link_args)]
|
||||||
|
|
||||||
#[link_args = "-foo -bar -baz"]
|
#[link_args = "-foo -bar -baz"]
|
||||||
|
@ -319,6 +319,53 @@ assert_eq!(3, answer);
|
|||||||
Now we take a trait object, a `&Fn`. And we have to make a reference
|
Now we take a trait object, a `&Fn`. And we have to make a reference
|
||||||
to our closure when we pass it to `call_with_one`, so we use `&||`.
|
to our closure when we pass it to `call_with_one`, so we use `&||`.
|
||||||
|
|
||||||
|
A quick note about closures that use explicit lifetimes. Sometimes you might have a closure
|
||||||
|
that takes a reference like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn call_with_ref<F>(some_closure:F) -> i32
|
||||||
|
where F: Fn(&i32) -> i32 {
|
||||||
|
|
||||||
|
let mut value = 0;
|
||||||
|
some_closure(&value)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Normally you can specify the lifetime of the parameter to our closure. We
|
||||||
|
could annotate it on the function declaration:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
fn call_with_ref<'a, F>(some_closure:F) -> i32
|
||||||
|
where F: Fn(&'a 32) -> i32 {
|
||||||
|
```
|
||||||
|
|
||||||
|
However this presents a problem with in our case. When you specify the explict
|
||||||
|
lifetime on a function it binds that lifetime to the *entire* scope of the function
|
||||||
|
instead of just the invocation scope of our closure. This means that the borrow checker
|
||||||
|
will see a mutable reference in the same lifetime as our immutable reference and fail
|
||||||
|
to compile.
|
||||||
|
|
||||||
|
In order to say that we only need the lifetime to be valid for the invocation scope
|
||||||
|
of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
fn call_with_ref<F>(some_closure:F) -> i32
|
||||||
|
where F: for<'a> Fn(&'a 32) -> i32 {
|
||||||
|
```
|
||||||
|
|
||||||
|
This lets the Rust compiler find the minimum lifetime to invoke our closure and
|
||||||
|
satisfy the borrow checker's rules. Our function then compiles and excutes as we
|
||||||
|
expect.
|
||||||
|
|
||||||
|
```
|
||||||
|
fn call_with_ref<F>(some_closure:F) -> i32
|
||||||
|
where F: for<'a> Fn(&'a i32) -> i32 {
|
||||||
|
|
||||||
|
let mut value = 0;
|
||||||
|
some_closure(&value)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# Function pointers and closures
|
# Function pointers and closures
|
||||||
|
|
||||||
A function pointer is kind of like a closure that has no environment. As such,
|
A function pointer is kind of like a closure that has no environment. As such,
|
||||||
@ -344,7 +391,7 @@ assert_eq!(2, answer);
|
|||||||
In this example, we don’t strictly need the intermediate variable `f`,
|
In this example, we don’t strictly need the intermediate variable `f`,
|
||||||
the name of the function works just fine too:
|
the name of the function works just fine too:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
let answer = call_with_one(&add_one);
|
let answer = call_with_one(&add_one);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ Let's write a plugin
|
|||||||
[`roman_numerals.rs`](https://github.com/rust-lang/rust/tree/master/src/test/auxiliary/roman_numerals.rs)
|
[`roman_numerals.rs`](https://github.com/rust-lang/rust/tree/master/src/test/auxiliary/roman_numerals.rs)
|
||||||
that implements Roman numeral integer literals.
|
that implements Roman numeral integer literals.
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
#![crate_type="dylib"]
|
#![crate_type="dylib"]
|
||||||
#![feature(plugin_registrar, rustc_private)]
|
#![feature(plugin_registrar, rustc_private)]
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
|||||||
|
|
||||||
Then we can use `rn!()` like any other macro:
|
Then we can use `rn!()` like any other macro:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
#![feature(plugin)]
|
#![feature(plugin)]
|
||||||
#![plugin(roman_numerals)]
|
#![plugin(roman_numerals)]
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ Some of the [macro debugging tips](macros.html#debugging-macro-code) are applica
|
|||||||
You can use `syntax::parse` to turn token trees into
|
You can use `syntax::parse` to turn token trees into
|
||||||
higher-level syntax elements like expressions:
|
higher-level syntax elements like expressions:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
||||||
-> Box<MacResult+'static> {
|
-> Box<MacResult+'static> {
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ infrastructure](../reference.html#lint-check-attributes) with additional checks
|
|||||||
code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
|
code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
|
||||||
that warns about any item named `lintme`.
|
that warns about any item named `lintme`.
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
#![feature(plugin_registrar)]
|
#![feature(plugin_registrar)]
|
||||||
#![feature(box_syntax, rustc_private)]
|
#![feature(box_syntax, rustc_private)]
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
|||||||
|
|
||||||
Then code like
|
Then code like
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
#![plugin(lint_plugin_test)]
|
#![plugin(lint_plugin_test)]
|
||||||
|
|
||||||
fn lintme() { }
|
fn lintme() { }
|
||||||
|
@ -165,7 +165,7 @@ concurrency bugs.
|
|||||||
As an example, here is a Rust program that would have a data race in many
|
As an example, here is a Rust program that would have a data race in many
|
||||||
languages. It will not compile:
|
languages. It will not compile:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ Calling `clone()` on an `Rc<T>` will return a new owned reference and bump the
|
|||||||
internal reference count. We create one of these for each thread:
|
internal reference count. We create one of these for each thread:
|
||||||
|
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -250,7 +250,7 @@ In essence, `Arc<T>` is a type that lets us share ownership of data _across
|
|||||||
threads_.
|
threads_.
|
||||||
|
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -336,7 +336,7 @@ The lock "release" here is implicit; when the result of the lock (in this case,
|
|||||||
Note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of
|
Note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of
|
||||||
[`Mutex`](../std/sync/struct.Mutex.html) has this signature:
|
[`Mutex`](../std/sync/struct.Mutex.html) has this signature:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
fn lock(&self) -> LockResult<MutexGuard<T>>
|
fn lock(&self) -> LockResult<MutexGuard<T>>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ Here’s an example of documenting a macro:
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```rust,should_panic
|
||||||
/// # #[macro_use] extern crate foo;
|
/// # #[macro_use] extern crate foo;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// panic_unless!(true == false, “I’m broken.”);
|
/// panic_unless!(true == false, “I’m broken.”);
|
||||||
@ -429,7 +429,7 @@ There are a few more annotations that are useful to help `rustdoc` do the right
|
|||||||
thing when testing your code:
|
thing when testing your code:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
/// ```ignore
|
/// ```rust,ignore
|
||||||
/// fn foo() {
|
/// fn foo() {
|
||||||
/// ```
|
/// ```
|
||||||
# fn foo() {}
|
# fn foo() {}
|
||||||
@ -441,7 +441,7 @@ with `text` if it's not code, or using `#`s to get a working example that
|
|||||||
only shows the part you care about.
|
only shows the part you care about.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
/// ```should_panic
|
/// ```rust,should_panic
|
||||||
/// assert!(false);
|
/// assert!(false);
|
||||||
/// ```
|
/// ```
|
||||||
# fn foo() {}
|
# fn foo() {}
|
||||||
@ -451,7 +451,7 @@ only shows the part you care about.
|
|||||||
not actually pass as a test.
|
not actually pass as a test.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
/// ```no_run
|
/// ```rust,no_run
|
||||||
/// loop {
|
/// loop {
|
||||||
/// println!("Hello, world");
|
/// println!("Hello, world");
|
||||||
/// }
|
/// }
|
||||||
@ -563,7 +563,7 @@ can be useful when changing some options, or when writing a macro.
|
|||||||
|
|
||||||
`rustdoc` will show the documentation for a public re-export in both places:
|
`rustdoc` will show the documentation for a public re-export in both places:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
extern crate foo;
|
extern crate foo;
|
||||||
|
|
||||||
pub use foo::bar;
|
pub use foo::bar;
|
||||||
@ -575,7 +575,7 @@ documentation in both places.
|
|||||||
|
|
||||||
This behavior can be suppressed with `no_inline`:
|
This behavior can be suppressed with `no_inline`:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
extern crate foo;
|
extern crate foo;
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
|
@ -28,7 +28,7 @@ and add `extern crate libc;` to your crate root.
|
|||||||
The following is a minimal example of calling a foreign function which will
|
The following is a minimal example of calling a foreign function which will
|
||||||
compile if snappy is installed:
|
compile if snappy is installed:
|
||||||
|
|
||||||
```no_run
|
```rust,no_run
|
||||||
# #![feature(libc)]
|
# #![feature(libc)]
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
use libc::size_t;
|
use libc::size_t;
|
||||||
@ -62,7 +62,7 @@ keeping the binding correct at runtime.
|
|||||||
|
|
||||||
The `extern` block can be extended to cover the entire snappy API:
|
The `extern` block can be extended to cover the entire snappy API:
|
||||||
|
|
||||||
```no_run
|
```rust,no_run
|
||||||
# #![feature(libc)]
|
# #![feature(libc)]
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
use libc::{c_int, size_t};
|
use libc::{c_int, size_t};
|
||||||
@ -209,7 +209,7 @@ A basic example is:
|
|||||||
|
|
||||||
Rust code:
|
Rust code:
|
||||||
|
|
||||||
```no_run
|
```rust,no_run
|
||||||
extern fn callback(a: i32) {
|
extern fn callback(a: i32) {
|
||||||
println!("I'm called from C with value {0}", a);
|
println!("I'm called from C with value {0}", a);
|
||||||
}
|
}
|
||||||
@ -262,7 +262,7 @@ referenced Rust object.
|
|||||||
|
|
||||||
Rust code:
|
Rust code:
|
||||||
|
|
||||||
```no_run
|
```rust,no_run
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct RustObject {
|
struct RustObject {
|
||||||
a: i32,
|
a: i32,
|
||||||
@ -406,7 +406,7 @@ Foreign APIs often export a global variable which could do something like track
|
|||||||
global state. In order to access these variables, you declare them in `extern`
|
global state. In order to access these variables, you declare them in `extern`
|
||||||
blocks with the `static` keyword:
|
blocks with the `static` keyword:
|
||||||
|
|
||||||
```no_run
|
```rust,no_run
|
||||||
# #![feature(libc)]
|
# #![feature(libc)]
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
@ -425,7 +425,7 @@ Alternatively, you may need to alter global state provided by a foreign
|
|||||||
interface. To do this, statics can be declared with `mut` so we can mutate
|
interface. To do this, statics can be declared with `mut` so we can mutate
|
||||||
them.
|
them.
|
||||||
|
|
||||||
```no_run
|
```rust,no_run
|
||||||
# #![feature(libc)]
|
# #![feature(libc)]
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ x = y = 5
|
|||||||
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
|
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
|
||||||
following will produce a compile-time error:
|
following will produce a compile-time error:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
let x = (let y = 5); // expected identifier, found keyword `let`
|
let x = (let y = 5); // expected identifier, found keyword `let`
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -283,7 +283,7 @@ stack backtrace:
|
|||||||
|
|
||||||
A diverging function can be used as any type:
|
A diverging function can be used as any type:
|
||||||
|
|
||||||
```should_panic
|
```rust,should_panic
|
||||||
# fn diverges() -> ! {
|
# fn diverges() -> ! {
|
||||||
# panic!("This function never returns!");
|
# panic!("This function never returns!");
|
||||||
# }
|
# }
|
||||||
|
@ -4,7 +4,7 @@ For extremely low-level manipulations and performance reasons, one
|
|||||||
might wish to control the CPU directly. Rust supports using inline
|
might wish to control the CPU directly. Rust supports using inline
|
||||||
assembly to do this via the `asm!` macro.
|
assembly to do this via the `asm!` macro.
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
asm!(assembly template
|
asm!(assembly template
|
||||||
: output operands
|
: output operands
|
||||||
: input operands
|
: input operands
|
||||||
|
@ -74,7 +74,7 @@ for x in 0..10 {
|
|||||||
|
|
||||||
In slightly more abstract terms,
|
In slightly more abstract terms,
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
for var in expression {
|
for var in expression {
|
||||||
code
|
code
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ macro_rules! vec {
|
|||||||
|
|
||||||
Whoa, that’s a lot of new syntax! Let’s break it down.
|
Whoa, that’s a lot of new syntax! Let’s break it down.
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
macro_rules! vec { ... }
|
macro_rules! vec { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ syntax and serves to distinguish a macro from an ordinary function.
|
|||||||
The macro is defined through a series of rules, which are pattern-matching
|
The macro is defined through a series of rules, which are pattern-matching
|
||||||
cases. Above, we had
|
cases. Above, we had
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
( $( $x:expr ),* ) => { ... };
|
( $( $x:expr ),* ) => { ... };
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ separated by commas.
|
|||||||
Aside from the special matcher syntax, any Rust tokens that appear in a matcher
|
Aside from the special matcher syntax, any Rust tokens that appear in a matcher
|
||||||
must match exactly. For example,
|
must match exactly. For example,
|
||||||
|
|
||||||
```rust
|
```rust,ignore
|
||||||
macro_rules! foo {
|
macro_rules! foo {
|
||||||
(x => $e:expr) => (println!("mode X: {}", $e));
|
(x => $e:expr) => (println!("mode X: {}", $e));
|
||||||
(y => $e:expr) => (println!("mode Y: {}", $e));
|
(y => $e:expr) => (println!("mode Y: {}", $e));
|
||||||
@ -147,7 +147,7 @@ The right-hand side of a macro rule is ordinary Rust syntax, for the most part.
|
|||||||
But we can splice in bits of syntax captured by the matcher. From the original
|
But we can splice in bits of syntax captured by the matcher. From the original
|
||||||
example:
|
example:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
$(
|
$(
|
||||||
temp_vec.push($x);
|
temp_vec.push($x);
|
||||||
)*
|
)*
|
||||||
@ -165,7 +165,7 @@ within the repeated block.
|
|||||||
Another detail: the `vec!` macro has *two* pairs of braces on the right-hand
|
Another detail: the `vec!` macro has *two* pairs of braces on the right-hand
|
||||||
side. They are often combined like so:
|
side. They are often combined like so:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
macro_rules! foo {
|
macro_rules! foo {
|
||||||
() => {{
|
() => {{
|
||||||
...
|
...
|
||||||
|
@ -55,6 +55,8 @@ fn foo(mut x: i32) {
|
|||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that here, the `x` is mutable, but not the `y`.
|
||||||
|
|
||||||
[pattern]: patterns.html
|
[pattern]: patterns.html
|
||||||
|
|
||||||
# Interior vs. Exterior Mutability
|
# Interior vs. Exterior Mutability
|
||||||
|
@ -123,7 +123,7 @@ fn main() {
|
|||||||
For `HasArea` and `Square`, we declare a type parameter `T` and replace
|
For `HasArea` and `Square`, we declare a type parameter `T` and replace
|
||||||
`f64` with it. The `impl` needs more involved modifications:
|
`f64` with it. The `impl` needs more involved modifications:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
impl<T> HasArea<T> for Square<T>
|
impl<T> HasArea<T> for Square<T>
|
||||||
where T: Mul<Output=T> + Copy { ... }
|
where T: Mul<Output=T> + Copy { ... }
|
||||||
```
|
```
|
||||||
|
@ -306,7 +306,7 @@ let y = TraitObject {
|
|||||||
Not every trait can be used to make a trait object. For example, vectors implement
|
Not every trait can be used to make a trait object. For example, vectors implement
|
||||||
`Clone`, but if we try to make a trait object:
|
`Clone`, but if we try to make a trait object:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
let v = vec![1, 2, 3];
|
let v = vec![1, 2, 3];
|
||||||
let o = &v as &Clone;
|
let o = &v as &Clone;
|
||||||
```
|
```
|
||||||
|
@ -195,7 +195,7 @@ fn main() {
|
|||||||
`is_square()` needs to check that the sides are equal, so the sides must be of
|
`is_square()` needs to check that the sides are equal, so the sides must be of
|
||||||
a type that implements the [`core::cmp::PartialEq`][PartialEq] trait:
|
a type that implements the [`core::cmp::PartialEq`][PartialEq] trait:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
impl<T: PartialEq> Rectangle<T> { ... }
|
impl<T: PartialEq> Rectangle<T> { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ The indices count from `0`, so the third element is `v[2]`.
|
|||||||
|
|
||||||
It’s also important to note that you must index with the `usize` type:
|
It’s also important to note that you must index with the `usize` type:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
let v = vec![1, 2, 3, 4, 5];
|
let v = vec![1, 2, 3, 4, 5];
|
||||||
|
|
||||||
let i: usize = 0;
|
let i: usize = 0;
|
||||||
@ -71,7 +71,7 @@ you cannot index with an `i32`.
|
|||||||
|
|
||||||
If you try to access an index that doesn’t exist:
|
If you try to access an index that doesn’t exist:
|
||||||
|
|
||||||
```ignore
|
```rust,ignore
|
||||||
let v = vec![1, 2, 3];
|
let v = vec![1, 2, 3];
|
||||||
println!("Item 7 is {}", v[7]);
|
println!("Item 7 is {}", v[7]);
|
||||||
```
|
```
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 6598e2cbfd7e09bfca249cc3dcbf889735f73ce1
|
Subproject commit b19b5465a1235be3323363cdc11838739b593029
|
@ -502,6 +502,33 @@ fn foo(a: &mut i32) {
|
|||||||
```
|
```
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
|
E0502: r##"
|
||||||
|
This error indicates that you are trying to borrow a variable as mutable when it
|
||||||
|
has already been borrowed as immutable.
|
||||||
|
|
||||||
|
Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail
|
||||||
|
fn bar(x: &mut i32) {}
|
||||||
|
fn foo(a: &mut i32) {
|
||||||
|
let ref y = a; // a is borrowed as immutable.
|
||||||
|
bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
|
||||||
|
// as immutable
|
||||||
|
}
|
||||||
|
```
|
||||||
|
To fix this error, ensure that you don't have any other references to the
|
||||||
|
variable before trying to access it mutably:
|
||||||
|
```
|
||||||
|
fn bar(x: &mut i32) {}
|
||||||
|
fn foo(a: &mut i32) {
|
||||||
|
bar(a);
|
||||||
|
let ref y = a; // ok!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
For more information on the rust ownership system, take a look at
|
||||||
|
https://doc.rust-lang.org/stable/book/references-and-borrowing.html.
|
||||||
|
"##,
|
||||||
|
|
||||||
E0504: r##"
|
E0504: r##"
|
||||||
This error occurs when an attempt is made to move a borrowed variable into a
|
This error occurs when an attempt is made to move a borrowed variable into a
|
||||||
closure.
|
closure.
|
||||||
@ -984,7 +1011,6 @@ fn main() {
|
|||||||
register_diagnostics! {
|
register_diagnostics! {
|
||||||
E0385, // {} in an aliasable location
|
E0385, // {} in an aliasable location
|
||||||
E0388, // {} in a static location
|
E0388, // {} in a static location
|
||||||
E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
|
|
||||||
E0503, // cannot use `..` because it was mutably borrowed
|
E0503, // cannot use `..` because it was mutably borrowed
|
||||||
E0508, // cannot move out of type `..`, a non-copy fixed-size array
|
E0508, // cannot move out of type `..`, a non-copy fixed-size array
|
||||||
E0524, // two closures require unique access to `..` at the same time
|
E0524, // two closures require unique access to `..` at the same time
|
||||||
|
@ -215,15 +215,18 @@ fn report_elision_failure(
|
|||||||
{
|
{
|
||||||
let mut m = String::new();
|
let mut m = String::new();
|
||||||
let len = params.len();
|
let len = params.len();
|
||||||
let mut any_lifetimes = false;
|
|
||||||
|
|
||||||
for (i, info) in params.into_iter().enumerate() {
|
let elided_params: Vec<_> = params.into_iter()
|
||||||
|
.filter(|info| info.lifetime_count > 0)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let elided_len = elided_params.len();
|
||||||
|
|
||||||
|
for (i, info) in elided_params.into_iter().enumerate() {
|
||||||
let ElisionFailureInfo {
|
let ElisionFailureInfo {
|
||||||
name, lifetime_count: n, have_bound_regions
|
name, lifetime_count: n, have_bound_regions
|
||||||
} = info;
|
} = info;
|
||||||
|
|
||||||
any_lifetimes = any_lifetimes || (n > 0);
|
|
||||||
|
|
||||||
let help_name = if name.is_empty() {
|
let help_name = if name.is_empty() {
|
||||||
format!("argument {}", i + 1)
|
format!("argument {}", i + 1)
|
||||||
} else {
|
} else {
|
||||||
@ -237,13 +240,14 @@ fn report_elision_failure(
|
|||||||
if have_bound_regions { "free " } else { "" } )
|
if have_bound_regions { "free " } else { "" } )
|
||||||
})[..]);
|
})[..]);
|
||||||
|
|
||||||
if len == 2 && i == 0 {
|
if elided_len == 2 && i == 0 {
|
||||||
m.push_str(" or ");
|
m.push_str(" or ");
|
||||||
} else if i + 2 == len {
|
} else if i + 2 == elided_len {
|
||||||
m.push_str(", or ");
|
m.push_str(", or ");
|
||||||
} else if i + 1 != len {
|
} else if i != elided_len - 1 {
|
||||||
m.push_str(", ");
|
m.push_str(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
@ -252,7 +256,7 @@ fn report_elision_failure(
|
|||||||
there is no value for it to be borrowed from");
|
there is no value for it to be borrowed from");
|
||||||
help!(db,
|
help!(db,
|
||||||
"consider giving it a 'static lifetime");
|
"consider giving it a 'static lifetime");
|
||||||
} else if !any_lifetimes {
|
} else if elided_len == 0 {
|
||||||
help!(db,
|
help!(db,
|
||||||
"this function's return type contains a borrowed value with \
|
"this function's return type contains a borrowed value with \
|
||||||
an elided lifetime, but the lifetime cannot be derived from \
|
an elided lifetime, but the lifetime cannot be derived from \
|
||||||
@ -260,7 +264,7 @@ fn report_elision_failure(
|
|||||||
help!(db,
|
help!(db,
|
||||||
"consider giving it an explicit bounded or 'static \
|
"consider giving it an explicit bounded or 'static \
|
||||||
lifetime");
|
lifetime");
|
||||||
} else if len == 1 {
|
} else if elided_len == 1 {
|
||||||
help!(db,
|
help!(db,
|
||||||
"this function's return type contains a borrowed value, but \
|
"this function's return type contains a borrowed value, but \
|
||||||
the signature does not say which {} it is borrowed from",
|
the signature does not say which {} it is borrowed from",
|
||||||
|
@ -1566,7 +1566,8 @@ impl<'a> fmt::Display for Item<'a> {
|
|||||||
write!(fmt, "</span>")?; // in-band
|
write!(fmt, "</span>")?; // in-band
|
||||||
write!(fmt, "<span class='out-of-band'>")?;
|
write!(fmt, "<span class='out-of-band'>")?;
|
||||||
if let Some(version) = self.item.stable_since() {
|
if let Some(version) = self.item.stable_since() {
|
||||||
write!(fmt, "<span class='since'>{}</span>", version)?;
|
write!(fmt, "<span class='since' title='Stable since Rust version {0}'>{0}</span>",
|
||||||
|
version)?;
|
||||||
}
|
}
|
||||||
write!(fmt,
|
write!(fmt,
|
||||||
r##"<span id='render-detail'>
|
r##"<span id='render-detail'>
|
||||||
@ -2136,7 +2137,7 @@ fn render_stability_since_raw<'a>(w: &mut fmt::Formatter,
|
|||||||
containing_ver: Option<&'a str>) -> fmt::Result {
|
containing_ver: Option<&'a str>) -> fmt::Result {
|
||||||
if let Some(v) = ver {
|
if let Some(v) = ver {
|
||||||
if containing_ver != ver && v.len() > 0 {
|
if containing_ver != ver && v.len() > 0 {
|
||||||
write!(w, "<div class=\"since\">{}</div>",
|
write!(w, "<div class='since' title='Stable since Rust version {0}'>{0}</div>",
|
||||||
v)?
|
v)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ impl EmitterWriter {
|
|||||||
&format!(" (defined in {})",
|
&format!(" (defined in {})",
|
||||||
self.cm.span_to_filename(def_site_span)));
|
self.cm.span_to_filename(def_site_span)));
|
||||||
}
|
}
|
||||||
let snippet = self.cm.span_to_string(sp);
|
let snippet = self.cm.span_to_string(trace.call_site);
|
||||||
print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?;
|
print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -70,15 +70,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
|||||||
|
|
||||||
// Keep going, outside-in.
|
// Keep going, outside-in.
|
||||||
let fully_expanded = fld.fold_expr(expanded_expr);
|
let fully_expanded = fld.fold_expr(expanded_expr);
|
||||||
let span = fld.new_span(span);
|
|
||||||
fld.cx.bt_pop();
|
fld.cx.bt_pop();
|
||||||
|
|
||||||
fully_expanded.map(|e| ast::Expr {
|
fully_expanded
|
||||||
id: ast::DUMMY_NODE_ID,
|
|
||||||
node: e.node,
|
|
||||||
span: span,
|
|
||||||
attrs: e.attrs,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ExprKind::InPlace(placer, value_expr) => {
|
ast::ExprKind::InPlace(placer, value_expr) => {
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// error-pattern: borrowed value does not live long enough
|
||||||
|
|
||||||
struct defer<'a> {
|
struct defer<'a> {
|
||||||
x: &'a [&'a str],
|
x: &'a [&'a str],
|
||||||
}
|
}
|
||||||
@ -28,6 +30,5 @@ fn defer<'r>(x: &'r [&'r str]) -> defer<'r> {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = defer(&vec!("Goodbye", "world!"));
|
let x = defer(&vec!("Goodbye", "world!"));
|
||||||
//~^ ERROR borrowed value does not live long enough
|
|
||||||
x.x[0];
|
x.x[0];
|
||||||
}
|
}
|
||||||
|
@ -11,22 +11,26 @@
|
|||||||
// macro f should not be able to inject a reference to 'n'.
|
// macro f should not be able to inject a reference to 'n'.
|
||||||
|
|
||||||
macro_rules! f { () => (n) }
|
macro_rules! f { () => (n) }
|
||||||
|
//~^ ERROR unresolved name `n`
|
||||||
|
//~| ERROR unresolved name `n`
|
||||||
|
//~| ERROR unresolved name `n`
|
||||||
|
//~| ERROR unresolved name `n`
|
||||||
|
|
||||||
fn main() -> (){
|
fn main() -> (){
|
||||||
for n in 0..1 {
|
for n in 0..1 {
|
||||||
println!("{}", f!()); //~ ERROR unresolved name `n`
|
println!("{}", f!());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(n) = None {
|
if let Some(n) = None {
|
||||||
println!("{}", f!()); //~ ERROR unresolved name `n`
|
println!("{}", f!());
|
||||||
}
|
}
|
||||||
|
|
||||||
if false {
|
if false {
|
||||||
} else if let Some(n) = None {
|
} else if let Some(n) = None {
|
||||||
println!("{}", f!()); //~ ERROR unresolved name `n`
|
println!("{}", f!());
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(n) = None {
|
while let Some(n) = None {
|
||||||
println!("{}", f!()); //~ ERROR unresolved name `n`
|
println!("{}", f!());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
src/test/compile-fail/issue-30255.rs
Normal file
35
src/test/compile-fail/issue-30255.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2016 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
//
|
||||||
|
// Test that lifetime elision error messages correctly omit parameters
|
||||||
|
// with no elided lifetimes
|
||||||
|
|
||||||
|
struct S<'a> {
|
||||||
|
field: &'a i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(a: &S, b: i32) -> &i32 {
|
||||||
|
//~^ ERROR missing lifetime specifier [E0106]
|
||||||
|
//~^^ HELP does not say which one of `a`'s 2 elided lifetimes it is borrowed from
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g(a: &S, b: bool, c: &i32) -> &i32 {
|
||||||
|
//~^ ERROR missing lifetime specifier [E0106]
|
||||||
|
//~^^ HELP does not say whether it is borrowed from one of `a`'s 2 elided lifetimes or `c`
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
|
||||||
|
//~^ ERROR missing lifetime specifier [E0106]
|
||||||
|
//~^^ HELP does not say whether it is borrowed from `a`, one of `c`'s 2 elided lifetimes, or `d`
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
@ -36,13 +36,13 @@ macro_rules! fake_method_expr {
|
|||||||
|
|
||||||
macro_rules! fake_field_expr {
|
macro_rules! fake_field_expr {
|
||||||
() => {
|
() => {
|
||||||
1.fake
|
1.fake //~ ERROR no field with that name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! fake_anon_field_expr {
|
macro_rules! fake_anon_field_expr {
|
||||||
() => {
|
() => {
|
||||||
(1).0
|
(1).0 //~ ERROR type was not a tuple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,8 +52,6 @@ fn main() {
|
|||||||
fake_anon_field_stmt!(); //~ NOTE in this expansion of
|
fake_anon_field_stmt!(); //~ NOTE in this expansion of
|
||||||
|
|
||||||
let _ = fake_method_expr!(); //~ NOTE in this expansion of
|
let _ = fake_method_expr!(); //~ NOTE in this expansion of
|
||||||
let _ = fake_field_expr!(); //~ ERROR no field with that name
|
let _ = fake_field_expr!(); //~ NOTE in this expansion of
|
||||||
//~^ NOTE in this expansion of
|
let _ = fake_anon_field_expr!(); //~ NOTE in this expansion of
|
||||||
let _ = fake_anon_field_expr!(); //~ ERROR type was not a tuple
|
|
||||||
//~^ NOTE in this expansion of
|
|
||||||
}
|
}
|
||||||
|
@ -12,20 +12,19 @@
|
|||||||
// we replace the span of the expanded expression with that of the call site.
|
// we replace the span of the expanded expression with that of the call site.
|
||||||
|
|
||||||
macro_rules! nested_expr {
|
macro_rules! nested_expr {
|
||||||
() => (fake)
|
() => (fake) //~ ERROR unresolved name
|
||||||
|
//~^ ERROR unresolved name
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! call_nested_expr {
|
macro_rules! call_nested_expr {
|
||||||
() => (nested_expr!())
|
() => (nested_expr!()) //~ NOTE in this expansion of nested_expr!
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! call_nested_expr_sum {
|
macro_rules! call_nested_expr_sum {
|
||||||
() => { 1 + nested_expr!(); } //~ ERROR unresolved name
|
() => { 1 + nested_expr!(); } //~ NOTE in this expansion of nested_expr!
|
||||||
//~^ NOTE in this expansion of nested_expr!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
1 + call_nested_expr!(); //~ ERROR unresolved name
|
1 + call_nested_expr!(); //~ NOTE in this expansion of call_nested_expr!
|
||||||
//~^ NOTE in this expansion of call_nested_expr!
|
|
||||||
call_nested_expr_sum!(); //~ NOTE in this expansion of
|
call_nested_expr_sum!(); //~ NOTE in this expansion of
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,11 @@ macro_rules! myprint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! myprintln {
|
macro_rules! myprintln {
|
||||||
($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0`
|
($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ NOTE in this expansion of myprint!
|
||||||
//~^ NOTE in this expansion of myprint!
|
//~^ NOTE in this expansion of concat!
|
||||||
//~^^ NOTE in this expansion of concat!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
myprintln!("{}"); //~ NOTE in this expansion of
|
myprintln!("{}"); //~ ERROR invalid reference to argument `0`
|
||||||
|
//~^ NOTE in this expansion of
|
||||||
}
|
}
|
||||||
|
30
src/test/compile-fail/variant-used-as-type.rs
Normal file
30
src/test/compile-fail/variant-used-as-type.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2016 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test error message when enum variants are used as types
|
||||||
|
|
||||||
|
|
||||||
|
// issue 21225
|
||||||
|
enum Ty {
|
||||||
|
A,
|
||||||
|
B(Ty::A),
|
||||||
|
//~^ ERROR: found value `Ty::A` used as a type
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// issue 19197
|
||||||
|
enum E {
|
||||||
|
A
|
||||||
|
}
|
||||||
|
|
||||||
|
impl E::A {}
|
||||||
|
//~^ ERROR: found value `E::A` used as a type
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user