-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Temporaries in match conditions should be freed if not required to stick around #38355
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
Comments
I also feel like this used to work. |
Now wait a minute, |
That's not what I'm proposing. I'm saying that if the match expression returns something that does not have a lifetime tied to that of the temporary, we should destroy it immediately. Changing the patterns will not change anything here. In this case, we return a boolean, with no lifetime. I can imagine that the following match would work: let x = RefCell::new(vec![1,2,3]);
match x.borrow().len() {
...
} but this would not: let x = RefCell::new(vec![1,2,3]);
match x.borrow().index(1) { // returns an &u8, lifetime tied to borrow
...
} |
Oh I see, it was |
Note that we already changed it for |
I've even seen |
Hmm, it's a bit more complicated -- |
Oh, that's why I think this used to work. It has worked for |
Workaround: use std::cell::RefCell;
macro_rules! drop_temps {
($e:expr) => {{
let x = $e;
x
}}
}
fn main() {
let x = RefCell::new(true);
match drop_temps!(*x.borrow()) {
_ => x.borrow_mut()
};
} |
Interestingly, your workaround doesn't make the This means that one way of implementing this is to simply internally treat match discriminants as (I say this because @eddyb thinks we need a new form of inference to implement this, but I feel like the mechanism to implement this already exists.) |
@Manishearth That thought is actually not entirely my own, both @nikomatsakis and @pnkfelix have considered this before, but I believe they're wary of the user-facing complexity resulting from it. As for reusing the |
I've come across this before, and I remember the conclusion being that non-lexical borrow scopes would fix this as well as many related issues, but I haven't heard of any movement on that feature in a long time. |
@abonander They're orthogonal, this is about ordering drops based on lifetimes, whereas non-lexical borrows obey the already computed drop scopes no matter what they are. |
@eddyb The worst user-facing complexity is when things don't work for no obvious reason; or, even worse, if there is inconsistency between different language constructs. Also, from my point of view, non-lexical borrow scopes is one of the most important features Rust currently lacks. |
non-lexical borrow scopes and drop order are completely orthogonal. Drop order changes the meaning of correct code (e.g., if the destructor contain I am not sure that making drop order more complicated is a good thing, and in any case it needs an RFC. |
So it seems that ultimately any changes here would need an RFC, so I'm going to close in favor of that. If anyone's actively interested, please file an RFC or an issue at rust-lang/rfcs. |
This actually caused deadlocks in a program I was working on. I had something like this: use std::sync::Arc;
use std::sync::Mutex;
struct S(i32);
impl S {
pub fn get_int(&self) -> i32 {
self.0
}
pub fn bump_int(&mut self) {
self.0 += 1;
}
}
fn main() {
let s = Arc::new(Mutex::new(S(0)));
match s.lock().unwrap().get_int() {
i => {
s.lock().unwrap().bump_int();
}
};
} This program never returns because |
Currently, the following code works:
but this panics:
(playpen)
Due to #12033 (implemented in #36029) we free temporaries from
if
conditions.We should also free temporaries in match subjects if there are no active borrows from them.
This would be semantically a [breaking change]. I do not think it will change how things compile. I am not sure if we need an rfc for this because IMO the fact that this doesn't work is a bug.
cc @eddyb @nikomatsakis
The text was updated successfully, but these errors were encountered: