Definition of a reference to a `func`

What exactly is a reference to a func?

I ask because I am getting the error:

A C function pointer can only be formed from a reference to a 'func' or a literal closure

when compiling this code:

struct Thread: ~Copyable {
    let pt: UnsafeMutablePointer <pthread_t?>
    
    init? (proc: @escaping (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer?, arg: UnsafeMutableRawPointer) {
        self.pt = .allocate (capacity: 1)
        
        let arg = Adapter (input: arg, proc: proc)
        let argPtr: UnsafeMutablePointer <Adapter> = .allocate (capacity: 1)
        argPtr.initialize (to: arg)
        
        func f (adapter: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer? {
            return Self.Adapter.f (adapter)
        }
        
    #if false
        let rv = pthread_create (pt, nil, f, argPtr) // Okay
    #else
        let rv = pthread_create (pt, nil, Self.Adapter.f, argPtr) // Error: A C function pointer can only be formed from a reference to a 'func' or a literal closure
    #endif
        
        if rv != 0 {
            return nil
        }
    }
}

extension Thread {
    struct Adapter {
        let input: UnsafeMutableRawPointer
        let proc: (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer?
    }
}

extension Thread.Adapter  {
    static func f (_ adapter: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer? {
        print (type (of: Self.self), #function, "...")
        typealias Adapter = Thread.Adapter
        adapter.withMemoryRebound (to: Adapter.self, capacity: 1) { pointer in
            let u: Adapter = pointer.pointee
            _ = u.proc (u.input)
        }
        return nil
    }
}

I don't understand why the func Thread.Adapter.f is not a reference to a function; it is a static function.

Try with @convention(c):

    init?(proc: @escaping @convention(c) (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer?, arg: UnsafeMutableRawPointer) {
	    ...

    struct Adapter {
    	...
        let proc: @convention(c) (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer?
    }

extension Thread.Adapter  {
    static let f: @convention(c) (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer? = { adapter in
    	...
2 Likes

Thank you, @tera

That works like a charm! :slight_smile:

The problem with the original code is a weird thing about how Swift represents methods, even static methods—they have a secret context parameter representing the containing type that only disappears during later stages of compilation! It would be nice™ if the compiler automatically handled the conversion to a C function in the static case, but meanwhile Tera's solution works, as well as providing an inline closure that just immediately calls the static method.

4 Likes