Lower imported C structs and unions as addressable-for-dependencies.

C code is highly likely to want to use pointers as references between dependent
structs, and we would like to be able to readily map these to lifetime-dependent
Swift values. Making C types addressable-for-dependencies ensures that any function
producing a dependency on such a value receives a stable in-memory address for that
value, allowing borrows and inout accesses to always be representable as pointers.

rdar://153648393
This commit is contained in:
Joe Groff
2025-07-01 17:31:56 -07:00
parent 06aa42b75c
commit 78a5f358b4
4 changed files with 28 additions and 5 deletions

View File

@@ -2528,6 +2528,11 @@ namespace {
// that a union contains a pointer.
if (recordDecl->isOrContainsUnion())
properties.setIsOrContainsRawPointer();
// Treat imported C structs and unions as addressable-for-dependencies
// so that Swift lifetime dependencies are more readily interoperable
// with pointers in C used for similar purposes.
properties.setAddressableForDependencies();
}
}

View File

@@ -130,9 +130,9 @@ private:
MoveOnly moveOnlyId(const MoveOnly& p [[clang::lifetimebound]]);
// CHECK: sil [clang makeOwner] {{.*}}: $@convention(c) () -> Owner
// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0, borrow 1) @owned View
// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow address_for_deps 0) @owned View
// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow address_for_deps 0) @owned View
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow address_for_deps 0, borrow address_for_deps 1) @owned View
// CHECK: sil [clang Owner.handOutView] {{.*}} : $@convention(cxx_method) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
// CHECK: sil [clang Owner.handOutView2] {{.*}} : $@convention(cxx_method) (View, @in_guaranteed Owner) -> @lifetime(borrow 1) @owned View
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (View, View) -> @lifetime(copy 0, copy 1) @owned View
@@ -140,10 +140,10 @@ MoveOnly moveOnlyId(const MoveOnly& p [[clang::lifetimebound]]);
// CHECK: sil [clang OtherView.init] {{.*}} : $@convention(c) (View) -> @lifetime(copy 0) @out OtherView
// CHECK: sil [clang returnsImmortal] {{.*}} : $@convention(c) () -> @lifetime(immortal) @owned View
// CHECK: sil [clang copyView] {{.*}} : $@convention(c) (View, @lifetime(copy 0) @inout View) -> ()
// CHECK: sil [clang getCaptureView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned CaptureView
// CHECK: sil [clang getCaptureView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow address_for_deps 0) @owned CaptureView
// CHECK: sil [clang CaptureView.captureView] {{.*}} : $@convention(cxx_method) (View, @lifetime(copy 0) @inout CaptureView) -> ()
// CHECK: sil [clang CaptureView.handOut] {{.*}} : $@convention(cxx_method) (@lifetime(copy 1) @inout View, @in_guaranteed CaptureView) -> ()
// CHECK: sil [clang NS.getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
// CHECK: sil [clang NS.getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow address_for_deps 0) @owned View
// CHECK: sil [clang moveOnlyId] {{.*}} : $@convention(c) (@in_guaranteed MoveOnly) -> @lifetime(borrow {{.*}}0) @out MoveOnly
//--- test.swift

View File

@@ -0,0 +1,2 @@
struct CStruct { int x; int y; };
union CUnion { int x; int y; };

View File

@@ -0,0 +1,16 @@
// RUN: %target-swift-emit-silgen -import-objc-header %S/Inputs/clang_records_addressable_for_dependencies.h -enable-experimental-feature Lifetimes %s | %FileCheck %s
// REQUIRES: swift_feature_Lifetimes
struct Dependent: ~Escapable {
@_lifetime(immortal)
init() { fatalError() }
}
// CHECK-LABEL: sil {{.*}} @${{.*}}12dependenceOn7cStruct{{.*}} : $@convention(thin) (@in_guaranteed CStruct)
@_lifetime(cStruct)
func dependenceOn(cStruct: CStruct) -> Dependent { fatalError() }
// CHECK-LABEL: sil {{.*}} @${{.*}}12dependenceOn6cUnion{{.*}} : $@convention(thin) (@in_guaranteed CUnion)
@_lifetime(cUnion)
func dependenceOn(cUnion: CUnion) -> Dependent { fatalError() }