Having a value of uninhabited type indicates that that code cannot be reached safely and that the linker can safely delete that code from the binary. The typeck does not know about panicking or anything like that, only about types, which it manipulates abstractly. For example, we can materialize a ! with
fn make_never() -> ! { loop {} }
I can create a reference to it, and dereference it, because ! is Copy:
let ref_never: &! = &make_never();
let never = *ref_never;
None of this code is UB.
Of course, at this point the compiler can assume that this code will never run because it manipulates empty types. As you know, there is no safe way to return a value from make_never. There are unsafe ways, and that is how you get UB. Usually, the compiler will insert a halt-and-catch-fire into these functions in debug mode, but will completely remove them in release mode.
It is completely silly to ban empty types by default, since empty types can be used in a generic context to express something that never happens. For example, if we get an analogue to C++'s ptr-to-memeber, you could imagine that T::*U could be made uninhabited if T has no field of type U. This adds a safety guarantee for calling functions with generic ptr-to-members, which would, in your proposal, generate bizarre errors.