Technically, code that contains UB is just UB, and unsound code is code that allows you to trigger UB using safe code only.
For example, this is UB:
unsafe { std::hint::unreachable_unchecked() };
And this is an unsound code, that may not contain any UB if I call `unsound()` with `false`: fn unsound(trigger: bool) {
if trigger { unsafe { std::hint::unreachable_unchecked() }; }
}
Also, I dislike the word "unsafe" since "unsafe code" is easily (mis)interpreted to mean "invalid/UB code", but "invalid/UB code" is officially called "unsound" rather than "unsafe". Unsafe blocks are used to call unsafe functions etc. (they pass information into unchecked operations via arguments), and unsafe trait impls are used by generic/etc. unsafe code like threading primitives (unsafe trait impls pass information into unchecked operations via return values or side effects).
unchecked would make a good keyword name for blocks calling unchecked operations, but I'm not so sure about using it for functions or traits.