aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/include/llvm/Support/Error.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/include/llvm/Support/Error.h')
-rw-r--r--contrib/llvm/include/llvm/Support/Error.h683
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