It adds runtime overhead by forcing the programmer to work around the single-ownership rules, via runtime checking (Arc, etc) and more expensive interfaces.
For example, consider a simple thread-local counter. In C this would be e.g. an object in the tdata section, accessible via thread-local addressing. But in Rust, you have to use something like RefCell, which requires runtime tracking of mutable borrows. So Rust's borrow checker inflicts runtime overhead in this case.
That's not actually true though. You can use an atomic with a relaxed ordering. For example: https://is.gd/M1Q3Bu
Now, to be fair, this is only one example and I'm sure you could come up with a better one. But this isn't especially controversial. Rust's entire standard library is living proof that you need unsafe to do some things efficiently. The value proposition is that such things can be bundled up behind an abstraction barrier.
In sum, I think "the borrow checker forces runtime overhead" is an incomplete picture. I think a better picture is, "if you completely ban explicit use of unsafe from your code, then you may miss out on some optimization opportunities." i.e., When the borrow checker fails you, you're given a choice: 1) accept safety and the possible performance loss or 2) accept the onus of proving safety and do the fastest thing possible.
I think the fact that those choices are available is an excellent thing. I choose (1) all the time because not every line of code is relevant to performance. But sometimes I get to choose (2), and I'm thankful that such a choice is always very explicit.
For good measure, here's the unsafe version without atomics: https://is.gd/V1K6nD
Edit: Zero overhead as compared to C, that is. Cell has a slight overhead in Rust because it prevents certain optimizations that aren't the default in C.
Because an atomic provides interior mutability for `usize`.
(It's a hack that plays on the GP's specific example of a counter. It doesn't generalize arbitrarily to removing use of RefCell for thread locals in safe code.)
You only need a Cell for a counter (not even an atomic). Cell has no overhead over C -- Cell turns off some optimizations that exist in Rust to give you a C-like type.
I've been programming in Rust and C++ codebases for a while now. In general I find that Rust lets you dance close to the line of unsafety without worrying, resorting to Arc/RefCell only when you have to. In contrast, most C++ codebases I have worked with make use of shared_ptr (or its equivalent) quite often, because the language doesn't give you the tools to thread scoped borrows safely through a chain of functions and have it stay safe in the face of future code changes.
Sorry I meant overhead in terms of code size/use case complexity - not runtime performance (although like someone below mentioned you can often do "unsafe" stuff that's faster but can't be proved by Rust)
For example, consider a simple thread-local counter. In C this would be e.g. an object in the tdata section, accessible via thread-local addressing. But in Rust, you have to use something like RefCell, which requires runtime tracking of mutable borrows. So Rust's borrow checker inflicts runtime overhead in this case.