Skip to content

Commit e18d1c8

Browse files
authored
Merge pull request swiftlang#29860 from gottesmm/pr-2c1006ea5973927c581d0cea0268e77ae33bc076
2 parents 4d0e2ad + 17082f3 commit e18d1c8

File tree

4 files changed

+89
-40
lines changed

4 files changed

+89
-40
lines changed

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 85 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,17 @@ class SILValueOwnershipChecker {
127127

128128
private:
129129
bool checkUses();
130-
bool isCompatibleDefUse(Operand *op, ValueOwnershipKind ownershipKind,
131-
bool isGuaranteed);
130+
bool isCompatibleDefUse(Operand *op, ValueOwnershipKind ownershipKind);
132131

133132
bool gatherUsers(SmallVectorImpl<Operand *> &lifetimeEndingUsers,
134133
SmallVectorImpl<Operand *> &regularUsers,
135134
SmallVectorImpl<Operand *> &implicitRegularUsers);
136135

136+
bool
137+
gatherNonGuaranteedUsers(SmallVectorImpl<Operand *> &lifetimeEndingUsers,
138+
SmallVectorImpl<Operand *> &regularUsers,
139+
SmallVectorImpl<Operand *> &implicitRegularUsers);
140+
137141
bool checkValueWithoutLifetimeEndingUses();
138142

139143
bool checkFunctionArgWithoutLifetimeEndingUses(SILFunctionArgument *arg);
@@ -188,9 +192,10 @@ bool SILValueOwnershipChecker::check() {
188192
}
189193

190194
bool SILValueOwnershipChecker::isCompatibleDefUse(
191-
Operand *op, ValueOwnershipKind ownershipKind, bool isGuaranteed) {
195+
Operand *op, ValueOwnershipKind ownershipKind) {
192196
bool isGuaranteedSubValue = false;
193-
if (isGuaranteed && isGuaranteedForwardingInst(op->getUser())) {
197+
if (ownershipKind == ValueOwnershipKind::Guaranteed &&
198+
isGuaranteedForwardingInst(op->getUser())) {
194199
isGuaranteedSubValue = true;
195200
}
196201
auto *user = op->getUser();
@@ -230,6 +235,64 @@ bool SILValueOwnershipChecker::isCompatibleDefUse(
230235
return false;
231236
}
232237

238+
bool SILValueOwnershipChecker::gatherNonGuaranteedUsers(
239+
SmallVectorImpl<Operand *> &lifetimeEndingUsers,
240+
SmallVectorImpl<Operand *> &nonLifetimeEndingUsers,
241+
SmallVectorImpl<Operand *> &implicitRegularUsers) {
242+
bool foundError = false;
243+
244+
auto ownershipKind = value.getOwnershipKind();
245+
bool isOwned = ownershipKind == ValueOwnershipKind::Owned;
246+
247+
// Since we are dealing with a non-guaranteed user, we do not have to recurse.
248+
for (auto *op : value->getUses()) {
249+
auto *user = op->getUser();
250+
251+
// If this op is a type dependent operand, skip it. It is not interesting
252+
// from an ownership perspective.
253+
if (user->isTypeDependentOperand(*op))
254+
continue;
255+
256+
// First check if this recursive use is compatible with our values ownership
257+
// kind. If not, flag the error and continue so that we can report more
258+
// errors.
259+
if (!isCompatibleDefUse(op, ownershipKind)) {
260+
foundError = true;
261+
continue;
262+
}
263+
264+
// First do a quick check if we have a consuming use. If so, stash the value
265+
// and continue.
266+
if (op->isConsumingUse()) {
267+
LLVM_DEBUG(llvm::dbgs() << " Lifetime Ending User: " << *user);
268+
lifetimeEndingUsers.push_back(op);
269+
continue;
270+
}
271+
272+
// Otherwise, we have a non lifetime ending user. Add it to our non lifetime
273+
// ending user list.
274+
LLVM_DEBUG(llvm::dbgs() << " Regular User: " << *user);
275+
nonLifetimeEndingUsers.push_back(op);
276+
277+
// If we do not have an owned value at this point, continue, we do not have
278+
// any further work to do.
279+
if (!isOwned) {
280+
continue;
281+
}
282+
283+
// Otherwise, check if we have a borrow scope operand. In such a case, add
284+
// the borrow scope operand's end scope instructions as implicit regular
285+
// users so we can ensure that the borrow scope operand's scope is
286+
// completely within our value's scope.
287+
if (auto scopedOperand = BorrowScopeOperand::get(op)) {
288+
scopedOperand->visitEndScopeInstructions(
289+
[&](Operand *op) { implicitRegularUsers.push_back(op); });
290+
}
291+
}
292+
293+
return foundError;
294+
}
295+
233296
bool SILValueOwnershipChecker::gatherUsers(
234297
SmallVectorImpl<Operand *> &lifetimeEndingUsers,
235298
SmallVectorImpl<Operand *> &nonLifetimeEndingUsers,
@@ -239,14 +302,22 @@ bool SILValueOwnershipChecker::gatherUsers(
239302
// we need to look through subobject uses for more uses. Otherwise, if we are
240303
// forwarding, we do not create any lifetime ending users/non lifetime ending
241304
// users since we verify against our base.
242-
auto ownershipKind = value.getOwnershipKind();
243-
bool isGuaranteed = ownershipKind == ValueOwnershipKind::Guaranteed;
244-
bool isOwned = ownershipKind == ValueOwnershipKind::Owned;
305+
if (value.getOwnershipKind() != ValueOwnershipKind::Guaranteed) {
306+
return !gatherNonGuaranteedUsers(
307+
lifetimeEndingUsers, nonLifetimeEndingUsers, implicitRegularUsers);
308+
}
245309

246-
if (isGuaranteed && isGuaranteedForwardingValue(value))
310+
// Ok, we have a value with guarantee ownership. Before we continue, check if
311+
// this value forwards guaranteed ownership. In such a case, we are going to
312+
// validate it as part of the borrow introducer from which the forwarding
313+
// value originates. So we can just return true and continue.
314+
if (isGuaranteedForwardingValue(value))
247315
return true;
248316

249-
// Then gather up our initial list of users.
317+
// Ok, we have some sort of borrow introducer. We need to recursively validate
318+
// that all of its uses (including sub-scopes) are before any end_borrows that
319+
// end the lifetime of the borrow introducer. With that in mind, gather up our
320+
// initial list of users.
250321
SmallVector<Operand *, 8> users;
251322
llvm::copy(value->getUses(), std::back_inserter(users));
252323

@@ -263,7 +334,7 @@ bool SILValueOwnershipChecker::gatherUsers(
263334
// First check if this recursive use is compatible with our values ownership
264335
// kind. If not, flag the error and continue so that we can report more
265336
// errors.
266-
if (!isCompatibleDefUse(op, ownershipKind, isGuaranteed)) {
337+
if (!isCompatibleDefUse(op, ValueOwnershipKind::Guaranteed)) {
267338
foundError = true;
268339
continue;
269340
}
@@ -276,30 +347,6 @@ bool SILValueOwnershipChecker::gatherUsers(
276347
nonLifetimeEndingUsers.push_back(op);
277348
}
278349

279-
// If our base value is not guaranteed, we do not to try to visit
280-
// subobjects.
281-
if (!isGuaranteed) {
282-
// But if we are owned, check if we have any end_borrows. We
283-
// need to treat these as sub-scope users. We can rely on the
284-
// end_borrow to prevent recursion.
285-
if (isOwned) {
286-
// Do a check if any of our users are begin_borrows. If we find such a
287-
// use, then we want to include the end_borrow associated with the
288-
// begin_borrow in our NonLifetimeEndingUser lists.
289-
//
290-
// For correctness reasons we use indices to make sure that we can
291-
// append to NonLifetimeEndingUsers without needing to deal with
292-
// iterator invalidation.
293-
for (auto *op : nonLifetimeEndingUsers) {
294-
if (auto scopedOperand = BorrowScopeOperand::get(op)) {
295-
scopedOperand->visitEndScopeInstructions(
296-
[&](Operand *op) { implicitRegularUsers.push_back(op); });
297-
}
298-
}
299-
}
300-
continue;
301-
}
302-
303350
// If we are guaranteed, but are not a guaranteed forwarding inst, we add
304351
// the end scope instructions of any new sub-scopes. This ensures that the
305352
// parent scope completely encloses the child borrow scope.
@@ -371,7 +418,8 @@ bool SILValueOwnershipChecker::gatherUsers(
371418
// needing to be verified. If it isn't verified appropriately, assert
372419
// when the verifier is destroyed.
373420
auto succArgOwnershipKind = succArg->getOwnershipKind();
374-
if (!succArgOwnershipKind.isCompatibleWith(ownershipKind)) {
421+
if (!succArgOwnershipKind.isCompatibleWith(
422+
ValueOwnershipKind::Guaranteed)) {
375423
// This is where the error would go.
376424
continue;
377425
}
@@ -416,7 +464,8 @@ bool SILValueOwnershipChecker::gatherUsers(
416464
// needing to be verified. If it isn't verified appropriately, assert
417465
// when the verifier is destroyed.
418466
auto succArgOwnershipKind = succArg->getOwnershipKind();
419-
if (!succArgOwnershipKind.isCompatibleWith(ownershipKind)) {
467+
if (!succArgOwnershipKind.isCompatibleWith(
468+
ValueOwnershipKind::Guaranteed)) {
420469
// This is where the error would go.
421470
continue;
422471
}

test/SIL/ownership-verifier/arguments.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ bb7:
322322
// CHECK-LABEL: Function: 'owned_argument_overuse_br1'
323323
// CHECK-NEXT: Found over consume?!
324324
// CHECK-NEXT: Value: %0 = argument of bb0 : $Builtin.NativeObject
325-
// CHECK-NEXT: User: br bb1(%0 : $Builtin.NativeObject)
325+
// CHECK-NEXT: User: destroy_value %0 : $Builtin.NativeObject
326326
// CHECK-NEXT: Block: bb0
327327

328328
// CHECK-LABEL: Function: 'owned_argument_overuse_br1'
@@ -343,7 +343,7 @@ bb1(%1 : @owned $Builtin.NativeObject):
343343
// CHECK-LABEL: Function: 'owned_argument_overuse_br2'
344344
// CHECK-NEXT: Found over consume?!
345345
// CHECK-NEXT: Value: %0 = argument of bb0 : $Builtin.NativeObject
346-
// CHECK-NEXT: User: br bb1(%0 : $Builtin.NativeObject)
346+
// CHECK-NEXT: User: destroy_value %0 : $Builtin.NativeObject
347347
// CHECK-NEXT: Block: bb0
348348
// CHECK-NOT: Block
349349
// CHECK-NOT: Function: 'owned_argument_overuse_br2'

test/SIL/ownership-verifier/cond_br_crash.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ bb2:
3939
// CHECK-LABEL: Function: 'test2'
4040
// CHECK: Found over consume?!
4141
// CHECK: Value: %0 = argument of bb0 : $Builtin.NativeObject
42-
// CHECK: User: destroy_value %0 : $Builtin.NativeObject
42+
// CHECK: User: cond_br undef, bb1(%0 : $Builtin.NativeObject), bb2
4343
// CHECK: Block: bb1
4444
sil [ossa] @test2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
4545
bb0(%0 : @owned $Builtin.NativeObject):

test/SIL/ownership-verifier/over_consume.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ bb0(%0 : @owned $RefWithInt):
182182
// CHECK-LABEL: Function: 'unchecked_enum_data_propagates_ownership'
183183
// CHECK: Found over consume?!
184184
// CHECK: Value: %0 = argument of bb0 : $Optional<Builtin.NativeObject>
185-
// CHECK: User: destroy_value %0 : $Optional<Builtin.NativeObject>
185+
// CHECK: User: %1 = unchecked_enum_data %0 : $Optional<Builtin.NativeObject>, #Optional.some!enumelt.1
186186
// CHECK: Block: bb0
187187
sil [ossa] @unchecked_enum_data_propagates_ownership : $@convention(thin) (@owned Optional<Builtin.NativeObject>) -> () {
188188
bb0(%0 : @owned $Optional<Builtin.NativeObject>):

0 commit comments

Comments
 (0)