diff options
Diffstat (limited to 'contrib/llvm/include/llvm/Support/Error.h')
-rw-r--r-- | contrib/llvm/include/llvm/Support/Error.h | 683 |
1 files changed, 368 insertions, 315 deletions
diff --git a/contrib/llvm/include/llvm/Support/Error.h b/contrib/llvm/include/llvm/Support/Error.h index 9a7fa0ae6356..8567af392fb0 100644 --- a/contrib/llvm/include/llvm/Support/Error.h +++ b/contrib/llvm/include/llvm/Support/Error.h @@ -246,18 +246,20 @@ public: } private: +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + // assertIsChecked() happens very frequently, but under normal circumstances + // is supposed to be a no-op. So we want it to be inlined, but having a bunch + // of debug prints can cause the function to be too large for inlining. So + // it's important that we define this function out of line so that it can't be + // inlined. + LLVM_ATTRIBUTE_NORETURN + void fatalUncheckedError() const; +#endif + void assertIsChecked() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS - 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(); - } + if (LLVM_UNLIKELY(!getChecked() || getPtr())) + fatalUncheckedError(); #endif } @@ -407,235 +409,6 @@ 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: -/// -/// @code{.cpp} -/// Result foo(Error &Err) { -/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set -/// // <body of foo> -/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed. -/// } -/// @endcode -/// -/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be -/// used with optional Errors (Error pointers that are allowed to be null). If -/// ErrorAsOutParameter took an Error reference, an instance would have to be -/// created inside every condition that verified that Error was non-null. By -/// taking an Error pointer we can just create one instance at the top of the -/// function. -class ErrorAsOutParameter { -public: - ErrorAsOutParameter(Error *Err) : Err(Err) { - // Raise the checked bit if Err is success. - if (Err) - (void)!!*Err; - } - - ~ErrorAsOutParameter() { - // Clear the checked bit. - if (Err && !*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 @@ -861,19 +634,26 @@ private: #endif } +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + LLVM_ATTRIBUTE_NORETURN + LLVM_ATTRIBUTE_NOINLINE + void fatalUncheckedExpected() const { + 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 + void assertIsChecked() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS - if (Unchecked) { - 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(); - } + if (LLVM_UNLIKELY(Unchecked)) + fatalUncheckedExpected(); #endif } @@ -887,6 +667,344 @@ private: #endif }; +/// 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); + +/// Report a fatal error if Err is a failure value. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns +/// // Error::success(). +/// Error foo(bool DoFallibleOperation); +/// +/// cantFail(foo(false)); +/// @endcode +inline void cantFail(Error Err, const char *Msg = nullptr) { + if (Err) { + if (!Msg) + Msg = "Failure value returned from cantFail wrapped call"; + llvm_unreachable(Msg); + } +} + +/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and +/// returns the contained value. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns an int. +/// Expected<int> foo(bool DoFallibleOperation); +/// +/// int X = cantFail(foo(false)); +/// @endcode +template <typename T> +T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) { + if (ValOrErr) + return std::move(*ValOrErr); + else { + if (!Msg) + Msg = "Failure value returned from cantFail wrapped call"; + llvm_unreachable(Msg); + } +} + +/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and +/// returns the contained reference. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns a Bar&. +/// Expected<Bar&> foo(bool DoFallibleOperation); +/// +/// Bar &X = cantFail(foo(false)); +/// @endcode +template <typename T> +T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) { + if (ValOrErr) + return *ValOrErr; + else { + if (!Msg) + Msg = "Failure value returned from cantFail wrapped call"; + llvm_unreachable(Msg); + } +} + +/// 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 'void (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>)'. +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, report_fatal_error() will be called. +template <typename... HandlerTs> +void handleAllErrors(Error E, HandlerTs &&... Handlers) { + cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...)); +} + +/// Check that E is a non-error, then drop it. +/// If E is an error report_fatal_error will be called. +inline void handleAllErrors(Error E) { + cantFail(std::move(E)); +} + +/// Handle any errors (if present) in an Expected<T>, then try a recovery path. +/// +/// If the incoming value is a success value it is returned unmodified. If it +/// is a failure value then it the contained error is passed to handleErrors. +/// If handleErrors is able to handle the error then the RecoveryPath functor +/// is called to supply the final result. If handleErrors is not able to +/// handle all errors then the unhandled errors are returned. +/// +/// This utility enables the follow pattern: +/// +/// @code{.cpp} +/// enum FooStrategy { Aggressive, Conservative }; +/// Expected<Foo> foo(FooStrategy S); +/// +/// auto ResultOrErr = +/// handleExpected( +/// foo(Aggressive), +/// []() { return foo(Conservative); }, +/// [](AggressiveStrategyError&) { +/// // Implicitly conusme this - we'll recover by using a conservative +/// // strategy. +/// }); +/// +/// @endcode +template <typename T, typename RecoveryFtor, typename... HandlerTs> +Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath, + HandlerTs &&... Handlers) { + if (ValOrErr) + return ValOrErr; + + if (auto Err = handleErrors(ValOrErr.takeError(), + std::forward<HandlerTs>(Handlers)...)) + return std::move(Err); + + return RecoveryPath(); +} + +/// 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: +/// +/// @code{.cpp} +/// Result foo(Error &Err) { +/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set +/// // <body of foo> +/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed. +/// } +/// @endcode +/// +/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be +/// used with optional Errors (Error pointers that are allowed to be null). If +/// ErrorAsOutParameter took an Error reference, an instance would have to be +/// created inside every condition that verified that Error was non-null. By +/// taking an Error pointer we can just create one instance at the top of the +/// function. +class ErrorAsOutParameter { +public: + ErrorAsOutParameter(Error *Err) : Err(Err) { + // Raise the checked bit if Err is success. + if (Err) + (void)!!*Err; + } + + ~ErrorAsOutParameter() { + // Clear the checked bit. + if (Err && !*Err) + *Err = Error::success(); + } + +private: + Error *Err; +}; + /// Helper for Expected<T>s used as out-parameters. /// /// See ErrorAsOutParameter. @@ -1032,71 +1150,6 @@ private: 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); - -/// Report a fatal error if Err is a failure value. -/// -/// This function can be used to wrap calls to fallible functions ONLY when it -/// is known that the Error will always be a success value. E.g. -/// -/// @code{.cpp} -/// // foo only attempts the fallible operation if DoFallibleOperation is -/// // true. If DoFallibleOperation is false then foo always returns -/// // Error::success(). -/// Error foo(bool DoFallibleOperation); -/// -/// cantFail(foo(false)); -/// @endcode -inline void cantFail(Error Err) { - if (Err) - llvm_unreachable("Failure value returned from cantFail wrapped call"); -} - -/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and -/// returns the contained value. -/// -/// This function can be used to wrap calls to fallible functions ONLY when it -/// is known that the Error will always be a success value. E.g. -/// -/// @code{.cpp} -/// // foo only attempts the fallible operation if DoFallibleOperation is -/// // true. If DoFallibleOperation is false then foo always returns an int. -/// Expected<int> foo(bool DoFallibleOperation); -/// -/// int X = cantFail(foo(false)); -/// @endcode -template <typename T> -T cantFail(Expected<T> ValOrErr) { - if (ValOrErr) - return std::move(*ValOrErr); - else - llvm_unreachable("Failure value returned from cantFail wrapped call"); -} - -/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and -/// returns the contained reference. -/// -/// This function can be used to wrap calls to fallible functions ONLY when it -/// is known that the Error will always be a success value. E.g. -/// -/// @code{.cpp} -/// // foo only attempts the fallible operation if DoFallibleOperation is -/// // true. If DoFallibleOperation is false then foo always returns a Bar&. -/// Expected<Bar&> foo(bool DoFallibleOperation); -/// -/// Bar &X = cantFail(foo(false)); -/// @endcode -template <typename T> -T& cantFail(Expected<T&> ValOrErr) { - if (ValOrErr) - return *ValOrErr; - else - llvm_unreachable("Failure value returned from cantFail wrapped call"); -} - } // end namespace llvm #endif // LLVM_SUPPORT_ERROR_H |