| 1 | ## Options for safer void* handling #
 | 
|---|
| 2 | C allows implicit conversions between `void*` and other pointer types, as per 
 | 
|---|
| 3 | section 6.3.2.3.1 of the standard. 
 | 
|---|
| 4 | Making these implicit conversions explicit in Cforall would provide 
 | 
|---|
| 5 | significant type-safety benefits, and is precedented in C++. 
 | 
|---|
| 6 | A weaker version of this proposal would be to allow implicit conversions to 
 | 
|---|
| 7 | `void*` (as a sort of "top type" for all pointer types), but to make the 
 | 
|---|
| 8 | unsafe conversion from `void*` back to a concrete pointer type an explicit 
 | 
|---|
| 9 | conversion. 
 | 
|---|
| 10 | However, `int *p = malloc( sizeof(int) );` and friends are hugely common 
 | 
|---|
| 11 | in C code, and rely on the unsafe implicit conversion from the `void*` return 
 | 
|---|
| 12 | type of `malloc` to the `int*` type of the variable - obviously it would be 
 | 
|---|
| 13 | too much of a source-compatibility break to disallow this for C code. 
 | 
|---|
| 14 | We do already need to wrap C code in an `extern "C"` block, though, so it is 
 | 
|---|
| 15 | technically feasible to make the `void*` conversions implicit in C but 
 | 
|---|
| 16 | explicit in Cforall. 
 | 
|---|
| 17 | 
 | 
|---|
| 18 | As a possible mitigation for calling C code with `void*`-based APIs, pointers-to-dtype are 
 | 
|---|
| 19 | calling-convention compatible with `void*`; we could read `void*` in function 
 | 
|---|
| 20 | signatures as essentially a fresh dtype type variable, e.g:
 | 
|---|
| 21 | 
 | 
|---|
| 22 |         void* malloc( size_t )
 | 
|---|
| 23 |                 => forall(dtype T0) T0* malloc( size_t )
 | 
|---|
| 24 |         void qsort( void*, size_t, size_t, int (*)( const void*, const void* ) )
 | 
|---|
| 25 |                 => forall(dtype T0, dtype T1, dtype T2)
 | 
|---|
| 26 |                    void qsort( T0*, size_t, size_t, int (*)( const T1*, const T2* ) )
 | 
|---|
| 27 | 
 | 
|---|
| 28 | In this case, there would be no conversion needed to call `malloc`, just the 
 | 
|---|
| 29 | polymorphic type binding.
 | 
|---|
| 30 | This should handle many of the uses of `void*` in C.
 | 
|---|
| 31 | 
 | 
|---|
| 32 | This feature would even allow us to leverage some of Cforall's type safety to write 
 | 
|---|
| 33 | better declarations for legacy C API functions, like the following wrapper for 
 | 
|---|
| 34 | `qsort`:
 | 
|---|
| 35 | 
 | 
|---|
| 36 |         extern "C" { // turns off name-mangling so that this calls the C library
 | 
|---|
| 37 |                 // call-compatible type-safe qsort signature
 | 
|---|
| 38 |                 forall(dtype T)
 | 
|---|
| 39 |                 void qsort( T*, size_t, size_t, int (*)( const T*, const T* ) );
 | 
|---|
| 40 |                 
 | 
|---|
| 41 |                 // forbid type-unsafe C signature from resolving
 | 
|---|
| 42 |                 void qsort( void*, size_t, size_t, int (*)( const void*, const void* ) )
 | 
|---|
| 43 |                         = delete;
 | 
|---|
| 44 |         }
 | 
|---|