The idea is &out can only be eliminated by assignment, in which case you are left with a &mut. If you move it (technically re-borrow and move it) and don’t end up with something with the same lifetime, it must have been written to. That means if you pass &out to a function that returns unit, lets say, the &out becomes a &mut just as if you assigned it yourself.
From an unwinding perspective, the basic thing one needs to know is whether something is borrowed, which is a statically analyzable property. I hope then that in all non-array cases the needed is-borrowed state could somehow be hard coded into the dwarf metadata so as not to occur any overhead unless panicking occurs. In normal operation, the &out must be eliminated before the borrowed thing is dropped, so actually I don’t think a drop flag is needed ever. Note that the same thing could be done for &muts, with mut-borrowed slots never running destructors and unborrowed &muts running them instead, though there is probably no reason to do this other than consistency with &out.
The array case is more complex as you say. Note that a Vec already tracks capacity vs length. It may be sufficient then to wrap the &out ptr in something which will bump the capacity on assignment as a side effect.
Granted this a bit of a cop-out out answer – Vec relies on yet another unsafe implementation detail, and the uninitiated values must be contiguous and at the end.
An interesting thing to note is that it is not allowed to refine an &out with a .field. One would need to pattern match to get an &out to each field of the struct/variant if one wants to fulfill each assign obligation separately – let &out (ref a, ref b) = some_out;. Fine grained borrowing would work on [T; n] more easily than [T], precisely because the former can be pattern matched so much more “thoroughly”.