-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Variables moved from in match guards are still accessible in other match arms. #29723
Comments
Possibly aided by #3478? |
fn main() {
let s = String::new();
let _s = match 0 {
0 if { drop(s); false } => String::from("oops"),
_ => {
// This should trigger an error,
// s could have been moved from.
s
}
};
} |
cc @rust-lang/compiler This would be solved by the MIR, right? |
Bringing mine and @eddyb 's IRC conversation into here for readability. The issue is that the path on the left in the image above does not chain into the path on the right, meaning that This seems to be a configuration issue in https://github.com/rust-lang/rust/blob/master/src/librustc/middle/cfg/construct.rs#L429-L529 |
Wait can you move in guards? |
@arielb1 you shouldn't be able to |
Hmm, looks like I missed this case when I fixed a very similar issue (moving in multiple guard expressions). The issue is that the way the final guard is handled means that it acts as if it can't fail. Wiring up the contents of @Manishearth I tried disallowing it, but there's some code around that moves in guards. Its also a breaking change. |
Ok, in trying to fix this I ran into an issue that is probably why I didn't handle this case last time. Borrows due to by-ref bindings in matches are scoped the match expression itself, meaning that something like: match foo_opt {
Some(ref foo) if cond => { ... }
None => { foo_opt.val = bar; }
} will complain that you can't assign to |
@eddyb How did you get rustc to spit out the CFG like that? |
@bstrie |
Oh, it's |
Key question is whether it's worth trying to fix this now, or just accelerate efforts to port borrowck to MIR. There are already a number of these sorts of issues that would be fixed by such a thing. @Aatch what efforts did you make to fix this? |
triage: P-high High because soundness but maybe we should downgrade to medium or otherwise try to solve via MIR. |
@nikomatsakis I tried to change the CFG to represent the control flow more accurately but ran into the issue I described above. I think there needs to be a change to the regions around match arms, but I'm less familiar with the code there and not sure what to change or how. |
triage: P-medium Since we're basically waiting for MIR to fix this, it's not really P-high |
(tagging with |
This is still relevant on the latest nightly. |
Turns out we need either NLL (the conditionally-canceled borrow part) or having differently-typed guard binding and body binding variables to make this work: use std::cell::RefCell;
fn assign<'a, 'b>(x: &RefCell<Option<&'a &'b mut u32>>, y: &'a &'b mut u32) {
*x.borrow_mut() = Some(y);
}
fn main() {
let (mut t, mut ten);
ten = 10;
t = Some(&mut ten);
unsound(&mut t);
}
fn unsound<'a>(opt: &'a mut Option<&'a mut u32>) -> Option<&'a mut u32> {
let store: RefCell<Option<&&mut u32>> = RefCell::new(None);
match *opt {
#[cfg(segfault)]
Some(ref mut x) if {
// this (making `x` escape from the arm) should be disallowed
// - `x` shouldn't be `&'a mut &'a mut u32` here
assign(&store, x);
false
} => {
None
}
#[cfg(not(segfault))]
Some(ref mut x) if { false } => {
// but just using `x` should be fine: `x` has the type `&'a mut &'a mut u32` here
Some(x)
}
ref mut x => {
*x = None;
println!("{:?}", store.borrow());
None
}
}
} |
The current status of MIR-borrowck indicates that we can address the first example and the second example. We also correctly reject the My inclination is to land regression tests, alongside |
FWIW, testing with ariel's example, NLL + MIR borrowck seems to accept |
I'm increasing priority on this because we should make sure we address it and other related issues as part of migration to NLL. |
This is fixed in MIR borrowck: https://play.rust-lang.org/?gist=3e78648bb9001bd5a96f59d09457f13b&version=nightly |
Added to #47366 -- this is basically E-needstest now |
triage: P-medium |
…omatsakis Add regression test for rust-lang#29723 cc rust-lang#29723 r? @nikomatsakis
Awesome! Thanks to everyone who played a part in resolving this |
…wck-test, r=Nilstrieb Test the borrowck behavior of if-let guards Add some tests to make sure that if-let guards behave the same as if guards with respect to borrow-checking. Most of them are a naive adaptation, replacing an `if` guard with `if let Some(())`. This includes regression tests for notable issues that arose for if guards (rust-lang#24535, rust-lang#27282, rust-lang#29723, rust-lang#31287) as suggested in rust-lang#51114 (comment). cc `@pnkfelix` are there any other tests that you would want to see? cc tracking issue rust-lang#51114
The following code segfaults at runtime on stable, beta, and nightly:
The text was updated successfully, but these errors were encountered: