This is often said about Rust, but isn't exactly true. If you'd like this to be true in your own code, you have to have be discipline and put all operations which may violate invariants required by unsafe code inside unsafe blocks, even if the compiler considers that code to be safe.
Imagine you're implementing a type like Vec<T> that has a (raw) pointer 'buf: *mut T' to some slab of memory it owns, and another field 'length: usize'. A safe method of Vec<T> could make a mistake while mutating the length field and violate memory safety in a completely correct 'unsafe' block that assumes '[buf, buf + length)' is a valid range of memory.
Tracking a semantic error in a call that's three calls away from where your unsafe block lives is much easier and structured than going through everything everywhere for any error from anything.
(I haven't done much work at all in Rust and avoid `unsafe` - and `mut` and `.unwrap`, for that matter - like the plague when I do use it, so I'm very open to being wrong in my interpretation.)
EDIT: I also think a reasonable comparison would be Haskell's `do` blocks. It's guaranteed that anything with side effects will live in a `do` block, but of course you can still have semantic errors. Again, you know exactly the "functions of interest" to look at if this is the case - there's no chance of `someFunc1` to be doing anything funny if it's never called by anything in the `do` block.
¹: Well, you can mess up in `unsafe` blocks. It's basically an “I'm smarter than the compiler” annotation. You can use it when Rust can't guarantee that something is memory safe. For example writing to the VGA text buffer at the special address `0xb8000` is totally safe, but Rust can't know that. We try to minimize the number of `unsafe` and to double check each use, but of course you can make mistakes and accidentally violate memory safety. But even then you just need to look at `unsafe` blocks to find the bug, which is still a big improvement over languages such as C.