I tried this code:
OpenStruct *myStruct = [[OpenStruct alloc] initWithDictionary:myDictionary];
NSLog(@"%@ says %@", @"Cow", [myStruct cowSound]);
I get warnings or errors with and without ARC, with LLVM 3.0 or LLVM GCC 4.2. I think you've misunderstood that forwardInvocation: still requires the method to be declared at some level, if only in a category (@interface) of the class you're sending the message to.
For example, when you do:
[someObject doSomething];
Then this will always generate at least a warning ("someObject may not respond to doSomething") if doSomething is not declared anywhere, regardless of whether the someObject class implements forwardInvocation or not. Like you noticed, the compiler is indeed not aware of the forwarding, and it also can't rely that your implementation of forwardInvocation guarantees message delivery. With LLVM 3.0 with or without ARC this may have been changed to generate an error instead, because ARC's development goal was to err on the side of more compiler errors rather than runtime issues.
Now you can still send messages to an object that doesn't implement a method. For example by using Objective-C runtime method objc_msgSend or via NSInvocation. But that voids the simple to use interface that you were planning to create.
Btw, your usage example for OpenStruct does not really justify why it is any simpler to access the dynamic struct via messaging compared to simple accessors like [struct getValueForKey:@"moo"]; … if you think this over then [struct moo] gives users little or no benefit over the first approach. The "moo" method is dynamic either way (a string or forwarded message) and a typo won't be caught at runtime.