Consider the following code snippet:
enum Value {
Int(i32),
Double(f64),
Long(i64),
Null
}
struct VM<'vm> {
pub stack: Vec<&'vm Value>
}
impl<'vm> VM<'vm> {
fn push_val(&mut self) {
self.stack.push(&Value::Null);
}
}
fn main() {
let mut vm = VM { stack: vec![] };
vm.push_val();
}
The code snippet above is a condensed example of some code (real code here) that I absentmindedly wrote the other day and noticed today that ostensibly should not be valid despite Cargo check
seeming to find no issue with it.
The issue is that VM.stack
is a vector of borrowed enums that must live for at least 'vm
, which is the lifetime of the VM
itself. However,
fn push_val(&mut self) {
self.stack.push(&Value::Null);
}
is a method that pushes a borrowed Value
instance that clearly doesn't live that long? If my understanding is correct (which evidently it isn't), Value::Null
, is a temp variable that is immediately borrowed and not anchored anywhere else in the program. So &Value::Null
is a borrow that only lives for as long as push()
is running. Therefore, &Value::Null
does not outlive 'vm
and thus does not live long enough to be pushed to VM's vector. Yet, Cargo seems to conclude that it does. What is going on here?