mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
SILGen: Treat read-formal-accessed lvalues as borrows.
A read access asserts that the memory location is immutable for the duration of the access, so it can be treated as a borrow rather than a mutable lvalue. Doing this allows the borrow formal access scope fixes from #79084 to apply to situations where a loadable type undergoes an accessor-based access with indirect arguments (such as for public accessors when library evolution is enabled for the type). Fixes rdar://143334632.
This commit is contained in:
@@ -8895,7 +8895,9 @@ class CopyValueInst
|
||||
friend class SILBuilder;
|
||||
|
||||
CopyValueInst(SILDebugLocation DebugLoc, SILValue operand)
|
||||
: UnaryInstructionBase(DebugLoc, operand, operand->getType()) {}
|
||||
: UnaryInstructionBase(DebugLoc, operand, operand->getType()) {
|
||||
assert(operand->getType().isObject());
|
||||
}
|
||||
};
|
||||
|
||||
class ExplicitCopyValueInst
|
||||
|
||||
@@ -23,6 +23,16 @@
|
||||
using namespace swift;
|
||||
using namespace Lowering;
|
||||
|
||||
ManagedValue ManagedValue::forFormalAccessedAddress(SILValue address,
|
||||
SGFAccessKind accessKind) {
|
||||
if (isReadAccess(accessKind)) {
|
||||
return forBorrowedAddressRValue(address);
|
||||
} else {
|
||||
return forLValue(address);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ManagedValue ManagedValue::forForwardedRValue(SILGenFunction &SGF,
|
||||
SILValue value) {
|
||||
if (!value)
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Lowering {
|
||||
|
||||
class Initialization;
|
||||
class SILGenFunction;
|
||||
enum class SGFAccessKind : uint8_t;
|
||||
|
||||
/// ManagedValue - represents a singular SIL value and an optional cleanup.
|
||||
/// Ownership of the ManagedValue can be "forwarded" to disable its cleanup when
|
||||
@@ -252,6 +253,13 @@ public:
|
||||
static ManagedValue forInContext() {
|
||||
return ManagedValue(SILValue(), true, CleanupHandle::invalid());
|
||||
}
|
||||
|
||||
/// Creates a managed value for an address that is undergoing a formal
|
||||
/// access. This will be `forLValue` if the `accessKind` is a mutating
|
||||
/// (exclusive) access or `forBorrowedRValueAddress` if the
|
||||
/// `accessKind` is borrowing (shared).
|
||||
static ManagedValue forFormalAccessedAddress(SILValue address,
|
||||
SGFAccessKind accessKind);
|
||||
|
||||
bool isValid() const {
|
||||
return valueAndFlag.getInt() || valueAndFlag.getPointer();
|
||||
|
||||
@@ -618,7 +618,8 @@ namespace {
|
||||
bool isFinal) override {
|
||||
loc.markAutoGenerated();
|
||||
|
||||
assert(base.isLValue());
|
||||
assert(base.isLValue() ||
|
||||
(base.isPlusZero() && base.getType().isAddress()));
|
||||
loc.markAutoGenerated();
|
||||
SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
|
||||
ExecutorHop.emit(SGF, loc);
|
||||
@@ -655,7 +656,8 @@ static SILValue enterAccessScope(SILGenFunction &SGF, SILLocation loc,
|
||||
/*fromBuiltin=*/false);
|
||||
|
||||
// Push a writeback to end it.
|
||||
auto accessedMV = ManagedValue::forLValue(addr);
|
||||
ManagedValue accessedMV
|
||||
= ManagedValue::forFormalAccessedAddress(addr, accessKind);
|
||||
std::unique_ptr<LogicalPathComponent> component(
|
||||
new EndAccessPseudoComponent(typeData, std::move(prevExecutor)));
|
||||
pushWriteback(SGF, loc, std::move(component), accessedMV,
|
||||
@@ -673,7 +675,7 @@ static ManagedValue enterAccessScope(SILGenFunction &SGF, SILLocation loc,
|
||||
bool noNestedConflict = false) {
|
||||
auto access = enterAccessScope(SGF, loc, base, addr.getValue(), typeData,
|
||||
accessKind, enforcement, actorIso, noNestedConflict);
|
||||
return ManagedValue::forLValue(access);
|
||||
return ManagedValue::forFormalAccessedAddress(access, accessKind);
|
||||
}
|
||||
|
||||
// Find the base of the formal access at `address`. If the base requires an
|
||||
@@ -1192,7 +1194,7 @@ namespace {
|
||||
enterAccessScope(SGF, loc, base, addr, getTypeData(), getAccessKind(),
|
||||
*Enforcement, takeActorIsolation());
|
||||
|
||||
return ManagedValue::forLValue(addr);
|
||||
return ManagedValue::forFormalAccessedAddress(addr, getAccessKind());
|
||||
}
|
||||
|
||||
bool isRValue() const override {
|
||||
@@ -2292,7 +2294,20 @@ namespace {
|
||||
static ManagedValue
|
||||
makeBaseConsumableMaterializedRValue(SILGenFunction &SGF,
|
||||
SILLocation loc, ManagedValue base) {
|
||||
if (base.isLValue()) {
|
||||
if (!SGF.useLoweredAddresses()
|
||||
&& base.getType().isTrivial(SGF.F)
|
||||
&& base.getType().isAddress()
|
||||
&& !base.isLValue()) {
|
||||
return SGF.emitLoad(loc, base.getValue(),
|
||||
SGF.getTypeLowering(base.getType()), SGFContext(),
|
||||
IsNotTake);
|
||||
}
|
||||
|
||||
bool isBorrowed = base.isPlusZeroRValueOrTrivial()
|
||||
&& !base.getType().isTrivial(SGF.F);
|
||||
|
||||
if (base.isLValue()
|
||||
|| (isBorrowed && base.getType().isAddress())) {
|
||||
if (SGF.useLoweredAddresses()) {
|
||||
auto tmp = SGF.emitTemporaryAllocation(loc, base.getType());
|
||||
SGF.B.createCopyAddr(loc, base.getValue(), tmp, IsNotTake,
|
||||
@@ -2304,8 +2319,6 @@ makeBaseConsumableMaterializedRValue(SILGenFunction &SGF,
|
||||
IsNotTake);
|
||||
}
|
||||
|
||||
bool isBorrowed = base.isPlusZeroRValueOrTrivial()
|
||||
&& !base.getType().isTrivial(SGF.F);
|
||||
if (!base.getType().isAddress() || isBorrowed) {
|
||||
if (SGF.useLoweredAddresses()) {
|
||||
auto tmp = SGF.emitTemporaryAllocation(loc, base.getType());
|
||||
|
||||
@@ -40,15 +40,15 @@ var lens = Lens(Rectangle(topLeft: topLeft,
|
||||
bottomRight: bottomRight))
|
||||
|
||||
// CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig
|
||||
// CHECK-NEXT: apply %45<Rectangle, Point>({{.*}})
|
||||
// CHECK-NEXT: apply %{{[0-9]+}}<Rectangle, Point>({{.*}})
|
||||
// CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig
|
||||
// CHECK-NEXT: apply %{{.*}}<Point, Int>({{.*}})
|
||||
// CHECK-NEXT: apply %{{[0-9]+}}<Point, Int>({{.*}})
|
||||
_ = lens.topLeft.x
|
||||
|
||||
// CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig
|
||||
// CHECK-NEXT: apply %68<Rectangle, Point>({{.*}})
|
||||
// CHECK-NEXT: apply %{{[0-9]+}}<Rectangle, Point>({{.*}})
|
||||
// CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig
|
||||
// CHECK-NEXT: apply {{%[0-9]+}}<Point, Int>({{.*}})
|
||||
// CHECK-NEXT: apply %{{[0-9]+}}<Point, Int>({{.*}})
|
||||
_ = lens.topLeft.y
|
||||
|
||||
lens.topLeft = Lens(Point(x: 1, y: 2)) // Ok
|
||||
|
||||
22
test/SILGen/indirect_accessor_access.swift
Normal file
22
test/SILGen/indirect_accessor_access.swift
Normal file
@@ -0,0 +1,22 @@
|
||||
// rdar://143334632
|
||||
|
||||
// RUN: %target-swift-emit-silgen -enable-library-evolution %s | %FileCheck %s
|
||||
|
||||
public struct Foo {
|
||||
// CHECK-LABEL: sil {{.*}} @$s{{.*}}3FooV3foo
|
||||
mutating func foo() -> Int {
|
||||
// CHECK: [[BEGIN_READ:%.*]] = begin_access [read] [unknown] %0
|
||||
// CHECK: ([[RESULT:%.*]], [[TOKEN:%.*]]) = begin_apply %{{.*}}([[BEGIN_READ]])
|
||||
// CHECK: end_apply [[TOKEN]]
|
||||
// CHECK: end_access [[BEGIN_READ]]
|
||||
// CHECK: return [[RESULT]]
|
||||
return self[]
|
||||
}
|
||||
|
||||
var object : AnyObject
|
||||
|
||||
subscript() -> Int {
|
||||
_read {fatalError()}
|
||||
_modify {fatalError()}
|
||||
}
|
||||
}
|
||||
@@ -433,10 +433,8 @@ func test_handling_of_nonmutating_set() {
|
||||
// CHECK: [[INIT_VALUE:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF4TestL_V5countSivpfi : $@convention(thin) () -> Int
|
||||
// CHECK-NEXT: [[VALUE:%.*]] = apply [[INIT_VALUE]]() : $@convention(thin) () -> Int
|
||||
// CHECK: assign_or_init [init] #<abstract function>Test.count, self [[SELF]] : $*Test, value [[VALUE]] : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
|
||||
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [static] [[SELF]] : $*Test
|
||||
// CHECK: assign_or_init [set] #<abstract function>Test.count, self [[SELF_REF]] : $*Test, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
|
||||
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [static] [[SELF]] : $*Test
|
||||
// CHECK: assign_or_init [set] #<abstract function>Test.count, self [[SELF_REF]] : $*Test, value [[ZERO:%.*]] : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
|
||||
// CHECK: assign_or_init [set] #<abstract function>Test.count, self [[SELF]] : $*Test, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
|
||||
// CHECK: assign_or_init [set] #<abstract function>Test.count, self [[SELF]] : $*Test, value [[ZERO:%.*]] : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
|
||||
init(count: Int) {
|
||||
self.count = count
|
||||
self.count = 0
|
||||
@@ -456,11 +454,10 @@ func test_handling_of_nonmutating_set() {
|
||||
|
||||
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5countADSi_tcfC
|
||||
// CHECK: [[SELF_REF:%.*]] = mark_uninitialized [rootself] %2
|
||||
// CHECK: [[SELF_ACCESS:%.*]] = begin_access [read] [static] [[SELF_REF]] : $*TestWithStored
|
||||
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5countSivs : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
|
||||
// CHECK: [[SELF:%.*]] = load [copy] {{.*}} : $*TestWithStored
|
||||
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF]]) : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
|
||||
// CHECK-NEXT: assign_or_init [init] #<abstract function>TestWithStored.count, self [[SELF_ACCESS]] : $*TestWithStored, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
|
||||
// CHECK-NEXT: assign_or_init [init] #<abstract function>TestWithStored.count, self [[SELF_REF]] : $*TestWithStored, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
|
||||
init(count: Int) {
|
||||
self.count = count
|
||||
}
|
||||
@@ -468,17 +465,15 @@ func test_handling_of_nonmutating_set() {
|
||||
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5valueADSi_tcfC
|
||||
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself] %2
|
||||
//
|
||||
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [static] [[SELF]] : $*TestWithStored
|
||||
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5countSivs : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
|
||||
// CHECK: [[SELF_COPY:%.*]] = load [copy] {{.*}} : $*TestWithStored
|
||||
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF_COPY]]) : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
|
||||
// CHECK-NEXT: assign_or_init [init] #<abstract function>TestWithStored.count, self [[SELF_REF]] : $*TestWithStored, value {{.*}} : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
|
||||
// CHECK-NEXT: assign_or_init [init] #<abstract function>TestWithStored.count, self [[SELF]] : $*TestWithStored, value {{.*}} : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
|
||||
//
|
||||
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [static] [[SELF]] : $*TestWithStored
|
||||
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5countSivs : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
|
||||
// CHECK: [[SELF_COPY:%.*]] = load [copy] {{.*}} : $*TestWithStored
|
||||
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF_COPY]]) : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
|
||||
// CHECK-NEXT: assign_or_init [set] #<abstract function>TestWithStored.count, self [[SELF_REF]] : $*TestWithStored, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
|
||||
// CHECK-NEXT: assign_or_init [set] #<abstract function>TestWithStored.count, self [[SELF]] : $*TestWithStored, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
|
||||
init(value: Int) {
|
||||
self.count = 0
|
||||
self.count = value
|
||||
|
||||
@@ -31,7 +31,7 @@ struct Test {
|
||||
// CHECK-NEXT: [[INIT:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[INIT_REF]]([[METATYPE]]) : $@convention(thin) (@owned String, @thin Test.Type) -> @out String
|
||||
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s4main4TestV4nameSSvs : $@convention(method) (@owned String, @in_guaranteed Test) -> ()
|
||||
// CHECK-NEXT: [[SETTER:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF_REF]]) : $@convention(method) (@owned String, @in_guaranteed Test) -> ()
|
||||
// CHECK-NEXT: assign_or_init #Test.name, self [[SELF_REF]] : $*Test, value {{.*}} : $String, init [[INIT]] : $@noescape @callee_guaranteed (@owned String) -> @out String, set [[SETTER]] : $@noescape @callee_guaranteed (@owned String) -> ()
|
||||
// CHECK-NEXT: assign_or_init #Test.name, self [[SELF]] : $*Test, value {{.*}} : $String, init [[INIT]] : $@noescape @callee_guaranteed (@owned String) -> @out String, set [[SETTER]] : $@noescape @callee_guaranteed (@owned String) -> ()
|
||||
init(id: ID, name: String) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
||||
Reference in New Issue
Block a user