when defining a function which should be able to efficiently accept concatenated
strings.
+.. _error_apis:
+
+Error handling
+--------------
+
+Proper error handling helps us identify bugs in our code, and helps end-users
+understand errors in their tool usage. Errors fall into two broad categories:
+*programmatic* and *recoverable*, with different strategies for handling and
+reporting.
+
+Programmatic Errors
+^^^^^^^^^^^^^^^^^^^
+
+Programmatic errors are violations of program invariants or API contracts, and
+represent bugs within the program itself. Our aim is to document invariants, and
+to abort quickly at the point of failure (providing some basic diagnostic) when
+invariants are broken at runtime.
+
+The fundamental tools for handling programmatic errors are assertions and the
+llvm_unreachable function. Assertions are used to express invariant conditions,
+and should include a message describing the invariant:
+
+.. code-block:: c++
+
+ assert(isPhysReg(R) && "All virt regs should have been allocated already.");
+
+The llvm_unreachable function can be used to document areas of control flow
+that should never be entered if the program invariants hold:
+
+.. code-block:: c++
+
+ enum { Foo, Bar, Baz } X = foo();
+
+ switch (X) {
+ case Foo: /* Handle Foo */; break;
+ case Bar: /* Handle Bar */; break;
+ default:
+ llvm_unreachable("X should be Foo or Bar here");
+ }
+
+Recoverable Errors
+^^^^^^^^^^^^^^^^^^
+
+Recoverable errors represent an error in the program's environment, for example
+a resource failure (a missing file, a dropped network connection, etc.), or
+malformed input. These errors should be detected and communicated to a level of
+the program where they can be handled appropriately. Handling the error may be
+as simple as reporting the issue to the user, or it may involve attempts at
+recovery.
+
+Recoverable errors are modeled using LLVM's ``Error`` scheme. This scheme
+represents errors using function return values, similar to classic C integer
+error codes, or C++'s ``std::error_code``. However, the ``Error`` class is
+actually a lightweight wrapper for user-defined error types, allowing arbitrary
+information to be attached to describe the error. This is similar to the way C++
+exceptions allow throwing of user-defined types.
+
+Success values are created by calling ``Error::success()``:
+
+.. code-block:: c++
+
+ Error foo() {
+ // Do something.
+ // Return success.
+ return Error::success();
+ }
+
+Success values are very cheap to construct and return - they have minimal
+impact on program performance.
+
+Failure values are constructed using ``make_error<T>``, where ``T`` is any class
+that inherits from the ErrorInfo utility:
+
+.. code-block:: c++
+
+ class MyError : public ErrorInfo<MyError> {
+ public:
+ MyError(std::string Msg) : Msg(Msg) {}
+ void log(OStream &OS) const override { OS << "MyError - " << Msg; }
+ private:
+ std::string Msg;
+ };
+
+ Error bar() {
+ if (checkErrorCondition)
+ return make_error<MyError>("Error condition detected");
+
+ // No error - proceed with bar.
+
+ // Return success value.
+ return Error::success();
+ }
+
+For functions that can fail but need to return a value the ``Expected<T>``
+utility can be used. Values of this type can be constructed with either a
+``T``, or a ``Error``. Values are implicitly convertible to boolean: true
+for success, false for error. If success, the ``T`` value can be accessed via
+the dereference operator. If failure, the ``Error`` value can be extracted
+using the ``takeError()`` method:
+
+.. code-block:: c++
+
+ Expected<float> parseAndSquareRoot(IStream &IS) {
+ float f;
+ OS >> f;
+ if (f < 0)
+ return make_error<FloatingPointError>(...);
+ return sqrt(f);
+ }
+
+ Error foo(IStream &IS) {
+ if (auto SqrtOrErr = parseAndSquartRoot(IS)) {
+ float Sqrt = *SqrtOrErr;
+ // ...
+ } else
+ return SqrtOrErr.takeError();
+ }
+
+All Error instances, whether success or failure, must be either checked or
+moved from (via std::move or a return) before they are destructed. Accidentally
+discarding an unchecked error will cause a program abort at the point where the
+unchecked value's destructor is run, making it easy to identify and fix
+violations of this rule.
+
+Success values are considered checked once they have been tested (by invoking
+the boolean conversion operator):
+
+.. code-block:: c++
+
+ if (auto Err = canFail(...))
+ return Err; // Failure value - move error to caller.
+
+ // Safe to continue: Err was checked.
+
+In contrast, the following code will always cause an abort, regardless of the
+return value of ``foo``:
+
+.. code-block:: c++
+
+ canFail();
+ // Program will always abort here, even if canFail() returns Success, since
+ // the value is not checked.
+
+Failure values are considered checked once a handler for the error type has
+been activated:
+
+.. code-block:: c++
+
+ auto Err = canFail(...);
+ if (auto Err2 =
+ handleErrors(std::move(Err),
+ [](std::unique_ptr<MyError> M) {
+ // Try to handle 'M'. If successful, return a success value from
+ // the handler.
+ if (tryToHandle(M))
+ return Error::success();
+
+ // We failed to handle 'M' - return it from the handler.
+ // This value will be passed back from catchErrors and
+ // wind up in Err2, where it will be returned from this function.
+ return Error(std::move(M));
+ })))
+ return Err2;
+
+
.. _function_apis:
+More information on Error and its related utilities can be found in the
+Error.h header file.
+
Passing functions and other callable objects
--------------------------------------------
--- /dev/null
+//===----- 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/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;
+
+ // 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 the 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 =
+/// checkErrors(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);
+
+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) {
+ // Move assignment shouldn't drop an existing error, but we won't complain
+ // about overwriting success.
+ 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()->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 &ID; }
+
+private:
+ static char ID;
+};
+
+template <typename MyErrT, typename ParentErrT>
+char ErrorInfo<MyErrT, ParentErrT>::ID = 0;
+
+/// 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";
+ }
+ }
+
+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 &E2List = static_cast<ErrorList &>(*E2.getPtr());
+ 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.
+template <typename... HandlerTs>
+void logAllUnhandledErrors(Error E, raw_ostream &OS, std::string ErrorBanner) {
+ if (!E)
+ return;
+ OS << ErrorBanner;
+ handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
+ EI.log(OS);
+ OS << "\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 &) {});
+}
+
+/// 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;
+
+public:
+ typedef typename std::conditional<isRef, wrap, T>::type storage_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) {
+ assert(Err && "Cannot create Expected 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) {
+ new (getStorage()) storage_type(std::move(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() {
+ if (!HasError)
+ getStorage()->~storage_type();
+ else
+ getErrorStorage()->~Error();
+ }
+
+ /// \brief Return false if there is an error.
+ explicit operator bool() const { return !HasError; }
+
+ /// \brief Returns a reference to the stored T value.
+ reference get() { return *getStorage(); }
+
+ /// \brief Returns a const reference to the stored T value.
+ const_reference get() const { 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() {
+ return HasError ? std::move(*getErrorStorage()) : Error();
+ }
+
+ /// \brief Returns a pointer to the stored T value.
+ pointer operator->() { return toPointer(getStorage()); }
+
+ /// \brief Returns a const pointer to the stored T value.
+ const_pointer operator->() const { return toPointer(getStorage()); }
+
+ /// \brief Returns a reference to the stored T value.
+ reference operator*() { return *getStorage(); }
+
+ /// \brief Returns a const reference to the stored T value.
+ const_reference operator*() const { 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) {
+ if (!Other.HasError) {
+ // Get the other value.
+ HasError = false;
+ new (getStorage()) storage_type(std::move(*Other.getStorage()));
+ } else {
+ // Get other's error.
+ HasError = true;
+ new (getErrorStorage()) Error(Other.takeError());
+ }
+ }
+
+ template <class OtherT> void moveAssign(Expected<OtherT> &&Other) {
+ 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 *getErrorStorage() {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<Error *>(ErrorStorage.buffer);
+ }
+
+ union {
+ AlignedCharArrayUnion<storage_type> TStorage;
+ AlignedCharArrayUnion<Error> ErrorStorage;
+ };
+ bool HasError : 1;
+};
+
+/// 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> {
+public:
+ ECError() = default;
+ ECError(std::error_code EC) : EC(EC) {}
+ std::error_code getErrorCode() const { return EC; }
+ void log(raw_ostream &OS) const override { OS << EC.message(); }
+
+protected:
+ std::error_code EC;
+};
+
+/// Helper for converting an std::error_code to a Error.
+inline Error errorCodeToError(std::error_code EC) {
+ if (!EC)
+ return Error::success();
+ return make_error<ECError>(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 ECError &ECE) { EC = ECE.getErrorCode(); });
+ return EC;
+}
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_ERROR_H
--- /dev/null
+//===----- unittests/ErrorTest.cpp - Error.h tests ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Errc.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+// Test:
+//
+// Constructing success.
+// - Silent acceptance of tested success.
+// - Programmatic error on untested success.
+//
+// Custom error class.
+// - Creation of a custom error class with a default base class.
+// - Handling of a custom error class with a default base class.
+// - Handler type deduction.
+// - Failure to handle a custom error class.
+// - Isa testing of a custom error class.
+//
+// - Creation of a custom error class with a custom base class.
+// - Handling of a custom error class with a default base class.
+// - Correct shadowing of handlers.
+//
+// Utility functions:
+// - join_errors to defer errors.
+// - consume_error to consume a "safe" error without any output.
+// - handleAllUnhandledErrors to assert that all errors are handled.
+// - logAllUnhandledErrors to log errors to a stream.
+//
+// Expected tests:
+// - Expected<T> with T.
+// - Expected<T> with Error.
+// - Failure to handle an Expected<T> in failure mode.
+// - Error extraction (Expected -> Error).
+//
+// std::error_code:
+// - std::error_code to Error in success mode.
+// - std::error_code to Error (ECError) in failure mode.
+// - Error to std::error_code in success mode.
+// - Error (ECError) to std::error_code in failure mode.
+
+// Custom error class with a default base class and some random 'info' attached.
+class CustomError : public ErrorInfo<CustomError> {
+public:
+ // Create an error with some info attached.
+ CustomError(int Info) : Info(Info) {}
+
+ // Get the info attached to this error.
+ int getInfo() const { return Info; }
+
+ // Log this error to a stream.
+ void log(raw_ostream &OS) const override {
+ OS << "CustomError { " << getInfo() << "}";
+ }
+
+protected:
+ // This error is subclassed below, but we can't use inheriting constructors
+ // yet, so we can't propagate the constructors through ErrorInfo. Instead
+ // we have to have a default constructor and have the subclass initialize all
+ // fields.
+ CustomError() : Info(0) {}
+
+ int Info;
+};
+
+// Custom error class with a custom base class and some additional random
+// 'info'.
+class CustomSubError : public ErrorInfo<CustomSubError, CustomError> {
+public:
+ // Create a sub-error with some info attached.
+ CustomSubError(int Info, int ExtraInfo) : ExtraInfo(ExtraInfo) {
+ this->Info = Info;
+ }
+
+ // Get the extra info attached to this error.
+ int getExtraInfo() const { return ExtraInfo; }
+
+ // Log this error to a stream.
+ void log(raw_ostream &OS) const override {
+ OS << "CustomSubError { " << getInfo() << ", " << getExtraInfo() << "}";
+ }
+
+protected:
+ int ExtraInfo;
+};
+
+// Verify that success values that are checked (i.e. cast to 'bool') are
+// destructed without error, and that unchecked success values cause an
+// abort.
+TEST(Error, CheckSuccess) {
+ // Test checked success.
+ {
+ Error E;
+ EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'";
+ }
+
+// Test unchecked success.
+// Test runs in debug mode only.
+#ifndef NDEBUG
+ {
+ auto DropUncheckedSuccess = []() { Error E; };
+ EXPECT_DEATH(DropUncheckedSuccess(),
+ "Program aborted due to an unhandled Error:")
+ << "Unchecked Error Succes value did not cause abort()";
+ }
+#endif
+}
+
+static Error handleCustomError(const CustomError &CE) { return Error(); }
+
+static void handleCustomErrorVoid(const CustomError &CE) {}
+
+static Error handleCustomErrorUP(std::unique_ptr<CustomError> CE) {
+ return Error();
+}
+
+static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {}
+
+// Verify creation and handling of custom error classes.
+TEST(Error, CheckCustomErrors) {
+// Check that we abort on unhandled failure cases. (Force conversion to bool
+// to make sure that we don't accidentally treat checked errors as handled).
+// Test runs in debug mode only.
+#ifndef NDEBUG
+ {
+ auto DropUnhandledError = []() {
+ Error E = make_error<CustomError>(42);
+ (void)!E;
+ };
+ EXPECT_DEATH(DropUnhandledError(),
+ "Program aborted due to an unhandled Error:")
+ << "Unhandled Error failure value did not cause abort()";
+ }
+#endif
+
+ // Check 'isA' handling.
+ {
+ Error E = make_error<CustomError>(1);
+ Error F = make_error<CustomSubError>(1, 2);
+
+ EXPECT_TRUE(E.isA<CustomError>());
+ EXPECT_FALSE(E.isA<CustomSubError>());
+ EXPECT_TRUE(F.isA<CustomError>());
+ EXPECT_TRUE(F.isA<CustomSubError>());
+
+ consumeError(std::move(E));
+ consumeError(std::move(F));
+ }
+
+ // Check that we can handle a custom error.
+ {
+ int CaughtErrorInfo = 0;
+ handleAllErrors(make_error<CustomError>(42), [&](const CustomError &CE) {
+ CaughtErrorInfo = CE.getInfo();
+ });
+
+ EXPECT_TRUE(CaughtErrorInfo == 42)
+ << "Wrong result from CustomError handler";
+ }
+
+ // Check that handler type deduction also works for handlers
+ // of the following types:
+ // void (const Err&)
+ // Error (const Err&) mutable
+ // void (const Err&) mutable
+ // Error (Err&)
+ // void (Err&)
+ // Error (Err&) mutable
+ // void (Err&) mutable
+ // Error (unique_ptr<Err>)
+ // void (unique_ptr<Err>)
+ // Error (unique_ptr<Err>) mutable
+ // void (unique_ptr<Err>) mutable
+
+ handleAllErrors(make_error<CustomError>(42), [](const CustomError &CE) {});
+
+ handleAllErrors(
+ make_error<CustomError>(42),
+ [](const CustomError &CE) mutable { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](const CustomError &CE) mutable {});
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](CustomError &CE) { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) {});
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](CustomError &CE) mutable { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) mutable {});
+
+ handleAllErrors(
+ make_error<CustomError>(42),
+ [](std::unique_ptr<CustomError> CE) { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](std::unique_ptr<CustomError> CE) {});
+
+ handleAllErrors(
+ make_error<CustomError>(42),
+ [](std::unique_ptr<CustomError> CE) mutable { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](std::unique_ptr<CustomError> CE) mutable {});
+
+ // Check that named handlers of type 'Error (const Err&)' work.
+ handleAllErrors(make_error<CustomError>(42), handleCustomError);
+
+ // Check that named handlers of type 'void (const Err&)' work.
+ handleAllErrors(make_error<CustomError>(42), handleCustomErrorVoid);
+
+ // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work.
+ handleAllErrors(make_error<CustomError>(42), handleCustomErrorUP);
+
+ // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work.
+ handleAllErrors(make_error<CustomError>(42), handleCustomErrorUPVoid);
+
+ // Check that we can handle a custom error with a custom base class.
+ {
+ int CaughtErrorInfo = 0;
+ int CaughtErrorExtraInfo = 0;
+ handleAllErrors(make_error<CustomSubError>(42, 7),
+ [&](const CustomSubError &SE) {
+ CaughtErrorInfo = SE.getInfo();
+ CaughtErrorExtraInfo = SE.getExtraInfo();
+ });
+
+ EXPECT_TRUE(CaughtErrorInfo == 42 && CaughtErrorExtraInfo == 7)
+ << "Wrong result from CustomSubError handler";
+ }
+
+ // Check that we trigger only the first handler that applies.
+ {
+ int DummyInfo = 0;
+ int CaughtErrorInfo = 0;
+ int CaughtErrorExtraInfo = 0;
+
+ handleAllErrors(make_error<CustomSubError>(42, 7),
+ [&](const CustomSubError &SE) {
+ CaughtErrorInfo = SE.getInfo();
+ CaughtErrorExtraInfo = SE.getExtraInfo();
+ },
+ [&](const CustomError &CE) { DummyInfo = CE.getInfo(); });
+
+ EXPECT_TRUE(CaughtErrorInfo == 42 && CaughtErrorExtraInfo == 7 &&
+ DummyInfo == 0)
+ << "Activated the wrong Error handler(s)";
+ }
+
+ // Check that general handlers shadow specific ones.
+ {
+ int CaughtErrorInfo = 0;
+ int DummyInfo = 0;
+ int DummyExtraInfo = 0;
+
+ handleAllErrors(
+ make_error<CustomSubError>(42, 7),
+ [&](const CustomError &CE) { CaughtErrorInfo = CE.getInfo(); },
+ [&](const CustomSubError &SE) {
+ DummyInfo = SE.getInfo();
+ DummyExtraInfo = SE.getExtraInfo();
+ });
+
+ EXPECT_TRUE(CaughtErrorInfo = 42 && DummyInfo == 0 && DummyExtraInfo == 0)
+ << "General Error handler did not shadow specific handler";
+ }
+}
+
+// Test utility functions.
+TEST(Error, CheckErrorUtilities) {
+
+ // Test joinErrors
+ {
+ int CustomErrorInfo1 = 0;
+ int CustomErrorInfo2 = 0;
+ int CustomErrorExtraInfo = 0;
+ Error E = joinErrors(make_error<CustomError>(7),
+ make_error<CustomSubError>(42, 7));
+
+ handleAllErrors(std::move(E),
+ [&](const CustomSubError &SE) {
+ CustomErrorInfo2 = SE.getInfo();
+ CustomErrorExtraInfo = SE.getExtraInfo();
+ },
+ [&](const CustomError &CE) {
+ // Assert that the CustomError instance above is handled
+ // before the
+ // CustomSubError - joinErrors should preserve error
+ // ordering.
+ EXPECT_EQ(CustomErrorInfo2, 0)
+ << "CustomErrorInfo2 should be 0 here. "
+ "joinErrors failed to preserve ordering.\n";
+ CustomErrorInfo1 = CE.getInfo();
+ });
+
+ EXPECT_TRUE(CustomErrorInfo1 == 7 && CustomErrorInfo2 == 42 &&
+ CustomErrorExtraInfo == 7)
+ << "Failed handling compound Error.";
+ }
+
+ // Test consumeError for both success and error cases.
+ {
+ Error E;
+ consumeError(std::move(E));
+ }
+ {
+ Error E = make_error<CustomError>(7);
+ consumeError(std::move(E));
+ }
+
+// Test that handleAllUnhandledErrors crashes if an error is not caught.
+// Test runs in debug mode only.
+#ifndef NDEBUG
+ {
+ auto FailToHandle = []() {
+ handleAllErrors(make_error<CustomError>(7),
+ [&](const CustomSubError &SE) {
+ errs() << "This should never be called";
+ exit(1);
+ });
+ };
+
+ EXPECT_DEATH(FailToHandle(), "Program aborted due to an unhandled Error:")
+ << "Unhandled Error in handleAllErrors call did not cause an "
+ "abort()";
+ }
+#endif
+
+// Test that handleAllUnhandledErrors crashes if an error is returned from a
+// handler.
+// Test runs in debug mode only.
+#ifndef NDEBUG
+ {
+ auto ReturnErrorFromHandler = []() {
+ handleAllErrors(make_error<CustomError>(7),
+ [&](std::unique_ptr<CustomSubError> SE) {
+ return Error(std::move(SE));
+ });
+ };
+
+ EXPECT_DEATH(ReturnErrorFromHandler(),
+ "Program aborted due to an unhandled Error:")
+ << " Error returned from handler in handleAllErrors call did not "
+ "cause abort()";
+ }
+#endif
+
+ // Test that we can return values from handleErrors.
+ {
+ int ErrorInfo = 0;
+
+ Error E = handleErrors(
+ make_error<CustomError>(7),
+ [&](std::unique_ptr<CustomError> CE) { return Error(std::move(CE)); });
+
+ handleAllErrors(std::move(E),
+ [&](const CustomError &CE) { ErrorInfo = CE.getInfo(); });
+
+ EXPECT_EQ(ErrorInfo, 7)
+ << "Failed to handle Error returned from handleErrors.";
+ }
+}
+
+// Test Expected behavior.
+TEST(Error, CheckExpected) {
+
+ // Check that non-errors convert to 'true'.
+ {
+ Expected<int> A = 7;
+ EXPECT_TRUE(!!A)
+ << "Expected with non-error value doesn't convert to 'true'";
+ }
+
+ // Check that non-error values are accessible via operator*.
+ {
+ Expected<int> A = 7;
+ EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value";
+ }
+
+ // Check that errors convert to 'false'.
+ {
+ Expected<int> A = make_error<CustomError>(42);
+ EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'";
+ consumeError(A.takeError());
+ }
+
+ // Check that error values are accessible via takeError().
+ {
+ Expected<int> A = make_error<CustomError>(42);
+ Error E = A.takeError();
+ EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value";
+ consumeError(std::move(E));
+ }
+
+// Check that an Expected instance with an error value doesn't allow access to
+// operator*.
+// Test runs in debug mode only.
+#ifndef NDEBUG
+ {
+ Expected<int> A = make_error<CustomError>(42);
+ EXPECT_DEATH(*A, "\\(!HasError && \"Cannot get value "
+ "when an error exists!\"\\)")
+ << "Incorrect Expected error value";
+ consumeError(A.takeError());
+ }
+#endif
+
+// Check that an Expected instance with an error triggers an abort if
+// unhandled.
+// Test runs in debug mode only.
+#ifndef NDEBUG
+ EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); },
+ "Program aborted due to an unhandled Error:")
+ << "Unchecked Expected<T> failure value did not cause an abort()";
+#endif
+
+ // Test covariance of Expected.
+ {
+ class B {};
+ class D : public B {};
+
+ Expected<B *> A1(Expected<D *>(nullptr));
+ A1 = Expected<D *>(nullptr);
+
+ Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr));
+ A2 = Expected<std::unique_ptr<D>>(nullptr);
+ }
+}
+
+TEST(Error, ECError) {
+
+ // Round-trip a success value to check that it converts correctly.
+ EXPECT_EQ(errorToErrorCode(errorCodeToError(std::error_code())),
+ std::error_code())
+ << "std::error_code() should round-trip via Error conversions";
+
+ // Round-trip an error value to check that it converts correctly.
+ EXPECT_EQ(errorToErrorCode(errorCodeToError(errc::invalid_argument)),
+ errc::invalid_argument)
+ << "std::error_code error value should round-trip via Error "
+ "conversions";
+}
+
+} // end anon namespace