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,14 +700,17 @@ /// /// 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); @@ -728,7 +731,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,7 +742,9 @@ 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); @@ -759,7 +765,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 +776,30 @@ 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); } } +#define llvm_cantFail_1_arg_macro(E, F, L) ::llvm::cantFail(E, nullptr, F, L) +#define llvm_cantFail_2_arg_marco(E, Msg, F, L) ::llvm::cantFail(E, Msg, F, L) + +#define llvm_cantFail_get_macro(arg1, arg2, macro, ...) macro +#define llvm_cantFail_macro_chooser(...) \ + llvm_cantFail_get_macro(__VA_ARGS__, llvm_cantFail_2_arg_macro, \ + llvm_cantFail_1_arg_macro, ) + +#ifndef NDEBUG +#define llvm_cantFail(...) \ + llvm_cantFail_macro_chooser(__VA_ARGS__)(__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 +946,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) {