Howdy! I had an issue with some (admittedly poor) code that seemed to behave differently in release and debug builds.
Here is a short repro of the offending code: https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=744b3dd0e3a8171675a1f2969c370915
In a debug build, this code will work as expected. In a release build, this code will sleep for an uncertain amount of time (or more likely be killed by the playground).
If both arms of the match return a ×pec, the issue becomes clear, and the compiler catches it correctly: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b788f0170f6d876aae8fc856d562b34f
It looks like the timespec in my example doesn't live long enough, and so may be freed (or even optimized out) in a release build.
Thanks so much!
This code is UB. foo has type *const timespec. You create a pointer to a temporary and store it in foo, then that temporary goes out of scope at the end of the match arm, invalidating the pointer before it is passed to nanosleep.
I suppose this is a good example of how the combination of type inference and implicit conversion from &T to *const T can lead to surprising results for users. Perhaps we could warn when we see code like let p: *const T = &{ unpromotable expr }?
Is there any case where the production of a temporary from a match arm is correct behavior? Why not just make that case a well-defined compile error?
Yes. It's correct in pretty much all cases. *const T has no special semantics as far as the borrow checker is concerned. It is treated the same as if the match arm evaluated to an integer.
@ecstatic-morse Thanks for the explanation, I see how this was my fault now.
Personally, I'd appreciate a warning like that, but that seems like it'd be needlessly noisy in cases where that promotion is intentional. I'll close this issue since it was very much a problem on my end.
Thanks again!
Most helpful comment
This code is UB.
foohas type*const timespec. You create a pointer to a temporary and store it infoo, then that temporary goes out of scope at the end of the match arm, invalidating the pointer before it is passed tonanosleep.I suppose this is a good example of how the combination of type inference and implicit conversion from
&Tto*const Tcan lead to surprising results for users. Perhaps we could warn when we see code likelet p: *const T = &{ unpromotable expr }?