Hi Martin, thank you for writing this proposal. This is just my two cents, but one-off void* functions, like qsort, are less of a pain point relative to generic containers. With generic containers it's common to have a collection of void* functions that must be consistently invoked with identical type T. Correct me if I'm wrong, but this proposal cannot genericize a struct field, i.e. it can genericize type 'T' but not 'T->someField'. The latter would be useful for something like 'vec_push(v,p)' where 'v->data[]' is the type T needed to determine if 'p' is a compatible type.
Tangentially related, the macro-based containers you've written here [1] are the best answer for type-generic containers I've come across. One "gotcha" is the container name must be a valid C identifier otherwise it doesn't token paste correctly (see Example #2 of your REAMDE where you typedef'd string* as string_ptr to workaround this). Would you give consideration to a new preprocessor mechanism for concatenating a list of tokens into a single valid C identifier? i.e. Something like CONCAT(struct Foo *) would produce struct_Foo_Ptr? The result is guaranteed token paste-able.
[1] https://github.com/uecker/noplate