RVO is a very specific optimization that has its own language in the standard (which is notable since the standard is pretty much silent on the vast majority of optimizations) and it is special precisely because it allows the optimization to occur even if it changes observable behavior. C does not have it, and compilers must compile the some code more conservatively because of it: e.g., if the address of return values escape in the caller and/or callee, a C compiler must ensure that the program always observes distinct addresses for distinct objects in the source, but in C++ one is free to observe that two apparently different objects are the same.
Now, sure, at least 90% of actual RVO is about eliminating constructors and destructors with side effects - which C doesn't have and so RVO simply doesn't apply most of the time: but one shouldn't conclude that "C has RVO", rather "C mostly doesn't need RVO, and in the cases were it could use it, it is not allowed and must be more conservative than C++".
For example the following code:
where the address of the caller's variable that will take the return value is passed along to the function returning it. Within the callee, f1 and f2 must be different objects in C, but not in C++.
All decent compilers compile this in C++ with only a single object, so sink() will receive identical objects. Most compilers "deoptimize" this in C since sink cannot receive identical objects: two objects are created so f1 and f2 have different addresses, and a copy is performed from f2 to the return value f1.
Due to a bug, clang mis-compiles this and applies the C++ RVO to C. So you maybe you are right: you can get RVO in C, but only due to a compiler bug!
Hah, sounds like you nailed the emergent philosophy of C there... :-)