You should always be using C when performance matters. Not Rust, not C++.
You clearly haven't written a significant amount of Rust (or C++) and then disassembled it to examine the output.
The thing that would make C/C++ code safer from the start to implicitly check the length of variables, instead of having to pass the length.
You mean, what Rust does.
In C is a UTF-8 string have a BOM?
Is a C string even UTF-8? You have no idea. The *only* thing you know about a C string is that it has some bytes and (you hope!) a NUL terminator.
If C and C++ natively did UTF-8
You mean, what Rust does.
It's the pointer stuff that trips up people who don't understand the underlying assembly language code it would make.
It's also the pointer stuff that trips up people who do understand the underlying assembly language code.
Fun fact "the switch" statement is a heavy use of the stack space, because the compiler is unwrapping this to a series of "jump if equal" which is equal to "if" statements.
Only if your compiler sucks, which hasn't been the case for a very long time. Back in the late 80s when I started writing C, compilers already optimized switch statements into binary searches of the target space. By the early 90s I'd encountered a couple of compilers that optimized them into extremely efficient hash tables, making them both faster and more compact. In the 2020s compilers are downright wizardly at optimizing these things.
This is actually really important for Rust, because Rust's type-safe-union enums strongly encourage heavy use of switches. Many cases that require vtable-based polymorphism in C++ (or structs of function pointers in C) end up as highly-optimized switches in Rust. You can do vtables in Rust, too, but they're strikingly less common than in C++ and even than in many common C styles.
This is the purpose of making functions as small and single-purpose as possible and antithesis of C++ classes.
Good C++ classes use functions that are as small and single-purpose as possible. You can write crap code in any language. You can write slow code in any language.
Rust seems to aim to be "better C" but doesn't necessarily do so since it technically runs on the C runtime.
This doesn't follow at all. Using the C runtime doesn't preclude being a better C, at all. The problems with C have very little to do with its runtime. C's problems are all about the lack of bounds checking, lack of dangling pointer checking, lack of thread synchronization checking. Note that in Rust the last two things are done entirely at compile time. It's like if "-Wall -Werror" got 1000 times smarter. Not because the compiler is smarter but because the language semantics don't require the compiler to allow a lot of potentially bad stuff.
It is true that sometimes Rust is too restrictive, disallowing provably safe code. Just yesterday, I couldn't convince the borrow checker that a function was safe without breaking a hashmap lookup into two steps. I actually considered using a small unsafe block to avoid the extra lookup. I decided against it, but this raises two points: First, in Rust if you need to you can always discard the protections (though note that even "unsafe" blocks are more restrictive than"-Wall -Werror") and drop down to a C style, or even assembler if you need to. Second, and more importantly, Rust points out when you're doing something potentially risky and forces you to think hard about it. C just lets you do it... even with -Wall -Werror.
I think Rust might be fine to use in things outside of kernel space, but it seems like it might be expensive to use in the kernel/driver space.
Rust is fine for both, though when using in the kernel, drivers or on bare metal, you have to configure it correctly. For context, I'm currently writing bare metal code in Rust on a device that has minimal stack and no heap. It's no_std, noalloc, abort-on-panic (though I'm using the marvelous no-panic crate to statically verify that my code cannot panic). The code is very compact and very efficient -- but also guaranteed to be safe against buffer overflows, dangling references, etc. and, IMO, substantially more readable than the same thing would be in C. Making it compact and efficient requires understanding the code that will be generated, of course. This is universally true.