diff options
author | Lang Hames <lhames@gmail.com> | 2016-05-27 01:37:32 +0000 |
---|---|---|
committer | Lang Hames <lhames@gmail.com> | 2016-05-27 01:37:32 +0000 |
commit | c5e0bbd781d45bf8ebd22ed90b6b64130affeb51 (patch) | |
tree | d928363532216da7bddec10bb81af4ccb4f87adc | |
parent | 76dacb4ba9e50c8583e5aaf37badc0de7a3da60c (diff) | |
download | bcm5719-llvm-c5e0bbd781d45bf8ebd22ed90b6b64130affeb51.tar.gz bcm5719-llvm-c5e0bbd781d45bf8ebd22ed90b6b64130affeb51.zip |
[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
-rw-r--r-- | llvm/include/llvm/Support/Error.h | 40 | ||||
-rw-r--r-- | llvm/lib/Support/Error.cpp | 52 | ||||
-rw-r--r-- | llvm/unittests/Support/ErrorTest.cpp | 16 |
3 files changed, 92 insertions, 16 deletions
diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h index a8152e871dc..8c7b92458be 100644 --- a/llvm/include/llvm/Support/Error.h +++ b/llvm/include/llvm/Support/Error.h @@ -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. diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp index 564b763ff32..6a8189596da 100644 --- a/llvm/lib/Support/Error.cpp +++ b/llvm/lib/Support/Error.cpp @@ -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; +} + +} diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp index c2a1673f42d..919bce53860 100644 --- a/llvm/unittests/Support/ErrorTest.cpp +++ b/llvm/unittests/Support/ErrorTest.cpp @@ -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; |