32
32
33
33
using namespace swift ;
34
34
35
+ unsigned LinearLifetimeChecker::ErrorBuilder::errorMessageCount = 0 ;
36
+
35
37
// ===----------------------------------------------------------------------===//
36
38
// Declarations
37
39
// ===----------------------------------------------------------------------===//
@@ -54,9 +56,12 @@ struct State {
54
56
// defining block.
55
57
SILInstruction *beginInst;
56
58
57
- // / The result error object that use to signal either that no errors were
58
- // / found or if errors are found the specific type of error that was found.
59
- LinearLifetimeChecker::Error error;
59
+ // / A builder object that we use to build a LinearLifetimeChecker::Error
60
+ // / object that describes exhaustively the set of errors that we encountered.
61
+ // /
62
+ // / It also handles any asserts/messages that need to be emitted if we are
63
+ // / supposed to fail hard.
64
+ LinearLifetimeChecker::ErrorBuilder errorBuilder;
60
65
61
66
// / The blocks that we have already visited.
62
67
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
@@ -87,20 +92,20 @@ struct State {
87
92
SmallSetVector<SILBasicBlock *, 8 > successorBlocksThatMustBeVisited;
88
93
89
94
State (SILValue value, SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
90
- LinearLifetimeChecker::ErrorBehaviorKind errorBehavior ,
95
+ LinearLifetimeChecker::ErrorBuilder errorBuilder ,
91
96
Optional<function_ref<void (SILBasicBlock *)>> leakingBlockCallback,
92
97
ArrayRef<Operand *> consumingUses, ArrayRef<Operand *> nonConsumingUses)
93
98
: value(value), beginInst(value->getDefiningInsertionPoint ()),
94
- error(errorBehavior ), visitedBlocks(visitedBlocks),
99
+ errorBuilder(errorBuilder ), visitedBlocks(visitedBlocks),
95
100
leakingBlockCallback(leakingBlockCallback),
96
101
consumingUses(consumingUses), nonConsumingUses(nonConsumingUses) {}
97
102
98
103
State (SILBasicBlock *beginBlock,
99
104
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
100
- LinearLifetimeChecker::ErrorBehaviorKind errorBehavior ,
105
+ LinearLifetimeChecker::ErrorBuilder &errorBuilder ,
101
106
Optional<function_ref<void (SILBasicBlock *)>> leakingBlockCallback,
102
107
ArrayRef<Operand *> consumingUses, ArrayRef<Operand *> nonConsumingUses)
103
- : value(), beginInst(&*beginBlock->begin ()), error(errorBehavior ),
108
+ : value(), beginInst(&*beginBlock->begin ()), errorBuilder(errorBuilder ),
104
109
visitedBlocks(visitedBlocks),
105
110
leakingBlockCallback(leakingBlockCallback),
106
111
consumingUses(consumingUses), nonConsumingUses(nonConsumingUses) {}
@@ -176,10 +181,9 @@ void State::initializeAllNonConsumingUses(
176
181
[&use](const SILInstruction &inst) -> bool {
177
182
return use->getUser () == &inst;
178
183
}) == userBlock->end ()) {
179
- error.handleUseAfterFree ([&] {
180
- llvm::errs () << " Function: '"
181
- << getBeginBlock ()->getParent ()->getName () << " '\n "
182
- << " Found use before def?!\n "
184
+
185
+ errorBuilder.handleUseAfterFree ([&] {
186
+ llvm::errs () << " Found use before def?!\n "
183
187
<< " Value: " ;
184
188
if (auto v = value) {
185
189
llvm::errs () << *v;
@@ -264,10 +268,8 @@ void State::initializeConsumingUse(Operand *consumingUse,
264
268
if (blocksWithConsumingUses.insert (userBlock).second )
265
269
return ;
266
270
267
- error.handleOverConsume ([&] {
268
- llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
269
- << " '\n "
270
- << " Found over consume?!\n " ;
271
+ errorBuilder.handleOverConsume ([&] {
272
+ llvm::errs () << " Found over consume?!\n " ;
271
273
if (auto v = value) {
272
274
llvm::errs () << " Value: " << *v;
273
275
} else {
@@ -298,10 +300,8 @@ void State::checkForSameBlockUseAfterFree(Operand *consumingUse,
298
300
[&nonConsumingUse](const SILInstruction &i) -> bool {
299
301
return nonConsumingUse->getUser () == &i;
300
302
}) != userBlock->end ()) {
301
- error.handleUseAfterFree ([&] {
302
- llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
303
- << " '\n "
304
- << " Found use after free?!\n "
303
+ errorBuilder.handleUseAfterFree ([&] {
304
+ llvm::errs () << " Found use after free?!\n "
305
305
<< " Value: " ;
306
306
if (auto v = value) {
307
307
llvm::errs () << *v;
@@ -336,10 +336,8 @@ void State::checkPredsForDoubleConsume(Operand *consumingUse,
336
336
}
337
337
}
338
338
339
- error.handleOverConsume ([&] {
340
- llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
341
- << " '\n "
342
- << " Found over consume?!\n "
339
+ errorBuilder.handleOverConsume ([&] {
340
+ llvm::errs () << " Found over consume?!\n "
343
341
<< " Value: " ;
344
342
if (auto v = value) {
345
343
llvm::errs () << *v;
@@ -368,10 +366,8 @@ void State::checkPredsForDoubleConsume(SILBasicBlock *userBlock) {
368
366
}
369
367
}
370
368
371
- error.handleOverConsume ([&] {
372
- llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
373
- << " '\n "
374
- << " Found over consume?!\n "
369
+ errorBuilder.handleOverConsume ([&] {
370
+ llvm::errs () << " Found over consume?!\n "
375
371
<< " Value: " ;
376
372
if (auto v = value) {
377
373
llvm::errs () << *v;
@@ -472,19 +468,17 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
472
468
}
473
469
474
470
// If we are supposed to error on leaks, do so now.
475
- error.handleLeak ([&] {
476
- llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
477
- << " '\n "
478
- << " Error! Found a leak due to a consuming post-dominance "
471
+ errorBuilder.handleLeak ([&] {
472
+ llvm::errs () << " Error! Found a leak due to a consuming post-dominance "
479
473
" failure!\n " ;
480
474
if (auto v = value) {
481
475
llvm::errs () << " Value: " << *value;
482
476
} else {
483
477
llvm::errs () << " Value: N/A\n " ;
484
478
}
485
- llvm::errs () << " Post Dominating Failure Blocks:\n " ;
479
+ llvm::errs () << " Post Dominating Failure Blocks:\n " ;
486
480
for (auto *succBlock : successorBlocksThatMustBeVisited) {
487
- llvm::errs () << " bb" << succBlock->getDebugID ();
481
+ llvm::errs () << " bb" << succBlock->getDebugID ();
488
482
}
489
483
llvm::errs () << ' \n ' ;
490
484
});
@@ -506,10 +500,8 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
506
500
continue ;
507
501
}
508
502
509
- error.handleUseAfterFree ([&] {
510
- llvm::errs () << " Function: '" << getBeginBlock ()->getParent ()->getName ()
511
- << " '\n "
512
- << " Found use after free due to unvisited non lifetime "
503
+ errorBuilder.handleUseAfterFree ([&] {
504
+ llvm::errs () << " Found use after free due to unvisited non lifetime "
513
505
" ending uses?!\n "
514
506
<< " Value: " ;
515
507
if (auto v = value) {
@@ -518,7 +510,7 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
518
510
llvm::errs () << " N/A. \n " ;
519
511
}
520
512
521
- llvm::errs () << " Remaining Users:\n " ;
513
+ llvm::errs () << " Remaining Users:\n " ;
522
514
for (auto &pair : blocksWithNonConsumingUses) {
523
515
llvm::errs () << " User:" << *pair.second ->getUser () << " Block: bb"
524
516
<< pair.first ->getDebugID () << " \n " ;
@@ -534,12 +526,12 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
534
526
535
527
LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl (
536
528
SILValue value, ArrayRef<Operand *> consumingUses,
537
- ArrayRef<Operand *> nonConsumingUses, ErrorBehaviorKind errorBehavior ,
529
+ ArrayRef<Operand *> nonConsumingUses, ErrorBuilder &errorBuilder ,
538
530
Optional<function_ref<void (SILBasicBlock *)>> leakingBlockCallback) {
539
531
assert ((!consumingUses.empty () || !deadEndBlocks.empty ()) &&
540
532
" Must have at least one consuming user?!" );
541
533
542
- State state (value, visitedBlocks, errorBehavior , leakingBlockCallback,
534
+ State state (value, visitedBlocks, errorBuilder , leakingBlockCallback,
543
535
consumingUses, nonConsumingUses);
544
536
545
537
// First add our non-consuming uses and their blocks to the
@@ -575,20 +567,18 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl(
575
567
return useParent != value->getParentBlock () &&
576
568
!deadEndBlocks.isDeadEnd (useParent);
577
569
})) {
578
- state.error .handleUseAfterFree ([&] {
579
- llvm::errs () << " Function: '" << value->getFunction ()->getName ()
580
- << " '\n "
581
- << " Found use after free due to unvisited non lifetime "
570
+ state.errorBuilder .handleUseAfterFree ([&] {
571
+ llvm::errs () << " Found use after free due to unvisited non lifetime "
582
572
" ending uses?!\n "
583
- << " Value: " << *value << " Remaining Users:\n " ;
573
+ << " Value: " << *value << " Remaining Users:\n " ;
584
574
for (const auto &use : nonConsumingUses) {
585
575
llvm::errs () << " User: " << *use->getUser ();
586
576
}
587
577
llvm::errs () << " \n " ;
588
578
});
589
579
}
590
580
591
- return state.error ;
581
+ return std::move ( state.errorBuilder ). getFinalError () ;
592
582
}
593
583
594
584
// Ok, we may have multiple consuming uses. Add the user block of each of our
@@ -623,29 +613,31 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl(
623
613
// ...and then check that the end state shows that we have a valid linear
624
614
// typed value.
625
615
state.checkDataflowEndState (deadEndBlocks);
626
- return state.error ;
616
+ return std::move ( state.errorBuilder ). getFinalError () ;
627
617
}
628
618
629
619
LinearLifetimeChecker::Error LinearLifetimeChecker::checkValue (
630
620
SILValue value, ArrayRef<Operand *> consumingUses,
631
- ArrayRef<Operand *> nonConsumingUses, ErrorBehaviorKind errorBehavior ) {
632
- return checkValueImpl (value, consumingUses, nonConsumingUses, errorBehavior ,
621
+ ArrayRef<Operand *> nonConsumingUses, ErrorBuilder &errorBuilder ) {
622
+ return checkValueImpl (value, consumingUses, nonConsumingUses, errorBuilder ,
633
623
None);
634
624
}
635
625
636
626
LinearLifetimeChecker::Error LinearLifetimeChecker::checkValue (
637
627
SILValue value, ArrayRef<Operand *> consumingUses,
638
- ArrayRef<Operand *> nonConsumingUses, ErrorBehaviorKind errorBehavior ,
628
+ ArrayRef<Operand *> nonConsumingUses, ErrorBuilder &errorBuilder ,
639
629
function_ref<void (SILBasicBlock *)> leakingBlocksCallback) {
640
- return checkValueImpl (value, consumingUses, nonConsumingUses, errorBehavior ,
630
+ return checkValueImpl (value, consumingUses, nonConsumingUses, errorBuilder ,
641
631
leakingBlocksCallback);
642
632
}
643
633
644
634
bool LinearLifetimeChecker::completeConsumingUseSet (
645
635
SILValue value, Operand *consumingUse,
646
636
function_ref<void (SILBasicBlock::iterator)> visitor) {
637
+ ErrorBuilder errorBuilder (*value->getFunction (),
638
+ ErrorBehaviorKind::ReturnFalse);
647
639
auto error =
648
- checkValue (value, {consumingUse}, {}, ErrorBehaviorKind::ReturnFalse ,
640
+ checkValue (value, {consumingUse}, {}, errorBuilder ,
649
641
[&](SILBasicBlock *block) { return visitor (block->begin ()); });
650
642
651
643
if (!error.getFoundError ()) {
@@ -659,7 +651,8 @@ bool LinearLifetimeChecker::completeConsumingUseSet(
659
651
bool LinearLifetimeChecker::validateLifetime (
660
652
SILValue value, ArrayRef<Operand *> consumingUses,
661
653
ArrayRef<Operand *> nonConsumingUses) {
662
- return !checkValue (value, consumingUses, nonConsumingUses,
663
- ErrorBehaviorKind::ReturnFalse)
654
+ ErrorBuilder errorBuilder (*value->getFunction (),
655
+ ErrorBehaviorKind::ReturnFalse);
656
+ return !checkValue (value, consumingUses, nonConsumingUses, errorBuilder)
664
657
.getFoundError ();
665
658
}
0 commit comments