| #ifndef C10_UTIL_EXCEPTION_H_ |
| #define C10_UTIL_EXCEPTION_H_ |
| |
| #include <c10/macros/Macros.h> |
| #include <c10/util/StringUtil.h> |
| |
| #include <cstddef> |
| #include <exception> |
| #include <string> |
| #include <variant> |
| #include <vector> |
| |
| #if defined(_MSC_VER) && _MSC_VER <= 1900 |
| #define __func__ __FUNCTION__ |
| #endif |
| |
| namespace c10 { |
| |
| /// The primary ATen error class. |
| /// Provides a complete error message with source location information via |
| /// `what()`, and a more concise message via `what_without_backtrace()`. |
| /// Don't throw this directly; use TORCH_CHECK/TORCH_INTERNAL_ASSERT instead. |
| /// |
| /// NB: c10::Error is handled specially by the default torch to suppress the |
| /// backtrace, see torch/csrc/Exceptions.h |
| class C10_API Error : public std::exception { |
| // The actual error message. |
| std::string msg_; |
| |
| // Context for the message (in order of decreasing specificity). Context will |
| // be automatically formatted appropriately, so it is not necessary to add |
| // extra leading/trailing newlines to strings inside this vector |
| std::vector<std::string> context_; |
| |
| // The C++ backtrace at the point when this exception was raised. This |
| // may be empty if there is no valid backtrace. (We don't use optional |
| // here to reduce the dependencies this file has.) |
| std::string backtrace_; |
| |
| // These two are derived fields from msg_stack_ and backtrace_, but we need |
| // fields for the strings so that we can return a const char* (as the |
| // signature of std::exception requires). Currently, the invariant |
| // is that these fields are ALWAYS populated consistently with respect |
| // to msg_stack_ and backtrace_. |
| std::string what_; |
| std::string what_without_backtrace_; |
| |
| // This is a little debugging trick: you can stash a relevant pointer |
| // in caller, and then when you catch the exception, you can compare |
| // against pointers you have on hand to get more information about |
| // where the exception came from. In Caffe2, this is used to figure |
| // out which operator raised an exception. |
| const void* caller_; |
| |
| public: |
| // PyTorch-style Error constructor. NB: the implementation of this |
| // is actually in Logging.cpp |
| Error(SourceLocation source_location, std::string msg); |
| |
| // Caffe2-style error message |
| Error( |
| const char* file, |
| const uint32_t line, |
| const char* condition, |
| const std::string& msg, |
| const std::string& backtrace, |
| const void* caller = nullptr); |
| |
| // Base constructor |
| Error(std::string msg, std::string backtrace, const void* caller = nullptr); |
| |
| // Add some new context to the message stack. The last added context |
| // will be formatted at the end of the context list upon printing. |
| // WARNING: This method is O(n) in the size of the stack, so don't go |
| // wild adding a ridiculous amount of context to error messages. |
| void add_context(std::string msg); |
| |
| const std::string& msg() const { |
| return msg_; |
| } |
| |
| const std::vector<std::string>& context() const { |
| return context_; |
| } |
| |
| const std::string& backtrace() const { |
| return backtrace_; |
| } |
| |
| /// Returns the complete error message, including the source location. |
| /// The returned pointer is invalidated if you call add_context() on |
| /// this object. |
| const char* what() const noexcept override { |
| return what_.c_str(); |
| } |
| |
| const void* caller() const noexcept { |
| return caller_; |
| } |
| |
| /// Returns only the error message string, without source location. |
| /// The returned pointer is invalidated if you call add_context() on |
| /// this object. |
| virtual const char* what_without_backtrace() const noexcept { |
| return what_without_backtrace_.c_str(); |
| } |
| |
| private: |
| void refresh_what(); |
| std::string compute_what(bool include_backtrace) const; |
| }; |
| |
| class C10_API Warning { |
| public: |
| class C10_API UserWarning {}; |
| class C10_API DeprecationWarning {}; |
| |
| using warning_variant_t = std::variant<UserWarning, DeprecationWarning>; |
| |
| Warning( |
| warning_variant_t type, |
| const SourceLocation& source_location, |
| std::string msg, |
| bool verbatim); |
| |
| Warning( |
| warning_variant_t type, |
| SourceLocation source_location, |
| const char* msg, |
| bool verbatim); |
| |
| Warning( |
| warning_variant_t type, |
| SourceLocation source_location, |
| ::c10::detail::CompileTimeEmptyString msg, |
| bool verbatim); |
| |
| // Getters for members |
| warning_variant_t type() const; |
| const SourceLocation& source_location() const; |
| const std::string& msg() const; |
| bool verbatim() const; |
| |
| private: |
| // The type of warning |
| warning_variant_t type_; |
| |
| // Where the warning happened. |
| SourceLocation source_location_; |
| |
| // The actual warning message. |
| std::string msg_; |
| |
| // See note: [Verbatim Warnings] |
| bool verbatim_; |
| }; |
| |
| using UserWarning = Warning::UserWarning; |
| using DeprecationWarning = Warning::DeprecationWarning; |
| |
| // Issue a warning with a given message. Dispatched to the current |
| // warning handler. |
| void C10_API warn(const Warning& warning); |
| |
| class C10_API WarningHandler { |
| public: |
| virtual ~WarningHandler() = default; |
| /// The default warning handler. Prints the message to stderr. |
| virtual void process(const Warning& warning); |
| }; |
| |
| namespace WarningUtils { |
| |
| // Note: [Verbatim Warnings] |
| // Warnings originating in C++ code can appear out-of-place to Python users: |
| // a user runs a line in Python, but the warning references a line in C++. |
| // Some parts of PyTorch, like the JIT, are cognizant of this mismatch |
| // and take care to map warnings back to the user's program, but most |
| // of PyTorch simply throws a context-free warning. To allow warning |
| // handlers to add context where appropriate, warn takes the |
| // "verbatim" flag. When this is false a warning handler might append |
| // the C++ warning to a Python warning message that relates the warning |
| // back to the user's program. Callers who have already accounted for |
| // context in their warnings should set verbatim to true so their warnings |
| // appear without modification. |
| |
| /// Sets the global warning handler. This is not thread-safe, so it should |
| /// generally be called once during initialization or while holding the GIL |
| /// for programs that use python. |
| /// User is responsible for keeping the WarningHandler alive until |
| /// it is not needed. |
| C10_API void set_warning_handler(WarningHandler* handler) noexcept(true); |
| /// Gets the global warning handler. |
| C10_API WarningHandler* get_warning_handler() noexcept(true); |
| |
| class C10_API WarningHandlerGuard { |
| WarningHandler* prev_handler_; |
| |
| public: |
| WarningHandlerGuard(WarningHandler* new_handler) |
| : prev_handler_(c10::WarningUtils::get_warning_handler()) { |
| c10::WarningUtils::set_warning_handler(new_handler); |
| } |
| ~WarningHandlerGuard() { |
| c10::WarningUtils::set_warning_handler(prev_handler_); |
| } |
| }; |
| |
| /// The TORCH_WARN_ONCE macro is difficult to test for. Use |
| /// setWarnAlways(true) to turn it into TORCH_WARN, which can be |
| /// tested for more easily. |
| C10_API void set_warnAlways(bool) noexcept(true); |
| C10_API bool get_warnAlways(void) noexcept(true); |
| |
| // A RAII guard that sets warn_always (not thread-local) on |
| // construction, and sets it back to the original value upon destruction. |
| struct C10_API WarnAlways { |
| public: |
| explicit WarnAlways(bool setting = true); |
| ~WarnAlways(); |
| |
| private: |
| bool prev_setting; |
| }; |
| |
| } // namespace WarningUtils |
| |
| // Like Error, but we always report the C++ backtrace, instead of only |
| // reporting when TORCH_SHOW_CPP_STACKTRACES |
| class C10_API ErrorAlwaysShowCppStacktrace : public Error { |
| using Error::Error; |
| const char* what_without_backtrace() const noexcept override { |
| return what(); |
| } |
| }; |
| |
| // Used in ATen for out-of-bound indices that can reasonably only be detected |
| // lazily inside a kernel (See: advanced indexing). These turn into |
| // IndexError when they cross to Python. |
| class C10_API IndexError : public Error { |
| using Error::Error; |
| }; |
| |
| // Used in ATen for invalid values. These turn into |
| // ValueError when they cross to Python. |
| class C10_API ValueError : public Error { |
| using Error::Error; |
| }; |
| |
| // Used in ATen for invalid types. These turn into |
| // TypeError when they cross to Python. |
| class C10_API TypeError : public Error { |
| using Error::Error; |
| }; |
| |
| // Used in ATen for functionality that is not implemented. These turn into |
| // NotImplementedError when they cross to Python. |
| class C10_API NotImplementedError : public Error { |
| using Error::Error; |
| }; |
| |
| // Used in ATen for non finite indices. These turn into |
| // ExitException when they cross to Python. |
| class C10_API EnforceFiniteError : public Error { |
| using Error::Error; |
| }; |
| |
| // Used in Onnxifi backend lowering. These turn into |
| // ExitException when they cross to Python. |
| class C10_API OnnxfiBackendSystemError : public Error { |
| using Error::Error; |
| }; |
| |
| // Used for numerical errors from the linalg module. These |
| // turn into LinAlgError when they cross into Python. |
| class C10_API LinAlgError : public Error { |
| using Error::Error; |
| }; |
| |
| class C10_API OutOfMemoryError : public Error { |
| using Error::Error; |
| }; |
| |
| // Base error type for all distributed errors. |
| // These turn into DistError when they cross into Python. |
| class C10_API DistError : public Error { |
| using Error::Error; |
| }; |
| |
| // Used for collective communication library errors from the distributed module. |
| // These turn into DistBackendError when they cross into Python. |
| class C10_API DistBackendError : public DistError { |
| using DistError::DistError; |
| }; |
| |
| // Used for errors originating from the store. |
| // These turn into DistStoreError when they cross into Python. |
| class C10_API DistStoreError : public DistError { |
| using DistError::DistError; |
| }; |
| |
| // Used for errors originating from the TCP/IP stack and not from collective |
| // libraries. These turn into DistNetworkError when they cross into Python. |
| class C10_API DistNetworkError : public DistError { |
| using DistError::DistError; |
| }; |
| |
| // A utility function to return an exception std::string by prepending its |
| // exception type before its what() content |
| C10_API std::string GetExceptionString(const std::exception& e); |
| |
| } // namespace c10 |
| |
| // Private helper macro for implementing TORCH_INTERNAL_ASSERT and TORCH_CHECK |
| // |
| // Note: In the debug build With MSVC, __LINE__ might be of long type (a.k.a |
| // int32_t), which is different from the definition of `SourceLocation` that |
| // requires unsigned int (a.k.a uint32_t) and may cause a compile error with the |
| // message: error C2397: conversion from 'long' to 'uint32_t' requires a |
| // narrowing conversion Here the static cast is used to pass the build. if this |
| // is used inside a lambda the __func__ macro expands to operator(), which isn't |
| // very useful, but hard to fix in a macro so suppressing the warning. |
| #define C10_THROW_ERROR(err_type, msg) \ |
| throw ::c10::err_type( \ |
| {__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, msg) |
| |
| // Private helper macro for workaround MSVC misexpansion of nested macro |
| // invocations involving __VA_ARGS__. See |
| // https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly |
| #define C10_EXPAND_MSVC_WORKAROUND(x) x |
| |
| // On nvcc, C10_UNLIKELY thwarts missing return statement analysis. In cases |
| // where the unlikely expression may be a constant, use this macro to ensure |
| // return statement analysis keeps working (at the cost of not getting the |
| // likely/unlikely annotation on nvcc). |
| // https://github.com/pytorch/pytorch/issues/21418 |
| // |
| // Currently, this is only used in the error reporting macros below. If you |
| // want to use it more generally, move me to Macros.h |
| // |
| // TODO: Brian Vaughan observed that we might be able to get this to work on |
| // nvcc by writing some sort of C++ overload that distinguishes constexpr inputs |
| // from non-constexpr. Since there isn't any evidence that losing C10_UNLIKELY |
| // in nvcc is causing us perf problems, this is not yet implemented, but this |
| // might be an interesting piece of C++ code for an intrepid bootcamper to |
| // write. |
| #if defined(__CUDACC__) |
| #define C10_UNLIKELY_OR_CONST(e) e |
| #else |
| #define C10_UNLIKELY_OR_CONST(e) C10_UNLIKELY(e) |
| #endif |
| |
| // ---------------------------------------------------------------------------- |
| // Error reporting macros |
| // ---------------------------------------------------------------------------- |
| |
| #ifdef STRIP_ERROR_MESSAGES |
| #define TORCH_RETHROW(e, ...) throw |
| #else |
| #define TORCH_RETHROW(e, ...) \ |
| do { \ |
| e.add_context(::c10::str(__VA_ARGS__)); \ |
| throw; \ |
| } while (false) |
| #endif |
| |
| // A utility macro to provide assert()-like functionality; that is, enforcement |
| // of internal invariants in code. It supports an arbitrary number of extra |
| // arguments (evaluated only on failure), which will be printed in the assert |
| // failure message using operator<< (this is useful to print some variables |
| // which may be useful for debugging.) |
| // |
| // Usage: |
| // TORCH_INTERNAL_ASSERT(should_be_true); |
| // TORCH_INTERNAL_ASSERT(x == 0, "x = ", x); |
| // |
| // Assuming no bugs in PyTorch, the conditions tested by this macro should |
| // always be true; e.g., it should be possible to disable all of these |
| // conditions without changing observable user behavior. If you would like to |
| // do error reporting for user input, please use TORCH_CHECK instead. |
| // |
| // NOTE: It is SAFE to use this macro in production code; on failure, this |
| // simply raises an exception, it does NOT unceremoniously quit the process |
| // (unlike assert()). |
| // |
| #ifdef STRIP_ERROR_MESSAGES |
| #define TORCH_INTERNAL_ASSERT(cond, ...) \ |
| if (C10_UNLIKELY_OR_CONST(!(cond))) { \ |
| ::c10::detail::torchCheckFail( \ |
| __func__, \ |
| __FILE__, \ |
| static_cast<uint32_t>(__LINE__), \ |
| #cond " INTERNAL ASSERT FAILED at " C10_STRINGIZE(__FILE__)); \ |
| } |
| #else |
| // It would be nice if we could build a combined string literal out of |
| // the TORCH_INTERNAL_ASSERT prefix and a user-provided string literal |
| // as the first argument, but there doesn't seem to be any good way to |
| // do that while still supporting having a first argument that isn't a |
| // string literal. |
| #define TORCH_INTERNAL_ASSERT(cond, ...) \ |
| if (C10_UNLIKELY_OR_CONST(!(cond))) { \ |
| ::c10::detail::torchInternalAssertFail( \ |
| __func__, \ |
| __FILE__, \ |
| static_cast<uint32_t>(__LINE__), \ |
| #cond \ |
| " INTERNAL ASSERT FAILED at " C10_STRINGIZE(__FILE__) ":" C10_STRINGIZE( \ |
| __LINE__) ", please report a bug to PyTorch. ", \ |
| c10::str(__VA_ARGS__)); \ |
| } |
| #endif |
| |
| // A utility macro to make it easier to test for error conditions from user |
| // input. Like TORCH_INTERNAL_ASSERT, it supports an arbitrary number of extra |
| // arguments (evaluated only on failure), which will be printed in the error |
| // message using operator<< (e.g., you can pass any object which has |
| // operator<< defined. Most objects in PyTorch have these definitions!) |
| // |
| // Usage: |
| // TORCH_CHECK(should_be_true); // A default error message will be provided |
| // // in this case; but we recommend writing an |
| // // explicit error message, as it is more |
| // // user friendly. |
| // TORCH_CHECK(x == 0, "Expected x to be 0, but got ", x); |
| // |
| // On failure, this macro will raise an exception. If this exception propagates |
| // to Python, it will convert into a Python RuntimeError. |
| // |
| // NOTE: It is SAFE to use this macro in production code; on failure, this |
| // simply raises an exception, it does NOT unceremoniously quit the process |
| // (unlike CHECK() from glog.) |
| // |
| #define TORCH_CHECK_WITH(error_t, cond, ...) \ |
| TORCH_CHECK_WITH_MSG(error_t, cond, "", __VA_ARGS__) |
| |
| #ifdef STRIP_ERROR_MESSAGES |
| #define TORCH_CHECK_MSG(cond, type, ...) \ |
| (#cond #type " CHECK FAILED at " C10_STRINGIZE(__FILE__)) |
| #define TORCH_CHECK_WITH_MSG(error_t, cond, type, ...) \ |
| if (C10_UNLIKELY_OR_CONST(!(cond))) { \ |
| C10_THROW_ERROR(Error, TORCH_CHECK_MSG(cond, type, __VA_ARGS__)); \ |
| } |
| #else |
| namespace c10 { |
| namespace detail { |
| template <typename... Args> |
| decltype(auto) torchCheckMsgImpl(const char* /*msg*/, const Args&... args) { |
| return ::c10::str(args...); |
| } |
| inline C10_API const char* torchCheckMsgImpl(const char* msg) { |
| return msg; |
| } |
| // If there is just 1 user-provided C-string argument, use it. |
| inline C10_API const char* torchCheckMsgImpl( |
| const char* /*msg*/, |
| const char* args) { |
| return args; |
| } |
| } // namespace detail |
| } // namespace c10 |
| |
| #define TORCH_CHECK_MSG(cond, type, ...) \ |
| (::c10::detail::torchCheckMsgImpl( \ |
| "Expected " #cond \ |
| " to be true, but got false. " \ |
| "(Could this error message be improved? If so, " \ |
| "please report an enhancement request to PyTorch.)", \ |
| ##__VA_ARGS__)) |
| #define TORCH_CHECK_WITH_MSG(error_t, cond, type, ...) \ |
| if (C10_UNLIKELY_OR_CONST(!(cond))) { \ |
| C10_THROW_ERROR(error_t, TORCH_CHECK_MSG(cond, type, __VA_ARGS__)); \ |
| } |
| #endif |
| |
| namespace c10 { |
| namespace detail { |
| |
| [[noreturn]] C10_API void torchCheckFail( |
| const char* func, |
| const char* file, |
| uint32_t line, |
| const std::string& msg); |
| [[noreturn]] C10_API void torchCheckFail( |
| const char* func, |
| const char* file, |
| uint32_t line, |
| const char* msg); |
| |
| // The c10::str() call that creates userMsg can have 1 of 3 return |
| // types depending on the number and types of arguments passed to |
| // TORCH_INTERNAL_ASSERT. 0 arguments will get a |
| // CompileTimeEmptyString, 1 const char * will be passed straight |
| // through, and anything else will get converted to std::string. |
| [[noreturn]] C10_API void torchInternalAssertFail( |
| const char* func, |
| const char* file, |
| uint32_t line, |
| const char* condMsg, |
| const char* userMsg); |
| [[noreturn]] inline C10_API void torchInternalAssertFail( |
| const char* func, |
| const char* file, |
| uint32_t line, |
| const char* condMsg, |
| ::c10::detail::CompileTimeEmptyString /*userMsg*/) { |
| torchCheckFail(func, file, line, condMsg); |
| } |
| [[noreturn]] C10_API void torchInternalAssertFail( |
| const char* func, |
| const char* file, |
| uint32_t line, |
| const char* condMsg, |
| const std::string& userMsg); |
| |
| } // namespace detail |
| } // namespace c10 |
| |
| #ifdef STRIP_ERROR_MESSAGES |
| #define TORCH_CHECK(cond, ...) \ |
| if (C10_UNLIKELY_OR_CONST(!(cond))) { \ |
| ::c10::detail::torchCheckFail( \ |
| __func__, \ |
| __FILE__, \ |
| static_cast<uint32_t>(__LINE__), \ |
| TORCH_CHECK_MSG(cond, "", __VA_ARGS__)); \ |
| } |
| #else |
| #define TORCH_CHECK(cond, ...) \ |
| if (C10_UNLIKELY_OR_CONST(!(cond))) { \ |
| ::c10::detail::torchCheckFail( \ |
| __func__, \ |
| __FILE__, \ |
| static_cast<uint32_t>(__LINE__), \ |
| TORCH_CHECK_MSG(cond, "", ##__VA_ARGS__)); \ |
| } |
| #endif |
| |
| // An utility macro that does what `TORCH_CHECK` does if compiled in the host |
| // code, otherwise does nothing. Supposed to be used in the code shared between |
| // host and device code as an alternative for `TORCH_CHECK`. |
| #if defined(__CUDACC__) || defined(__HIPCC__) |
| #define TORCH_CHECK_IF_NOT_ON_CUDA(cond, ...) |
| #else |
| #define TORCH_CHECK_IF_NOT_ON_CUDA(cond, ...) TORCH_CHECK(cond, ##__VA_ARGS__) |
| #endif |
| |
| // Debug only version of TORCH_INTERNAL_ASSERT. This macro only checks in debug |
| // build, and does nothing in release build. It is appropriate to use |
| // in situations where you want to add an assert to a hotpath, but it is |
| // too expensive to run this assert on production builds. |
| #ifdef NDEBUG |
| // Optimized version - generates no code. |
| #define TORCH_INTERNAL_ASSERT_DEBUG_ONLY(...) \ |
| while (false) \ |
| C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__)) |
| #else |
| #define TORCH_INTERNAL_ASSERT_DEBUG_ONLY(...) \ |
| C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__)) |
| #endif |
| |
| // TODO: We're going to get a lot of similar looking string literals |
| // this way; check if this actually affects binary size. |
| |
| // Like TORCH_CHECK, but raises LinAlgError instead of Error. |
| #define TORCH_CHECK_LINALG(cond, ...) \ |
| TORCH_CHECK_WITH_MSG(LinAlgError, cond, "LINALG", __VA_ARGS__) |
| |
| // Like TORCH_CHECK, but raises IndexErrors instead of Errors. |
| #define TORCH_CHECK_INDEX(cond, ...) \ |
| TORCH_CHECK_WITH_MSG(IndexError, cond, "INDEX", __VA_ARGS__) |
| |
| // Like TORCH_CHECK, but raises ValueErrors instead of Errors. |
| #define TORCH_CHECK_VALUE(cond, ...) \ |
| TORCH_CHECK_WITH_MSG(ValueError, cond, "VALUE", __VA_ARGS__) |
| |
| // Like TORCH_CHECK, but raises TypeErrors instead of Errors. |
| #define TORCH_CHECK_TYPE(cond, ...) \ |
| TORCH_CHECK_WITH_MSG(TypeError, cond, "TYPE", __VA_ARGS__) |
| |
| // Like TORCH_CHECK, but raises NotImplementedErrors instead of Errors. |
| #define TORCH_CHECK_NOT_IMPLEMENTED(cond, ...) \ |
| TORCH_CHECK_WITH_MSG(NotImplementedError, cond, "TYPE", __VA_ARGS__) |
| |
| #define TORCH_CHECK_ALWAYS_SHOW_CPP_STACKTRACE(cond, ...) \ |
| TORCH_CHECK_WITH_MSG(ErrorAlwaysShowCppStacktrace, cond, "TYPE", __VA_ARGS__) |
| |
| #ifdef STRIP_ERROR_MESSAGES |
| #define WARNING_MESSAGE_STRING(...) \ |
| ::c10::detail::CompileTimeEmptyString {} |
| #else |
| #define WARNING_MESSAGE_STRING(...) ::c10::str(__VA_ARGS__) |
| #endif |
| |
| // Report a warning to the user. Accepts an arbitrary number of extra |
| // arguments which are concatenated into the warning message using operator<< |
| // |
| #ifdef DISABLE_WARN |
| #define _TORCH_WARN_WITH(...) ((void)0); |
| #else |
| #define _TORCH_WARN_WITH(warning_t, ...) \ |
| ::c10::warn(::c10::Warning( \ |
| warning_t(), \ |
| {__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, \ |
| WARNING_MESSAGE_STRING(__VA_ARGS__), \ |
| false)); |
| #endif |
| |
| #define TORCH_WARN(...) _TORCH_WARN_WITH(::c10::UserWarning, __VA_ARGS__); |
| |
| #define TORCH_WARN_DEPRECATION(...) \ |
| _TORCH_WARN_WITH(::c10::DeprecationWarning, __VA_ARGS__); |
| |
| // Report a warning to the user only once. Accepts an arbitrary number of extra |
| // arguments which are concatenated into the warning message using operator<< |
| // |
| #define _TORCH_WARN_ONCE(...) \ |
| C10_UNUSED static const auto C10_ANONYMOUS_VARIABLE(torch_warn_once_) = \ |
| [&] { \ |
| TORCH_WARN(__VA_ARGS__); \ |
| return true; \ |
| }() |
| |
| #ifdef DISABLE_WARN |
| #define TORCH_WARN_ONCE(...) ((void)0); |
| #else |
| #define TORCH_WARN_ONCE(...) \ |
| if (::c10::WarningUtils::get_warnAlways()) { \ |
| TORCH_WARN(__VA_ARGS__); \ |
| } else { \ |
| _TORCH_WARN_ONCE(__VA_ARGS__); \ |
| } |
| #endif |
| |
| // Report an error with a specific argument |
| // NOTE: using the argument name in TORCH_CHECK's message is preferred |
| #define TORCH_CHECK_ARG(cond, argN, ...) \ |
| TORCH_CHECK(cond, "invalid argument ", argN, ": ", __VA_ARGS__) |
| |
| // ---------------------------------------------------------------------------- |
| // Deprecated macros |
| // ---------------------------------------------------------------------------- |
| |
| namespace c10 { |
| namespace detail { |
| |
| /* |
| // Deprecation disabled until we fix sites in our codebase |
| C10_DEPRECATED_MESSAGE("AT_ERROR(msg) is deprecated, use TORCH_CHECK(false, msg) |
| instead.") |
| */ |
| inline void deprecated_AT_ERROR() {} |
| |
| /* |
| // Deprecation disabled until we fix sites in our codebase |
| C10_DEPRECATED_MESSAGE("AT_ASSERT is deprecated, if you mean to indicate an |
| internal invariant failure, use " \ |
| "TORCH_INTERNAL_ASSERT instead; if you mean to do user |
| error checking, use " \ "TORCH_CHECK. See |
| https://github.com/pytorch/pytorch/issues/20287 for more details.") |
| */ |
| inline void deprecated_AT_ASSERT() {} |
| |
| /* |
| // Deprecation disabled until we fix sites in our codebase |
| C10_DEPRECATED_MESSAGE("AT_ASSERTM is deprecated, if you mean to indicate an |
| internal invariant failure, use " \ |
| "TORCH_INTERNAL_ASSERT instead; if you mean to do user |
| error checking, use " \ "TORCH_CHECK. See |
| https://github.com/pytorch/pytorch/issues/20287 for more details.") |
| */ |
| inline void deprecated_AT_ASSERTM() {} |
| |
| } // namespace detail |
| } // namespace c10 |
| |
| // Deprecated alias; this alias was deprecated because people kept mistakenly |
| // using it for user error checking. Use TORCH_INTERNAL_ASSERT or TORCH_CHECK |
| // instead. See https://github.com/pytorch/pytorch/issues/20287 for more |
| // details. |
| #define AT_ASSERT(...) \ |
| do { \ |
| ::c10::detail::deprecated_AT_ASSERT(); \ |
| C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__)); \ |
| } while (false) |
| |
| // Deprecated alias, like AT_ASSERT. The new TORCH_INTERNAL_ASSERT macro |
| // supports both 0-ary and variadic calls, so having a separate |
| // message-accepting macro is not necessary. |
| // |
| // NB: we MUST include cond explicitly here, as MSVC will miscompile the macro |
| // expansion, shunting all of __VA_ARGS__ to cond. An alternate workaround |
| // can be seen at |
| // https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly |
| #define AT_ASSERTM(cond, ...) \ |
| do { \ |
| ::c10::detail::deprecated_AT_ASSERTM(); \ |
| C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(cond, __VA_ARGS__)); \ |
| } while (false) |
| |
| // Deprecated alias; this alias was deprecated because it represents extra API |
| // surface that makes it hard for people to understand what macro to use. |
| // Use TORCH_CHECK(false, ...) or TORCH_INTERNAL_ASSERT(false, ...) to |
| // unconditionally fail at a line of code. |
| #define AT_ERROR(...) \ |
| do { \ |
| ::c10::detail::deprecated_AT_ERROR(); \ |
| C10_EXPAND_MSVC_WORKAROUND(TORCH_CHECK(false, ::c10::str(__VA_ARGS__))); \ |
| } while (false) |
| |
| #endif // C10_UTIL_EXCEPTION_H_ |