How to use withUnsafeMutablePointer with Swift 5.2

Filling in the details a little bit more:

&output creates a pointer that is temporarily bound to output during the scope of the call to UnsafeMutableBufferPointer.init. I.e. this line is effectively equivalent to:

let buffer = withUnsafeMutablePointer(to: &output) {
  UnsafeMutableBufferPointer(start: $0, count: 1)
}

Rewritten like this, the problem becomes more clear; because output is a value (at least for the usual FixedWidthInteger types), rather than an object with a fixed memory address, the pointer is no longer semantically bound to output once UnsafeMutableBufferPointer.init returns--buffer is never semantically bound to output at any point in the code!

I am frankly somewhat amazed that this ever "worked"--I would expect it to produce meaningless results even in older versions of Swift, as the optimizer would be free to simply assume that the call to copyBytes does not update output and return 0.

I would note that you may also be able to use the approach I sketched here to avoid any pointer shenanigans at all and still get reasonable performance.

(Tagging @Andrew_Trick, who's the real guru w.r.t. this corner of Swift, in case he wants to make my terminology more precise or offer other suggestions). I should note that none of us, especially not me and Andy, are very happy with the road hazard you're encountering here--the warning will help a lot of people figure out that they did something wrong, but we need to do a much better job of giving people good patterns that let them avoid the problem to begin with.

2 Likes