mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[sema] Ban user created read/set accessor that produce noncopyable types.
The reason why we are doing this is that this combination of read/set forces the compiler to emit a copy if we want to emit a modify operation. The reason why we are forced to emit such a copy is that: 1. _read provides a guaranteed value in memory 2. performing a modify requires an owned value in memory. This together implies that the only way we can do this is to copy from the _read into temporary memory. But we have a noncopyable type so we can't do this. rdar://112915525
This commit is contained in:
@@ -7365,6 +7365,9 @@ ERROR(noncopyable_types_cannot_be_resilient, none,
|
||||
"non-@frozen public and @usableFromInline noncopyable types are not "
|
||||
"supported",
|
||||
(const ValueDecl *))
|
||||
ERROR(noncopyable_cannot_have_read_set_accessor,none,
|
||||
"noncopyable %select{variable|subscript}0 cannot provide a read and set accessor",
|
||||
(unsigned))
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// MARK: Runtime discoverable attributes (@runtimeMetadata)
|
||||
|
||||
@@ -2479,10 +2479,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// If this is an init accessor property with a default initializer,
|
||||
// make sure that it subsumes initializers of all of its "initializes"
|
||||
// stored properties.
|
||||
if (auto *var = PBD->getSingleVar()) {
|
||||
|
||||
// If this is an init accessor property with a default initializer,
|
||||
// make sure that it subsumes initializers of all of its "initializes"
|
||||
// stored properties.
|
||||
auto *initAccessor = var->getAccessor(AccessorKind::Init);
|
||||
if (initAccessor && PBD->isInitialized(0)) {
|
||||
for (auto *property : initAccessor->getInitializedProperties()) {
|
||||
@@ -2491,6 +2492,26 @@ public:
|
||||
propertyBinding->setInitializerSubsumed(0);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a pure noncopyable type, we cannot have explicit read/set
|
||||
// accessors since this means that we cannot call mutating methods without
|
||||
// copying. We do not want to support types that one cannot define a
|
||||
// modify operation via a get/set or a modify.
|
||||
if (var->getInterfaceType()->isPureMoveOnly()) {
|
||||
if (auto *read = var->getAccessor(AccessorKind::Read)) {
|
||||
if (!read->isImplicit()) {
|
||||
if (auto *set = var->getAccessor(AccessorKind::Set)) {
|
||||
if (!set->isImplicit()) {
|
||||
var->diagnose(diag::noncopyable_cannot_have_read_set_accessor,
|
||||
0);
|
||||
PBD->setInvalid();
|
||||
var->setInvalid();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2562,6 +2583,23 @@ public:
|
||||
.fixItReplace(SD->getStaticLoc(), "static");
|
||||
}
|
||||
|
||||
// Reject noncopyable typed subscripts with read/set accessors since we
|
||||
// cannot define modify operations upon them without copying the read.
|
||||
if (SD->getElementInterfaceType()->isPureMoveOnly()) {
|
||||
if (auto *read = SD->getAccessor(AccessorKind::Read)) {
|
||||
if (!read->isImplicit()) {
|
||||
if (auto *set = SD->getAccessor(AccessorKind::Set)) {
|
||||
if (!set->isImplicit()) {
|
||||
SD->diagnose(diag::noncopyable_cannot_have_read_set_accessor,
|
||||
1);
|
||||
SD->setInvalid();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now check all the accessors.
|
||||
SD->visitEmittedAccessors([&](AccessorDecl *accessor) {
|
||||
visit(accessor);
|
||||
|
||||
@@ -1818,477 +1818,6 @@ public func testSubscriptGetSetThroughParentClass_BaseLoadable_ResultAddressOnly
|
||||
m.computedTester2[0].mutatingFunc()
|
||||
}
|
||||
|
||||
// MARK: read and setter
|
||||
// This is different since adding a setter changes how we codegen.
|
||||
|
||||
public struct LoadableSubscriptReadSetTester : ~Copyable {
|
||||
subscript(_ i: Int) -> AddressOnlyProtocol {
|
||||
_read {
|
||||
fatalError()
|
||||
}
|
||||
set {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () {
|
||||
// CHECK: [[BOX:%.*]] = alloc_box $
|
||||
// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]]
|
||||
// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]]
|
||||
//
|
||||
// The read call
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[MARK]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// The assignment:
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}) : $@convention(method) (@thin AddressOnlyProtocol.Type) -> @out AddressOnlyProtocol
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJECT]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[MARK]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// The mutating function call.
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJECT]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[MARK]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[MARK]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// CHECK: } // end sil function '$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_VaryyF'
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Var() {
|
||||
var m = LoadableSubscriptReadSetTester()
|
||||
m = LoadableSubscriptReadSetTester()
|
||||
m[0].nonMutatingFunc()
|
||||
m[0] = AddressOnlyProtocol()
|
||||
m[0].mutatingFunc()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () {
|
||||
// CHECK: [[BOX:%.*]] = alloc_box $
|
||||
// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]]
|
||||
// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]]
|
||||
//
|
||||
// The get call
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]]
|
||||
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: apply {{%.*}}([[TEMP]])
|
||||
// CHECK: destroy_addr [[TEMP]]
|
||||
// CHECK: end_borrow [[LOAD_BORROW]]
|
||||
// CHECK: } // end sil function '$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_LetyyF'
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Let() {
|
||||
let m = LoadableSubscriptReadSetTester()
|
||||
m[0].nonMutatingFunc()
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly57testSubscriptReadSet_BaseLoadable_ResultAddressOnly_InOut1myAA0gcdE6TesterVz_tF : $@convention(thin) (@inout LoadableSubscriptReadSetTester) -> () {
|
||||
// CHECK: bb0([[ARG:%.*]] : $*
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[ARG]]
|
||||
//
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[MARK]]
|
||||
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[ACCESS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD_BORROW]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// The assignment:
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[MARK]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[ACCESS]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// The mutating function call.
|
||||
// Getter
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[MARK]]
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[ACCESS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// Mutating Func
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// Setter
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[ACCESS]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// CHECK: } // end sil function '$s8moveonly57testSubscriptReadSet_BaseLoadable_ResultAddressOnly_InOut1myAA0gcdE6TesterVz_tF
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadSetTester) {
|
||||
m[0].nonMutatingFunc()
|
||||
m[0] = AddressOnlyProtocol()
|
||||
m[0].mutatingFunc()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly58testSubscriptReadSet_BaseLoadable_ResultAddressOnly_GlobalyyF : $@convention(thin) () -> () {
|
||||
// CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s8moveonly36globalLoadableSubscriptReadSetTesterAA0cdefG0Vvp
|
||||
//
|
||||
// The get call
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[GLOBAL_ADDR]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
|
||||
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD_BORROW]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// The assignment:
|
||||
// CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s8moveonly36globalLoadableSubscriptReadSetTesterAA0cdefG0Vvp
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}) : $@convention(method) (@thin AddressOnlyProtocol.Type) -> @out AddressOnlyProtocol
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL_ADDR]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[MARK]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// The mutating function call.
|
||||
// CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s8moveonly36globalLoadableSubscriptReadSetTesterAA0cdefG0Vvp
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL_ADDR]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
|
||||
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD_BORROW]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[MARK]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// CHECK: } // end sil function '$s8moveonly58testSubscriptReadSet_BaseLoadable_ResultAddressOnly_GlobalyyF'
|
||||
var globalLoadableSubscriptReadSetTester = LoadableSubscriptReadSetTester()
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Global() {
|
||||
globalLoadableSubscriptReadSetTester[0].nonMutatingFunc()
|
||||
globalLoadableSubscriptReadSetTester[0] = AddressOnlyProtocol()
|
||||
globalLoadableSubscriptReadSetTester[0].mutatingFunc()
|
||||
}
|
||||
|
||||
// Make sure that we get the same behavior when we access through another noncopyable struct.
|
||||
public struct LoadableSubscriptReadSetTesterNonCopyableStructParent : ~Copyable {
|
||||
var tester = LoadableSubscriptReadSetTester()
|
||||
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () {
|
||||
// CHECK: [[BOX:%.*]] = alloc_box $
|
||||
// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]]
|
||||
// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]]
|
||||
//
|
||||
// The first get call
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
|
||||
// CHECK: [[GEP:%.*]] = struct_element_addr [[MARK]]
|
||||
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[GEP]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD_BORROW]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// The mutating call.
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJECT]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
|
||||
// CHECK: [[GEP:%.*]] = struct_element_addr [[MARK]]
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
|
||||
// TODO: Another case where we need to expand coroutines
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[GEP]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// The second get call.
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
|
||||
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
|
||||
// CHECK: [[TESTER:%.*]] = apply {{%.*}}([[LOAD_BORROW]])
|
||||
// CHECK: end_borrow [[LOAD_BORROW]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: [[BORROWED_TESTER:%.*]] = begin_borrow [[TESTER]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[BORROWED_TESTER]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[BORROWED_TESTER]]
|
||||
// } // end sil function '$s8moveonly077testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressE4_VaryyF'
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Var() {
|
||||
var m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
m.computedTester[0].nonMutatingFunc()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () {
|
||||
// CHECK: [[BOX:%.*]] = alloc_box ${ let L
|
||||
// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]]
|
||||
// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]]
|
||||
//
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[MARK]]
|
||||
// CHECK: [[EXT:%.*]] = struct_extract [[LOAD]]
|
||||
// CHECK: [[COPY:%.*]] = copy_value [[EXT]]
|
||||
// CHECK: [[BORROW:%.*]] = begin_borrow [[COPY]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[BORROW]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: } // end sil function '$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF'
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Let() {
|
||||
let m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly87testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_InOut1myAA0lcde6TesterghjI0Vz_tF : $@convention(thin) (@inout LoadableSubscriptReadSetTesterNonCopyableStructParent) -> () {
|
||||
// CHECK: bb0([[ARG:%.*]] :
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[ARG]]
|
||||
//
|
||||
// Call to non_mutating
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[MARK]]
|
||||
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]]
|
||||
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[GEP]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD_BORROW]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// Modify
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[MARK]]
|
||||
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]]
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[GEP]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: } // end sil function '$s8moveonly87testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_InOut1myAA0lcde6TesterghjI0Vz_tF'
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadSetTesterNonCopyableStructParent) {
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly88testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_GlobalyyF : $@convention(thin) () -> () {
|
||||
// CHECK: [[GLOBAL:%.*]] = global_addr @$s8moveonly59globalLoadableSubscriptReadSetTesterNonCopyableStructParentAA0cdefghijK0Vvp :
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[GLOBAL]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
|
||||
// CHECK: [[GEP:%.*]] = struct_element_addr [[MARK]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
//
|
||||
// CHECK: [[GLOBAL:%.*]] = global_addr @$s8moveonly59globalLoadableSubscriptReadSetTesterNonCopyableStructParentAA0cdefghijK0Vvp :
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]]
|
||||
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
|
||||
// CHECK: [[GEP:%.*]] = struct_element_addr [[MARK]]
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[LOAD]]
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[GEP]])
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: } // end sil function '$s8moveonly88testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_GlobalyyF'
|
||||
var globalLoadableSubscriptReadSetTesterNonCopyableStructParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Global() {
|
||||
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].nonMutatingFunc()
|
||||
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].mutatingFunc()
|
||||
}
|
||||
|
||||
public class LoadableSubscriptReadSetTesterClassParent {
|
||||
var tester = LoadableSubscriptReadSetTester()
|
||||
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
|
||||
var computedTester2: LoadableSubscriptReadSetTester {
|
||||
get { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
var testerParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @$s8moveonly73testSubscriptReadSetThroughParentClass_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () {
|
||||
// CHECK: [[BOX:%.*]] = alloc_box $
|
||||
// CHECK: [[BORROW:%.*]] = begin_borrow [lexical] [[BOX]]
|
||||
// CHECK: [[PROJECT:%.*]] = project_box [[BORROW]]
|
||||
//
|
||||
// First read.
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
|
||||
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[CORO_RESULT]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT_2]])
|
||||
// CHECK: end_apply [[CORO_TOKEN_2]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
|
||||
// CHECK: destroy_value [[COPYABLE_CLASS]]
|
||||
//
|
||||
// First mutation.
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[CORO_RESULT]]
|
||||
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: copy_addr [[CORO_RESULT_2]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN_2]]
|
||||
// Mutating Func
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// Setter
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
|
||||
// CHECK: destroy_value [[COPYABLE_CLASS]]
|
||||
//
|
||||
// Second read.
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
|
||||
// CHECK: [[EXT:%.*]] = struct_extract [[CORO_RESULT]]
|
||||
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[EXT]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT_2]])
|
||||
// CHECK: end_apply [[CORO_TOKEN_2]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
|
||||
// CHECK: destroy_value [[COPYABLE_CLASS]]
|
||||
//
|
||||
// Second mutate
|
||||
//
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
|
||||
// CHECK: [[GEP:%.*]] = struct_element_addr [[CORO_RESULT]]
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
|
||||
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: copy_addr [[CORO_RESULT_2]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN_2]]
|
||||
// Mutating Func
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// Setter
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[GEP]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
|
||||
// CHECK: destroy_value [[COPYABLE_CLASS]]
|
||||
//
|
||||
// Third read. This is a case that we can't handle today due to the way the AST
|
||||
// looks:
|
||||
//
|
||||
// (subscript_expr type='AddressOnlyProtocol'
|
||||
// (member_ref_expr type='LoadableSubscriptReadSetTester'
|
||||
// (load_expr implicit type='LoadableSubscriptReadSetTesterClassParent'
|
||||
// (declref_expr type='@lvalue LoadableSubscriptReadSetTesterClassParent'
|
||||
// (argument_list
|
||||
// (argument
|
||||
// (integer_literal_expr type='Int'
|
||||
//
|
||||
// due to the load_expr in the subscript base, SILGen emits a base rvalue for
|
||||
// the load_expr and copies it, ending the coroutine. What we need is the
|
||||
// ability to have an lvalue pseudo-component that treats the declref_expr (and
|
||||
// any member_ref_expr) as a base and allows for a load_expr to be followed by N
|
||||
// member_ref_expr.
|
||||
//
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
|
||||
// CHECK: [[CORO_RESULT_COPY:%.*]] = copy_value [[CORO_RESULT]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: [[BORROW:%.*]] = begin_borrow [[CORO_RESULT_COPY]]
|
||||
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[BORROW]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT_2]])
|
||||
// CHECK: end_apply [[CORO_TOKEN_2]]
|
||||
//
|
||||
// Fourth read
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
|
||||
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[CORO_RESULT]])
|
||||
// CHECK: apply {{%.*}}([[CORO_RESULT_2]])
|
||||
// CHECK: end_apply [[CORO_TOKEN_2]]
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
|
||||
// CHECK: destroy_value [[COPYABLE_CLASS]]
|
||||
//
|
||||
// Fourth Mutation
|
||||
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
|
||||
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
|
||||
// CHECK: end_access [[ACCESS]]
|
||||
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
|
||||
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
|
||||
// CHECK: [[TEMP:%.*]] = alloc_stack $
|
||||
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
|
||||
// CHECK: [[LOAD:%.*]] = load_borrow [[CORO_RESULT]]
|
||||
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
|
||||
// CHECK: copy_addr [[CORO_RESULT_2]] to [init] [[MARK_TEMP]]
|
||||
// CHECK: end_apply [[CORO_TOKEN_2]]
|
||||
// CHECK: end_borrow [[LOAD]]
|
||||
// Mutating Func
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]])
|
||||
// Setter
|
||||
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[CORO_RESULT]])
|
||||
// CHECK: end_apply [[CORO_TOKEN]]
|
||||
// CHECK: } // end sil function '$s8moveonly73testSubscriptReadSetThroughParentClass_BaseLoadable_ResultAddressOnly_VaryyF'
|
||||
public func testSubscriptReadSetThroughParentClass_BaseLoadable_ResultAddressOnly_Var() {
|
||||
var m = LoadableSubscriptReadSetTesterClassParent()
|
||||
m = LoadableSubscriptReadSetTesterClassParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
m.testerParent.tester[0].nonMutatingFunc()
|
||||
m.testerParent.tester[0].mutatingFunc()
|
||||
m.computedTester[0].nonMutatingFunc()
|
||||
m.computedTester2[0].nonMutatingFunc()
|
||||
m.computedTester2[0].mutatingFunc()
|
||||
}
|
||||
|
||||
// MARK: _read and _modify
|
||||
|
||||
public struct LoadableSubscriptReadModifyTester : ~Copyable {
|
||||
|
||||
@@ -183,110 +183,6 @@ public func testSubscriptGetSetThroughParentClass_BaseLoadable_ResultAddressOnly
|
||||
m.computedTester2[0].mutatingFunc()
|
||||
}
|
||||
|
||||
// MARK: read and setter
|
||||
// This is different since adding a setter changes how we codegen.
|
||||
|
||||
public struct LoadableSubscriptReadSetTester : ~Copyable {
|
||||
subscript(_ i: Int) -> AddressOnlyMoveOnlyContainingProtocol {
|
||||
_read {
|
||||
fatalError()
|
||||
}
|
||||
set {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Var() {
|
||||
var m = LoadableSubscriptReadSetTester()
|
||||
m = LoadableSubscriptReadSetTester()
|
||||
m[0].nonMutatingFunc()
|
||||
m[0] = AddressOnlyMoveOnlyContainingProtocol()
|
||||
m[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Let() {
|
||||
let m = LoadableSubscriptReadSetTester()
|
||||
m[0].nonMutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadSetTester) {
|
||||
m[0].nonMutatingFunc()
|
||||
m[0] = AddressOnlyMoveOnlyContainingProtocol()
|
||||
m[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
var globalLoadableSubscriptReadSetTester = LoadableSubscriptReadSetTester()
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Global() {
|
||||
globalLoadableSubscriptReadSetTester[0].nonMutatingFunc()
|
||||
globalLoadableSubscriptReadSetTester[0] = AddressOnlyMoveOnlyContainingProtocol()
|
||||
globalLoadableSubscriptReadSetTester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
// Make sure that we get the same behavior when we access through another noncopyable struct.
|
||||
public struct LoadableSubscriptReadSetTesterNonCopyableStructParent : ~Copyable {
|
||||
var tester = LoadableSubscriptReadSetTester()
|
||||
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
|
||||
}
|
||||
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Var() {
|
||||
var m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
m.computedTester[0].nonMutatingFunc()
|
||||
}
|
||||
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Let() {
|
||||
let m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
}
|
||||
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadSetTesterNonCopyableStructParent) {
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
var globalLoadableSubscriptReadSetTesterNonCopyableStructParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Global() {
|
||||
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].nonMutatingFunc()
|
||||
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
public class LoadableSubscriptReadSetTesterClassParent {
|
||||
var tester = LoadableSubscriptReadSetTester()
|
||||
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
|
||||
var computedTester2: LoadableSubscriptReadSetTester {
|
||||
get { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
var testerParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
}
|
||||
|
||||
public func testSubscriptReadSetThroughParentClass_BaseLoadable_ResultAddressOnly_Var() {
|
||||
var m = LoadableSubscriptReadSetTesterClassParent()
|
||||
m = LoadableSubscriptReadSetTesterClassParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
m.testerParent.tester[0].nonMutatingFunc()
|
||||
m.testerParent.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
m.computedTester[0].nonMutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
m.computedTester2[0].nonMutatingFunc()
|
||||
m.computedTester2[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
// MARK: _read and _modify
|
||||
|
||||
public struct LoadableSubscriptReadModifyTester : ~Copyable {
|
||||
|
||||
@@ -180,110 +180,6 @@ public func testSubscriptGetSetThroughParentClass_BaseLoadable_ResultLoadable_Va
|
||||
m.computedTester2[0].mutatingFunc()
|
||||
}
|
||||
|
||||
// MARK: read and setter
|
||||
// This is different since adding a setter changes how we codegen.
|
||||
|
||||
public struct LoadableSubscriptReadSetTester : ~Copyable {
|
||||
subscript(_ i: Int) -> LoadableMoveOnlyContainingProtocol {
|
||||
_read {
|
||||
fatalError()
|
||||
}
|
||||
set {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultLoadable_Var() {
|
||||
var m = LoadableSubscriptReadSetTester()
|
||||
m = LoadableSubscriptReadSetTester()
|
||||
m[0].nonMutatingFunc()
|
||||
m[0] = LoadableMoveOnlyContainingProtocol()
|
||||
m[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultLoadable_Let() {
|
||||
let m = LoadableSubscriptReadSetTester()
|
||||
m[0].nonMutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultLoadable_InOut(m: inout LoadableSubscriptReadSetTester) {
|
||||
m[0].nonMutatingFunc()
|
||||
m[0] = LoadableMoveOnlyContainingProtocol()
|
||||
m[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
var globalLoadableSubscriptReadSetTester = LoadableSubscriptReadSetTester()
|
||||
public func testSubscriptReadSet_BaseLoadable_ResultLoadable_Global() {
|
||||
globalLoadableSubscriptReadSetTester[0].nonMutatingFunc()
|
||||
globalLoadableSubscriptReadSetTester[0] = LoadableMoveOnlyContainingProtocol()
|
||||
globalLoadableSubscriptReadSetTester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
// Make sure that we get the same behavior when we access through another noncopyable struct.
|
||||
public struct LoadableSubscriptReadSetTesterNonCopyableStructParent : ~Copyable {
|
||||
var tester = LoadableSubscriptReadSetTester()
|
||||
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
|
||||
}
|
||||
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultLoadable_Var() {
|
||||
var m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
m.computedTester[0].nonMutatingFunc()
|
||||
}
|
||||
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultLoadable_Let() {
|
||||
let m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
}
|
||||
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultLoadable_InOut(m: inout LoadableSubscriptReadSetTesterNonCopyableStructParent) {
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
var globalLoadableSubscriptReadSetTesterNonCopyableStructParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultLoadable_Global() {
|
||||
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].nonMutatingFunc()
|
||||
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
public class LoadableSubscriptReadSetTesterClassParent {
|
||||
var tester = LoadableSubscriptReadSetTester()
|
||||
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
|
||||
var computedTester2: LoadableSubscriptReadSetTester {
|
||||
get { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
var testerParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
|
||||
}
|
||||
|
||||
public func testSubscriptReadSetThroughParentClass_BaseLoadable_ResultLoadable_Var() {
|
||||
var m = LoadableSubscriptReadSetTesterClassParent()
|
||||
m = LoadableSubscriptReadSetTesterClassParent()
|
||||
m.tester[0].nonMutatingFunc()
|
||||
m.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
m.testerParent.tester[0].nonMutatingFunc()
|
||||
m.testerParent.tester[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
m.computedTester[0].nonMutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
m.computedTester2[0].nonMutatingFunc()
|
||||
m.computedTester2[0].mutatingFunc()
|
||||
// expected-error @-1 {{copy of noncopyable typed value}}
|
||||
}
|
||||
|
||||
// MARK: _read and _modify
|
||||
|
||||
public struct LoadableSubscriptReadModifyTester : ~Copyable {
|
||||
|
||||
64
test/Sema/moveonly_read_set_ban.swift
Normal file
64
test/Sema/moveonly_read_set_ban.swift
Normal file
@@ -0,0 +1,64 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
// RUN: %target-typecheck-verify-swift -enable-library-evolution
|
||||
|
||||
@frozen
|
||||
public struct NonCopyableS : ~Copyable {}
|
||||
@frozen
|
||||
public enum NonCopyableE : ~Copyable {}
|
||||
|
||||
public struct S {
|
||||
public var x: NonCopyableS { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public var x2: NonCopyableE { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public subscript(x x: Int) -> NonCopyableS { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public subscript(y y: Int) -> NonCopyableE { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
}
|
||||
|
||||
public class C {
|
||||
public var x: NonCopyableS { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public var x2: NonCopyableE { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public subscript(x x: Int) -> NonCopyableS { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public subscript(y y: Int) -> NonCopyableE { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
}
|
||||
|
||||
public enum E {
|
||||
public var x: NonCopyableS { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public var x2: NonCopyableE { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public subscript(x x: Int) -> NonCopyableS { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
public subscript(y y: Int) -> NonCopyableE { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
|
||||
_read { fatalError() }
|
||||
set { fatalError() }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user