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 @@ -700,20 +700,27 @@ /// /// cantFail(foo(false)); /// @endcode -inline void cantFail(Error Err, const char *Msg = nullptr) { +inline void cantFail(Error Err, const char *Msg = nullptr, + const char *file = nullptr, unsigned line = 0) { if (Err) { if (!Msg) Msg = "Failure value returned from cantFail wrapped call"; #ifndef NDEBUG std::string Str; raw_string_ostream OS(Str); - OS << Msg << "\n" << Err; + OS << Err << "\n" << Msg; + if (file) + OS << " at " << file << ":" << line; Msg = OS.str().c_str(); #endif llvm_unreachable(Msg); } } +inline void cantFail(Error Err, const char *file, unsigned line) { + cantFail(std::move(Err), nullptr, file, line); +} + /// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and /// returns the contained value. /// @@ -728,7 +735,8 @@ /// int X = cantFail(foo(false)); /// @endcode template -T cantFail(Expected ValOrErr, const char *Msg = nullptr) { +T cantFail(Expected ValOrErr, const char *Msg = nullptr, + const char *file = nullptr, unsigned line = 0) { if (ValOrErr) return std::move(*ValOrErr); else { @@ -738,13 +746,20 @@ std::string Str; raw_string_ostream OS(Str); auto E = ValOrErr.takeError(); - OS << Msg << "\n" << E; + OS << E << "\n" << Msg; + if (file) + OS << " at " << file << ":" << line; Msg = OS.str().c_str(); #endif llvm_unreachable(Msg); } } +template +T cantFail(Expected ValOrErr, const char *file, unsigned line) { + return cantFail>(std::move(ValOrErr), nullptr, file, line); +} + /// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and /// returns the contained reference. /// @@ -759,7 +774,8 @@ /// Bar &X = cantFail(foo(false)); /// @endcode template -T& cantFail(Expected ValOrErr, const char *Msg = nullptr) { +T &cantFail(Expected ValOrErr, const char *Msg = nullptr, + const char *file = nullptr, unsigned line = 0) { if (ValOrErr) return *ValOrErr; else { @@ -769,13 +785,26 @@ std::string Str; raw_string_ostream OS(Str); auto E = ValOrErr.takeError(); - OS << Msg << "\n" << E; + OS << E << "\n" << Msg; + if (file) + OS << " at " << file << ":" << line;; Msg = OS.str().c_str(); #endif llvm_unreachable(Msg); } } +template +T &cantFail(Expected ValOrErr, const char *file, unsigned line) { + return cantFail>(std::move(ValOrErr), nullptr, file, line); +} + +#ifndef NDEBUG +#define llvm_cantFail(...) ::llvm::cantFail(__VA_ARGS__, __FILE__, __LINE__) +#else +#define llvm_cantFail(...) ::llvm::cantFail(__VA_ARGS__) +#endif + /// Helper for testing applicability of, and applying, handlers for /// ErrorInfo types. template @@ -922,13 +951,13 @@ /// errors after running the handlers, or llvm_unreachable is called). template void handleAllErrors(Error E, HandlerTs &&... Handlers) { - cantFail(handleErrors(std::move(E), std::forward(Handlers)...)); + llvm_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)); + llvm_cantFail(std::move(E)); } /// Handle any errors (if present) in an Expected, then try a recovery path. diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp --- a/llvm/unittests/Support/ErrorTest.cpp +++ b/llvm/unittests/Support/ErrorTest.cpp @@ -390,8 +390,8 @@ }; EXPECT_DEATH(FailToHandle(), - "Failure value returned from cantFail wrapped call\n" - "CustomError \\{7\\}") + "CustomError \\{7\\}\n" + "Failure value returned from cantFail wrapped call") << "Unhandled Error in handleAllErrors call did not cause an " "abort()"; } @@ -410,8 +410,8 @@ }; EXPECT_DEATH(ReturnErrorFromHandler(), - "Failure value returned from cantFail wrapped call\n" - "CustomError \\{7\\}") + "CustomError \\{7\\}\n" + "Failure value returned from cantFail wrapped call") << " Error returned from handler in handleAllErrors call did not " "cause abort()"; } @@ -515,8 +515,8 @@ EXPECT_DEATH(cantFail(make_error("Original error message", inconvertibleErrorCode()), "Cantfail call failed"), - "Cantfail call failed\n" - "Original error message") + "Original error message\n" + "Cantfail call failed") << "cantFail(Error) did not cause an abort for failure value"; EXPECT_DEATH( @@ -530,6 +530,24 @@ } #endif +TEST(Error, CantFailSourceLocation) { + std::string ErrStr; + raw_string_ostream OS(ErrStr); + OS << "\nFailure value returned from cantFail wrapped call"; + +#if defined(NDEBUG) + // __FILE__ and __LINE_ not added + OS << "\n"; + EXPECT_DEATH(llvm_cantFail(make_error(1)), OS.str()) + << "cantFail(Error) did not cause an abort for failure value"; +#else + // __FILE__ and __LINE__ added + int Line = __LINE__; + OS << " at " << __FILE__ << ":" << (Line + 2) << "\n"; + EXPECT_DEATH(llvm_cantFail(make_error(1)), OS.str()) + << "cantFail(Error) did not cause an abort for failure value"; +#endif +} // Test Checked Expected in success mode. TEST(Error, CheckedExpectedInSuccessMode) {