diff options
Diffstat (limited to 'tests/ui/async-await/async-closures/precise-captures.rs')
| -rw-r--r-- | tests/ui/async-await/async-closures/precise-captures.rs | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/tests/ui/async-await/async-closures/precise-captures.rs b/tests/ui/async-await/async-closures/precise-captures.rs new file mode 100644 index 00000000000..e82dd1dbaf0 --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.rs @@ -0,0 +1,157 @@ +//@ aux-build:block-on.rs +//@ edition:2021 +//@ run-pass +//@ check-run-results +//@ revisions: call call_once force_once + +// call - Call the closure regularly. +// call_once - Call the closure w/ `async FnOnce`, so exercising the by_move shim. +// force_once - Force the closure mode to `FnOnce`, so exercising what was fixed +// in <https://github.com/rust-lang/rust/pull/123350>. + +#![feature(async_closure)] +#![allow(unused_mut)] + +extern crate block_on; + +#[cfg(any(call, force_once))] +macro_rules! call { + ($c:expr) => { ($c)() } +} + +#[cfg(call_once)] +async fn call_once(f: impl async FnOnce()) { + f().await +} + +#[cfg(call_once)] +macro_rules! call { + ($c:expr) => { call_once($c) } +} + +#[cfg(not(force_once))] +macro_rules! guidance { + ($c:expr) => { $c } +} + +#[cfg(force_once)] +fn infer_fnonce(c: impl async FnOnce()) -> impl async FnOnce() { c } + +#[cfg(force_once)] +macro_rules! guidance { + ($c:expr) => { infer_fnonce($c) } +} + +#[derive(Debug)] +struct Drop(&'static str); + +impl std::ops::Drop for Drop { + fn drop(&mut self) { + println!("{}", self.0); + } +} + +struct S { + a: i32, + b: Drop, + c: Drop, +} + +async fn async_main() { + // Precise capture struct + { + let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture &mut struct + { + let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct by move + { + let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async move || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture &mut struct by move + { + let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async move || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + // `s` is still captured fully as `&mut S`. + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct, consume field + { + let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") }; + let c = guidance!(async move || { + // s.a = 2; // FIXME(async_closures): Figure out why this fails + drop(s.b); + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct by move, consume field + { + let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") }; + let c = guidance!(async move || { + // s.a = 2; // FIXME(async_closures): Figure out why this fails + drop(s.b); + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } +} + +fn main() { + block_on::block_on(async_main()); +} |
