diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 | 
| commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
| tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /include/llvm/Support/Error.h | |
| parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) | |
Notes
Diffstat (limited to 'include/llvm/Support/Error.h')
| -rw-r--r-- | include/llvm/Support/Error.h | 683 | 
1 files changed, 368 insertions, 315 deletions
| diff --git a/include/llvm/Support/Error.h b/include/llvm/Support/Error.h index 9a7fa0ae6356..8567af392fb0 100644 --- a/include/llvm/Support/Error.h +++ b/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 | 
