summaryrefslogtreecommitdiff
path: root/include/llvm/Support/Error.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Support/Error.h')
-rw-r--r--include/llvm/Support/Error.h950
1 files changed, 950 insertions, 0 deletions
diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h
new file mode 100644
index 0000000000000..5f515a88a021a
--- /dev/null
+++ b/include/llvm/Support/Error.h
@@ -0,0 +1,950 @@
+//===----- llvm/Support/Error.h - Recoverable error handling ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an API used to report recoverable errors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERROR_H
+#define LLVM_SUPPORT_ERROR_H
+
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
+
+namespace llvm {
+
+class Error;
+class ErrorList;
+
+/// Base class for error info classes. Do not extend this directly: Extend
+/// the ErrorInfo template subclass instead.
+class ErrorInfoBase {
+public:
+ virtual ~ErrorInfoBase() {}
+
+ /// Print an error message to an output stream.
+ virtual void log(raw_ostream &OS) const = 0;
+
+ /// Return the error message as a string.
+ virtual std::string message() const {
+ std::string Msg;
+ raw_string_ostream OS(Msg);
+ log(OS);
+ return OS.str();
+ }
+
+ /// Convert this error to a std::error_code.
+ ///
+ /// This is a temporary crutch to enable interaction with code still
+ /// using std::error_code. It will be removed in the future.
+ virtual std::error_code convertToErrorCode() const = 0;
+
+ // Check whether this instance is a subclass of the class identified by
+ // ClassID.
+ virtual bool isA(const void *const ClassID) const {
+ return ClassID == classID();
+ }
+
+ // Check whether this instance is a subclass of ErrorInfoT.
+ template <typename ErrorInfoT> bool isA() const {
+ return isA(ErrorInfoT::classID());
+ }
+
+ // Returns the class ID for this type.
+ static const void *classID() { return &ID; }
+
+private:
+ virtual void anchor();
+ static char ID;
+};
+
+/// Lightweight error class with error context and mandatory checking.
+///
+/// Instances of this class wrap a ErrorInfoBase pointer. Failure states
+/// are represented by setting the pointer to a ErrorInfoBase subclass
+/// instance containing information describing the failure. Success is
+/// represented by a null pointer value.
+///
+/// Instances of Error also contains a 'Checked' flag, which must be set
+/// before the destructor is called, otherwise the destructor will trigger a
+/// runtime error. This enforces at runtime the requirement that all Error
+/// instances be checked or returned to the caller.
+///
+/// There are two ways to set the checked flag, depending on what state the
+/// Error instance is in. For Error instances indicating success, it
+/// is sufficient to invoke the boolean conversion operator. E.g.:
+///
+/// Error foo(<...>);
+///
+/// if (auto E = foo(<...>))
+/// return E; // <- Return E if it is in the error state.
+/// // We have verified that E was in the success state. It can now be safely
+/// // destroyed.
+///
+/// A success value *can not* be dropped. For example, just calling 'foo(<...>)'
+/// without testing the return value will raise a runtime error, even if foo
+/// returns success.
+///
+/// For Error instances representing failure, you must use either the
+/// handleErrors or handleAllErrors function with a typed handler. E.g.:
+///
+/// class MyErrorInfo : public ErrorInfo<MyErrorInfo> {
+/// // Custom error info.
+/// };
+///
+/// Error foo(<...>) { return make_error<MyErrorInfo>(...); }
+///
+/// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo.
+/// auto NewE =
+/// handleErrors(E,
+/// [](const MyErrorInfo &M) {
+/// // Deal with the error.
+/// },
+/// [](std::unique_ptr<OtherError> M) -> Error {
+/// if (canHandle(*M)) {
+/// // handle error.
+/// return Error::success();
+/// }
+/// // Couldn't handle this error instance. Pass it up the stack.
+/// return Error(std::move(M));
+/// );
+/// // Note - we must check or return NewE in case any of the handlers
+/// // returned a new error.
+///
+/// The handleAllErrors function is identical to handleErrors, except
+/// that it has a void return type, and requires all errors to be handled and
+/// no new errors be returned. It prevents errors (assuming they can all be
+/// handled) from having to be bubbled all the way to the top-level.
+///
+/// *All* Error instances must be checked before destruction, even if
+/// they're moved-assigned or constructed from Success values that have already
+/// been checked. This enforces checking through all levels of the call stack.
+class Error {
+
+ // ErrorList needs to be able to yank ErrorInfoBase pointers out of this
+ // class to add to the error list.
+ friend class ErrorList;
+
+ // handleErrors needs to be able to set the Checked flag.
+ template <typename... HandlerTs>
+ friend Error handleErrors(Error E, HandlerTs &&... Handlers);
+
+ // Expected<T> needs to be able to steal the payload when constructed from an
+ // error.
+ template <typename T> class Expected;
+
+public:
+ /// Create a success value. Prefer using 'Error::success()' for readability
+ /// where possible.
+ Error() {
+ setPtr(nullptr);
+ setChecked(false);
+ }
+
+ /// Create a success value. This is equivalent to calling the default
+ /// constructor, but should be preferred for readability where possible.
+ static Error success() { return Error(); }
+
+ // Errors are not copy-constructable.
+ Error(const Error &Other) = delete;
+
+ /// Move-construct an error value. The newly constructed error is considered
+ /// unchecked, even if the source error had been checked. The original error
+ /// becomes a checked Success value, regardless of its original state.
+ Error(Error &&Other) {
+ setChecked(true);
+ *this = std::move(Other);
+ }
+
+ /// Create an error value. Prefer using the 'make_error' function, but
+ /// this constructor can be useful when "re-throwing" errors from handlers.
+ Error(std::unique_ptr<ErrorInfoBase> Payload) {
+ setPtr(Payload.release());
+ setChecked(false);
+ }
+
+ // Errors are not copy-assignable.
+ Error &operator=(const Error &Other) = delete;
+
+ /// Move-assign an error value. The current error must represent success, you
+ /// you cannot overwrite an unhandled error. The current error is then
+ /// considered unchecked. The source error becomes a checked success value,
+ /// regardless of its original state.
+ Error &operator=(Error &&Other) {
+ // Don't allow overwriting of unchecked values.
+ assertIsChecked();
+ setPtr(Other.getPtr());
+
+ // This Error is unchecked, even if the source error was checked.
+ setChecked(false);
+
+ // Null out Other's payload and set its checked bit.
+ Other.setPtr(nullptr);
+ Other.setChecked(true);
+
+ return *this;
+ }
+
+ /// Destroy a Error. Fails with a call to abort() if the error is
+ /// unchecked.
+ ~Error() {
+ assertIsChecked();
+ delete getPtr();
+ }
+
+ /// Bool conversion. Returns true if this Error is in a failure state,
+ /// and false if it is in an accept state. If the error is in a Success state
+ /// it will be considered checked.
+ explicit operator bool() {
+ setChecked(getPtr() == nullptr);
+ return getPtr() != nullptr;
+ }
+
+ /// Check whether one error is a subclass of another.
+ template <typename ErrT> bool isA() const {
+ return getPtr() && getPtr()->isA(ErrT::classID());
+ }
+
+private:
+ void assertIsChecked() {
+#ifndef NDEBUG
+ if (!getChecked() || getPtr()) {
+ dbgs() << "Program aborted due to an unhandled Error:\n";
+ if (getPtr())
+ getPtr()->log(dbgs());
+ else
+ dbgs()
+ << "Error value was Success. (Note: Success values must still be "
+ "checked prior to being destroyed).\n";
+ abort();
+ }
+#endif
+ }
+
+ ErrorInfoBase *getPtr() const {
+#ifndef NDEBUG
+ return PayloadAndCheckedBit.getPointer();
+#else
+ return Payload;
+#endif
+ }
+
+ void setPtr(ErrorInfoBase *EI) {
+#ifndef NDEBUG
+ PayloadAndCheckedBit.setPointer(EI);
+#else
+ Payload = EI;
+#endif
+ }
+
+ bool getChecked() const {
+#ifndef NDEBUG
+ return PayloadAndCheckedBit.getInt();
+#else
+ return true;
+#endif
+ }
+
+ void setChecked(bool V) {
+#ifndef NDEBUG
+ PayloadAndCheckedBit.setInt(V);
+#endif
+ }
+
+ std::unique_ptr<ErrorInfoBase> takePayload() {
+ std::unique_ptr<ErrorInfoBase> Tmp(getPtr());
+ setPtr(nullptr);
+ setChecked(true);
+ return Tmp;
+ }
+
+#ifndef NDEBUG
+ PointerIntPair<ErrorInfoBase *, 1> PayloadAndCheckedBit;
+#else
+ ErrorInfoBase *Payload;
+#endif
+};
+
+/// Make a Error instance representing failure using the given error info
+/// type.
+template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
+ return Error(llvm::make_unique<ErrT>(std::forward<ArgTs>(Args)...));
+}
+
+/// Base class for user error types. Users should declare their error types
+/// like:
+///
+/// class MyError : public ErrorInfo<MyError> {
+/// ....
+/// };
+///
+/// This class provides an implementation of the ErrorInfoBase::kind
+/// method, which is used by the Error RTTI system.
+template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
+class ErrorInfo : public ParentErrT {
+public:
+ bool isA(const void *const ClassID) const override {
+ return ClassID == classID() || ParentErrT::isA(ClassID);
+ }
+
+ static const void *classID() { return &ThisErrT::ID; }
+};
+
+/// Special ErrorInfo subclass representing a list of ErrorInfos.
+/// Instances of this class are constructed by joinError.
+class ErrorList final : public ErrorInfo<ErrorList> {
+
+ // handleErrors needs to be able to iterate the payload list of an
+ // ErrorList.
+ template <typename... HandlerTs>
+ friend Error handleErrors(Error E, HandlerTs &&... Handlers);
+
+ // joinErrors is implemented in terms of join.
+ friend Error joinErrors(Error, Error);
+
+public:
+ void log(raw_ostream &OS) const override {
+ OS << "Multiple errors:\n";
+ for (auto &ErrPayload : Payloads) {
+ ErrPayload->log(OS);
+ OS << "\n";
+ }
+ }
+
+ std::error_code convertToErrorCode() const override;
+
+ // Used by ErrorInfo::classID.
+ static char ID;
+
+private:
+ ErrorList(std::unique_ptr<ErrorInfoBase> Payload1,
+ std::unique_ptr<ErrorInfoBase> Payload2) {
+ assert(!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() &&
+ "ErrorList constructor payloads should be singleton errors");
+ Payloads.push_back(std::move(Payload1));
+ Payloads.push_back(std::move(Payload2));
+ }
+
+ static Error join(Error E1, Error E2) {
+ if (!E1)
+ return E2;
+ if (!E2)
+ return E1;
+ if (E1.isA<ErrorList>()) {
+ auto &E1List = static_cast<ErrorList &>(*E1.getPtr());
+ if (E2.isA<ErrorList>()) {
+ auto E2Payload = E2.takePayload();
+ auto &E2List = static_cast<ErrorList &>(*E2Payload);
+ for (auto &Payload : E2List.Payloads)
+ E1List.Payloads.push_back(std::move(Payload));
+ } else
+ E1List.Payloads.push_back(E2.takePayload());
+
+ return E1;
+ }
+ if (E2.isA<ErrorList>()) {
+ auto &E2List = static_cast<ErrorList &>(*E2.getPtr());
+ E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload());
+ return E2;
+ }
+ return Error(std::unique_ptr<ErrorList>(
+ new ErrorList(E1.takePayload(), E2.takePayload())));
+ }
+
+ std::vector<std::unique_ptr<ErrorInfoBase>> Payloads;
+};
+
+/// Concatenate errors. The resulting Error is unchecked, and contains the
+/// ErrorInfo(s), if any, contained in E1, followed by the
+/// ErrorInfo(s), if any, contained in E2.
+inline Error joinErrors(Error E1, Error E2) {
+ return ErrorList::join(std::move(E1), std::move(E2));
+}
+
+/// Helper for testing applicability of, and applying, handlers for
+/// ErrorInfo types.
+template <typename HandlerT>
+class ErrorHandlerTraits
+ : public ErrorHandlerTraits<decltype(
+ &std::remove_reference<HandlerT>::type::operator())> {};
+
+// Specialization functions of the form 'Error (const ErrT&)'.
+template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ return H(static_cast<ErrT &>(*E));
+ }
+};
+
+// Specialization functions of the form 'void (const ErrT&)'.
+template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ H(static_cast<ErrT &>(*E));
+ return Error::success();
+ }
+};
+
+/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
+template <typename ErrT>
+class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
+ return H(std::move(SubE));
+ }
+};
+
+/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
+template <typename ErrT>
+class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
+ H(std::move(SubE));
+ return Error::success();
+ }
+};
+
+// Specialization for member functions of the form 'RetT (const ErrT&)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(ErrT &)>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(ErrT &) const>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(const ErrT &)>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+/// Specialization for member functions of the form
+/// 'RetT (std::unique_ptr<ErrT>) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)>
+ : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
+
+/// Specialization for member functions of the form
+/// 'RetT (std::unique_ptr<ErrT>) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const>
+ : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
+
+inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) {
+ return Error(std::move(Payload));
+}
+
+template <typename HandlerT, typename... HandlerTs>
+Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload,
+ HandlerT &&Handler, HandlerTs &&... Handlers) {
+ if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload))
+ return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler),
+ std::move(Payload));
+ return handleErrorImpl(std::move(Payload),
+ std::forward<HandlerTs>(Handlers)...);
+}
+
+/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any
+/// unhandled errors (or Errors returned by handlers) are re-concatenated and
+/// returned.
+/// Because this function returns an error, its result must also be checked
+/// or returned. If you intend to handle all errors use handleAllErrors
+/// (which returns void, and will abort() on unhandled errors) instead.
+template <typename... HandlerTs>
+Error handleErrors(Error E, HandlerTs &&... Hs) {
+ if (!E)
+ return Error::success();
+
+ std::unique_ptr<ErrorInfoBase> Payload = E.takePayload();
+
+ if (Payload->isA<ErrorList>()) {
+ ErrorList &List = static_cast<ErrorList &>(*Payload);
+ Error R;
+ for (auto &P : List.Payloads)
+ R = ErrorList::join(
+ std::move(R),
+ handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...));
+ return R;
+ }
+
+ return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...);
+}
+
+/// Behaves the same as handleErrors, except that it requires that all
+/// errors be handled by the given handlers. If any unhandled error remains
+/// after the handlers have run, abort() will be called.
+template <typename... HandlerTs>
+void handleAllErrors(Error E, HandlerTs &&... Handlers) {
+ auto F = handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...);
+ // Cast 'F' to bool to set the 'Checked' flag if it's a success value:
+ (void)!F;
+}
+
+/// Check that E is a non-error, then drop it.
+inline void handleAllErrors(Error E) {
+ // Cast 'E' to a bool to set the 'Checked' flag if it's a success value:
+ (void)!E;
+}
+
+/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner
+/// will be printed before the first one is logged. A newline will be printed
+/// after each error.
+///
+/// This is useful in the base level of your program to allow clean termination
+/// (allowing clean deallocation of resources, etc.), while reporting error
+/// information to the user.
+void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner);
+
+/// Write all error messages (if any) in E to a string. The newline character
+/// is used to separate error messages.
+inline std::string toString(Error E) {
+ SmallVector<std::string, 2> Errors;
+ handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {
+ Errors.push_back(EI.message());
+ });
+ return join(Errors.begin(), Errors.end(), "\n");
+}
+
+/// Consume a Error without doing anything. This method should be used
+/// only where an error can be considered a reasonable and expected return
+/// value.
+///
+/// Uses of this method are potentially indicative of design problems: If it's
+/// legitimate to do nothing while processing an "error", the error-producer
+/// might be more clearly refactored to return an Optional<T>.
+inline void consumeError(Error Err) {
+ handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
+}
+
+/// Helper for Errors used as out-parameters.
+///
+/// This helper is for use with the Error-as-out-parameter idiom, where an error
+/// is passed to a function or method by reference, rather than being returned.
+/// In such cases it is helpful to set the checked bit on entry to the function
+/// so that the error can be written to (unchecked Errors abort on assignment)
+/// and clear the checked bit on exit so that clients cannot accidentally forget
+/// to check the result. This helper performs these actions automatically using
+/// RAII:
+///
+/// Result foo(Error &Err) {
+/// ErrorAsOutParameter ErrAsOutParam(Err); // 'Checked' flag set
+/// // <body of foo>
+/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
+/// }
+class ErrorAsOutParameter {
+public:
+ ErrorAsOutParameter(Error &Err) : Err(Err) {
+ // Raise the checked bit if Err is success.
+ (void)!!Err;
+ }
+ ~ErrorAsOutParameter() {
+ // Clear the checked bit.
+ if (!Err)
+ Err = Error::success();
+ }
+
+private:
+ Error &Err;
+};
+
+/// Tagged union holding either a T or a Error.
+///
+/// This class parallels ErrorOr, but replaces error_code with Error. Since
+/// Error cannot be copied, this class replaces getError() with
+/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
+/// error class type.
+template <class T> class Expected {
+ template <class OtherT> friend class Expected;
+ static const bool isRef = std::is_reference<T>::value;
+ typedef ReferenceStorage<typename std::remove_reference<T>::type> wrap;
+
+ typedef std::unique_ptr<ErrorInfoBase> error_type;
+
+public:
+ typedef typename std::conditional<isRef, wrap, T>::type storage_type;
+ typedef T value_type;
+
+private:
+ typedef typename std::remove_reference<T>::type &reference;
+ typedef const typename std::remove_reference<T>::type &const_reference;
+ typedef typename std::remove_reference<T>::type *pointer;
+ typedef const typename std::remove_reference<T>::type *const_pointer;
+
+public:
+ /// Create an Expected<T> error value from the given Error.
+ Expected(Error Err)
+ : HasError(true)
+#ifndef NDEBUG
+ ,
+ Checked(false)
+#endif
+ {
+ assert(Err && "Cannot create Expected<T> from Error success value.");
+ new (getErrorStorage()) Error(std::move(Err));
+ }
+
+ /// Create an Expected<T> success value from the given OtherT value, which
+ /// must be convertible to T.
+ template <typename OtherT>
+ Expected(OtherT &&Val,
+ typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
+ * = nullptr)
+ : HasError(false)
+#ifndef NDEBUG
+ ,
+ Checked(false)
+#endif
+ {
+ new (getStorage()) storage_type(std::forward<OtherT>(Val));
+ }
+
+ /// Move construct an Expected<T> value.
+ Expected(Expected &&Other) { moveConstruct(std::move(Other)); }
+
+ /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
+ /// must be convertible to T.
+ template <class OtherT>
+ Expected(Expected<OtherT> &&Other,
+ typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
+ * = nullptr) {
+ moveConstruct(std::move(Other));
+ }
+
+ /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
+ /// isn't convertible to T.
+ template <class OtherT>
+ explicit Expected(
+ Expected<OtherT> &&Other,
+ typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
+ nullptr) {
+ moveConstruct(std::move(Other));
+ }
+
+ /// Move-assign from another Expected<T>.
+ Expected &operator=(Expected &&Other) {
+ moveAssign(std::move(Other));
+ return *this;
+ }
+
+ /// Destroy an Expected<T>.
+ ~Expected() {
+ assertIsChecked();
+ if (!HasError)
+ getStorage()->~storage_type();
+ else
+ getErrorStorage()->~error_type();
+ }
+
+ /// \brief Return false if there is an error.
+ explicit operator bool() {
+#ifndef NDEBUG
+ Checked = !HasError;
+#endif
+ return !HasError;
+ }
+
+ /// \brief Returns a reference to the stored T value.
+ reference get() {
+ assertIsChecked();
+ return *getStorage();
+ }
+
+ /// \brief Returns a const reference to the stored T value.
+ const_reference get() const {
+ assertIsChecked();
+ return const_cast<Expected<T> *>(this)->get();
+ }
+
+ /// \brief Check that this Expected<T> is an error of type ErrT.
+ template <typename ErrT> bool errorIsA() const {
+ return HasError && getErrorStorage()->template isA<ErrT>();
+ }
+
+ /// \brief Take ownership of the stored error.
+ /// After calling this the Expected<T> is in an indeterminate state that can
+ /// only be safely destructed. No further calls (beside the destructor) should
+ /// be made on the Expected<T> vaule.
+ Error takeError() {
+#ifndef NDEBUG
+ Checked = true;
+#endif
+ return HasError ? Error(std::move(*getErrorStorage())) : Error::success();
+ }
+
+ /// \brief Returns a pointer to the stored T value.
+ pointer operator->() {
+ assertIsChecked();
+ return toPointer(getStorage());
+ }
+
+ /// \brief Returns a const pointer to the stored T value.
+ const_pointer operator->() const {
+ assertIsChecked();
+ return toPointer(getStorage());
+ }
+
+ /// \brief Returns a reference to the stored T value.
+ reference operator*() {
+ assertIsChecked();
+ return *getStorage();
+ }
+
+ /// \brief Returns a const reference to the stored T value.
+ const_reference operator*() const {
+ assertIsChecked();
+ return *getStorage();
+ }
+
+private:
+ template <class T1>
+ static bool compareThisIfSameType(const T1 &a, const T1 &b) {
+ return &a == &b;
+ }
+
+ template <class T1, class T2>
+ static bool compareThisIfSameType(const T1 &a, const T2 &b) {
+ return false;
+ }
+
+ template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) {
+ HasError = Other.HasError;
+
+#ifndef NDEBUG
+ Checked = false;
+ Other.Checked = true;
+#endif
+
+ if (!HasError)
+ new (getStorage()) storage_type(std::move(*Other.getStorage()));
+ else
+ new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage()));
+ }
+
+ template <class OtherT> void moveAssign(Expected<OtherT> &&Other) {
+ assertIsChecked();
+
+ if (compareThisIfSameType(*this, Other))
+ return;
+
+ this->~Expected();
+ new (this) Expected(std::move(Other));
+ }
+
+ pointer toPointer(pointer Val) { return Val; }
+
+ const_pointer toPointer(const_pointer Val) const { return Val; }
+
+ pointer toPointer(wrap *Val) { return &Val->get(); }
+
+ const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
+
+ storage_type *getStorage() {
+ assert(!HasError && "Cannot get value when an error exists!");
+ return reinterpret_cast<storage_type *>(TStorage.buffer);
+ }
+
+ const storage_type *getStorage() const {
+ assert(!HasError && "Cannot get value when an error exists!");
+ return reinterpret_cast<const storage_type *>(TStorage.buffer);
+ }
+
+ error_type *getErrorStorage() {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<error_type *>(ErrorStorage.buffer);
+ }
+
+ void assertIsChecked() {
+#ifndef NDEBUG
+ if (!Checked) {
+ dbgs() << "Expected<T> must be checked before access or destruction.\n";
+ if (HasError) {
+ dbgs() << "Unchecked Expected<T> contained error:\n";
+ (*getErrorStorage())->log(dbgs());
+ } else
+ dbgs() << "Expected<T> value was in success state. (Note: Expected<T> "
+ "values in success mode must still be checked prior to being "
+ "destroyed).\n";
+ abort();
+ }
+#endif
+ }
+
+ union {
+ AlignedCharArrayUnion<storage_type> TStorage;
+ AlignedCharArrayUnion<error_type> ErrorStorage;
+ };
+ bool HasError : 1;
+#ifndef NDEBUG
+ bool Checked : 1;
+#endif
+};
+
+/// This class wraps a std::error_code in a Error.
+///
+/// This is useful if you're writing an interface that returns a Error
+/// (or Expected) and you want to call code that still returns
+/// std::error_codes.
+class ECError : public ErrorInfo<ECError> {
+ friend Error errorCodeToError(std::error_code);
+public:
+ void setErrorCode(std::error_code EC) { this->EC = EC; }
+ std::error_code convertToErrorCode() const override { return EC; }
+ void log(raw_ostream &OS) const override { OS << EC.message(); }
+
+ // Used by ErrorInfo::classID.
+ static char ID;
+
+protected:
+ ECError() = default;
+ ECError(std::error_code EC) : EC(EC) {}
+ 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 inconvertibleErrorCode();
+
+/// Helper for converting an std::error_code to a Error.
+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().
+std::error_code errorToErrorCode(Error Err);
+
+/// Convert an ErrorOr<T> to an Expected<T>.
+template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) {
+ if (auto EC = EO.getError())
+ return errorCodeToError(EC);
+ return std::move(*EO);
+}
+
+/// Convert an Expected<T> to an ErrorOr<T>.
+template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) {
+ if (auto Err = E.takeError())
+ return errorToErrorCode(std::move(Err));
+ 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).
+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.
+///
+class ExitOnError {
+public:
+ /// Create an error on exit helper.
+ ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1)
+ : Banner(std::move(Banner)),
+ GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {}
+
+ /// Set the banner string for any errors caught by operator().
+ void setBanner(std::string Banner) { this->Banner = std::move(Banner); }
+
+ /// Set the exit-code mapper function.
+ void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) {
+ this->GetExitCode = std::move(GetExitCode);
+ }
+
+ /// Check Err. If it's in a failure state log the error(s) and exit.
+ void operator()(Error Err) const { checkError(std::move(Err)); }
+
+ /// Check E. If it's in a success state then return the contained value. If
+ /// it's in a failure state log the error(s) and exit.
+ template <typename T> T operator()(Expected<T> &&E) const {
+ checkError(E.takeError());
+ return std::move(*E);
+ }
+
+ /// Check E. If it's in a success state then return the contained reference. If
+ /// it's in a failure state log the error(s) and exit.
+ template <typename T> T& operator()(Expected<T&> &&E) const {
+ checkError(E.takeError());
+ return *E;
+ }
+
+private:
+ void checkError(Error Err) const {
+ if (Err) {
+ int ExitCode = GetExitCode(Err);
+ logAllUnhandledErrors(std::move(Err), errs(), Banner);
+ exit(ExitCode);
+ }
+ }
+
+ std::string Banner;
+ std::function<int(const Error &)> GetExitCode;
+};
+
+/// Report a serious error, calling any installed error handler. See
+/// ErrorHandling.h.
+LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err,
+ bool gen_crash_diag = true);
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_ERROR_H