4aba2c55e6
Start pointing to where bindings were declared when they are captured in closures: ``` error[E0597]: `x` does not live long enough --> $DIR/suggest-return-closure.rs:23:9 | LL | let x = String::new(); | - binding `x` declared here ... LL | |c| { | --- value captured here LL | x.push(c); | ^ borrowed value does not live long enough ... LL | } | -- borrow later used here | | | `x` dropped here while still borrowed ``` Suggest cloning in more cases involving closures: ``` error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19 | LL | if { (|| { let mut bar = foo; bar.take() })(); false } => {}, | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard help: consider cloning the value if the performance cost is acceptable | LL | if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {}, | ++++++++ ```
67 lines
1.8 KiB
Rust
67 lines
1.8 KiB
Rust
#![feature(if_let_guard)]
|
|
#![allow(unused_mut)]
|
|
//@ run-rustfix
|
|
|
|
// Here is arielb1's basic example from rust-lang/rust#27282
|
|
// that AST borrowck is flummoxed by:
|
|
|
|
fn should_reject_destructive_mutate_in_guard() {
|
|
match Some(&4) {
|
|
None => {},
|
|
ref mut foo if {
|
|
(|| { let mut bar = foo.clone(); bar.take() })();
|
|
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
|
|
false } => { },
|
|
Some(s) => std::process::exit(*s),
|
|
}
|
|
|
|
match Some(&4) {
|
|
None => {},
|
|
ref mut foo if let Some(()) = {
|
|
(|| { let mut bar = foo.clone(); bar.take() })();
|
|
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
|
|
None } => { },
|
|
Some(s) => std::process::exit(*s),
|
|
}
|
|
}
|
|
|
|
// Here below is a case that needs to keep working: we only use the
|
|
// binding via immutable-borrow in the guard, and we mutate in the arm
|
|
// body.
|
|
fn allow_mutate_in_arm_body() {
|
|
match Some(&4) {
|
|
None => {},
|
|
ref mut foo if foo.is_some() => { foo.take(); () }
|
|
Some(s) => std::process::exit(*s),
|
|
}
|
|
|
|
match Some(&4) {
|
|
None => {},
|
|
ref mut foo if let Some(_) = foo => { foo.take(); () }
|
|
Some(s) => std::process::exit(*s),
|
|
}
|
|
}
|
|
|
|
// Here below is a case that needs to keep working: we only use the
|
|
// binding via immutable-borrow in the guard, and we move into the arm
|
|
// body.
|
|
fn allow_move_into_arm_body() {
|
|
match Some(&4) {
|
|
None => {},
|
|
mut foo if foo.is_some() => { foo.unwrap(); () }
|
|
Some(s) => std::process::exit(*s),
|
|
}
|
|
|
|
match Some(&4) {
|
|
None => {},
|
|
mut foo if let Some(_) = foo => { foo.unwrap(); () }
|
|
Some(s) => std::process::exit(*s),
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
should_reject_destructive_mutate_in_guard();
|
|
allow_mutate_in_arm_body();
|
|
allow_move_into_arm_body();
|
|
}
|