Sized deallocation and availability


The sized deallocation functions in libc++ are currently marked as unavailable (with the availability attributes) before macosx10.12. This is fine since the required functions are not in the dylib prior to macosx10.12. However, we incorrectly trigger an error even when the sized deallocation functions are provided by the user. In other words, the following code triggers a compiler error because of the availability attributes:

$ cat <<EOF | clang++ -xc++ - -std=c++17 -mmacosx-version-min=10.11

void operator delete(void *p, std::size_t s) noexcept { }

int main() {
std::size_t size = 3;
void* ptr = nullptr;
::operator delete(ptr, size);

Also note that even passing -fsized-deallocation will not fix the problem, since it does not turn off the availability annotations. Here’s how I think we should solve the problem (IIUC this is the same approach that was taken for aligned allocation):

  1. In Clang: if the deployment target does not support sized deallocation, trigger an error whenever a sized deallocation function is used.

  2. In Clang: take the deployment target into account when defining the feature-test macro __cpp_sized_deallocation, i.e. do not define __cpp_sized_deallocation when the deployment target is older than macosx10.12.

  3. In Clang: when -fsized-deallocation is passed on the command-line, define __cpp_sized_deallocation regardless of other considerations, and do not trigger errors when sized allocation functions are used (regardless of the deployment target).

  4. In libc++: remove the availability attributes on the sized deallocation functions.

  5. In libc++: do not provide declarations for the sized deallocation functions when __cpp_sized_deallocation is not defined (this is already the case today).

I have a couple of questions:

  1. My understanding is that the bullets above describe what we did for aligned allocation – is that correct?
  2. Is there any reason not to do the above for sized deallocation? I think I remember Eric telling me they were different, but I’m not sure how.
  3. Why do we even bother declaring the deallocation functions (and the allocation functions while we’re at it) in , given they are implicitly declared by the compiler?
  4. What makes sized deallocation and aligned allocation different from just any other function in the dylib is that users can define those functions themselves. Would it make sense to develop a more general mechanism for achieving the above? I’m sure we will see other similar functions in the future.
  5. Why don’t we enable sized deallocation by default (when the proper requirements are met)? I think I remember hearing it was because sized deallocation is an ABI break, but I don’t remember the details.

I’m posting this to the list so that others can see the reasoning and chime in. I’m especially looking for feedback from Eric, who was involved in aligned allocation and (I think) knows all the details I’m looking for.