Skip to content

Commit 07738e5

Browse files
authored
Merge pull request swiftlang#31372 from gottesmm/pr-a228d2ed487a6a6b96c2db1fcbd78c78583bb5ce
[ownership] Cleanup how we emit filecheck-compatible verification errors for the ownership verifier.
2 parents a1716fe + 973a82e commit 07738e5

File tree

7 files changed

+436
-322
lines changed

7 files changed

+436
-322
lines changed

include/swift/SIL/LinearLifetimeChecker.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class LinearLifetimeChecker {
4848
public:
4949
class Error;
5050
struct ErrorBehaviorKind;
51+
class ErrorBuilder;
5152

5253
private:
5354
friend class SILOwnershipVerifier;
@@ -97,16 +98,16 @@ class LinearLifetimeChecker {
9798
/// to leak. Can be used to insert missing destroys.
9899
Error checkValue(SILValue value, ArrayRef<Operand *> consumingUses,
99100
ArrayRef<Operand *> nonConsumingUses,
100-
ErrorBehaviorKind errorBehavior);
101+
ErrorBuilder &errorBuilder);
101102

102103
Error checkValue(SILValue value, ArrayRef<Operand *> consumingUses,
103104
ArrayRef<Operand *> nonConsumingUses,
104-
ErrorBehaviorKind errorBehavior,
105+
ErrorBuilder &errorBuilder,
105106
function_ref<void(SILBasicBlock *)> leakingBlockCallback);
106107

107108
Error checkValueImpl(
108109
SILValue value, ArrayRef<Operand *> consumingUses,
109-
ArrayRef<Operand *> nonConsumingUses, ErrorBehaviorKind errorBehavior,
110+
ArrayRef<Operand *> nonConsumingUses, ErrorBuilder &errorBuilder,
110111
Optional<function_ref<void(SILBasicBlock *)>> leakingBlockCallback);
111112
};
112113

lib/SIL/Verifier/LinearLifetimeChecker.cpp

Lines changed: 47 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
using namespace swift;
3434

35+
unsigned LinearLifetimeChecker::ErrorBuilder::errorMessageCount = 0;
36+
3537
//===----------------------------------------------------------------------===//
3638
// Declarations
3739
//===----------------------------------------------------------------------===//
@@ -54,9 +56,12 @@ struct State {
5456
// defining block.
5557
SILInstruction *beginInst;
5658

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;
6065

6166
/// The blocks that we have already visited.
6267
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
@@ -87,20 +92,20 @@ struct State {
8792
SmallSetVector<SILBasicBlock *, 8> successorBlocksThatMustBeVisited;
8893

8994
State(SILValue value, SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
90-
LinearLifetimeChecker::ErrorBehaviorKind errorBehavior,
95+
LinearLifetimeChecker::ErrorBuilder errorBuilder,
9196
Optional<function_ref<void(SILBasicBlock *)>> leakingBlockCallback,
9297
ArrayRef<Operand *> consumingUses, ArrayRef<Operand *> nonConsumingUses)
9398
: value(value), beginInst(value->getDefiningInsertionPoint()),
94-
error(errorBehavior), visitedBlocks(visitedBlocks),
99+
errorBuilder(errorBuilder), visitedBlocks(visitedBlocks),
95100
leakingBlockCallback(leakingBlockCallback),
96101
consumingUses(consumingUses), nonConsumingUses(nonConsumingUses) {}
97102

98103
State(SILBasicBlock *beginBlock,
99104
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
100-
LinearLifetimeChecker::ErrorBehaviorKind errorBehavior,
105+
LinearLifetimeChecker::ErrorBuilder &errorBuilder,
101106
Optional<function_ref<void(SILBasicBlock *)>> leakingBlockCallback,
102107
ArrayRef<Operand *> consumingUses, ArrayRef<Operand *> nonConsumingUses)
103-
: value(), beginInst(&*beginBlock->begin()), error(errorBehavior),
108+
: value(), beginInst(&*beginBlock->begin()), errorBuilder(errorBuilder),
104109
visitedBlocks(visitedBlocks),
105110
leakingBlockCallback(leakingBlockCallback),
106111
consumingUses(consumingUses), nonConsumingUses(nonConsumingUses) {}
@@ -176,10 +181,9 @@ void State::initializeAllNonConsumingUses(
176181
[&use](const SILInstruction &inst) -> bool {
177182
return use->getUser() == &inst;
178183
}) == 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"
183187
<< "Value: ";
184188
if (auto v = value) {
185189
llvm::errs() << *v;
@@ -264,10 +268,8 @@ void State::initializeConsumingUse(Operand *consumingUse,
264268
if (blocksWithConsumingUses.insert(userBlock).second)
265269
return;
266270

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";
271273
if (auto v = value) {
272274
llvm::errs() << "Value: " << *v;
273275
} else {
@@ -298,10 +300,8 @@ void State::checkForSameBlockUseAfterFree(Operand *consumingUse,
298300
[&nonConsumingUse](const SILInstruction &i) -> bool {
299301
return nonConsumingUse->getUser() == &i;
300302
}) != 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"
305305
<< "Value: ";
306306
if (auto v = value) {
307307
llvm::errs() << *v;
@@ -336,10 +336,8 @@ void State::checkPredsForDoubleConsume(Operand *consumingUse,
336336
}
337337
}
338338

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"
343341
<< "Value: ";
344342
if (auto v = value) {
345343
llvm::errs() << *v;
@@ -368,10 +366,8 @@ void State::checkPredsForDoubleConsume(SILBasicBlock *userBlock) {
368366
}
369367
}
370368

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"
375371
<< "Value: ";
376372
if (auto v = value) {
377373
llvm::errs() << *v;
@@ -472,19 +468,17 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
472468
}
473469

474470
// 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 "
479473
"failure!\n";
480474
if (auto v = value) {
481475
llvm::errs() << "Value: " << *value;
482476
} else {
483477
llvm::errs() << "Value: N/A\n";
484478
}
485-
llvm::errs() << " Post Dominating Failure Blocks:\n";
479+
llvm::errs() << "Post Dominating Failure Blocks:\n";
486480
for (auto *succBlock : successorBlocksThatMustBeVisited) {
487-
llvm::errs() << " bb" << succBlock->getDebugID();
481+
llvm::errs() << "bb" << succBlock->getDebugID();
488482
}
489483
llvm::errs() << '\n';
490484
});
@@ -506,10 +500,8 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
506500
continue;
507501
}
508502

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 "
513505
"ending uses?!\n"
514506
<< "Value: ";
515507
if (auto v = value) {
@@ -518,7 +510,7 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
518510
llvm::errs() << "N/A. \n";
519511
}
520512

521-
llvm::errs() << " Remaining Users:\n";
513+
llvm::errs() << "Remaining Users:\n";
522514
for (auto &pair : blocksWithNonConsumingUses) {
523515
llvm::errs() << "User:" << *pair.second->getUser() << "Block: bb"
524516
<< pair.first->getDebugID() << "\n";
@@ -534,12 +526,12 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
534526

535527
LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl(
536528
SILValue value, ArrayRef<Operand *> consumingUses,
537-
ArrayRef<Operand *> nonConsumingUses, ErrorBehaviorKind errorBehavior,
529+
ArrayRef<Operand *> nonConsumingUses, ErrorBuilder &errorBuilder,
538530
Optional<function_ref<void(SILBasicBlock *)>> leakingBlockCallback) {
539531
assert((!consumingUses.empty() || !deadEndBlocks.empty()) &&
540532
"Must have at least one consuming user?!");
541533

542-
State state(value, visitedBlocks, errorBehavior, leakingBlockCallback,
534+
State state(value, visitedBlocks, errorBuilder, leakingBlockCallback,
543535
consumingUses, nonConsumingUses);
544536

545537
// First add our non-consuming uses and their blocks to the
@@ -575,20 +567,18 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl(
575567
return useParent != value->getParentBlock() &&
576568
!deadEndBlocks.isDeadEnd(useParent);
577569
})) {
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 "
582572
"ending uses?!\n"
583-
<< "Value: " << *value << " Remaining Users:\n";
573+
<< "Value: " << *value << "Remaining Users:\n";
584574
for (const auto &use : nonConsumingUses) {
585575
llvm::errs() << "User: " << *use->getUser();
586576
}
587577
llvm::errs() << "\n";
588578
});
589579
}
590580

591-
return state.error;
581+
return std::move(state.errorBuilder).getFinalError();
592582
}
593583

594584
// Ok, we may have multiple consuming uses. Add the user block of each of our
@@ -623,29 +613,31 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl(
623613
// ...and then check that the end state shows that we have a valid linear
624614
// typed value.
625615
state.checkDataflowEndState(deadEndBlocks);
626-
return state.error;
616+
return std::move(state.errorBuilder).getFinalError();
627617
}
628618

629619
LinearLifetimeChecker::Error LinearLifetimeChecker::checkValue(
630620
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,
633623
None);
634624
}
635625

636626
LinearLifetimeChecker::Error LinearLifetimeChecker::checkValue(
637627
SILValue value, ArrayRef<Operand *> consumingUses,
638-
ArrayRef<Operand *> nonConsumingUses, ErrorBehaviorKind errorBehavior,
628+
ArrayRef<Operand *> nonConsumingUses, ErrorBuilder &errorBuilder,
639629
function_ref<void(SILBasicBlock *)> leakingBlocksCallback) {
640-
return checkValueImpl(value, consumingUses, nonConsumingUses, errorBehavior,
630+
return checkValueImpl(value, consumingUses, nonConsumingUses, errorBuilder,
641631
leakingBlocksCallback);
642632
}
643633

644634
bool LinearLifetimeChecker::completeConsumingUseSet(
645635
SILValue value, Operand *consumingUse,
646636
function_ref<void(SILBasicBlock::iterator)> visitor) {
637+
ErrorBuilder errorBuilder(*value->getFunction(),
638+
ErrorBehaviorKind::ReturnFalse);
647639
auto error =
648-
checkValue(value, {consumingUse}, {}, ErrorBehaviorKind::ReturnFalse,
640+
checkValue(value, {consumingUse}, {}, errorBuilder,
649641
[&](SILBasicBlock *block) { return visitor(block->begin()); });
650642

651643
if (!error.getFoundError()) {
@@ -659,7 +651,8 @@ bool LinearLifetimeChecker::completeConsumingUseSet(
659651
bool LinearLifetimeChecker::validateLifetime(
660652
SILValue value, ArrayRef<Operand *> consumingUses,
661653
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)
664657
.getFoundError();
665658
}

0 commit comments

Comments
 (0)