void foo(int *) {}
void bar(void *) {}
forall(otype T) void baz(T *);
forall(dtype T) void qux(T *);
forall(dtype T | sized(T)) void quux(T *);

struct A; // incomplete
struct B {}; // complete

int main() {
	int *i;
	void *v;

	A * x;
	A * y;
	B * x;
	B * z;

	// okay
	*i;
	*x; // picks B
	*z;
	foo(i);
	bar(i);
	baz(i);
	qux(i);
	quux(i);

	bar(v);
	qux(v);

	// bad
	*v;
	*y;
	foo(v);
	baz(v);
	quux(v);
}


forall(otype T)
void baz(T * x) {
	// okay
	bar(x);
	baz(x);
	qux(x);
	quux(x);
	*x;
}

forall(dtype T)
void qux(T * y) {
	// okay
	bar(y);
	qux(y);

	// bad
	baz(y);
	quux(y);
	*y;
}

forall(dtype T | sized(T))
void quux(T * z) {
	// okay
	bar(z);
	qux(z);
	quux(z);
	*z;

	// bad
	baz(z);
}
