From 86d26a321e5816b4eb4442bf434fee0af6af793e Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Tue, 7 Sep 2021 08:17:50 +0800 Subject: [PATCH] Add UI tests for `get_or_try_insert_with` --- .../ui/future/try_get_with_non_send_future.rs | 24 +++++++++++ .../try_get_with_non_send_future.stderr | 12 ++++++ .../future/try_get_with_non_static_future.rs | 25 +++++++++++ .../try_get_with_non_static_future.stderr | 41 +++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 tests/ui/future/try_get_with_non_send_future.rs create mode 100644 tests/ui/future/try_get_with_non_send_future.stderr create mode 100644 tests/ui/future/try_get_with_non_static_future.rs create mode 100644 tests/ui/future/try_get_with_non_static_future.stderr diff --git a/tests/ui/future/try_get_with_non_send_future.rs b/tests/ui/future/try_get_with_non_send_future.rs new file mode 100644 index 00000000..2817f918 --- /dev/null +++ b/tests/ui/future/try_get_with_non_send_future.rs @@ -0,0 +1,24 @@ +// https://github.com/moka-rs/moka/issues/31 + +use moka::future::Cache; +use std::rc::Rc; + +#[tokio::main] +async fn main() { + let cache: Cache<_, String> = Cache::new(100); + + // Rc is !Send. + let data = Rc::new("zero".to_string()); + let data1 = Rc::clone(&data); + + cache + .get_or_try_insert_with(0, async move { + // A data race may occur. + // The async block can be executed by a different thread + // but Rc's internal reference counters are not thread safe. + Ok(data1.to_string()) + }) + .await; + + println!("{:?}", data); +} diff --git a/tests/ui/future/try_get_with_non_send_future.stderr b/tests/ui/future/try_get_with_non_send_future.stderr new file mode 100644 index 00000000..da513f93 --- /dev/null +++ b/tests/ui/future/try_get_with_non_send_future.stderr @@ -0,0 +1,12 @@ +error: future cannot be sent between threads safely + --> $DIR/try_get_with_non_send_future.rs:15:10 + | +15 | .get_or_try_insert_with(0, async move { + | ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc` +note: captured value is not `Send` + --> $DIR/try_get_with_non_send_future.rs:19:16 + | +19 | Ok(data1.to_string()) + | ^^^^^ has type `Rc` which is not `Send` diff --git a/tests/ui/future/try_get_with_non_static_future.rs b/tests/ui/future/try_get_with_non_static_future.rs new file mode 100644 index 00000000..65ce8527 --- /dev/null +++ b/tests/ui/future/try_get_with_non_static_future.rs @@ -0,0 +1,25 @@ +// https://github.com/moka-rs/moka/issues/31 + +use moka::future::Cache; + +#[tokio::main] +async fn main() { + let cache: Cache<_, String> = Cache::new(100); + + let data = "zero".to_string(); + { + // Not 'static. + let data_ref = &data; + + cache + .get_or_try_insert_with(0, async { + // This may become a dangling pointer. + // The async block can be executed by a different thread so + // the captured reference `data_ref` may outlive its value. + Ok(data_ref.to_string()) + }) + .await; + } + + println!("{:?}", data); +} diff --git a/tests/ui/future/try_get_with_non_static_future.stderr b/tests/ui/future/try_get_with_non_static_future.stderr new file mode 100644 index 00000000..06fe8894 --- /dev/null +++ b/tests/ui/future/try_get_with_non_static_future.stderr @@ -0,0 +1,41 @@ +error[E0597]: `data` does not live long enough + --> $DIR/try_get_with_non_static_future.rs:12:24 + | +12 | let data_ref = &data; + | ^^^^^ borrowed value does not live long enough +... +15 | .get_or_try_insert_with(0, async { + | ________________________________________- +16 | | // This may become a dangling pointer. +17 | | // The async block can be executed by a different thread so +18 | | // the captured reference `data_ref` may outlive its value. +19 | | Ok(data_ref.to_string()) +20 | | }) + | |_____________- argument requires that `data` is borrowed for `'static` +... +25 | } + | - `data` dropped here while still borrowed + +error[E0373]: async block may outlive the current function, but it borrows `data_ref`, which is owned by the current function + --> $DIR/try_get_with_non_static_future.rs:15:46 + | +15 | .get_or_try_insert_with(0, async { + | ______________________________________________^ +16 | | // This may become a dangling pointer. +17 | | // The async block can be executed by a different thread so +18 | | // the captured reference `data_ref` may outlive its value. +19 | | Ok(data_ref.to_string()) + | | -------- `data_ref` is borrowed here +20 | | }) + | |_____________^ may outlive borrowed value `data_ref` + | + = note: async blocks are not executed immediately and must either take a reference or ownership of outside variables they use +help: to force the async block to take ownership of `data_ref` (and any other referenced variables), use the `move` keyword + | +15 | .get_or_try_insert_with(0, async move { +16 | // This may become a dangling pointer. +17 | // The async block can be executed by a different thread so +18 | // the captured reference `data_ref` may outlive its value. +19 | Ok(data_ref.to_string()) +20 | }) + |