I have created some counterexamples to show that the following bounds are necessary (making miri show there is UB by relaxing any of the 3):
unsafe impl<T: ?Sized + Send + Sync> Send for Arc<T> {}
unsafe impl<T: ?Sized + Sync> Sync for Arc<T> {}
However, I can't come up with a counterexample for why we also need T to be Send for Arc<T> to be Sync, if we still require the 3 other bounds.
As discussed in Why T: Sync does not means Arc<T>: Sync it is apparently possible to send the T to another thread by using Arc::try_unwrap.
However, I can't seem to come up with an example where this is possible.
Sure we can create an Arc<T> and a reference to it in one thread, send the reference to another thread and obtain another Arc<T> in that thread.
However, the reference needs to still be valid for the other thread, so the original Arc<T> can't be dropped before the thread is done running.
So I can't see how to make Arc::try_unwrap succeed in the second way.
I guess the problem is that, the reference needs to still be valid for the other thread is not really guaranteed at language level. (std::thread::scope is a library API). I will try to come up with a better counter example when I got time.
It doesn't matter that Arc isn't Send here, and thread C isn't needed to cause a problem. 2 is problematic because it is cloning the Arc, and it is the fact that Arc can be cloned to gain ownership from a shared reference that means Send needs to be required for it to be Sync. Consider the following:
Thread A constructs x: Arc<T> then spawns thread B with &x captured.
Thread B calls Arc::clone() to get an owned Arc<T>.
Thread A drops x. Thread B's clone is now the only remaining Arc pointing to the original T.
Thread B terminates or otherwise drops its Arc, the T is then dropped on the wrong thread (this can matter for something like MutexGuard, which is not Send).
it seems to me, although we can get an owned Arc by cloning, the cloned Arc cannot escape the scope of the borrow's lifetime without Send. so I tend to agree with you, maybe T: Send is unnecessary for Arc<T>: Sync? that's an interesting discovery.
The scoped thread API may not provide any easy way to do it, but what I described is still allowed and follows all of the rules. And in fact @steffahn already shared an example of how you can do it by having the second Arc<T> escape via a thread-local.