Open tmandry opened 5 years ago
await
is my primary motivation here, but I'm sure there are others. Today, foo.await;
translates roughly to
{
let pinned = foo;
// use `Pin::new_unchecked(&mut pinned)`
} // `pinned` implicitly dropped here
Implicit drops at the end of scope are lowered directly to MIR drop. Because this does not involve moving, the invariants around Pin::new_unchecked
are satisfied. However, if we could write it like this:
{
// use `Pin::new_unchecked(&mut foo)`
drop(foo);
}
and calling std::mem::drop(foo)
was guaranteed not to move foo
, then we would get rid of all moves. This would solve #59087 and #62321 with respect to await
.
We also need to emit StorageDead
on both the return and unwind edges of our MIR drop, or we'll break generator optimizations merged in #60187. (See #61015)
I would guess that adding this guarantee to std::mem::drop
is going to require an RFC (cc @rust-lang/lang). If so, let's define a separate unstable function that we can make the guarantee for. As long as we can invoke it from HIR lowering, that would unblock the case I care most about.
How close would it get if drop
were just marked [inline(always)]
? (Assuming the perf of running the mir inliner for that is acceptable, since there's no body so it'd be hopefully easy.)
@scottmcm I definitely wouldn't consider the possibility of inlining and optimization enough to be relied on for soundness of any async fn
, especially in debug mode.
Today, calling
drop(_1)
results in the following MIR:We could instead inline this directly to a MIR drop, with no move. This makes it simpler to do some optimizations in MIR.
This issue specifically tracks having such a
drop
available in HIR lowering; whether or not to blessstd::mem::drop
with this guarantee is up for discussion.cc @cramertj @withoutboats