Skip to content

Commit ca7b8e2

Browse files
authored
Merge pull request #66445 from jckarter/noncopyable-computed-property-address-only-base
SILGen: Don't copy a borrowed noncopyable address-only base of a computed property access.
2 parents 37b8be9 + f066219 commit ca7b8e2

File tree

4 files changed

+96
-5
lines changed

4 files changed

+96
-5
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6455,7 +6455,12 @@ ArgumentSource AccessorBaseArgPreparer::prepareAccessorAddressBaseArg() {
64556455
// If the base is currently an address, we may have to copy it.
64566456
if (shouldLoadBaseAddress()) {
64576457
if (selfParam.isConsumed() ||
6458-
base.getType().isAddressOnly(SGF.F)) {
6458+
(base.getType().isAddressOnly(SGF.F)
6459+
// If a move-only base is borrowed, then we have to try our best to
6460+
// borrow it in-place without copying.
6461+
// TODO: Can we avoid copying a non-move-only value too in this
6462+
// circumstance?
6463+
&& !base.getType().isMoveOnly())) {
64596464
// The load can only be a take if the base is a +1 rvalue.
64606465
auto shouldTake = IsTake_t(base.hasCleanup());
64616466

@@ -6464,6 +6469,11 @@ ArgumentSource AccessorBaseArgPreparer::prepareAccessorAddressBaseArg() {
64646469
SGFContext(), shouldTake);
64656470
return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base));
64666471
}
6472+
6473+
// If the type is address-only, we can borrow the memory location as is.
6474+
if (base.getType().isAddressOnly(SGF.F)) {
6475+
return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base));
6476+
}
64676477

64686478
// If we do not have a consumed base and need to perform a load, perform a
64696479
// formal access load borrow.

lib/SILGen/SILGenLValue.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,11 @@ namespace {
11711171
assert(base
11721172
&& base.getType().isAddress()
11731173
&& "should have an address base to borrow from");
1174+
// If the base value is address-only then we can borrow from the
1175+
// address in-place.
1176+
if (!base.getType().isLoadable(SGF.F)) {
1177+
return base;
1178+
}
11741179
auto result = SGF.B.createLoadBorrow(loc, base.getValue());
11751180
return SGF.emitFormalEvaluationManagedBorrowedRValueWithCleanup(loc,
11761181
base.getValue(), result);

test/ModuleInterface/moveonly_user.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,13 @@
55
// RUN: %target-swift-frontend -emit-sil -sil-verify-all -I %t %s > /dev/null
66

77
// >> now again with library evolution; we expect the same result.
8-
// FIXME: move checker doesn't like it when you specify library evolution
98
// RUN: %target-swift-frontend -DSYNTHESIZE_ACCESSORS -enable-library-evolution -emit-module -o %t/Hello.swiftmodule %S/Inputs/moveonly_api.swift
109
// RUN: %target-swift-frontend -emit-sil -sil-verify-all -I %t %s > /dev/null
1110

1211
// FIXME: ideally this would also try executing the program rather than just generating SIL
1312

1413
// FIXME: make this test work when we're not synthesizing the accessors
1514

16-
// rdar://106164128
17-
// XFAIL: *
18-
1915
import Hello
2016

2117
func simpleTest() {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -emit-sil -verify %s
3+
4+
// rdar://109161396
5+
6+
public protocol P {}
7+
8+
@_moveOnly
9+
public struct M {
10+
private var x: P
11+
var other: CInt { 0 }
12+
13+
var otherMoveOnly: M {
14+
_read {
15+
yield self
16+
}
17+
}
18+
19+
@_silgen_name("no")
20+
init()
21+
}
22+
23+
// CHECK-LABEL: sil [ossa] @${{.*}}4test3mut
24+
// CHECK: [[CHECK:%.*]] = mark_must_check [consumable_and_assignable] %0
25+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[CHECK]]
26+
// CHECK: [[RESULT:%.*]] = apply {{.*}}([[ACCESS]])
27+
// CHECK; end_access [[ACCESS]]
28+
// CHECK: return [[RESULT]]
29+
public func test(mut: inout M) -> CInt {
30+
return mut.other
31+
}
32+
33+
// CHECK-LABEL: sil [ossa] @${{.*}}4test6borrow
34+
// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] %0
35+
// CHECK: [[RESULT:%.*]] = apply {{.*}}([[CHECK]])
36+
// CHECK: return [[RESULT]]
37+
public func test(borrow: borrowing M) -> CInt {
38+
return borrow.other
39+
}
40+
41+
// CHECK-LABEL: sil [ossa] @${{.*}}4test7consume
42+
// CHECK: [[BOX:%.*]] = project_box
43+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[BOX]]
44+
// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
45+
// CHECK: [[RESULT:%.*]] = apply {{.*}}([[CHECK]])
46+
// CHECK; end_access [[ACCESS]]
47+
// CHECK: return [[RESULT]]
48+
public func test(consume: consuming M) -> CInt {
49+
return consume.other
50+
}
51+
52+
// CHECK-LABEL: sil [ossa] @${{.*}}4test3own
53+
// CHECK: [[CHECK:%.*]] = mark_must_check [consumable_and_assignable] %0
54+
// CHECK: [[RESULT:%.*]] = apply {{.*}}([[CHECK]])
55+
// CHECK: return [[RESULT]]
56+
public func test(own: __owned M) -> CInt {
57+
return own.other
58+
}
59+
60+
func use(_: CInt, andMutate _: inout M) {}
61+
func use(_: CInt, andConsume _: consuming M) {}
62+
func borrow(_: borrowing M, andMutate _: inout M) {}
63+
func borrow(_: borrowing M, andConsume _: consuming M) {}
64+
65+
public func testNoInterferenceGet(mut: inout M, extra: consuming M) {
66+
// This should not cause exclusivity interference, since the result of
67+
// the getter can have an independent lifetime from the borrow.
68+
use(mut.other, andMutate: &mut)
69+
use(mut.other, andConsume: mut)
70+
mut = extra
71+
}
72+
73+
public func testInterferenceRead(mut: inout M, extra: consuming M) {
74+
// This should cause exclusivity interference, since in order to borrow
75+
// the yielded result from the `_read`, we need to keep the borrow of
76+
// the base going.
77+
borrow(mut.otherMoveOnly, andMutate: &mut) // expected-error{{}} expected-note{{}}
78+
borrow(mut.otherMoveOnly, andConsume: mut) // expected-error{{}} expected-note{{}}
79+
mut = extra
80+
}

0 commit comments

Comments
 (0)