Here is a concrete example of how they are different. If you had
struct Foo<T> {
b: Option<Box<Foo<T>>>
}
you can imagine that the “auto trait” impl is something like
unsafe impl Send for Foo<T>
where Option<Box<Foo<T>>>: Send
{ }
so if want to show that Foo<T>: Send, we have to first show that Option<Box<Foo<T>>>: Send. But that in turn means we must show Box<Foo<T>>: Send (because that’s what the Option impl will require) and then Foo<T>: Send (because that’s what the Box impl will require).
You might think that we could write the Send impl like so:
unsafe impl Send for Foo<T>
where T: Send
{ }
except that this doesn’t work for all structs, most notably around associated types:
struct Bar<T: Iterator> {
x: Option<Box<Bar<T::Item>>>
}
Here the impl would be:
unsafe impl<T: Iterator> Send for Bar<T>
where T::Item: Send
{ }
but what if we have Bar<Baz> where Baz: Iterator<Item=Bar<Baz>>? Now to prove that Bar<Baz>: Send, we have to show that Baz::Item: Send, and Baz::Item is (again) Bar<Baz>. So we’re stuck.