/* { dg-do compile } */
/* { dg-options "-O3 -Warray-bounds=2" } */

typedef __SIZE_TYPE__ size_t;
extern void* malloc(size_t x);

int e[3];

struct f { int f[3]; };

extern void bar(int v[]);

struct h {

	int i;
	int j[];
};

struct h0 {

	int i;
	int j[0];
};

struct h0b {

	int i;
	int j[0];
	int k;
};

struct h1 {

	int i;
	int j[1];
};

struct h1b {

	int i;
	int j[1];
	int k;
};

struct h3 {

	int i;
	int j[3];
};

struct h3b {

	int i;
	int j[3];
	int k;
};

void foo(int (*a)[3])
{
	(*a)[4] = 1;	/* { dg-warning "subscript 4 is above array bound" } */
	a[0][0] = 1;	// ok
	a[1][0] = 1;	// ok
	a[1][4] = 1;	/* { dg-warning "subscript 4 is above array bound" } */

	int c[3] = { 0 };

	c[4] = 1;	/* { dg-warning "subscript 4 is above array bound" } */

	e[4] = 1;	/* { dg-warning "subscript 4 is above array bound" } */

	struct f f;
	f.f[4] = 1;	/* { dg-warning "subscript 4 is above array bound" } */

	struct h* h = malloc(sizeof(struct h) + 3 * sizeof(int));
	struct h0* h0 = malloc(sizeof(struct h0) + 3 * sizeof(int));
	struct h1* h1 = malloc(sizeof(struct h1) + 3 * sizeof(int));
	struct h3* h3 = malloc(sizeof(struct h3));

	h->j[4] = 1;	// flexible array member
	h0->j[4] = 1;	// zero-sized array extension
	h1->j[4] = 1;	/* { dg-warning "subscript 4 is above array bound" } */
	h3->j[4] = 1;	/* { dg-warning "subscript 4 is above array bound" } */

	struct h0b* h0b = malloc(sizeof(struct h) + 3 * sizeof(int));
	struct h1b* h1b = malloc(sizeof(struct h1b) + 3 * sizeof(int));
	struct h3b* h3b = malloc(sizeof(struct h3b));
//	h0b->j[4] = 1;
	h1b->j[4] = 1;;	/* { dg-warning "subscript 4 is above array bound" } */
	h3b->j[4] = 1;;	/* { dg-warning "subscript 4 is above array bound" } */

	// make sure nothing gets optimized away
	bar(*a);
	bar(c);
	bar(e);
	bar(f.f);
	bar(h1->j);
	bar(h3->j);
	bar(h3b->j);
	bar(h1b->j);
	bar(h->j);
	bar(h0->j);
}

