This is basically Cyclone, a "dialect" of C (but, effectively, its own language) which was a major influence on Rust. See https://cyclone.thelanguage.org/ and http://www.cs.umd.edu/~mwh/papers/cyclone-cuj.pdf for details. Cyclone primarily provides memory safety (bounds-checked pointer dereferences, lifetimes) and also provides things like type-safe tagged unions.
But Cyclone is a separate language (and so is Rust) because in order for memory or type safety to be useful, you need to carry information that cannot be represented in the C type system. The only information a C pointer carries, besides the pointer address, is the C type. You can't have it carry a lifetime, a bound, or a type that isn't a valid C type. So you lose your safety properties at the boundary between C and Cyclone/Rust. You can't pass a tagged union from Cyclone/Rust into C, because the C compiler isn't going to enforce that C code updates the tag properly - if it did, it would start rejecting valid C code. At that point it's just a matter of style/taste whether you have a language that looks like C but isn't (Cyclone) or looks less like C (Rust).
(Come to think of it, C++ also has the same property of being built from C and being mostly backwards-compatible, but being a separate language.)
Both Rust and Cyclone make it easy to call into C for interoperating with existing code, even though such calls cannot be guaranteed safe at the language level. So it's quite feasible to take a large C project and start converting parts of the code to Rust one at a time, ensuring that you can maintain safety within the parts that you've already converted. (Rust in particular is the unique memory-safe language at the intersection of "actively developed and popular" and "can be used as a drop-in replacement for C and export C-compatible binary interfaces back to any calling code, without overhead" - there are a number of neat languages, not just Cyclone, if you don't have the former requirement, and there are a number of great languages like Go or Java if you don't have the latter requirement.)
But Cyclone is a separate language (and so is Rust) because in order for memory or type safety to be useful, you need to carry information that cannot be represented in the C type system. The only information a C pointer carries, besides the pointer address, is the C type. You can't have it carry a lifetime, a bound, or a type that isn't a valid C type. So you lose your safety properties at the boundary between C and Cyclone/Rust. You can't pass a tagged union from Cyclone/Rust into C, because the C compiler isn't going to enforce that C code updates the tag properly - if it did, it would start rejecting valid C code. At that point it's just a matter of style/taste whether you have a language that looks like C but isn't (Cyclone) or looks less like C (Rust).
(Come to think of it, C++ also has the same property of being built from C and being mostly backwards-compatible, but being a separate language.)
Both Rust and Cyclone make it easy to call into C for interoperating with existing code, even though such calls cannot be guaranteed safe at the language level. So it's quite feasible to take a large C project and start converting parts of the code to Rust one at a time, ensuring that you can maintain safety within the parts that you've already converted. (Rust in particular is the unique memory-safe language at the intersection of "actively developed and popular" and "can be used as a drop-in replacement for C and export C-compatible binary interfaces back to any calling code, without overhead" - there are a number of neat languages, not just Cyclone, if you don't have the former requirement, and there are a number of great languages like Go or Java if you don't have the latter requirement.)