Skip to content

Commit 820d204

Browse files
committed
[ownership] Change the ownership verifier textual error dumper to emit error counts on a per function instead of global basis.
This will just make them easier to update over time since adding a new function doesn't require one to renumber the /entire/ file... *face-palm*. Originally the reason why I added this is b/c I need to ensure that we handle all errors exactly once so making sure we control the exact amount of emitted errors is important. I can still do this with the new approach by just doing per-function max error counts. Thus I also in this commit added FileCheck patterns that implemented this scheme so now we have everything.
1 parent 0640f33 commit 820d204

File tree

6 files changed

+226
-150
lines changed

6 files changed

+226
-150
lines changed

lib/SIL/Verifier/LinearLifetimeChecker.cpp

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

3333
using namespace swift;
3434

35-
unsigned LinearLifetimeChecker::ErrorBuilder::errorMessageCount = 0;
36-
3735
//===----------------------------------------------------------------------===//
3836
// Declarations
3937
//===----------------------------------------------------------------------===//
@@ -61,7 +59,7 @@ struct State {
6159
///
6260
/// It also handles any asserts/messages that need to be emitted if we are
6361
/// supposed to fail hard.
64-
LinearLifetimeChecker::ErrorBuilder errorBuilder;
62+
LinearLifetimeChecker::ErrorBuilder &errorBuilder;
6563

6664
/// The blocks that we have already visited.
6765
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
@@ -92,7 +90,7 @@ struct State {
9290
SmallSetVector<SILBasicBlock *, 8> successorBlocksThatMustBeVisited;
9391

9492
State(SILValue value, SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
95-
LinearLifetimeChecker::ErrorBuilder errorBuilder,
93+
LinearLifetimeChecker::ErrorBuilder &errorBuilder,
9694
Optional<function_ref<void(SILBasicBlock *)>> leakingBlockCallback,
9795
ArrayRef<Operand *> consumingUses, ArrayRef<Operand *> nonConsumingUses)
9896
: value(value), beginInst(value->getDefiningInsertionPoint()),
@@ -578,7 +576,7 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl(
578576
});
579577
}
580578

581-
return std::move(state.errorBuilder).getFinalError();
579+
return std::move(state.errorBuilder).consumeAndGetFinalError();
582580
}
583581

584582
// Ok, we may have multiple consuming uses. Add the user block of each of our
@@ -613,7 +611,7 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl(
613611
// ...and then check that the end state shows that we have a valid linear
614612
// typed value.
615613
state.checkDataflowEndState(deadEndBlocks);
616-
return std::move(state.errorBuilder).getFinalError();
614+
return std::move(state.errorBuilder).consumeAndGetFinalError();
617615
}
618616

619617
LinearLifetimeChecker::Error LinearLifetimeChecker::checkValue(

lib/SIL/Verifier/LinearLifetimeCheckerPrivate.h

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -79,36 +79,64 @@ class LLVM_LIBRARY_VISIBILITY LinearLifetimeChecker::ErrorBuilder {
7979
StringRef functionName;
8080
ErrorBehaviorKind behavior;
8181
Optional<Error> error;
82-
83-
// NOTE: This is only here so that we can emit a unique id for all errors to
84-
// ease working with FileCheck.
85-
static unsigned errorMessageCount;
82+
unsigned *errorMessageCounter;
8683

8784
public:
8885
ErrorBuilder(const SILFunction &fn,
89-
LinearLifetimeChecker::ErrorBehaviorKind behavior)
90-
: functionName(fn.getName()), behavior(behavior), error(Error()) {}
86+
LinearLifetimeChecker::ErrorBehaviorKind behavior,
87+
unsigned *errorMessageCounter = nullptr)
88+
: functionName(fn.getName()), behavior(behavior), error(Error()),
89+
errorMessageCounter(errorMessageCounter) {}
9190

9291
ErrorBuilder(const SILFunction &fn,
93-
LinearLifetimeChecker::ErrorBehaviorKind::inner_t behavior)
94-
: functionName(fn.getName()), behavior(behavior), error(Error()) {}
92+
LinearLifetimeChecker::ErrorBehaviorKind::inner_t behavior,
93+
unsigned *errorMessageCounter = nullptr)
94+
: ErrorBuilder(fn, LinearLifetimeChecker::ErrorBehaviorKind(behavior),
95+
errorMessageCounter) {}
96+
97+
ErrorBuilder(const ErrorBuilder &other)
98+
: functionName(other.functionName), behavior(other.behavior),
99+
error(other.error), errorMessageCounter(other.errorMessageCounter) {}
100+
101+
ErrorBuilder &operator=(const ErrorBuilder &other) {
102+
functionName = other.functionName;
103+
behavior = other.behavior;
104+
error = other.error;
105+
errorMessageCounter = other.errorMessageCounter;
106+
return *this;
107+
}
95108

96-
Error getFinalError() && {
109+
Error consumeAndGetFinalError() && {
97110
auto result = *error;
98111
error = None;
112+
errorMessageCounter = nullptr;
99113
return result;
100114
}
101115

116+
void tryDumpErrorCounter() const {
117+
if (!errorMessageCounter) {
118+
return;
119+
}
120+
llvm::errs() << "Error#: " << *errorMessageCounter << ". ";
121+
}
122+
123+
void tryIncrementErrorCounter() {
124+
if (!errorMessageCounter) {
125+
return;
126+
}
127+
++(*errorMessageCounter);
128+
}
129+
102130
bool handleLeak(llvm::function_ref<void()> &&messagePrinterFunc) {
103131
error->foundLeak = true;
104132

105133
if (behavior.shouldPrintMessage()) {
106-
llvm::errs() << "Error#: " << errorMessageCount
107-
<< ". Begin Error in Function: '" << functionName << "'\n";
134+
tryDumpErrorCounter();
135+
llvm::errs() << "Begin Error in Function: '" << functionName << "'\n";
108136
messagePrinterFunc();
109-
llvm::errs() << "Error#: " << errorMessageCount
110-
<< ". End Error in Function: '" << functionName << "'\n";
111-
++errorMessageCount;
137+
tryDumpErrorCounter();
138+
llvm::errs() << "End Error in Function: '" << functionName << "'\n";
139+
tryIncrementErrorCounter();
112140
}
113141

114142
if (behavior.shouldReturnFalseOnLeak()) {
@@ -139,14 +167,15 @@ class LLVM_LIBRARY_VISIBILITY LinearLifetimeChecker::ErrorBuilder {
139167
bool quiet = false) const {
140168
if (behavior.shouldPrintMessage()) {
141169
if (!quiet) {
142-
llvm::errs() << "Error#: " << errorMessageCount
143-
<< ". Begin Error in Function: '" << functionName << "'\n";
170+
tryDumpErrorCounter();
171+
llvm::errs() << "Begin Error in Function: '" << functionName << "'\n";
144172
}
145173
messagePrinterFunc();
146174
if (!quiet) {
147-
llvm::errs() << "Error#: " << errorMessageCount
148-
<< ". End Error in Function: '" << functionName << "'\n";
149-
++errorMessageCount;
175+
tryDumpErrorCounter();
176+
llvm::errs() << "End Error in Function: '" << functionName << "'\n";
177+
auto *self = const_cast<ErrorBuilder *>(this);
178+
self->tryIncrementErrorCounter();
150179
}
151180
}
152181

lib/SIL/Verifier/SILOwnershipVerifier.cpp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class SILValueOwnershipChecker {
8989

9090
/// The builder that the checker uses to emit error messages, crash if asked
9191
/// for, or supply back interesting info to the caller.
92-
LinearLifetimeChecker::ErrorBuilder errorBuilder;
92+
LinearLifetimeChecker::ErrorBuilder &errorBuilder;
9393

9494
/// The list of lifetime ending users that we found. Only valid if check is
9595
/// successful.
@@ -113,7 +113,7 @@ class SILValueOwnershipChecker {
113113
public:
114114
SILValueOwnershipChecker(
115115
DeadEndBlocks &deadEndBlocks, SILValue value,
116-
LinearLifetimeChecker::ErrorBuilder errorBuilder,
116+
LinearLifetimeChecker::ErrorBuilder &errorBuilder,
117117
llvm::SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks)
118118
: result(), deadEndBlocks(deadEndBlocks), value(value),
119119
errorBuilder(errorBuilder), visitedBlocks(visitedBlocks) {
@@ -882,8 +882,10 @@ void SILInstruction::verifyOperandOwnership() const {
882882
}
883883
}
884884

885-
static void verifySILValueHelper(const SILFunction *f, SILValue value,
886-
DeadEndBlocks *deadEndBlocks) {
885+
static void
886+
verifySILValueHelper(const SILFunction *f, SILValue value,
887+
LinearLifetimeChecker::ErrorBuilder &errorBuilder,
888+
DeadEndBlocks *deadEndBlocks) {
887889
assert(!isa<SILUndef>(value) &&
888890
"We assume we are always passed arguments or instruction results");
889891

@@ -892,21 +894,13 @@ static void verifySILValueHelper(const SILFunction *f, SILValue value,
892894
if (!f->hasOwnership() || !f->shouldVerifyOwnership())
893895
return;
894896

895-
using BehaviorKind = LinearLifetimeChecker::ErrorBehaviorKind;
896-
Optional<LinearLifetimeChecker::ErrorBuilder> errorBuilder;
897-
if (IsSILOwnershipVerifierTestingEnabled) {
898-
errorBuilder.emplace(*f, BehaviorKind::PrintMessageAndReturnFalse);
899-
} else {
900-
errorBuilder.emplace(*f, BehaviorKind::PrintMessageAndAssert);
901-
}
902-
903897
SmallPtrSet<SILBasicBlock *, 32> liveBlocks;
904898
if (deadEndBlocks) {
905-
SILValueOwnershipChecker(*deadEndBlocks, value, *errorBuilder, liveBlocks)
899+
SILValueOwnershipChecker(*deadEndBlocks, value, errorBuilder, liveBlocks)
906900
.check();
907901
} else {
908902
DeadEndBlocks deadEndBlocks(f);
909-
SILValueOwnershipChecker(deadEndBlocks, value, *errorBuilder, liveBlocks)
903+
SILValueOwnershipChecker(deadEndBlocks, value, errorBuilder, liveBlocks)
910904
.check();
911905
}
912906
}
@@ -951,7 +945,11 @@ void SILValue::verifyOwnership(DeadEndBlocks *deadEndBlocks) const {
951945
// a real function. Assert in case this assumption is no longer true.
952946
auto *f = (*this)->getFunction();
953947
assert(f && "Instructions and arguments should have a function");
954-
verifySILValueHelper(f, *this, deadEndBlocks);
948+
949+
using BehaviorKind = LinearLifetimeChecker::ErrorBehaviorKind;
950+
LinearLifetimeChecker::ErrorBuilder errorBuilder(
951+
*f, BehaviorKind::PrintMessageAndAssert);
952+
verifySILValueHelper(f, *this, errorBuilder, deadEndBlocks);
955953
}
956954

957955
void SILFunction::verifyOwnership(DeadEndBlocks *deadEndBlocks) const {
@@ -976,14 +974,26 @@ void SILFunction::verifyOwnership(DeadEndBlocks *deadEndBlocks) const {
976974
if (!hasOwnership() || !shouldVerifyOwnership())
977975
return;
978976

977+
using BehaviorKind = LinearLifetimeChecker::ErrorBehaviorKind;
978+
unsigned errorCounter = 0;
979+
Optional<LinearLifetimeChecker::ErrorBuilder> errorBuilder;
980+
if (IsSILOwnershipVerifierTestingEnabled) {
981+
errorBuilder.emplace(*this, BehaviorKind::PrintMessageAndReturnFalse,
982+
&errorCounter);
983+
} else {
984+
errorBuilder.emplace(*this, BehaviorKind::PrintMessageAndAssert);
985+
}
986+
979987
for (auto &block : *this) {
980988
for (auto *arg : block.getArguments()) {
981-
verifySILValueHelper(this, arg, deadEndBlocks);
989+
LinearLifetimeChecker::ErrorBuilder newBuilder = *errorBuilder;
990+
verifySILValueHelper(this, arg, newBuilder, deadEndBlocks);
982991
}
983992

984993
for (auto &inst : block) {
985994
for (auto result : inst.getResults()) {
986-
verifySILValueHelper(this, result, deadEndBlocks);
995+
LinearLifetimeChecker::ErrorBuilder newBuilder = *errorBuilder;
996+
verifySILValueHelper(this, result, newBuilder, deadEndBlocks);
987997
}
988998
}
989999
}

0 commit comments

Comments
 (0)