From my perspective, depending on the C headers in this fashion is a big hack. When Objective-C was born, it wasn't such a big deal (since there was only one runtime).
I completely agree. It's a horrible hack, but that doesn't alter the fact that a large body of existing code that depends on this old behaviour has accumulated over the last two decades.
Now that id/Class are more 'builtin', Chris/I decided that ObjCIsaExpr worked nicely as a compatibility bridge.
It's fine for id (well, almost; the GNU runtime calls this field class_pointer, which is horrible but, again, something lots of existing code depends on). For Class / MetaClass, it's a much bigger problem.
I just figured the same approach could be used for your situation. At Apple, we've totally moved away from allowing user code to directly access the meta-data. In our non-fragile runtime, all the same meta-data can be accessed using C functions (so we don't have this problem for Class).
Unless you can deprecate some of this stuff (by replacing it with C function accessors), I'm afraid anything we do is a hack.
For new code, that's fine. I've written a compatibility framework that sits on top of the GNU runtime and provides exactly the same functionality with the same interfaces, but there is still a fair body of legacy code for both the GNU runtime and the legacy Apple runtime that directly manipulates the class structures and currently clang can't compile this code, so some form of hack is required. We also need to maintain compatibility with GCC in a lot of this code, which does require these headers for accessing fields on id / Class / MetaClass. Deprecating it is fine - and I'd be really happy with a compiler switch that let us error on code that attempted to access fields other than isa on these types even with when their definitions are available - but deprecating and removing are two different things.
I've attached an updated version of the diff that fixes all of the corner cases found by compiling GNUstep's Foundation. It's a hack, but it's a less-invasive hack than adding a load of new expression types. I think the ideal solution would be to have a flag on typedef types that indicated that they can be used as Objective-C message receivers. I assumed __attribute__((NSObject)) would do this, but it seems not to. If we had such a flag then we could just use id and Class typedefs if they were provided with that flag set, which would provide an even less-invasive hack.
clang.diff (10 KB)