Surprised today to find out this doesn't compile:
use rayon::prelude::*;
// Pretend we have a type that is neither Send nor Sync.
struct NotThreadSafe(*const ());
fn foo(f: &impl Fn(&NotThreadSafe) -> i32) -> impl ParallelIterator<Item = i32> {
let huge_container = vec![1, 2, 3, 4, 5, 6, 7, 8];
huge_container.par_iter().map(|x| {
let n = NotThreadSafe(std::ptr::null());
f(&n)
})
}
Gives the error:
Checking playground v0.1.0 (/home/xxxxx/playground)
error[E0277]: `impl Fn(&NotThreadSafe) -> i32` cannot be shared between threads safely
--> src/lib.rs:14:35
|
14 | huge_container.par_iter().map(|x| {
| --- ^--
| | |
| _______________________________|___within this `[closure@src/lib.rs:14:35: 14:38]`
| | |
| | required by a bound introduced by this call
15 | | let n = NotThreadSafe(std::ptr::null());
16 | | f(&n)
17 | | })
| |_____^ `impl Fn(&NotThreadSafe) -> i32` cannot be shared between threads safely
|
= note: required because it appears within the type `&impl Fn(&NotThreadSafe) -> i32`
note: required because it's used within this closure
I can understand that a closure that captures something !Sync
should not be Sync
, but I don't understand why taking an argument by reference to one should make it so. I don't see any safety issue at least in my example code. If this was allowed could I somehow put it to nefarious purposes?