Skip to content

Commit d54044c

Browse files
committed
Update MoveOnlyObjectChecker for borrow accessors
1 parent c2dab58 commit d54044c

File tree

4 files changed

+169
-1
lines changed

4 files changed

+169
-1
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2421,6 +2421,12 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
24212421
return true;
24222422
}
24232423

2424+
if (operand->isBorrowAccessorResult()) {
2425+
moveChecker.diagnosticEmitter.emitObjectGuaranteedDiagnostic(
2426+
markedValue);
2427+
return true;
2428+
}
2429+
24242430
// Finally try to emit either a global or class field error...
24252431
if (!moveChecker.diagnosticEmitter
24262432
.emitGlobalOrClassFieldLoadedAndConsumed(markedValue)) {

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,17 @@ bool Implementation::gatherUses(SILValue value) {
302302
// copyable values as normal uses.
303303
if (auto *cvi = dyn_cast<CopyValueInst>(nextUse->getUser())) {
304304
if (cvi->getOperand()->getType().isMoveOnly()) {
305+
// Borrow accessor's callsite consists of copy_value +
306+
// mark_unresolved_non_copyable_value instructions.
307+
// It's diagnostics are driven by the
308+
// mark_unresolved_non_copyable_value instruction.
309+
// Ignore the copy_value uses to avoid an incoherent error.
310+
if (cvi->getOperand()->isBorrowAccessorResult()) {
311+
assert(isa<MarkUnresolvedNonCopyableValueInst>(
312+
cvi->getSingleConsumingUse()->getUser()));
313+
continue;
314+
}
315+
305316
LLVM_DEBUG(llvm::dbgs() << " Found copy value of move only "
306317
"field... looking through!\n");
307318
for (auto *use : cvi->getUses())

lib/SILOptimizer/Mandatory/MoveOnlyObjectCheckerUtils.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,13 @@ bool MoveOnlyObjectCheckerPImpl::eraseMarkWithCopiedOperand(
561561
// %copy = copy_value %yield
562562
// %mark = mark_unresolved_noncopyable_value [no_consume_or_assign]
563563
// %copy
564-
if (isa_and_nonnull<BeginApplyInst>(orig->getDefiningInstruction())) {
564+
// Borrow accessors:
565+
// %borrowed_return = apply
566+
// %copy = copy_value %borrowed_return
567+
// %mark = mark_unresolved_noncopyable_value [no_consume_or_assign]
568+
// %copy
569+
if (isa_and_nonnull<BeginApplyInst>(orig->getDefiningInstruction()) ||
570+
isa_and_nonnull<ApplyInst>(orig->getDefiningInstruction())) {
565571
if (orig->getOwnershipKind() == OwnershipKind::Guaranteed) {
566572
for (auto *use : markedInst->getConsumingUses()) {
567573
destroys.push_back(cast<DestroyValueInst>(use->getUser()));
@@ -574,6 +580,7 @@ bool MoveOnlyObjectCheckerPImpl::eraseMarkWithCopiedOperand(
574580
return true;
575581
}
576582
}
583+
577584
return false;
578585
}
579586

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// RUN: %target-swift-frontend -sil-verify-all -verify -emit-sil -enable-experimental-feature BorrowAndMutateAccessors %s
2+
3+
// REQUIRES: swift_feature_BorrowAndMutateAccessors
4+
5+
public struct NC : ~Copyable {}
6+
7+
func use<T : ~Copyable>(_ t: borrowing T) {}
8+
func consume<T : ~Copyable>(_ t: consuming T) {}
9+
10+
public struct GenSimpleNCWrapper<T : ~Copyable> : ~Copyable {
11+
var _prop: T
12+
13+
var prop: T {
14+
borrow {
15+
return _prop
16+
}
17+
}
18+
}
19+
20+
public struct GenNCWrapper<T : ~Copyable> : ~Copyable {
21+
var _prop: T
22+
var _w: GenSimpleNCWrapper<T>
23+
24+
public var prop: T {
25+
borrow {
26+
return _prop
27+
}
28+
}
29+
30+
var nested1: T {
31+
borrow {
32+
return _w.prop
33+
}
34+
}
35+
36+
var nested2: T {
37+
borrow {
38+
return prop
39+
}
40+
}
41+
42+
subscript(index: Int) -> T {
43+
borrow {
44+
return _prop
45+
}
46+
}
47+
48+
var nested_subscript: T {
49+
borrow {
50+
return self[0]
51+
}
52+
}
53+
54+
var literal: Int {
55+
borrow {
56+
return 0
57+
}
58+
}
59+
}
60+
61+
public struct SimpleNCWrapper: ~Copyable {
62+
var _nc: NC
63+
64+
var nc: NC {
65+
borrow {
66+
return _nc
67+
}
68+
}
69+
}
70+
71+
public struct NCWrapper: ~Copyable {
72+
var _nc: NC
73+
var _s: SimpleNCWrapper
74+
75+
var nc: NC {
76+
borrow {
77+
return _nc
78+
}
79+
}
80+
81+
var nested1: NC {
82+
borrow {
83+
return _s.nc
84+
}
85+
}
86+
87+
var nested2: NC {
88+
borrow {
89+
return nc
90+
}
91+
}
92+
93+
subscript(index: Int) -> NC {
94+
borrow {
95+
return _nc
96+
}
97+
}
98+
99+
var nested_subscript: NC {
100+
borrow {
101+
return self[0]
102+
}
103+
}
104+
105+
var literal: Int {
106+
borrow {
107+
return 0
108+
}
109+
}
110+
}
111+
112+
func nctest() {
113+
let w1 = GenNCWrapper(_prop: NC(), _w: GenSimpleNCWrapper(_prop: NC()))
114+
use(w1.prop)
115+
use(w1.nested1)
116+
use(w1.nested2)
117+
use(w1._w.prop)
118+
consume(w1.prop) //expected-error{{'w1.prop' is borrowed and cannot be consumed}} expected-note{{consumed here}}
119+
120+
let w2 = GenNCWrapper(_prop: NC(), _w: GenSimpleNCWrapper(_prop: NC()))
121+
var k1 = w2.prop //expected-error{{'w2.prop' is borrowed and cannot be consumed}} expected-note{{consumed here}}
122+
123+
use(k1)
124+
k1 = NC()
125+
use(k1)
126+
127+
let w3 = GenNCWrapper(_prop: NC(), _w: GenSimpleNCWrapper(_prop: NC())) //expected-error{{'w3' used after consume}}
128+
consume(w3) // expected-note{{consumed here}}
129+
use(w3.prop) // expected-note{{used here}}
130+
131+
let w4 = NCWrapper(_nc: NC(), _s: SimpleNCWrapper(_nc: NC()))
132+
use(w4.nc)
133+
use(w4.nested1)
134+
use(w4.nested2)
135+
use(w4._s.nc)
136+
consume(w4.nc) // expected-error{{'w4.nc' is borrowed and cannot be consumed}} expected-note{{consumed here}}
137+
138+
139+
let w5 = NCWrapper(_nc: NC(), _s: SimpleNCWrapper(_nc: NC()))
140+
var k2 = w5.nc // expected-error{{'w5.nc' is borrowed and cannot be consumed}} expected-note{{consumed here}}
141+
use(k2)
142+
k2 = NC()
143+
use(k2)
144+
}

0 commit comments

Comments
 (0)