mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
It is a way to indicate to the compiler that the line can't be reached. On some configurations, it does happen to trap, as desired. Use a function that always traps, since that's the intent.
218 lines
6.4 KiB
C++
218 lines
6.4 KiB
C++
//===--- LinearLifetimeCheckerPrivate.h -----------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SIL_LINEARLIFETIMECHECKER_PRIVATE_H
|
|
#define SWIFT_SIL_LINEARLIFETIMECHECKER_PRIVATE_H
|
|
|
|
#include "swift/SIL/LinearLifetimeChecker.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
namespace swift {
|
|
|
|
struct LLVM_LIBRARY_VISIBILITY LinearLifetimeChecker::ErrorBehaviorKind {
|
|
enum inner_t {
|
|
Invalid = 0,
|
|
ReturnFalse = 1,
|
|
PrintMessage = 2,
|
|
Assert = 4,
|
|
ReturnFalseOnLeak = 8,
|
|
StoreNonConsumingUsesOutsideLifetime = 16,
|
|
PrintMessageAndReturnFalse = PrintMessage | ReturnFalse,
|
|
PrintMessageAndAssert = PrintMessage | Assert,
|
|
ReturnFalseOnLeakAssertOtherwise = ReturnFalseOnLeak | Assert,
|
|
} Value;
|
|
|
|
ErrorBehaviorKind() : Value(Invalid) {}
|
|
ErrorBehaviorKind(inner_t Inner) : Value(Inner) { assert(Value != Invalid); }
|
|
ErrorBehaviorKind(unsigned Inner) : Value(inner_t(Inner)) {
|
|
assert(Value != Invalid);
|
|
}
|
|
|
|
bool shouldStoreNonConsumingUsesOutsideLifetime() const {
|
|
assert(Value != Invalid);
|
|
return Value & StoreNonConsumingUsesOutsideLifetime;
|
|
}
|
|
|
|
bool shouldAssert() const {
|
|
assert(Value != Invalid);
|
|
return Value & Assert;
|
|
}
|
|
|
|
bool shouldReturnFalseOnLeak() const {
|
|
assert(Value != Invalid);
|
|
return Value & ReturnFalseOnLeak;
|
|
}
|
|
|
|
bool shouldPrintMessage() const {
|
|
assert(Value != Invalid);
|
|
return Value & PrintMessage;
|
|
}
|
|
|
|
bool shouldReturnFalse() const {
|
|
assert(Value != Invalid);
|
|
return Value & ReturnFalse;
|
|
}
|
|
};
|
|
|
|
class LLVM_LIBRARY_VISIBILITY LinearLifetimeChecker::Error {
|
|
friend class ErrorBuilder;
|
|
|
|
bool foundUseAfterFree = false;
|
|
bool foundLeak = false;
|
|
bool foundOverConsume = false;
|
|
bool foundUseOutsideOfLifetime = false;
|
|
|
|
public:
|
|
Error() {}
|
|
|
|
bool getFoundError() const {
|
|
return foundUseAfterFree || foundLeak || foundOverConsume ||
|
|
foundUseOutsideOfLifetime;
|
|
}
|
|
|
|
bool getFoundLeak() const { return foundLeak; }
|
|
|
|
bool getFoundUseAfterFree() const { return foundUseAfterFree; }
|
|
|
|
bool getFoundOverConsume() const { return foundOverConsume; }
|
|
|
|
bool getFoundUseOutsideOfLifetime() const {
|
|
return foundUseOutsideOfLifetime;
|
|
}
|
|
};
|
|
|
|
class LLVM_LIBRARY_VISIBILITY LinearLifetimeChecker::ErrorBuilder {
|
|
StringRef functionName;
|
|
ErrorBehaviorKind behavior;
|
|
std::optional<Error> error;
|
|
unsigned *errorMessageCounter;
|
|
|
|
public:
|
|
ErrorBuilder(const SILFunction &fn,
|
|
LinearLifetimeChecker::ErrorBehaviorKind behavior,
|
|
unsigned *errorMessageCounter = nullptr)
|
|
: functionName(fn.getName()), behavior(behavior), error(Error()),
|
|
errorMessageCounter(errorMessageCounter) {}
|
|
|
|
ErrorBuilder(const SILFunction &fn,
|
|
LinearLifetimeChecker::ErrorBehaviorKind::inner_t behavior,
|
|
unsigned *errorMessageCounter = nullptr)
|
|
: ErrorBuilder(fn, LinearLifetimeChecker::ErrorBehaviorKind(behavior),
|
|
errorMessageCounter) {}
|
|
|
|
ErrorBuilder(const ErrorBuilder &other)
|
|
: functionName(other.functionName), behavior(other.behavior),
|
|
error(other.error), errorMessageCounter(other.errorMessageCounter) {}
|
|
|
|
ErrorBuilder &operator=(const ErrorBuilder &other) {
|
|
functionName = other.functionName;
|
|
behavior = other.behavior;
|
|
error = other.error;
|
|
errorMessageCounter = other.errorMessageCounter;
|
|
return *this;
|
|
}
|
|
|
|
Error consumeAndGetFinalError() && {
|
|
auto result = *error;
|
|
error = std::nullopt;
|
|
errorMessageCounter = nullptr;
|
|
return result;
|
|
}
|
|
|
|
void tryDumpErrorCounter() const {
|
|
if (!errorMessageCounter) {
|
|
return;
|
|
}
|
|
llvm::errs() << "Error#: " << *errorMessageCounter << ". ";
|
|
}
|
|
|
|
void tryIncrementErrorCounter() {
|
|
if (!errorMessageCounter) {
|
|
return;
|
|
}
|
|
++(*errorMessageCounter);
|
|
}
|
|
|
|
bool handleLeak(llvm::function_ref<void()> &&messagePrinterFunc) {
|
|
error->foundLeak = true;
|
|
|
|
if (behavior.shouldPrintMessage()) {
|
|
tryDumpErrorCounter();
|
|
llvm::errs() << "Begin Error in Function: '" << functionName << "'\n";
|
|
messagePrinterFunc();
|
|
tryDumpErrorCounter();
|
|
llvm::errs() << "End Error in Function: '" << functionName << "'\n";
|
|
tryIncrementErrorCounter();
|
|
}
|
|
|
|
if (behavior.shouldReturnFalseOnLeak()) {
|
|
return false;
|
|
}
|
|
|
|
// We already printed out our error if we needed to, so don't pass it along.
|
|
return handleError([]() {}, true);
|
|
}
|
|
|
|
bool handleOverConsume(llvm::function_ref<void()> &&messagePrinterFunc) {
|
|
error->foundOverConsume = true;
|
|
return handleError(std::move(messagePrinterFunc));
|
|
}
|
|
|
|
bool handleUseAfterFree(llvm::function_ref<void()> &&messagePrinterFunc) {
|
|
error->foundUseAfterFree = true;
|
|
return handleError(std::move(messagePrinterFunc));
|
|
}
|
|
|
|
bool
|
|
handleMalformedSIL(llvm::function_ref<void()> &&messagePrinterFunc) const {
|
|
return handleError(std::move(messagePrinterFunc));
|
|
}
|
|
|
|
/// Handle a case where we either found a use-after-free due to a
|
|
/// non-consuming use after our lifetime has ended /or/ if we found a use
|
|
/// before def of a non consuming value.
|
|
void
|
|
handleUseOutsideOfLifetime(llvm::function_ref<void()> &&messagePrinterFunc) {
|
|
error->foundUseOutsideOfLifetime = true;
|
|
handleError(std::move(messagePrinterFunc));
|
|
}
|
|
|
|
private:
|
|
bool handleError(llvm::function_ref<void()> &&messagePrinterFunc,
|
|
bool quiet = false) const {
|
|
if (behavior.shouldPrintMessage()) {
|
|
if (!quiet) {
|
|
tryDumpErrorCounter();
|
|
llvm::errs() << "Begin Error in Function: '" << functionName << "'\n";
|
|
}
|
|
messagePrinterFunc();
|
|
if (!quiet) {
|
|
tryDumpErrorCounter();
|
|
llvm::errs() << "End Error in Function: '" << functionName << "'\n";
|
|
auto *self = const_cast<ErrorBuilder *>(this);
|
|
self->tryIncrementErrorCounter();
|
|
}
|
|
}
|
|
|
|
if (behavior.shouldReturnFalse()) {
|
|
return false;
|
|
}
|
|
|
|
llvm::errs() << "Found ownership error?!\n";
|
|
llvm::report_fatal_error("triggering standard assertion failure routine");
|
|
}
|
|
};
|
|
|
|
} // namespace swift
|
|
|
|
#endif
|