RVO/NRVO are clearly allowed under the “as-if” rule in C.
In C++ you can get observable side-effects because you’ve overloaded the constructor, destructor, and/or assignment operator to give those side effects (e.g., print something out when one of those operations happens), but in C you don’t have any ability to overload those operators, and the built-in ones have no observable side effects.
Without overloading them, you get no observable side-effects from copy elision, and therefore nothing to stop a compiler from doing it.