1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[Support] Add a StringError convenience class to Error.h

StringError can be used to represent Errors that aren't recoverable based on
the error type, but that have a useful error message that can be reported to
the user or logged.

llvm-svn: 270948
This commit is contained in:
Lang Hames 2016-05-27 01:37:32 +00:00
parent 902fe15d1a
commit 776aaf18f4
3 changed files with 92 additions and 16 deletions

View File

@ -26,6 +26,7 @@ namespace llvm {
class Error;
class ErrorList;
class Twine;
/// Base class for error info classes. Do not extend this directly: Extend
/// the ErrorInfo template subclass instead.
@ -850,24 +851,22 @@ protected:
std::error_code EC;
};
/// The value returned by this function can be returned from convertToErrorCode
/// for Error values where no sensible translation to std::error_code exists.
/// It should only be used in this situation, and should never be used where a
/// sensible conversion to std::error_code is available, as attempts to convert
/// to/from this error will result in a fatal error. (i.e. it is a programmatic
///error to try to convert such a value).
std::error_code unconvertibleErrorCode();
/// Helper for converting an std::error_code to a Error.
inline Error errorCodeToError(std::error_code EC) {
if (!EC)
return Error::success();
return Error(llvm::make_unique<ECError>(ECError(EC)));
}
Error errorCodeToError(std::error_code EC);
/// Helper for converting an ECError to a std::error_code.
///
/// This method requires that Err be Error() or an ECError, otherwise it
/// will trigger a call to abort().
inline std::error_code errorToErrorCode(Error Err) {
std::error_code EC;
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
EC = EI.convertToErrorCode();
});
return EC;
}
std::error_code errorToErrorCode(Error Err);
/// Convert an ErrorOr<T> to an Expected<T>.
template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) {
@ -883,6 +882,23 @@ template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) {
return std::move(*E);
}
/// This class wraps a string in an Error.
///
/// StringError is useful in cases where the client is not expected to be able
/// to consume the specific error message programmatically (for example, if the
/// error message is to be presented to the user). It cannot be converted to a
/// std::error_code.
class StringError : public ErrorInfo<StringError> {
public:
static char ID;
StringError(const Twine &S, std::error_code EC);
void log(raw_ostream &OS) const override;
std::error_code convertToErrorCode() const override;
private:
std::string Msg;
std::error_code EC;
};
/// Helper for check-and-exit error handling.
///
/// For tool use only. NOT FOR USE IN LIBRARY CODE.

View File

@ -8,15 +8,19 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Error.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
using namespace llvm;
namespace {
enum class ErrorErrorCode {
MultipleErrors
enum class ErrorErrorCode : int {
MultipleErrors = 1,
UnconvertibleError
};
// FIXME: This class is only here to support the transition to llvm::Error. It
@ -30,21 +34,61 @@ namespace {
switch (static_cast<ErrorErrorCode>(condition)) {
case ErrorErrorCode::MultipleErrors:
return "Multiple errors";
};
case ErrorErrorCode::UnconvertibleError:
return "Unconvertible error value. An error has occurred that could "
"not be converted to a known std::error_code. Please file a "
"bug.";
}
llvm_unreachable("Unhandled error code");
}
};
}
static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
namespace llvm {
void ErrorInfoBase::anchor() {}
char ErrorInfoBase::ID = 0;
char ErrorList::ID = 0;
char ECError::ID = 0;
char StringError::ID = 0;
static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
std::error_code ErrorList::convertToErrorCode() const {
return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),
*ErrorErrorCat);
}
std::error_code unconvertibleErrorCode() {
return std::error_code(static_cast<int>(ErrorErrorCode::UnconvertibleError),
*ErrorErrorCat);
}
Error errorCodeToError(std::error_code EC) {
if (!EC)
return Error::success();
return Error(llvm::make_unique<ECError>(ECError(EC)));
}
std::error_code errorToErrorCode(Error Err) {
std::error_code EC;
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
EC = EI.convertToErrorCode();
});
if (EC == unconvertibleErrorCode())
report_fatal_error(EC.message());
return EC;
}
StringError::StringError(const Twine &S, std::error_code EC)
: Msg(S.str()), EC(EC) {}
void StringError::log(raw_ostream &OS) const { OS << Msg; }
std::error_code StringError::convertToErrorCode() const {
return EC;
}
}

View File

@ -8,6 +8,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Error.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "gtest/gtest.h"
@ -376,6 +378,20 @@ TEST(Error, CatchErrorFromHandler) {
<< "Failed to handle Error returned from handleErrors.";
}
TEST(Error, StringError) {
std::string Msg;
raw_string_ostream S(Msg);
logAllUnhandledErrors(make_error<StringError>("foo" + Twine(42),
unconvertibleErrorCode()),
S, "");
EXPECT_EQ(S.str(), "foo42\n") << "Unexpected StringError log result";
auto EC =
errorToErrorCode(make_error<StringError>("", errc::invalid_argument));
EXPECT_EQ(EC, errc::invalid_argument)
<< "Failed to convert StringError to error_code.";
}
// Test that the ExitOnError utility works as expected.
TEST(Error, ExitOnError) {
ExitOnError ExitOnErr;