#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#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
*/

}
