Don't implement Sync on generic if data type does not

I have a generic object defined for a type, however there isn't actually an instance of the type stored in the object. Since all the data elements I do have implement Sync, my object implements Sync regardless of the type.

However this could allow a client to implement problematic code. Is it possible to add something that tells the compiler to only implement Sync if the Type implements Sync?

struct X<T> {
    _f: fn(T), // doesn't actually store a T
}

unsafe impl<T> Sync for X<T> where T: Sync {}

fn main() {
    fn assert_sync<T: Sync>() {}
    assert_sync::<X<i32>>();

    // Without the impl, this is ok. With the impl, this fails because
    // "the trait bound `*const i32: std::marker::Sync` is not satisfied."
    assert_sync::<X<*const i32>>();
}

Cool, that worked, thanks...So if you implement Sync manually for certain conditions the compiler won't automatically implement it for the others?

I don't see it in the docs, but that's what it looks like.

One thing this doesn't let you do is disable Sync for all cases (because what cases would you impl it for). The Rustonomicon mentions a different way to do that:

#![feature(optin_builtin_traits)]

// I have some magic semantics for some synchronization primitive!
struct SpecialThreadToken(u8);

impl !Sync for SpecialThreadToken {}

An easier way of disabling Sync on a type is to add a PhantomData<Cell<()>> field to it.

1 Like

Wouldn't the correct way be to add a PhantomData<T> to suggest that the type contains a T and thus rustc should correctly infer the Sync and Send implementations.

2 Likes

Sometimes you want to suppress the automatically derived Sync: deque/lib.rs at master · kinghajj/deque · GitHub

Ahh, I didn't realize that there was a concept of PhantomData baked into the language, that seems like the correct way to solve this issue.