#include #include #include #ifdef ERRS #define ERR(...) __VA_ARGS__ #else #define ERR(...) #endif int main() { /* These attempts to assign @y@ to @x@ and vice-versa are obviously ill-typed. */ float * x; // x points at a floating-point number void (*y)(void); // y points at a function ERR( x = y; // wrong y = x; // wrong ) /* The first gets warning: assignment to `float *' from incompatible pointer type `void (*)(void)' and the second gets the opposite. Similarly, */ float pi = 3.14; void f( void (*g)(void) ) { g(); } ERR( f( & pi ); // wrong ) /* gets warning: passing argument 1 of `f' from incompatible pointer type with a segmentation fault at runtime. That @f@'s attempt to call @g@ fails is not due to 3.14 being a particularly unlucky choice of value to put in the variable @pi@. Rather, it is because obtaining a program that includes this essential fragment, yet exhibits a behaviour other than "doomed to crash," is a matter for an obfuscated coding competition. A "tractable syntactic method for proving the absence of certain program behaviours by classifying phrases according to the kinds of values they compute"*1 rejected the program. The behaviour (whose absence is unprovable) is neither minor nor unlikely. The rejection shows that the program is ill-typed. Yet, the rejection presents as a GCC warning. In the discussion following, ``ill-typed'' means giving a nonzero @gcc -Werror@ exit condition with a message that discusses typing. *1 TAPL-pg1 definition of a type system */ }