You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Make async futures Unpin if they don't borrow anything across .awaits #82187
Am I missing something or could rustc in principle make the anonymous (return) type of async fn and async {} blocks implement Unpin (or maybe it should be "not implement !Unpin") if the body does not contain any borrows across .await points? I couldn't find an existing issue about this.
This seems like it would cause problems regarding accidental breaking changes. Changing a function to now borrow something across an await point is an incredibly easy change to accidentally make and would result in the Unpin impl being removed from the return type.
An alternative would be to make it possible to explicitly mark that an async function/block should be Unpin (removing the possibility of an accidental breaking change). I don't see how to do this in function signatures without introducing an additional keyword though (pub unpin async fn or such) and that's probably not worth the effort.
function authors that want to make it Unpin can specify the return type as impl Future + Unpin manually
You mean by making it a regular fn and wrapping the entire body in async move {}? I think a similar strategy could be used to create an attribute macro that asserts Send / Sync / Unpin for async fn (not sure about async blocks, can proc-macro attrs be used on expressions?), but doing it manually would be super annoying.
Closing this as it's better tracked in the https://github.com/jplatte/async_auto_traits/issues/1 issue, and it is better to have it contained in one issue instead of having 2 issues tracking it in different places
@Dylan-DPC I think you misunderstood something, that is about preventing the leak of auto-traits of async fn future types. It only relates to Unpin in that it would sometime be useful to be able to stop leaking an Unpin implementation in a public interface if the compiler generated those impls at all (which this issue is about).
Reacted by Alec Mocatta, Daiki Mizukami, min and Pēteris Pakalns
I was experimenting today with replacing the likes of futures_util::future::ok() (which is IMO a little ugly -- it reeks of the futures 0.1 times) with async move {} blocks and was surprised that I needed an explicit pin!() call wrapped around the async move {} block even with trivial Copy types (like usize).
I ran into this, unfortunately. While I completely understand the commentary on it being too prone to accidentally breaking changes, I'd love if if it was explicitly marked, then Unpin would be eligible to propagate up the library.
One note is I don't have Unpin async blocks though. I have async blocks which are naturally Unpin if their generics are Unpin. I accordingly can't guarantee the returned future is Unpin. For my use-case, I'd need that conditional to be modelled.
A note for people who run into this: Coroutines do not have this limitation. I've heard that is unlikely to become stable, but it's worth knowing about.
(BTW, I ran into this issue while trying to poll a future once before scheduling it (for performance reasons). This works, but you are forced to allocate a Box even if the future completes in the first poll call, since you can't move the future from the stack to the heap after the poll. Whether this matters in my context is an open question, but the limitation is still interesting.)
Activity
JakobDegen commentedon Feb 16, 2021
This seems like it would cause problems regarding accidental breaking changes. Changing a function to now borrow something across an await point is an incredibly easy change to accidentally make and would result in the
Unpinimpl being removed from the return type.An alternative would be to make it possible to explicitly mark that an async function/block should be
Unpin(removing the possibility of an accidental breaking change). I don't see how to do this in function signatures without introducing an additional keyword though (pub unpin async fnor such) and that's probably not worth the effort.jplatte commentedon Feb 16, 2021
@JakobDegen I don't see how
Unpinwould be different toSendandSyncin this regard.jplatte commentedon Feb 16, 2021
You mean by making it a regular
fnand wrapping the entire body inasync move {}? I think a similar strategy could be used to create an attribute macro that assertsSend/Sync/Unpinforasync fn(not sure aboutasyncblocks, can proc-macro attrs be used on expressions?), but doing it manually would be super annoying.jplatte commentedon Feb 16, 2021
I guess I'll create that then 😄
jplatte commentedon Feb 16, 2021
The amount of code required is smaller than I expected. I've hardly tested it, but I think it should work: https://docs.rs/async_auto_traits/0.1
jplatte commentedon Feb 16, 2021
jplatte commentedon Feb 17, 2021
Okay, let's move this discussion to an issue on https://github.com/jplatte/async_auto_traits.
@hyd-dev I suggest hiding your previous two comments here.
Dylan-DPC commentedon Jan 15, 2024
Closing this as it's better tracked in the https://github.com/jplatte/async_auto_traits/issues/1 issue, and it is better to have it contained in one issue instead of having 2 issues tracking it in different places
jplatte commentedon Jan 15, 2024
@Dylan-DPC I think you misunderstood something, that is about preventing the leak of auto-traits of
async fnfuture types. It only relates toUnpinin that it would sometime be useful to be able to stop leaking anUnpinimplementation in a public interface if the compiler generated those impls at all (which this issue is about).djc commentedon Sep 17, 2024
I was experimenting today with replacing the likes of
futures_util::future::ok()(which is IMO a little ugly -- it reeks of the futures 0.1 times) withasync move {}blocks and was surprised that I needed an explicitpin!()call wrapped around theasync move {}block even with trivialCopytypes (likeusize).kayabaNerve commentedon Nov 10, 2025
I ran into this, unfortunately. While I completely understand the commentary on it being too prone to accidentally breaking changes, I'd love if if it was explicitly marked, then Unpin would be eligible to propagate up the library.
One note is I don't have Unpin async blocks though. I have async blocks which are naturally Unpin if their generics are Unpin. I accordingly can't guarantee the returned future is Unpin. For my use-case, I'd need that conditional to be modelled.
arthurp commentedon Mar 10, 2026
A note for people who run into this: Coroutines do not have this limitation. I've heard that is unlikely to become stable, but it's worth knowing about.
(BTW, I ran into this issue while trying to
polla future once before scheduling it (for performance reasons). This works, but you are forced to allocate a Box even if the future completes in the firstpollcall, since you can't move the future from the stack to the heap after thepoll. Whether this matters in my context is an open question, but the limitation is still interesting.)theemathas commentedon Mar 11, 2026
(Hypothetical)
Unpinasync futures and (existing on nightly)Unpincoroutines have a soundness issue: #153688