@@ -127,13 +127,17 @@ class SILValueOwnershipChecker {
127
127
128
128
private:
129
129
bool checkUses ();
130
- bool isCompatibleDefUse (Operand *op, ValueOwnershipKind ownershipKind,
131
- bool isGuaranteed);
130
+ bool isCompatibleDefUse (Operand *op, ValueOwnershipKind ownershipKind);
132
131
133
132
bool gatherUsers (SmallVectorImpl<Operand *> &lifetimeEndingUsers,
134
133
SmallVectorImpl<Operand *> ®ularUsers,
135
134
SmallVectorImpl<Operand *> &implicitRegularUsers);
136
135
136
+ bool
137
+ gatherNonGuaranteedUsers (SmallVectorImpl<Operand *> &lifetimeEndingUsers,
138
+ SmallVectorImpl<Operand *> ®ularUsers,
139
+ SmallVectorImpl<Operand *> &implicitRegularUsers);
140
+
137
141
bool checkValueWithoutLifetimeEndingUses ();
138
142
139
143
bool checkFunctionArgWithoutLifetimeEndingUses (SILFunctionArgument *arg);
@@ -188,9 +192,10 @@ bool SILValueOwnershipChecker::check() {
188
192
}
189
193
190
194
bool SILValueOwnershipChecker::isCompatibleDefUse (
191
- Operand *op, ValueOwnershipKind ownershipKind, bool isGuaranteed ) {
195
+ Operand *op, ValueOwnershipKind ownershipKind) {
192
196
bool isGuaranteedSubValue = false ;
193
- if (isGuaranteed && isGuaranteedForwardingInst (op->getUser ())) {
197
+ if (ownershipKind == ValueOwnershipKind::Guaranteed &&
198
+ isGuaranteedForwardingInst (op->getUser ())) {
194
199
isGuaranteedSubValue = true ;
195
200
}
196
201
auto *user = op->getUser ();
@@ -230,6 +235,64 @@ bool SILValueOwnershipChecker::isCompatibleDefUse(
230
235
return false ;
231
236
}
232
237
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
+
233
296
bool SILValueOwnershipChecker::gatherUsers (
234
297
SmallVectorImpl<Operand *> &lifetimeEndingUsers,
235
298
SmallVectorImpl<Operand *> &nonLifetimeEndingUsers,
@@ -239,14 +302,22 @@ bool SILValueOwnershipChecker::gatherUsers(
239
302
// we need to look through subobject uses for more uses. Otherwise, if we are
240
303
// forwarding, we do not create any lifetime ending users/non lifetime ending
241
304
// 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
+ }
245
309
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))
247
315
return true ;
248
316
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.
250
321
SmallVector<Operand *, 8 > users;
251
322
llvm::copy (value->getUses (), std::back_inserter (users));
252
323
@@ -263,7 +334,7 @@ bool SILValueOwnershipChecker::gatherUsers(
263
334
// First check if this recursive use is compatible with our values ownership
264
335
// kind. If not, flag the error and continue so that we can report more
265
336
// errors.
266
- if (!isCompatibleDefUse (op, ownershipKind, isGuaranteed )) {
337
+ if (!isCompatibleDefUse (op, ValueOwnershipKind::Guaranteed )) {
267
338
foundError = true ;
268
339
continue ;
269
340
}
@@ -276,30 +347,6 @@ bool SILValueOwnershipChecker::gatherUsers(
276
347
nonLifetimeEndingUsers.push_back (op);
277
348
}
278
349
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
-
303
350
// If we are guaranteed, but are not a guaranteed forwarding inst, we add
304
351
// the end scope instructions of any new sub-scopes. This ensures that the
305
352
// parent scope completely encloses the child borrow scope.
@@ -371,7 +418,8 @@ bool SILValueOwnershipChecker::gatherUsers(
371
418
// needing to be verified. If it isn't verified appropriately, assert
372
419
// when the verifier is destroyed.
373
420
auto succArgOwnershipKind = succArg->getOwnershipKind ();
374
- if (!succArgOwnershipKind.isCompatibleWith (ownershipKind)) {
421
+ if (!succArgOwnershipKind.isCompatibleWith (
422
+ ValueOwnershipKind::Guaranteed)) {
375
423
// This is where the error would go.
376
424
continue ;
377
425
}
@@ -416,7 +464,8 @@ bool SILValueOwnershipChecker::gatherUsers(
416
464
// needing to be verified. If it isn't verified appropriately, assert
417
465
// when the verifier is destroyed.
418
466
auto succArgOwnershipKind = succArg->getOwnershipKind ();
419
- if (!succArgOwnershipKind.isCompatibleWith (ownershipKind)) {
467
+ if (!succArgOwnershipKind.isCompatibleWith (
468
+ ValueOwnershipKind::Guaranteed)) {
420
469
// This is where the error would go.
421
470
continue ;
422
471
}
0 commit comments