Provide guidance on bounds-safe interfaces for function pointers.
The specification allows bounds-safe interfaces on parameters of function pointer types. Right now, we can write something like:
void qsort(void *base : byte_count(nmemb * size),
size_t nmemb, size_t size,
int(*compar)(const void *, const void *) :
itype(_Ptr<int(const void * : itype(_Ptr<const void>),
const void * : itype(_Ptr<const void>))>));
The bounds-safe interface type for compar is pretty confusing. It could be_Ptr<int (const void *, const void *)> or Ptr<int (Ptr<const void>, Ptr<const void>) The first is a checked pointer to a function that takes unchecked pointer arguments. The second is a checked pointer to a function that takes checked pointer arguments.
In the event that qsort is called from code that mixes checked and unchecked code, we require that if one parameter takes a checked type, all the other parameters with pointer type have to take a checked type. It seems non-intuitive that we'd allow base to be a checked array and compar to be a function that operates on unchecked pointers.
The intent of a bounds-safe interface type is to define a checked interface to existing unchecked code. I suggest that we simplify things for now by forbidding bounds-safe interfaces on parameters in function types. The revised definition would be:
void qsort(void *base : byte_count(nmemb * size),
size_t nmemb, size_t size,
int(*compar)(const void *, const void *) :
itype(_Ptr<int (_Ptr<const void>, _Ptr<const void>)>))
In this approach, the bounds-safe interface type specifies one of two alternatives, and there is no question about what the intending types for the parameters for the interface type are.
After further thought, it seems reasonable and concise to allow bounds-safe interfaces on parameters of function types. As the prior comment says, there is a problem in that function pointer types will end up having unchecked pointer types, which will lead to problems in checked code. It may be that we should infer an interface type for the entire function pointer type that is a checked pointer type.
We'd have to decide on exactly what the rules are, but it certainly makes sense to infer a checked pointer type if (1) there is an interface type on a parameter or return (2) all the parameters that have unchecked pointer types have interface types for them (3) if the return type has an unchecked pointer type, it has an interface for them (4) no interface type is specified by the programmer.
This inference would avoid a lot of redundant typing for programmers. To build on the qsort example, it would have the declaration:
void qsort(void *base : byte_count(nmemb * size),
size_t nmemb, size_t size,
int(*compar)(const void * : itype(_Ptr<const void>),
const void * : itype(_Ptr<const void>)));
The inferred interface type for compar could be:
itype(_Ptr<int(_Ptr<const void>. _Ptr<const void>)>)
After more experience with Checked C, I think the important thing is to provide guidance on how to write a bounds-safe interface for a function pointer type.
Given a function pointer p with the C type Ty1 (Ty2, Ty3, ... Tn), use an interface type (itype) to declared a fully checked type if possible. For example, if the checked types for Ty1 ... Tyn are CTy1 ... TyN, declare the interface itype(ptr<CTy1 (CTy2 .. CTyn>)`.
For functions that need to be converted to a checked function pointer, provide bounds-safe interfaces for the return and the parameters of the functions.