I once tried to use c2rust as a starting point for rustification of code and... it's not even good at that. The code is just too freakishly literal to the original C semantics that you can't even take the non-pointery bits and strip off the unsafe block and use that as a basis.
(To give you a sense, it translates something like a + 1 to a.unwrapped_add(1i32), and my recollection is that for (int i = 0; i < 10; i++) gets helpfully turned into a while loop instead of a for loop).
In general, the various challenges that all need to be solved that aren't solved yet are:
a) when is integer overflow intentional in the original code so that you know when to use wrapping_op instead of regular Rust operators?
b) how to convert unions into Rust enums
c) when pointers are slices, and what corresponds to the length of the slice
d) convert pointers to references, and know when they're mutable or const references
e) work out lifetime annotations where necessary
f) know when to add interior mutability to structs
g) wrap things in Mutex/RwLock/etc. for multithreaded access
We're a very long way from having full-application conversion workable, and that might be sufficiently difficult that it's impossible.
That doesn't mention the affine type problem. Rust references are restricted to single ownership. If A has a reference to B, B can't have a reference to A. Bi-directional references are not only a common idiom in C, they're an inherent part of C++ objects.
Rust has to use reference counts in such situations. You have an Rc wrapped around structs, sometimes a RefCell, and .borrow() calls that panic when you have a conflict. C code translates badly into that kind of structure.
Static analysis might help find .borrow() and .borrow_mut() calls that will panic, or which won't panic. It's very similar to finding lock deadlocks of the type where one thread locks the same lock twice.
(If static analysis shows that no .borrow() or .borrow_mut() for an RwLock will panic, you don't really need the RwLock. That's worth pursuing as a way to allow Rust to have back references.)
I'd lump that analysis somewhere in the d-g, because you have to remember that &mut is also noalias and work out downstream implications of that. It's probably presumptive of me to assume a particular workflow for reconstructing the ownership model to express in Rust, and dividing that into the steps I did isn't the only way to do it.
In any case, it's the difficulty of that reconstruction step that leaves me thinking that automated conversion of whole-application to Rust is a near-impossibility. Conversion of an individual function that works on plain-old-data structures is probably doable, if somewhat challenging.
An off-the-cuff idea I just had is to implement a semi-automated transformation, where the user has to input what a final conversion of a struct type should look like (including all Cell/Rc/whatever wrappers as needed), and the tool can use that to work out the rest of the translation. There's probably a lot of ways that can go horribly wrong, but it seems more feasible than trying to figure out all of the wrappers need to be.