# include <stdlib.h>

typedef int ***(**f1)(void);       /* f1 is a pointer to a function taking no args, returning int ***  */
typedef int (*f2)(void);           /* f2 is a function taking no args, returning an int */
typedef int **(*f3)(void);         /* f3 is a function taking no args, returning a pointer to a pointer to an int */
typedef int *(*f4[])(void);        /* f4 is an array of functions taking no args, returning pointers to ints */
typedef int *(f5)(int);            /* f5 is a function taking an int, returning a pointer to an int */ 
typedef int *(*f6(int,int))(int);  /* f6 is a function taking 2 int args, returns a function taking an int and
				     returning a pointer to an int */
             /* gcc complains if the pointer before f6 is omitted.  why? */
/*@-paramuse*/
int func1(void) { return 3;}
int *func2(void) { return (int *)malloc(sizeof(int));} 
     /* 1. Possibly null storage returned as non-null
     ** 2. Returned storage not completely defined (allocated only)
     */
/*@null@*/ int **func3(void) { return (int **)0;}
/*@null@*/ int ***func4(void) { return (int ***)0;}
int *func5(int i) { return &i; } /* 3. Immediate address &i returned as only: &i */
int *(*func6(int x, int y))(int) { return func5; }

int main (void)
{
  f1 t1; f2 t2; f3 t3; f3 *t3p; f4 *t4; f6 t6;
  int x, *xp, ***xppp;

  t1 = func1; /* 4. Assignment of int () * to f1 */        
  t1 = func4; /* 5. Assignment of int * * * () * to f1 */
  *t1 = func4; 

  t2 = func1; 
  t2 = func2; /* 6. Assignment of int * () * to f2 */

  t3 = func3;  
  t3p = func3; /* 7. Assignment of int * * () * to f3 *: t3p = func3 */

  t4 = func2; /* 8. Assignment of int * () * to f4 *: t4 = func2 */

  xppp = (*t1)(); 
  x = (t1)(); /* 9. Call to non-function (type f1): (t1) */
  x = (t2)(); 
  xp = (*t1)(); /* 10. Assignment of int * * * to int *: xp = (*t1)() */
  xp = (t4)(); /* 11. Call to non-function (type f4 *): (t4) */

  t6 = func1; /* 12. Assignment of int () * to f6: t6 = func1 */
              /* 13. Invalid left-hand side of assignment (function type f6): t6 */ 
  t6 = func6; /* 14. Invalid left-hand side of assignment (function type f6): t6 */ 
  (void) (t6)(); /* 15. Function (t6) called with 0 args, expects 2 */
  (void) (t6)(3); /* 16. Function (t6) called with 1 args, expects 2 */
  (void) ((t6)(3))(); /* 17. Function (t6) called with 1 args, expects 2 */
                      /* 18. Function ((t6)(3)) called with 0 args, expects 1 */
  (void) ((t6)(5, 3))(7); 
  return 3;
}
  
/* function pointer bug, provided by Marc Espie; additional pointer to function
 * type bug provided by Mihail Groza */

typedef void (*func)(void);
typedef int (pred)(int);

void (*f[10])(void);
func g[10];
extern pred *p;

void a(void)
{
}

void b(void)
{
  func *h;
  
  h = f;
  f[0] = a;
  g[0] = a;
  f[1] = g[0];
  h[2] = a;

  if (p(7) > 0)
    {
      h[1](7); /* 19. Function h[1] called with 1 args, declared void */
      g[0]();
    }
}

