diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h --- a/llvm/include/llvm/Support/Error.h +++ b/llvm/include/llvm/Support/Error.h @@ -162,7 +162,7 @@ // handleErrors needs to be able to set the Checked flag. template - friend Error handleErrors(Error E, HandlerTs &&... Handlers); + friend Error handleErrors(Error E, HandlerTs &&...Handlers); // Expected needs to be able to steal the payload when constructed from an // error. @@ -244,7 +244,7 @@ /// Returns the dynamic class id of this error, or null if this is a success /// value. - const void* dynamicClassID() const { + const void *dynamicClassID() const { if (!getPtr()) return nullptr; return getPtr()->dynamicClassID(); @@ -270,9 +270,8 @@ ErrorInfoBase *getPtr() const { #if LLVM_ENABLE_ABI_BREAKING_CHECKS - return reinterpret_cast( - reinterpret_cast(Payload) & - ~static_cast(0x1)); + return reinterpret_cast( + reinterpret_cast(Payload) & ~static_cast(0x1)); #else return Payload; #endif @@ -280,10 +279,9 @@ void setPtr(ErrorInfoBase *EI) { #if LLVM_ENABLE_ABI_BREAKING_CHECKS - Payload = reinterpret_cast( - (reinterpret_cast(EI) & - ~static_cast(0x1)) | - (reinterpret_cast(Payload) & 0x1)); + Payload = reinterpret_cast( + (reinterpret_cast(EI) & ~static_cast(0x1)) | + (reinterpret_cast(Payload) & 0x1)); #else Payload = EI; #endif @@ -299,10 +297,9 @@ void setChecked(bool V) { #if LLVM_ENABLE_ABI_BREAKING_CHECKS - Payload = reinterpret_cast( - (reinterpret_cast(Payload) & - ~static_cast(0x1)) | - (V ? 0 : 1)); + Payload = reinterpret_cast( + (reinterpret_cast(Payload) & ~static_cast(0x1)) | + (V ? 0 : 1)); #endif } @@ -333,7 +330,7 @@ /// Make a Error instance representing failure using the given error info /// type. -template Error make_error(ArgTs &&... Args) { +template Error make_error(ArgTs &&...Args) { return Error(std::make_unique(std::forward(Args)...)); } @@ -366,7 +363,7 @@ // handleErrors needs to be able to iterate the payload list of an // ErrorList. template - friend Error handleErrors(Error E, HandlerTs &&... Handlers); + friend Error handleErrors(Error E, HandlerTs &&...Handlers); // joinErrors is implemented in terms of join. friend Error joinErrors(Error, Error); @@ -436,6 +433,40 @@ /// Error cannot be copied, this class replaces getError() with /// takeError(). It also adds an bool errorIsA() method for testing the /// error class type. +/// +/// Example usage of 'Expected' as a function return type: +/// +/// @code{.cpp} +/// Expected myDivide(int A, int B) { +/// if (B == 0) { +/// // return an Error +/// return createStringError(inconvertibleErrorCode(), +/// "B must not be zero!"); +/// } +/// // return an integer +/// return A / B; +/// } +/// @endcode +/// +/// Checking the results of to a function returning 'Expected': +/// @code{.cpp} +/// auto Result = myDivide(X,Y); +/// if (auto E = Result.takeError()) { +/// // We must consume the error. Typically one of: +/// // - return the error to our caller +/// // - toString(), when logging +/// // - consumeError(), to silently swallow the error +/// // - handleErrors(), to distinguish error types +/// errs() << "Problem with division " +/// << toString(Result.takeError()) << "\n"; +/// } +/// // use the result +/// outs() << "The answer is " << *Result << "\n"; +/// @endcode +/// +/// For unit-testing a function returning an 'Expceted', see the +/// 'EXPECT_THAT_EXPECTED' macros in llvm/Testing/Support/Error.h + template class LLVM_NODISCARD Expected { template friend class ExpectedAsOutParameter; template friend class Expected; @@ -462,7 +493,8 @@ : HasError(true) #if LLVM_ENABLE_ABI_BREAKING_CHECKS // Expected is unchecked upon construction in Debug builds. - , Unchecked(true) + , + Unchecked(true) #endif { assert(Err && "Cannot create Expected from Error success value."); @@ -764,7 +796,7 @@ /// Bar &X = cantFail(foo(false)); /// @endcode template -T& cantFail(Expected ValOrErr, const char *Msg = nullptr) { +T &cantFail(Expected ValOrErr, const char *Msg = nullptr) { if (ValOrErr) return *ValOrErr; else { @@ -785,8 +817,8 @@ /// ErrorInfo types. template class ErrorHandlerTraits - : public ErrorHandlerTraits::type::operator())> {}; + : public ErrorHandlerTraits< + decltype(&std::remove_reference::type::operator())> {}; // Specialization functions of the form 'Error (const ErrT&)'. template class ErrorHandlerTraits { @@ -888,7 +920,7 @@ template Error handleErrorImpl(std::unique_ptr Payload, - HandlerT &&Handler, HandlerTs &&... Handlers) { + HandlerT &&Handler, HandlerTs &&...Handlers) { if (ErrorHandlerTraits::appliesTo(*Payload)) return ErrorHandlerTraits::apply(std::forward(Handler), std::move(Payload)); @@ -903,7 +935,7 @@ /// or returned. If you intend to handle all errors use handleAllErrors /// (which returns void, and will abort() on unhandled errors) instead. template -Error handleErrors(Error E, HandlerTs &&... Hs) { +Error handleErrors(Error E, HandlerTs &&...Hs) { if (!E) return Error::success(); @@ -926,15 +958,13 @@ /// *must* be handled by the given handlers (i.e. there must be no remaining /// errors after running the handlers, or llvm_unreachable is called). template -void handleAllErrors(Error E, HandlerTs &&... Handlers) { +void handleAllErrors(Error E, HandlerTs &&...Handlers) { cantFail(handleErrors(std::move(E), std::forward(Handlers)...)); } /// Check that E is a non-error, then drop it. /// If E is an error, llvm_unreachable will be called. -inline void handleAllErrors(Error E) { - cantFail(std::move(E)); -} +inline void handleAllErrors(Error E) { cantFail(std::move(E)); } /// Handle any errors (if present) in an Expected, then try a recovery path. /// @@ -962,7 +992,7 @@ /// @endcode template Expected handleExpected(Expected ValOrErr, RecoveryFtor &&RecoveryPath, - HandlerTs &&... Handlers) { + HandlerTs &&...Handlers) { if (ValOrErr) return ValOrErr; @@ -1078,11 +1108,9 @@ /// Helper for Expecteds used as out-parameters. /// /// See ErrorAsOutParameter. -template -class ExpectedAsOutParameter { +template class ExpectedAsOutParameter { public: - ExpectedAsOutParameter(Expected *ValOrErr) - : ValOrErr(ValOrErr) { + ExpectedAsOutParameter(Expected *ValOrErr) : ValOrErr(ValOrErr) { if (ValOrErr) (void)!!*ValOrErr; } @@ -1126,7 +1154,7 @@ /// It should only be used in this situation, and should never be used where a /// sensible conversion to std::error_code is available, as attempts to convert /// to/from this error will result in a fatal error. (i.e. it is a programmatic -///error to try to convert such a value). +/// error to try to convert such a value). std::error_code inconvertibleErrorCode(); /// Helper for converting an std::error_code to a Error. @@ -1200,7 +1228,7 @@ /// Create formatted StringError object. template inline Error createStringError(std::error_code EC, char const *Fmt, - const Ts &... Vals) { + const Ts &...Vals) { std::string Buffer; raw_string_ostream Stream(Buffer); Stream << format(Fmt, Vals...); @@ -1215,7 +1243,7 @@ template inline Error createStringError(std::errc EC, char const *Fmt, - const Ts &... Vals) { + const Ts &...Vals) { return createStringError(std::make_error_code(EC), Fmt, Vals...); } @@ -1285,7 +1313,7 @@ return FileError::build(F, Optional(Line), std::move(E)); } -/// Concatenate a source file path and/or name with a std::error_code +/// Concatenate a source file path and/or name with a std::error_code /// to form an Error object. inline Error createFileError(const Twine &F, std::error_code EC) { return createFileError(F, errorCodeToError(EC)); @@ -1328,9 +1356,9 @@ return std::move(*E); } - /// Check E. If it's in a success state then return the contained reference. If - /// it's in a failure state log the error(s) and exit. - template T& operator()(Expected &&E) const { + /// Check E. If it's in a success state then return the contained reference. + /// If it's in a failure state log the error(s) and exit. + template T &operator()(Expected &&E) const { checkError(E.takeError()); return *E; }