Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
llvm/include/llvm/Support/Error.h
Show First 20 Lines • Show All 681 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
}; | }; | ||||
/// Report a serious error, calling any installed error handler. See | /// Report a serious error, calling any installed error handler. See | ||||
/// ErrorHandling.h. | /// ErrorHandling.h. | ||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, | LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, | ||||
bool gen_crash_diag = true); | bool gen_crash_diag = true); | ||||
namespace detail { | |||||
inline LLVM_ATTRIBUTE_NORETURN void handleError(Error Err, const char *Msg, | |||||
const char *file = nullptr, | |||||
unsigned line = 0) { | |||||
if (!Msg) | |||||
Msg = "Failure value returned from cantFail wrapped call"; | |||||
#ifndef NDEBUG | |||||
std::string Str; | |||||
raw_string_ostream OS(Str); | |||||
OS << Err << "\n" << Msg; | |||||
if (file) | |||||
OS << " at " << file << ":" << line; | |||||
Msg = OS.str().c_str(); | |||||
#endif | |||||
llvm_unreachable(Msg); | |||||
} | |||||
inline void cantFail_annotated(const char *file, unsigned line, Error Err, | |||||
const char *Msg = nullptr) { | |||||
if (Err) | |||||
handleError(std::move(Err), Msg, file, line); | |||||
} | |||||
template <typename T> | |||||
T cantFail_annotated(const char *file, unsigned line, Expected<T> ValOrErr, | |||||
const char *Msg = nullptr) { | |||||
if (ValOrErr) | |||||
return std::move(*ValOrErr); | |||||
handleError(std::move(ValOrErr.takeError()), Msg, file, line); | |||||
} | |||||
template <typename T> | |||||
T &cantFail_annotated(const char *file, unsigned line, Expected<T &> ValOrErr, | |||||
const char *Msg = nullptr) { | |||||
if (ValOrErr) | |||||
return *ValOrErr; | |||||
handleError(std::move(ValOrErr.takeError()), Msg, file, line); | |||||
} | |||||
} // namespace detail | |||||
/// Report a fatal error if Err is a failure value. | /// Report a fatal error if Err is a failure value. | ||||
/// | /// | ||||
/// This function can be used to wrap calls to fallible functions ONLY when it | /// 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. | /// is known that the Error will always be a success value. E.g. | ||||
/// | /// | ||||
/// @code{.cpp} | /// @code{.cpp} | ||||
/// // foo only attempts the fallible operation if DoFallibleOperation is | /// // foo only attempts the fallible operation if DoFallibleOperation is | ||||
/// // true. If DoFallibleOperation is false then foo always returns | /// // true. If DoFallibleOperation is false then foo always returns | ||||
/// // Error::success(). | /// // Error::success(). | ||||
/// Error foo(bool DoFallibleOperation); | /// Error foo(bool DoFallibleOperation); | ||||
/// | /// | ||||
/// cantFail(foo(false)); | /// cantFail(foo(false)); | ||||
/// @endcode | /// @endcode | ||||
inline void cantFail(Error Err, const char *Msg = nullptr) { | inline void cantFail(Error Err, const char *Msg = nullptr) { | ||||
if (Err) { | if (Err) | ||||
if (!Msg) | detail::handleError(std::move(Err), Msg); | ||||
Msg = "Failure value returned from cantFail wrapped call"; | |||||
#ifndef NDEBUG | |||||
std::string Str; | |||||
raw_string_ostream OS(Str); | |||||
OS << Msg << "\n" << Err; | |||||
Msg = OS.str().c_str(); | |||||
#endif | |||||
llvm_unreachable(Msg); | |||||
} | |||||
} | } | ||||
/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and | /// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and | ||||
/// returns the contained value. | /// returns the contained value. | ||||
/// | /// | ||||
/// This function can be used to wrap calls to fallible functions ONLY when it | /// 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. | /// is known that the Error will always be a success value. E.g. | ||||
/// | /// | ||||
/// @code{.cpp} | /// @code{.cpp} | ||||
/// // foo only attempts the fallible operation if DoFallibleOperation is | /// // foo only attempts the fallible operation if DoFallibleOperation is | ||||
/// // true. If DoFallibleOperation is false then foo always returns an int. | /// // true. If DoFallibleOperation is false then foo always returns an int. | ||||
/// Expected<int> foo(bool DoFallibleOperation); | /// Expected<int> foo(bool DoFallibleOperation); | ||||
/// | /// | ||||
/// int X = cantFail(foo(false)); | /// int X = cantFail(foo(false)); | ||||
/// @endcode | /// @endcode | ||||
template <typename T> | template <typename T> | ||||
T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) { | T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) { | ||||
if (ValOrErr) | if (ValOrErr) | ||||
return std::move(*ValOrErr); | return std::move(*ValOrErr); | ||||
else { | detail::handleError(std::move(ValOrErr.takeError()), Msg); | ||||
if (!Msg) | |||||
Msg = "Failure value returned from cantFail wrapped call"; | |||||
#ifndef NDEBUG | |||||
std::string Str; | |||||
raw_string_ostream OS(Str); | |||||
auto E = ValOrErr.takeError(); | |||||
OS << Msg << "\n" << E; | |||||
Msg = OS.str().c_str(); | |||||
#endif | |||||
llvm_unreachable(Msg); | |||||
} | |||||
} | } | ||||
/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and | /// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and | ||||
/// returns the contained reference. | /// returns the contained reference. | ||||
/// | /// | ||||
/// This function can be used to wrap calls to fallible functions ONLY when it | /// 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. | /// is known that the Error will always be a success value. E.g. | ||||
/// | /// | ||||
/// @code{.cpp} | /// @code{.cpp} | ||||
/// // foo only attempts the fallible operation if DoFallibleOperation is | /// // foo only attempts the fallible operation if DoFallibleOperation is | ||||
/// // true. If DoFallibleOperation is false then foo always returns a Bar&. | /// // true. If DoFallibleOperation is false then foo always returns a Bar&. | ||||
/// Expected<Bar&> foo(bool DoFallibleOperation); | /// Expected<Bar&> foo(bool DoFallibleOperation); | ||||
/// | /// | ||||
/// Bar &X = cantFail(foo(false)); | /// Bar &X = cantFail(foo(false)); | ||||
/// @endcode | /// @endcode | ||||
template <typename T> | template <typename T> | ||||
T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) { | T &cantFail(Expected<T &> ValOrErr, const char *Msg = nullptr) { | ||||
if (ValOrErr) | if (ValOrErr) | ||||
return *ValOrErr; | return *ValOrErr; | ||||
else { | detail::handleError(std::move(ValOrErr.takeError()), Msg); | ||||
if (!Msg) | } | ||||
Msg = "Failure value returned from cantFail wrapped call"; | |||||
#ifndef NDEBUG | #ifndef NDEBUG | ||||
std::string Str; | #define llvm_cantFail(...) \ | ||||
raw_string_ostream OS(Str); | ::llvm::detail::cantFail_annotated(__FILE__, __LINE__, __VA_ARGS__) | ||||
auto E = ValOrErr.takeError(); | #else | ||||
OS << Msg << "\n" << E; | #define llvm_cantFail(...) \ | ||||
Msg = OS.str().c_str(); | ::llvm::detail::cantFail_annotated(nullptr, 0, __VA_ARGS__) | ||||
#endif | #endif | ||||
llvm_unreachable(Msg); | |||||
} | |||||
} | |||||
/// Helper for testing applicability of, and applying, handlers for | /// Helper for testing applicability of, and applying, handlers for | ||||
/// ErrorInfo types. | /// ErrorInfo types. | ||||
template <typename HandlerT> | template <typename HandlerT> | ||||
class ErrorHandlerTraits | class ErrorHandlerTraits | ||||
: public ErrorHandlerTraits<decltype( | : public ErrorHandlerTraits<decltype( | ||||
&std::remove_reference<HandlerT>::type::operator())> {}; | &std::remove_reference<HandlerT>::type::operator())> {}; | ||||
▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | Error handleErrors(Error E, HandlerTs &&... Hs) { | ||||
return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...); | return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...); | ||||
} | } | ||||
/// Behaves the same as handleErrors, except that by contract all errors | /// Behaves the same as handleErrors, except that by contract all errors | ||||
/// *must* be handled by the given handlers (i.e. there must be no remaining | /// *must* be handled by the given handlers (i.e. there must be no remaining | ||||
/// errors after running the handlers, or llvm_unreachable is called). | /// errors after running the handlers, or llvm_unreachable is called). | ||||
template <typename... HandlerTs> | template <typename... HandlerTs> | ||||
void handleAllErrors(Error E, HandlerTs &&... Handlers) { | void handleAllErrors(Error E, HandlerTs &&... Handlers) { | ||||
cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...)); | llvm_cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...)); | ||||
} | } | ||||
/// Check that E is a non-error, then drop it. | /// Check that E is a non-error, then drop it. | ||||
/// If E is an error, llvm_unreachable will be called. | /// If E is an error, llvm_unreachable will be called. | ||||
inline void handleAllErrors(Error E) { | inline void handleAllErrors(Error E) { | ||||
cantFail(std::move(E)); | llvm_cantFail(std::move(E)); | ||||
} | } | ||||
/// Handle any errors (if present) in an Expected<T>, then try a recovery path. | /// 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 | /// 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. | /// 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 | /// 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 | /// is called to supply the final result. If handleErrors is not able to | ||||
▲ Show 20 Lines • Show All 412 Lines • Show Last 20 Lines |