mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
SILGen: emit mark_dependence for unsafeAddress
Fixes a correctness issue with unsafe addressors: `unsafeAddress` and `unsafeMutableAddress`. Previously, the resulting `Unsafe[Mutable]Pointer` did not depend on `self`, meaning that the compiler is allowed to destroy `self` before any uses of the pointer. This happens to be valid for `UnsafePointer.pointee` because, in that case, `self` does not have a lifetime anyway; the correctness burden was on the programmer to use `withExtendedLifetime` around all uses of `self`. Now, unsafe addressors can be used for arbitrary `Self` types. This also enables lifetime dependence diagnostics when the addressor points to a `~Escapable` type. Addressors can now be used as an implementation of borrowed properties.
This commit is contained in:
@@ -7304,22 +7304,32 @@ ManagedValue SILGenFunction::emitAddressorAccessor(
|
||||
emission.apply().getAll(results);
|
||||
|
||||
assert(results.size() == 1);
|
||||
auto pointer = results[0].getUnmanagedValue();
|
||||
auto result = results[0].getUnmanagedValue();
|
||||
|
||||
// Drill down to the raw pointer using intrinsic knowledge of those types.
|
||||
auto pointerType =
|
||||
pointer->getType().castTo<BoundGenericStructType>()->getDecl();
|
||||
result->getType().castTo<BoundGenericStructType>()->getDecl();
|
||||
auto props = pointerType->getStoredProperties();
|
||||
assert(props.size() == 1);
|
||||
VarDecl *rawPointerField = props[0];
|
||||
pointer = B.createStructExtract(loc, pointer, rawPointerField,
|
||||
SILType::getRawPointerType(getASTContext()));
|
||||
auto rawPointer =
|
||||
B.createStructExtract(loc, result, rawPointerField,
|
||||
SILType::getRawPointerType(getASTContext()));
|
||||
|
||||
// Convert to the appropriate address type and return.
|
||||
SILValue address = B.createPointerToAddress(loc, pointer, addressType,
|
||||
SILValue address = B.createPointerToAddress(loc, rawPointer, addressType,
|
||||
/*isStrict*/ true,
|
||||
/*isInvariant*/ false);
|
||||
|
||||
// Create a dependency on self: the pointer is only valid as long as self is
|
||||
// alive.
|
||||
auto apply = cast<ApplyInst>(result);
|
||||
// global addressors don't have a source value. Presumably, the addressor
|
||||
// is the only way to get at them.
|
||||
if (apply->hasSelfArgument()) {
|
||||
auto selfSILValue = apply->getSelfArgument();
|
||||
address = B.createMarkDependence(loc, address, selfSILValue,
|
||||
MarkDependenceKind::Unresolved);
|
||||
}
|
||||
return ManagedValue::forLValue(address);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ func test0() {
|
||||
// CHECK: [[T1:%.*]] = apply [[T0]]({{%.*}}, [[AVAL]])
|
||||
// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafePointer<Int32>, #UnsafePointer._rawValue
|
||||
// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[T3]] : $*Int32
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [[T3]] : $*Int32 on [[AVAL]] : $A
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[MD]] : $*Int32
|
||||
// CHECK: [[Z:%.*]] = load [[ACCESS]] : $*Int32
|
||||
let z = a[10]
|
||||
|
||||
@@ -68,7 +69,8 @@ func test0() {
|
||||
// CHECK: [[T1:%.*]] = apply [[T0]]({{%.*}}, [[WRITE]])
|
||||
// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
|
||||
// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[T3]] : $*Int32
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [nonescaping] [[T3]] : $*Int32 on [[WRITE]] : $*A
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]] : $*Int32
|
||||
// CHECK: load
|
||||
// CHECK: sadd_with_overflow_Int{{32|64}}
|
||||
// CHECK: store {{%.*}} to [[ACCESS]]
|
||||
@@ -79,7 +81,8 @@ func test0() {
|
||||
// CHECK: [[T1:%.*]] = apply [[T0]]({{%.*}}, [[WRITE]])
|
||||
// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
|
||||
// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[T3]] : $*Int32
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [nonescaping] [[T3]] : $*Int32 on [[WRITE]] : $*A
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]] : $*Int32
|
||||
// CHECK: store {{%.*}} to [[ACCESS]]
|
||||
a[3] = 6
|
||||
}
|
||||
@@ -93,7 +96,8 @@ func test1() -> Int32 {
|
||||
// CHECK: [[PTR:%.*]] = apply [[ACCESSOR]]({{%.*}}, [[A]]) : $@convention(method) (Int32, A) -> UnsafePointer<Int32>
|
||||
// CHECK: [[T0:%.*]] = struct_extract [[PTR]] : $UnsafePointer<Int32>, #UnsafePointer._rawValue
|
||||
// CHECK: [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[T1]] : $*Int32
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [[T1]] : $*Int32 on [[A]] : $A
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[MD]] : $*Int32
|
||||
// CHECK: [[T2:%.*]] = load [[ACCESS]] : $*Int32
|
||||
// CHECK: return [[T2]] : $Int32
|
||||
return A()[0]
|
||||
@@ -147,7 +151,8 @@ struct B : Subscriptable {
|
||||
// CHECK: [[PTR:%.*]] = apply [[T0]]([[INDEX]], [[WRITE]])
|
||||
// CHECK: [[T0:%.*]] = struct_extract [[PTR]] : $UnsafeMutablePointer<Int32>,
|
||||
// CHECK: [[ADDR:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[ADDR]] : $*Int32
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [nonescaping] [[ADDR]] : $*Int32 on [[WRITE]] : $*B
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]] : $*Int32
|
||||
// Accept either of struct_extract+load or load+struct_element_addr.
|
||||
// CHECK: load
|
||||
// CHECK: [[T1:%.*]] = builtin "or_Int32"
|
||||
@@ -176,7 +181,8 @@ func test_carray(_ array: inout CArray<(Int32) -> Int32>) -> Int32 {
|
||||
// CHECK: [[T1:%.*]] = apply [[T0]]<(Int32) -> Int32>({{%.*}}, [[WRITE]])
|
||||
// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<(Int32) -> Int32>, #UnsafeMutablePointer._rawValue
|
||||
// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int32, Int32>
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[T3]]
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [nonescaping] [[T3]] : $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int32, Int32> on [[WRITE]] : $*CArray<(Int32) -> Int32>
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]]
|
||||
// CHECK: store {{%.*}} to [[ACCESS]] :
|
||||
array[0] = id_int
|
||||
|
||||
@@ -186,7 +192,9 @@ func test_carray(_ array: inout CArray<(Int32) -> Int32>) -> Int32 {
|
||||
// CHECK: [[T2:%.*]] = apply [[T1]]<(Int32) -> Int32>({{%.*}}, [[T0]])
|
||||
// CHECK: [[T3:%.*]] = struct_extract [[T2]] : $UnsafePointer<(Int32) -> Int32>, #UnsafePointer._rawValue
|
||||
// CHECK: [[T4:%.*]] = pointer_to_address [[T3]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int32, Int32>
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[T4]]
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [[T4]] : $*@callee_guaranteed @substituted <τ_0_0, τ_0_1>
|
||||
// (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int32, Int32> on [[T0]] : $CArray<(Int32) -> Int32>
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[MD]]
|
||||
// CHECK: [[T5:%.*]] = load [[ACCESS]]
|
||||
return array[1](5)
|
||||
}
|
||||
@@ -209,7 +217,8 @@ struct D : Subscriptable {
|
||||
// SILGEN: [[PTR:%.*]] = apply [[T0]]([[I]], [[ACCESS]])
|
||||
// SILGEN: [[T0:%.*]] = struct_extract [[PTR]] : $UnsafeMutablePointer<Int32>,
|
||||
// SILGEN: [[ADDR:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
|
||||
// SILGEN: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[ADDR]] : $*Int32
|
||||
// SILGEN: [[MD:%.*]] = mark_dependence [unresolved] [[ADDR]] : $*Int32 on %6 : $*D
|
||||
// SILGEN: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]] : $*Int32
|
||||
// SILGEN: assign [[VALUE]] to [[ACCESS]] : $*Int32
|
||||
|
||||
// SILGEN-LABEL: sil hidden [transparent] [ossa] @$s10addressors1DVys5Int32VAEciM
|
||||
@@ -219,7 +228,8 @@ struct D : Subscriptable {
|
||||
// SILGEN: [[PTR:%.*]] = apply [[T0]]([[I]], [[SELF_ACCESS]])
|
||||
// SILGEN: [[ADDR_TMP:%.*]] = struct_extract [[PTR]] : $UnsafeMutablePointer<Int32>,
|
||||
// SILGEN: [[ADDR:%.*]] = pointer_to_address [[ADDR_TMP]]
|
||||
// SILGEN: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[ADDR]]
|
||||
// SILGEN: [[MD:%.*]] = mark_dependence [unresolved] [[ADDR]] : $*Int32 on [[SELF_ACCESS]] : $*D
|
||||
// SILGEN: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]]
|
||||
// SILGEN: yield [[ACCESS]]
|
||||
// SILGEN: end_access [[ACCESS]]
|
||||
|
||||
@@ -236,7 +246,8 @@ func test_d(_ array: inout D) -> Int32 {
|
||||
// CHECK: [[T1:%.*]] = apply [[T0]]({{%.*}}, [[WRITE]])
|
||||
// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>,
|
||||
// CHECK: [[ADDR:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[ADDR]] : $*Int32
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [nonescaping] [[ADDR]] : $*Int32 on [[WRITE]] : $*D
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]] : $*Int32
|
||||
// CHECK: store [[V]] to [[ACCESS]] : $*Int32
|
||||
array[0] = make_int()
|
||||
|
||||
@@ -245,7 +256,8 @@ func test_d(_ array: inout D) -> Int32 {
|
||||
// CHECK: [[T1:%.*]] = apply [[T0]]({{%.*}}, [[WRITE]])
|
||||
// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>,
|
||||
// CHECK: [[ADDR:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[ADDR]] : $*Int32
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [nonescaping] [[ADDR]] : $*Int32 on [[WRITE]] : $*D
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]] : $*Int32
|
||||
// CHECK: [[FN:%.*]] = function_ref @$s10addressors14take_int_inoutyys5Int32VzF
|
||||
// CHECK: apply [[FN]]([[ACCESS]])
|
||||
take_int_inout(&array[1])
|
||||
@@ -271,7 +283,8 @@ struct E {
|
||||
// CHECK: [[T1:%.*]] = apply [[T0]]([[E]])
|
||||
// CHECK: [[T2:%.*]] = struct_extract [[T1]]
|
||||
// CHECK: [[T3:%.*]] = pointer_to_address [[T2]]
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[T3]] : $*Int32
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [[T3]] : $*Int32 on %0 : $E
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]] : $*Int32
|
||||
// CHECK: store {{%.*}} to [[ACCESS]] : $*Int32
|
||||
func test_e(_ e: E) {
|
||||
e.value = 0
|
||||
|
||||
@@ -16,7 +16,8 @@ public struct FA<T> {
|
||||
// CHECK: [[POINTER:%[^,]+]] = apply [[ADDRESSOR]]
|
||||
// CHECK: [[RAW_POINTER:%[^,]+]] = struct_extract [[POINTER]]
|
||||
// CHECK: [[ADDR:%[^,]+]] = pointer_to_address [[RAW_POINTER]]
|
||||
// CHECK: [[ACCESS:%[^,]+]] = begin_access [read] [unsafe] [[ADDR]]
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [unresolved] [[ADDR]] : $*T
|
||||
// CHECK: [[ACCESS:%[^,]+]] = begin_access [read] [unsafe] [[MD]]
|
||||
// Verify that no spurious temporary is emitted.
|
||||
// CHECK-NOT: alloc_stack
|
||||
// CHECK: yield [[ACCESS]] : $*T, resume [[SUCCESS:bb[0-9]+]], unwind [[FAILURE:bb[0-9]+]]
|
||||
|
||||
@@ -12,7 +12,8 @@ func load(b: UnsafeMutableBufferPointer<Foo>) -> Int {
|
||||
// Ensure the borrowing invocation of `load` happens within the access to
|
||||
// the pointed-at memory.
|
||||
// CHECK: [[PTR:%.*]] = pointer_to_address
|
||||
// CHECK: [[BEGIN:%.*]] = begin_access [read] [unsafe] [[PTR]]
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [unresolved] [[PTR]] : $*Foo on %0 : $UnsafeMutableBufferPointer<Foo>
|
||||
// CHECK: [[BEGIN:%.*]] = begin_access [read] [unsafe] [[MD]]
|
||||
// CHECK: [[FN:%.*]] = function_ref @load
|
||||
// CHECK: apply [[FN]]
|
||||
// CHECK: end_access [[BEGIN]]
|
||||
|
||||
@@ -606,7 +606,8 @@ func testAddressor(p: UnsafePointer<Int>) -> Int {
|
||||
// CHECK: apply
|
||||
// CHECK: struct_extract
|
||||
// CHECK: [[ADR:%.*]] = pointer_to_address
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[ADR]] : $*Int
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [unresolved] [[ADR]] : $*Int on %0 : $UnsafePointer<Int>
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[MD]] : $*Int
|
||||
// CHECK: load [trivial] [[ACCESS]] : $*Int
|
||||
// CHECK: return
|
||||
// CHECK-LABEL: } // end sil function '$s20access_marker_verify13testAddressor1pSiSPySiG_tF'
|
||||
@@ -1021,7 +1022,8 @@ func testPointerInit(x: Int, y: UnsafeMutablePointer<Int>) {
|
||||
// CHECK: [[POINTEE:%.*]] = apply %{{.*}}<Int>(%1) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0>
|
||||
// CHECK: [[RAWPTR:%.*]] = struct_extract [[POINTEE]] : $UnsafeMutablePointer<Int>, #UnsafeMutablePointer._rawValue
|
||||
// CHECK: [[ADR:%.*]] = pointer_to_address [[RAWPTR]] : $Builtin.RawPointer to [strict] $*Int
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[ADR]] : $*Int
|
||||
// CHECK: [[MD:%.*]] = mark_dependence [unresolved] [[ADR]] : $*Int on %1 : $UnsafeMutablePointer<Int> // user: %9
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[MD]] : $*Int
|
||||
// CHECK: assign %0 to [[ACCESS]] : $*Int
|
||||
// CHECK-LABEL: } // end sil function '$s20access_marker_verify15testPointerInit1x1yySi_SpySiGtF'
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ bb0(%0 : $*SNC):
|
||||
%6 = apply %5(%4) : $@convention(method) (@guaranteed SNC) -> UnsafePointer<NC>
|
||||
%7 = struct_extract %6 : $UnsafePointer<NC>, #UnsafePointer._rawValue
|
||||
%8 = pointer_to_address %7 : $Builtin.RawPointer to [strict] $*NC
|
||||
%9 = mark_dependence [unresolved] %8 : $*NC on %3 : $*SNC
|
||||
%9 = mark_dependence [nonescaping] %8 : $*NC on %3 : $*SNC
|
||||
%10 = begin_access [read] [unsafe] %9 : $*NC
|
||||
%11 = mark_unresolved_non_copyable_value [no_consume_or_assign] %10 : $*NC // expected-error {{'unknown' is borrowed and cannot be consumed}}
|
||||
%12 = load [copy] %11 : $*NC
|
||||
|
||||
Reference in New Issue
Block a user