I've been tinkering with some basic C++ interop recently in the compiler, and it was suggested that I try to pick off non-trivially copyable C structs as an easier-to-chew task that still makes some progress in that overall direction.
I've changed ClangImporter (draft PR) to generate the following Swift interface for a C struct:
// C struct
typedef struct {
int intValue;
double doubleValue;
MyClass* unqualifiedObject;
__strong MyClass* strongObject;
__weak MyClass* weakObject;
__unsafe_unretained MyClass* unsafeUnretainedObject;
} MyStruct;
// Swift interface, according to swift-ide-test
struct MyStruct {
var intValue: Int32
var doubleValue: Double
var unqualifiedObject: MyClass!
var strongObject: MyClass!
weak var weakObject: @sil_weak MyClass!
var unsafeUnretainedObject: Unmanaged<MyClass>!
init()
init(
intValue: Int32, doubleValue: Double, unqualifiedObject: MyClass!,
strongObject: MyClass!, weakObject: MyClass!,
unsafeUnretainedObject: Unmanaged<MyClass>!)
}
(I kept the existing Unmanaged
-wrapping behavior for __unsafe_unretained
fields, though I wonder if using the unowned(unsafe)
storage type would also be appropriate here. That would be source-breaking, though.)
With that done, I need some advice on how to handle the SIL bits that need to be changed. Clang emits struct-layout-derived functions to act as the default-constructor, assignment, and destructor functions for these types (among others) which handle the necessary retains/releases for those fields.
My thinking so far is this:
- Instead of generating an
init()
that calls thezeroInitializer
built-in, I need to generate and call__default_constructor_<layout>
. - The memberwise
init
should call__default_constructor_<layout>
before setting the fields. - Value assignment should call
__copy_assignment_<layout>
instead of the SILassign
instruction. -
__destructor_<layout>
needs to be called before the SILdestroy_value
instruction.
At the IRGen level, it seems like I could use Clang's CodeGen to emit these special functions, and the nice thing about Swift is that I might be able to emit them in the context of the struct itself (as opposed to C, where they are emitted as static functions in the context of the call sites due to the lack of ODR).
But I'm unsure what to do at the SILGen level to glue things together between the imported Swift interface and the code I want Clang to generate (if that's what I should be doing here).
Am I on the right track here?