I am investigating possible reasons that prevent the Rust compiler from optimizing certain code pieces. I found this comment in an issue in rust-lang that alerts me.
We must not optimize away storage of locals that are mutably borrowed, because as @matthewjasper notes in #61430, it isn't decided that the following is UB:
let mut x = String::new(); let p = &mut x as *mut String; let y = x; p.write(String::new());
I thought that the lifetime of x
ends when it is moved to y
. p
is dangling while being .write()
through. But why this is not decided as UB?
In the same thread, a bit further, there is this other comment by cramertj that I think explains a bit this issue. The code exemplified in this other comment is:
let mut x = String::new();
let addr_x: *const String = reference_to_pointer(&x);
drop(x);
ptr::write(addr_x as *mut String, String::new());
The basic idea of this snippet is to be able to drop
a local value to run its destructor and reuse its memory allocation to store a new value. This is a pattern that some think it may be useful, but others think it should be UB.
Remember that drop()
is not a special function in any way, it just moves the x
into its own scope that finishes immediately, so it is more or less equivalent to your original code. You could even use forget()
or push the value into a container and the example still holds.
Note that this idiom is actually valid if you use allocated dynamic memory (it is what Vec
does under the hood). The issue here is whether it is also valid for stack allocated automatic memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With