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); }