Nowadays its *RARE* to find a MCU still in production that isn't supported by a C compiler, either GCC, SDCC, or the manufacturer's or a third party's proprietary C compiler. Many MCU families have more than one C compiler to choose from.
Yes, it's more than rare. It's even an oddity. And by nowadays, you can make that at least for the last 20 years.
Now a few, "recent" niche MCUs do not have a C compiler, likely because their architecture is too simplistic for that. We can think of the Padauk MCUs, which are ultra simple (and ultra cheap), and come with a vendor-supplied compiler supporting some kind of very stripped-down C. But this is really part of the few exceptions, and it still looks like C, even though the language is a lot more limited than C.
I'd be curious to hear about other examples.
It's interesting to think (as a compiler writer) what would prevent something from running C reasonably efficiently.
Severe lack of RAM, but it has to be really severe. You can write C programs on a 512 byte ATTiny85 no problems, or even its smaller sisters the 45 and 25, to the extent that you can write anything on them at all.
You need a way to load literals. You need bitwise boolean operations. NAND or NOR would be enough. You need addition. (Synthesizing from bitwise is too slow because you have to ripple carries). You need conditional branch based on zero / not zero. You need a right shift. You need at least 16 bit arithmetic (the preceding is sufficient to synthesize it from smaller units)
On a von Neumann architecture (which I'll define as one where you can run code from RAM) you can cover up many of the following sins with self-modifying code, at reduced but still reasonable efficiency. By definition a Turing machine (which is effectively a restricted form of a Harvard architecture, as the FSM is fixed) can compute anything, but it can be extremely inefficient.
You need pointers to arbitrary RAM addressees, and to add integers to pointers and subtract pointers, and to be able to load and store via these pointers.
You need to be able to call subroutines, and return from them. You need to have arbitrary (or at least large) return stack depth, or be able to access the return address easily and manipulate it as data. You need to be able to call subroutines via pointer, though not arbitrary pointer. Note on a Harvard architecture these can be a different kind of pointer than data pointers.