Error: use of extraneous '&'

I have a big C struct expecting a UnsafePointer<VkPhysicalDeviceFeatures>?

Since withUnsafePointer work only with non Optional, I'm trying to determine if the field containing VkPhysicalDeviceFeatures is nil or not, and if not, assign its reference to a variable

        var enabledFeatures: VkPhysicalDeviceFeatures?

        func native<R>(_ block: (VkDeviceCreateInfo) -> R) -> R {
            var pFeatures: UnsafePointer<VkPhysicalDeviceFeatures>?
            if var features = enabledFeatures {
                pFeatures = &features
            }
            return block(VkDeviceCreateInfo(
                ... 
                pEnabledFeatures: &features))
            }
        }

but the compiler keeps complaining:

error: use of extraneous '&'

then I'm forced to do the following:

        var enabledFeatures: VkPhysicalDeviceFeatures?

        func native<R>(_ block: (VkDeviceCreateInfo) -> R) -> R {
            if var features = enabledFeatures {
                return block(VkDeviceCreateInfo(
                    ... 
                    pEnabledFeatures: &features))
            }
            return block(VkDeviceCreateInfo(
                ... 
                pEnabledFeatures: nil))
        }

which is obviously quite verbose and annoying..

Do I have a better choice?

If I understand correctly, you have a variable of type T?, and a function which takes an argument of type UnsafePointer<T>?, and you want to lift the variable so you can pass it to the function. Is that correct?

yep

Try this:

if var features = enabledFeatures {
  pFeatures = UnsafePointer(&features)
}
2 Likes

Unless I am mistaken, that would be undefined behavior: A pointer to the variable storage is created and passed to the UnsafePointer constructor. That pointer must not be used after the function (here: the init method) returns.

4 Likes

I just need it in block, there should be still valid, shouldn't?

I don't think so. But what you could do is to define a helper function, similar to the existing withUnsafePointer function:

public func withOptionalUnsafePointer<T, Result>(to value: T?, _ body: (UnsafePointer<T>?) -> Result) -> Result {
    if let value = value {
        return withUnsafePointer(to: value, body)
    } else {
        return body(nil)
    }
}

and use it like

return withOptionalUnsafePointer(to: enabledFeatures) {
    block(VkDeviceCreateInfo(pEnabledFeatures: $0))
}

But again note that the pointer in $0 is only valid for the execution of the block. (If I remember correctly, only global variables and static member variables are guaranteed to have a fixed address.)

@Martin is 100% correct. Creating an UnsafePointer using the UnsafePointer(&foo) when foo is a Swift type is never valid, it creates a pointer that is immediately invalid and must not be used. The correct thing to do is to use the withUnsafePointer function along with a helper that can handle optionality.

Might be a good candidate for a warning.

I think it would be better to simply forbid it entirely: [SR-2790] Reject UnsafePointer initialization via implicit pointer conversion. · Issue #4326 · apple/swift-corelibs-foundation · GitHub

2 Likes