As I understand what’s going on with the MutexGuard (please correct me if I’m wrong), there are two problems here – first, the &Mutex<T> is not restrictive enough to make MutexGuard<T> to be Sync only when T is Sync. And the second problem is that the presence of &Mutex is overly restrictive – it requires Mutex<T>: Sync, thus T: Send to satisfy MutexGuard<T>: Sync, which is not strictly necessary (note that this overly restrictive issue affects only Send-but-not-Sync types put in the Mutex that you can use only in a single thread).
Both of these problems arise from the fact that the guard uses Mutex with different kind of API than a public one – (1) it accesses the T directly and (2) it promises not to use the lock method. I think the right solution would be to communicate that fact to the type system. I thought of introducing a wrapper type that indicates that we’re using different kind of API, eg.:
struct AssertSync<T>(T);
The meaning of this type is “I will manually provide the Sync property of this object”. This type can have eg. unsafe constructor and implement Deref, or instead of Deref it can have unsafe method to access the interior type. With such a wrapper, we could redefine the guard struct as:
pub struct MutexGuard<'a, T: ?Sized + 'a> {
__lock: AssertSync<&'a Mutex<T>>, // deals with "overly restrictive Sync"
__poison: poison::Guard,
__phantom: PhantomData<&'a mut T>, // deals with "Sync not restrictive enough"
}
Adding just __phantom, as @ubsan suggested, will deal with the first (not restrictive enough) issue, but not with the second (overly restrictive), as @RalfJung noted. That’s why I tried to find a way to “disable a field from auto-trait analysis”.
Alternatively, the wrapper struct could be something different (this may require some help from the compiler, I guess):
/// Store X, but treat as Y for the purpose of borrow-checking and auto-traits.
pub struct IWillUseXAsItWasY<X, Y>(X);
Also, I have a related thought about implementing smart pointers (let’s say that smart pointer is a type that provides a direct access to a reference (eg. through Deref). So Box, Rc, Arc, MutexGuard, but not Mutex). I think that any implementor of a smart pointer that uses unsafe code should provide an appropriate PhantomData field (or other field providing equivalent semantics wrt. auto-traits and borrow-checking). This rule could be enforced with a lint and would lessen the likelyhood for library writers to make the same mistake as the MutexGuard.