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