@@ -53,6 +53,11 @@ struct State {
53
53
// / The blocks that we have already visited.
54
54
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
55
55
56
+ // / If non-null a list that we should place any detected leaking blocks for
57
+ // / our caller. The intention is that this can be used in a failing case to
58
+ // / put in missing destroys.
59
+ SmallVectorImpl<SILBasicBlock *> *leakingBlocks;
60
+
56
61
// / The set of blocks with consuming uses.
57
62
SmallPtrSet<SILBasicBlock *, 8 > blocksWithConsumingUses;
58
63
@@ -66,12 +71,13 @@ struct State {
66
71
67
72
// / A list of successor blocks that we must visit by the time the algorithm
68
73
// / terminates.
69
- SmallPtrSet <SILBasicBlock *, 8 > successorBlocksThatMustBeVisited;
74
+ SmallSetVector <SILBasicBlock *, 8 > successorBlocksThatMustBeVisited;
70
75
71
76
State (SILValue value, SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
72
- ErrorBehaviorKind errorBehavior)
77
+ ErrorBehaviorKind errorBehavior,
78
+ SmallVectorImpl<SILBasicBlock *> *leakingBlocks)
73
79
: value(value), errorBehavior(errorBehavior),
74
- visitedBlocks (visitedBlocks) {}
80
+ visitedBlocks (visitedBlocks), leakingBlocks(leakingBlocks) {}
75
81
76
82
void initializeAllNonConsumingUses (
77
83
ArrayRef<BranchPropagatedUser> nonConsumingUsers);
@@ -331,7 +337,7 @@ bool State::performDataflow(DeadEndBlocks &deBlocks) {
331
337
// First remove BB from the SuccessorBlocksThatMustBeVisited list. This
332
338
// ensures that when the algorithm terminates, we know that BB was not the
333
339
// beginning of a non-covered path to the exit.
334
- successorBlocksThatMustBeVisited.erase (block);
340
+ successorBlocksThatMustBeVisited.remove (block);
335
341
336
342
// Then remove BB from BlocksWithNonLifetimeEndingUses so we know that
337
343
// this block was properly joint post-dominated by our lifetime ending
@@ -395,23 +401,41 @@ bool State::performDataflow(DeadEndBlocks &deBlocks) {
395
401
bool State::checkDataflowEndState (DeadEndBlocks &deBlocks) {
396
402
// Make sure that we visited all successor blocks that we needed to visit to
397
403
// make sure we didn't leak.
404
+ bool doesntHaveAnyLeaks = true ;
405
+
398
406
if (!successorBlocksThatMustBeVisited.empty ()) {
399
- return handleError ([&] {
400
- llvm::errs ()
401
- << " Function: '" << value->getFunction ()->getName () << " '\n "
402
- << " Error! Found a leak due to a consuming post-dominance failure!\n "
403
- << " Value: " << *value << " Post Dominating Failure Blocks:\n " ;
404
- for (auto *succBlock : successorBlocksThatMustBeVisited) {
405
- llvm::errs () << " bb" << succBlock->getDebugID ();
406
- }
407
- llvm::errs () << ' \n ' ;
408
- });
407
+ // If we are asked to store any leaking blocks, put them in the leaking
408
+ // blocks array.
409
+ if (leakingBlocks) {
410
+ copy (successorBlocksThatMustBeVisited,
411
+ std::back_inserter (*leakingBlocks));
412
+ }
413
+
414
+ // If we are supposed to error on leaks, do so now.
415
+ if (!errorBehavior.shouldReturnFalseOnLeak ()) {
416
+ return handleError ([&] {
417
+ llvm::errs () << " Function: '" << value->getFunction ()->getName ()
418
+ << " '\n "
419
+ << " Error! Found a leak due to a consuming post-dominance "
420
+ " failure!\n "
421
+ << " Value: " << *value
422
+ << " Post Dominating Failure Blocks:\n " ;
423
+ for (auto *succBlock : successorBlocksThatMustBeVisited) {
424
+ llvm::errs () << " bb" << succBlock->getDebugID ();
425
+ }
426
+ llvm::errs () << ' \n ' ;
427
+ });
428
+ }
429
+
430
+ // Otherwise... see if we have any other failures. This signals the user
431
+ // wants us to tell it where to insert compensating destroys.
432
+ doesntHaveAnyLeaks = false ;
409
433
}
410
434
411
435
// Make sure that we do not have any lifetime ending uses left to visit that
412
436
// are not transitively unreachable blocks.... so return early.
413
437
if (blocksWithNonConsumingUses.empty ()) {
414
- return true ;
438
+ return doesntHaveAnyLeaks ;
415
439
}
416
440
417
441
// If we do have remaining blocks, then these non lifetime ending uses must be
@@ -436,7 +460,7 @@ bool State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
436
460
437
461
// If all of our remaining blocks were dead uses, then return true. We are
438
462
// good.
439
- return true ;
463
+ return doesntHaveAnyLeaks ;
440
464
}
441
465
442
466
// ===----------------------------------------------------------------------===//
@@ -447,10 +471,11 @@ bool swift::valueHasLinearLifetime(
447
471
SILValue value, ArrayRef<BranchPropagatedUser> consumingUses,
448
472
ArrayRef<BranchPropagatedUser> nonConsumingUses,
449
473
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks, DeadEndBlocks &deBlocks,
450
- ErrorBehaviorKind errorBehavior) {
474
+ ErrorBehaviorKind errorBehavior,
475
+ SmallVectorImpl<SILBasicBlock *> *leakingBlocks) {
451
476
assert (!consumingUses.empty () && " Must have at least one consuming user?!" );
452
477
453
- State state (value, visitedBlocks, errorBehavior);
478
+ State state (value, visitedBlocks, errorBehavior, leakingBlocks );
454
479
455
480
// First add our non-consuming uses and their blocks to the
456
481
// blocksWithNonConsumingUses map. While we do this, if we have multiple uses
0 commit comments