xref: /aosp_15_r20/external/pytorch/c10/util/Exception.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1 #ifndef C10_UTIL_EXCEPTION_H_
2 #define C10_UTIL_EXCEPTION_H_
3 
4 #include <c10/macros/Export.h>
5 #include <c10/macros/Macros.h>
6 #include <c10/util/Backtrace.h>
7 #include <c10/util/Lazy.h>
8 #include <c10/util/StringUtil.h>
9 
10 #include <cstdint>
11 #include <exception>
12 #include <memory>
13 #include <string>
14 #include <variant>
15 #include <vector>
16 
17 #if defined(_MSC_VER) && _MSC_VER <= 1900
18 #define __func__ __FUNCTION__
19 #endif
20 
21 namespace c10 {
22 
23 /// The primary ATen error class.
24 /// Provides a complete error message with source location information via
25 /// `what()`, and a more concise message via `what_without_backtrace()`.
26 /// Don't throw this directly; use TORCH_CHECK/TORCH_INTERNAL_ASSERT instead.
27 ///
28 /// NB: c10::Error is handled specially by the default torch to suppress the
29 /// backtrace, see torch/csrc/Exceptions.h
30 class C10_API Error : public std::exception {
31  private:
32   // The actual error message.
33   std::string msg_;
34 
35   // Context for the message (in order of decreasing specificity).  Context will
36   // be automatically formatted appropriately, so it is not necessary to add
37   // extra leading/trailing newlines to strings inside this vector
38   std::vector<std::string> context_;
39 
40   // The C++ backtrace at the point when this exception was raised.  This
41   // may be empty if there is no valid backtrace.  (We don't use optional
42   // here to reduce the dependencies this file has.)
43   Backtrace backtrace_;
44 
45   // These two are derived fields from msg_stack_ and backtrace_, but we need
46   // fields for the strings so that we can return a const char* (as the
47   // signature of std::exception requires).  Currently, the invariant
48   // is that these fields are ALWAYS populated consistently with respect
49   // to msg_stack_ and backtrace_.
50   mutable OptimisticLazy<std::string> what_;
51   std::string what_without_backtrace_;
52 
53   // This is a little debugging trick: you can stash a relevant pointer
54   // in caller, and then when you catch the exception, you can compare
55   // against pointers you have on hand to get more information about
56   // where the exception came from.  In Caffe2, this is used to figure
57   // out which operator raised an exception.
58   const void* caller_;
59 
60  public:
61   // PyTorch-style Error constructor.  NB: the implementation of this
62   // is actually in Logging.cpp
63   Error(SourceLocation source_location, std::string msg);
64 
65   // Caffe2-style error message
66   Error(
67       const char* file,
68       const uint32_t line,
69       const char* condition,
70       const std::string& msg,
71       Backtrace backtrace,
72       const void* caller = nullptr);
73 
74   // Base constructor
75   Error(
76       std::string msg,
77       Backtrace backtrace = nullptr,
78       const void* caller = nullptr);
79 
80   // Add some new context to the message stack.  The last added context
81   // will be formatted at the end of the context list upon printing.
82   // WARNING: This method is O(n) in the size of the stack, so don't go
83   // wild adding a ridiculous amount of context to error messages.
84   void add_context(std::string msg);
85 
msg()86   const std::string& msg() const {
87     return msg_;
88   }
89 
context()90   const std::vector<std::string>& context() const {
91     return context_;
92   }
93 
94   const Backtrace& backtrace() const;
95 
96   /// Returns the complete error message, including the source location.
97   /// The returned pointer is invalidated if you call add_context() on
98   /// this object.
99   const char* what() const noexcept override;
100 
caller()101   const void* caller() const noexcept {
102     return caller_;
103   }
104 
105   /// Returns only the error message string, without source location.
106   /// The returned pointer is invalidated if you call add_context() on
107   /// this object.
what_without_backtrace()108   virtual const char* what_without_backtrace() const noexcept {
109     return what_without_backtrace_.c_str();
110   }
111 
112  private:
113   void refresh_what();
114   std::string compute_what(bool include_backtrace) const;
115 };
116 
117 class C10_API Warning {
118  public:
119   class C10_API UserWarning {};
120   class C10_API DeprecationWarning {};
121 
122   using warning_variant_t = std::variant<UserWarning, DeprecationWarning>;
123 
124   Warning(
125       warning_variant_t type,
126       const SourceLocation& source_location,
127       std::string msg,
128       bool verbatim);
129 
130   Warning(
131       warning_variant_t type,
132       SourceLocation source_location,
133       const char* msg,
134       bool verbatim);
135 
136   Warning(
137       warning_variant_t type,
138       SourceLocation source_location,
139       ::c10::detail::CompileTimeEmptyString msg,
140       bool verbatim);
141 
142   // Getters for members
143   warning_variant_t type() const;
144   const SourceLocation& source_location() const;
145   const std::string& msg() const;
146   bool verbatim() const;
147 
148  private:
149   // The type of warning
150   warning_variant_t type_;
151 
152   // Where the warning happened.
153   SourceLocation source_location_;
154 
155   // The actual warning message.
156   std::string msg_;
157 
158   // See note: [Verbatim Warnings]
159   bool verbatim_;
160 };
161 
162 using UserWarning = Warning::UserWarning;
163 using DeprecationWarning = Warning::DeprecationWarning;
164 
165 // Issue a warning with a given message. Dispatched to the current
166 // warning handler.
167 void C10_API warn(const Warning& warning);
168 
169 class C10_API WarningHandler {
170  public:
171   virtual ~WarningHandler() = default;
172   /// The default warning handler. Prints the message to stderr.
173   virtual void process(const Warning& warning);
174 };
175 
176 namespace WarningUtils {
177 
178 // Note: [Verbatim Warnings]
179 // Warnings originating in C++ code can appear out-of-place to Python users:
180 // a user runs a line in Python, but the warning references a line in C++.
181 // Some parts of PyTorch, like the JIT, are cognizant of this mismatch
182 // and take care to map warnings back to the user's program, but most
183 // of PyTorch simply throws a context-free warning. To allow warning
184 // handlers to add context where appropriate, warn takes the
185 // "verbatim" flag. When this is false a warning handler might append
186 // the C++ warning to a Python warning message that relates the warning
187 // back to the user's program. Callers who have already accounted for
188 // context in their warnings should set verbatim to true so their warnings
189 // appear without modification.
190 
191 /// Sets the global warning handler. This is not thread-safe, so it should
192 /// generally be called once during initialization or while holding the GIL
193 /// for programs that use python.
194 /// User is responsible for keeping the WarningHandler alive until
195 /// it is not needed.
196 C10_API void set_warning_handler(WarningHandler* handler) noexcept(true);
197 /// Gets the global warning handler.
198 C10_API WarningHandler* get_warning_handler() noexcept(true);
199 
200 class C10_API WarningHandlerGuard {
201   WarningHandler* prev_handler_;
202 
203  public:
WarningHandlerGuard(WarningHandler * new_handler)204   WarningHandlerGuard(WarningHandler* new_handler)
205       : prev_handler_(c10::WarningUtils::get_warning_handler()) {
206     c10::WarningUtils::set_warning_handler(new_handler);
207   }
~WarningHandlerGuard()208   ~WarningHandlerGuard() {
209     c10::WarningUtils::set_warning_handler(prev_handler_);
210   }
211 };
212 
213 /// The TORCH_WARN_ONCE macro is difficult to test for. Use
214 /// setWarnAlways(true) to turn it into TORCH_WARN, which can be
215 /// tested for more easily.
216 C10_API void set_warnAlways(bool) noexcept(true);
217 C10_API bool get_warnAlways() noexcept(true);
218 
219 // A RAII guard that sets warn_always (not thread-local) on
220 // construction, and sets it back to the original value upon destruction.
221 struct C10_API WarnAlways {
222  public:
223   explicit WarnAlways(bool setting = true);
224   ~WarnAlways();
225 
226  private:
227   bool prev_setting;
228 };
229 
230 } // namespace WarningUtils
231 
232 // Like Error, but we always report the C++ backtrace, instead of only
233 // reporting when TORCH_SHOW_CPP_STACKTRACES
234 class C10_API ErrorAlwaysShowCppStacktrace : public Error {
235   using Error::Error;
what_without_backtrace()236   const char* what_without_backtrace() const noexcept override {
237     return what();
238   }
239 };
240 
241 // Used in ATen for out-of-bound indices that can reasonably only be detected
242 // lazily inside a kernel (See: advanced indexing).  These turn into
243 // IndexError when they cross to Python.
244 class C10_API IndexError : public Error {
245   using Error::Error;
246 };
247 
248 // Used in ATen for invalid values.  These turn into
249 // ValueError when they cross to Python.
250 class C10_API ValueError : public Error {
251   using Error::Error;
252 };
253 
254 // Used in ATen for invalid types.  These turn into
255 // TypeError when they cross to Python.
256 class C10_API TypeError : public Error {
257   using Error::Error;
258 };
259 
260 // Used in ATen for functionality that is not implemented.  These turn into
261 // NotImplementedError when they cross to Python.
262 class C10_API NotImplementedError : public Error {
263   using Error::Error;
264 };
265 
266 // Used in ATen for non finite indices.  These turn into
267 // ExitException when they cross to Python.
268 class C10_API EnforceFiniteError : public Error {
269   using Error::Error;
270 };
271 
272 // Used in Onnxifi backend lowering.  These turn into
273 // ExitException when they cross to Python.
274 class C10_API OnnxfiBackendSystemError : public Error {
275   using Error::Error;
276 };
277 
278 // Used for numerical errors from the linalg module. These
279 // turn into LinAlgError when they cross into Python.
280 class C10_API LinAlgError : public Error {
281   using Error::Error;
282 };
283 
284 class C10_API OutOfMemoryError : public Error {
285   using Error::Error;
286 };
287 
288 // Base error type for all distributed errors.
289 // These turn into DistError when they cross into Python.
290 class C10_API DistError : public Error {
291   using Error::Error;
292 };
293 
294 // Used for collective communication library errors from the distributed module.
295 // These turn into DistBackendError when they cross into Python.
296 class C10_API DistBackendError : public DistError {
297   using DistError::DistError;
298 };
299 
300 // Used for errors originating from the store.
301 // These turn into DistStoreError when they cross into Python.
302 class C10_API DistStoreError : public DistError {
303   using DistError::DistError;
304 };
305 
306 // Used for errors originating from the TCP/IP stack and not from collective
307 // libraries. These turn into DistNetworkError when they cross into Python.
308 class C10_API DistNetworkError : public DistError {
309   using DistError::DistError;
310 };
311 
312 // A utility function to return an exception std::string by prepending its
313 // exception type before its what() content
314 C10_API std::string GetExceptionString(const std::exception& e);
315 
316 } // namespace c10
317 
318 // Private helper macro for implementing TORCH_INTERNAL_ASSERT and TORCH_CHECK
319 //
320 // Note: In the debug build With MSVC, __LINE__ might be of long type (a.k.a
321 // int32_t), which is different from the definition of `SourceLocation` that
322 // requires unsigned int (a.k.a uint32_t) and may cause a compile error with the
323 // message: error C2397: conversion from 'long' to 'uint32_t' requires a
324 // narrowing conversion Here the static cast is used to pass the build. if this
325 // is used inside a lambda the __func__ macro expands to operator(), which isn't
326 // very useful, but hard to fix in a macro so suppressing the warning.
327 #define C10_THROW_ERROR(err_type, msg) \
328   throw ::c10::err_type(               \
329       {__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, msg)
330 
331 #define C10_BUILD_ERROR(err_type, msg) \
332   ::c10::err_type({__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, msg)
333 
334 // Private helper macro for workaround MSVC misexpansion of nested macro
335 // invocations involving __VA_ARGS__.  See
336 // https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
337 #define C10_EXPAND_MSVC_WORKAROUND(x) x
338 
339 // On nvcc, C10_UNLIKELY thwarts missing return statement analysis.  In cases
340 // where the unlikely expression may be a constant, use this macro to ensure
341 // return statement analysis keeps working (at the cost of not getting the
342 // likely/unlikely annotation on nvcc).
343 // https://github.com/pytorch/pytorch/issues/21418
344 //
345 // Currently, this is only used in the error reporting macros below.  If you
346 // want to use it more generally, move me to Macros.h
347 //
348 // TODO: Brian Vaughan observed that we might be able to get this to work on
349 // nvcc by writing some sort of C++ overload that distinguishes constexpr inputs
350 // from non-constexpr.  Since there isn't any evidence that losing C10_UNLIKELY
351 // in nvcc is causing us perf problems, this is not yet implemented, but this
352 // might be an interesting piece of C++ code for an intrepid bootcamper to
353 // write.
354 #if defined(__CUDACC__)
355 #define C10_UNLIKELY_OR_CONST(e) e
356 #else
357 #define C10_UNLIKELY_OR_CONST(e) C10_UNLIKELY(e)
358 #endif
359 
360 // ----------------------------------------------------------------------------
361 // Error reporting macros
362 // ----------------------------------------------------------------------------
363 
364 #ifdef STRIP_ERROR_MESSAGES
365 #define TORCH_RETHROW(e, ...) throw
366 #else
367 #define TORCH_RETHROW(e, ...)               \
368   do {                                      \
369     e.add_context(::c10::str(__VA_ARGS__)); \
370     throw;                                  \
371   } while (false)
372 #endif
373 
374 // A utility macro to provide assert()-like functionality; that is, enforcement
375 // of internal invariants in code.  It supports an arbitrary number of extra
376 // arguments (evaluated only on failure), which will be printed in the assert
377 // failure message using operator<< (this is useful to print some variables
378 // which may be useful for debugging.)
379 //
380 // Usage:
381 //    TORCH_INTERNAL_ASSERT(should_be_true);
382 //    TORCH_INTERNAL_ASSERT(x == 0, "x = ", x);
383 //
384 // Assuming no bugs in PyTorch, the conditions tested by this macro should
385 // always be true; e.g., it should be possible to disable all of these
386 // conditions without changing observable user behavior.  If you would like to
387 // do error reporting for user input, please use TORCH_CHECK instead.
388 //
389 // NOTE: It is SAFE to use this macro in production code; on failure, this
390 // simply raises an exception, it does NOT unceremoniously quit the process
391 // (unlike assert()).
392 //
393 #ifdef STRIP_ERROR_MESSAGES
394 #define TORCH_INTERNAL_ASSERT(cond, ...)                              \
395   if (C10_UNLIKELY_OR_CONST(!(cond))) {                               \
396     ::c10::detail::torchCheckFail(                                    \
397         __func__,                                                     \
398         __FILE__,                                                     \
399         static_cast<uint32_t>(__LINE__),                              \
400         #cond " INTERNAL ASSERT FAILED at " C10_STRINGIZE(__FILE__)); \
401   }
402 #else
403 // It would be nice if we could build a combined string literal out of
404 // the TORCH_INTERNAL_ASSERT prefix and a user-provided string literal
405 // as the first argument, but there doesn't seem to be any good way to
406 // do that while still supporting having a first argument that isn't a
407 // string literal.
408 #define TORCH_INTERNAL_ASSERT(cond, ...)                                         \
409   if (C10_UNLIKELY_OR_CONST(!(cond))) {                                          \
410     ::c10::detail::torchInternalAssertFail(                                      \
411         __func__,                                                                \
412         __FILE__,                                                                \
413         static_cast<uint32_t>(__LINE__),                                         \
414         #cond                                                                    \
415         " INTERNAL ASSERT FAILED at " C10_STRINGIZE(__FILE__) ":" C10_STRINGIZE( \
416             __LINE__) ", please report a bug to PyTorch. ",                      \
417         c10::str(__VA_ARGS__));                                                  \
418   }
419 #endif
420 
421 // A utility macro to make it easier to test for error conditions from user
422 // input.  Like TORCH_INTERNAL_ASSERT, it supports an arbitrary number of extra
423 // arguments (evaluated only on failure), which will be printed in the error
424 // message using operator<< (e.g., you can pass any object which has
425 // operator<< defined.  Most objects in PyTorch have these definitions!)
426 //
427 // Usage:
428 //    TORCH_CHECK(should_be_true); // A default error message will be provided
429 //                                 // in this case; but we recommend writing an
430 //                                 // explicit error message, as it is more
431 //                                 // user friendly.
432 //    TORCH_CHECK(x == 0, "Expected x to be 0, but got ", x);
433 //
434 // On failure, this macro will raise an exception.  If this exception propagates
435 // to Python, it will convert into a Python RuntimeError.
436 //
437 // NOTE: It is SAFE to use this macro in production code; on failure, this
438 // simply raises an exception, it does NOT unceremoniously quit the process
439 // (unlike CHECK() from glog.)
440 //
441 #define TORCH_CHECK_WITH(error_t, cond, ...) \
442   TORCH_CHECK_WITH_MSG(error_t, cond, "", __VA_ARGS__)
443 
444 #ifdef STRIP_ERROR_MESSAGES
445 #define TORCH_CHECK_MSG(cond, type, ...) \
446   (#cond #type " CHECK FAILED at " C10_STRINGIZE(__FILE__))
447 #define TORCH_CHECK_WITH_MSG(error_t, cond, type, ...)                \
448   if (C10_UNLIKELY_OR_CONST(!(cond))) {                               \
449     C10_THROW_ERROR(Error, TORCH_CHECK_MSG(cond, type, __VA_ARGS__)); \
450   }
451 #else
452 
453 namespace c10::detail {
454 template <typename... Args>
decltype(auto)455 decltype(auto) torchCheckMsgImpl(const char* /*msg*/, const Args&... args) {
456   return ::c10::str(args...);
457 }
torchCheckMsgImpl(const char * msg)458 inline C10_API const char* torchCheckMsgImpl(const char* msg) {
459   return msg;
460 }
461 // If there is just 1 user-provided C-string argument, use it.
torchCheckMsgImpl(const char *,const char * args)462 inline C10_API const char* torchCheckMsgImpl(
463     const char* /*msg*/,
464     const char* args) {
465   return args;
466 }
467 } // namespace c10::detail
468 
469 #define TORCH_CHECK_MSG(cond, type, ...)                   \
470   (::c10::detail::torchCheckMsgImpl(                       \
471       "Expected " #cond                                    \
472       " to be true, but got false.  "                      \
473       "(Could this error message be improved?  If so, "    \
474       "please report an enhancement request to PyTorch.)", \
475       ##__VA_ARGS__))
476 #define TORCH_CHECK_WITH_MSG(error_t, cond, type, ...)                  \
477   if (C10_UNLIKELY_OR_CONST(!(cond))) {                                 \
478     C10_THROW_ERROR(error_t, TORCH_CHECK_MSG(cond, type, __VA_ARGS__)); \
479   }
480 #endif
481 
482 namespace c10::detail {
483 
484 [[noreturn]] C10_API void torchCheckFail(
485     const char* func,
486     const char* file,
487     uint32_t line,
488     const std::string& msg);
489 [[noreturn]] C10_API void torchCheckFail(
490     const char* func,
491     const char* file,
492     uint32_t line,
493     const char* msg);
494 
495 // The c10::str() call that creates userMsg can have 1 of 3 return
496 // types depending on the number and types of arguments passed to
497 // TORCH_INTERNAL_ASSERT.  0 arguments will get a
498 // CompileTimeEmptyString, 1 const char * will be passed straight
499 // through, and anything else will get converted to std::string.
500 [[noreturn]] C10_API void torchInternalAssertFail(
501     const char* func,
502     const char* file,
503     uint32_t line,
504     const char* condMsg,
505     const char* userMsg);
torchInternalAssertFail(const char * func,const char * file,uint32_t line,const char * condMsg,::c10::detail::CompileTimeEmptyString)506 [[noreturn]] inline C10_API void torchInternalAssertFail(
507     const char* func,
508     const char* file,
509     uint32_t line,
510     const char* condMsg,
511     ::c10::detail::CompileTimeEmptyString /*userMsg*/) {
512   torchCheckFail(func, file, line, condMsg);
513 }
514 [[noreturn]] C10_API void torchInternalAssertFail(
515     const char* func,
516     const char* file,
517     uint32_t line,
518     const char* condMsg,
519     const std::string& userMsg);
520 
521 } // namespace c10::detail
522 
523 #ifdef STRIP_ERROR_MESSAGES
524 #define TORCH_CHECK(cond, ...)                   \
525   if (C10_UNLIKELY_OR_CONST(!(cond))) {          \
526     ::c10::detail::torchCheckFail(               \
527         __func__,                                \
528         __FILE__,                                \
529         static_cast<uint32_t>(__LINE__),         \
530         TORCH_CHECK_MSG(cond, "", __VA_ARGS__)); \
531   }
532 #else
533 #define TORCH_CHECK(cond, ...)                     \
534   if (C10_UNLIKELY_OR_CONST(!(cond))) {            \
535     ::c10::detail::torchCheckFail(                 \
536         __func__,                                  \
537         __FILE__,                                  \
538         static_cast<uint32_t>(__LINE__),           \
539         TORCH_CHECK_MSG(cond, "", ##__VA_ARGS__)); \
540   }
541 #endif
542 
543 // An utility macro that does what `TORCH_CHECK` does if compiled in the host
544 // code, otherwise does nothing. Supposed to be used in the code shared between
545 // host and device code as an alternative for `TORCH_CHECK`.
546 #if defined(__CUDACC__) || defined(__HIPCC__)
547 #define TORCH_CHECK_IF_NOT_ON_CUDA(cond, ...)
548 #else
549 #define TORCH_CHECK_IF_NOT_ON_CUDA(cond, ...) TORCH_CHECK(cond, ##__VA_ARGS__)
550 #endif
551 
552 // Debug only version of TORCH_INTERNAL_ASSERT. This macro only checks in debug
553 // build, and does nothing in release build.  It is appropriate to use
554 // in situations where you want to add an assert to a hotpath, but it is
555 // too expensive to run this assert on production builds.
556 #ifdef NDEBUG
557 // Optimized version - generates no code.
558 #define TORCH_INTERNAL_ASSERT_DEBUG_ONLY(...) \
559   while (false)                               \
560   C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__))
561 #else
562 #define TORCH_INTERNAL_ASSERT_DEBUG_ONLY(...) \
563   C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__))
564 #endif
565 
566 // TODO: We're going to get a lot of similar looking string literals
567 // this way; check if this actually affects binary size.
568 
569 // Like TORCH_CHECK, but raises LinAlgError instead of Error.
570 #define TORCH_CHECK_LINALG(cond, ...) \
571   TORCH_CHECK_WITH_MSG(LinAlgError, cond, "LINALG", __VA_ARGS__)
572 
573 // Like TORCH_CHECK, but raises IndexErrors instead of Errors.
574 #define TORCH_CHECK_INDEX(cond, ...) \
575   TORCH_CHECK_WITH_MSG(IndexError, cond, "INDEX", __VA_ARGS__)
576 
577 // Like TORCH_CHECK, but raises ValueErrors instead of Errors.
578 #define TORCH_CHECK_VALUE(cond, ...) \
579   TORCH_CHECK_WITH_MSG(ValueError, cond, "VALUE", __VA_ARGS__)
580 
581 // Like TORCH_CHECK, but raises TypeErrors instead of Errors.
582 #define TORCH_CHECK_TYPE(cond, ...) \
583   TORCH_CHECK_WITH_MSG(TypeError, cond, "TYPE", __VA_ARGS__)
584 
585 // Like TORCH_CHECK, but raises NotImplementedErrors instead of Errors.
586 #define TORCH_CHECK_NOT_IMPLEMENTED(cond, ...) \
587   TORCH_CHECK_WITH_MSG(NotImplementedError, cond, "TYPE", __VA_ARGS__)
588 
589 #define TORCH_CHECK_ALWAYS_SHOW_CPP_STACKTRACE(cond, ...) \
590   TORCH_CHECK_WITH_MSG(                                   \
591       ErrorAlwaysShowCppStacktrace, cond, "TYPE", ##__VA_ARGS__)
592 
593 #ifdef STRIP_ERROR_MESSAGES
594 #define WARNING_MESSAGE_STRING(...) \
595   ::c10::detail::CompileTimeEmptyString {}
596 #else
597 #define WARNING_MESSAGE_STRING(...) ::c10::str(__VA_ARGS__)
598 #endif
599 
600 // Report a warning to the user.  Accepts an arbitrary number of extra
601 // arguments which are concatenated into the warning message using operator<<
602 //
603 #ifdef DISABLE_WARN
604 #define _TORCH_WARN_WITH(...) ((void)0);
605 #else
606 #define _TORCH_WARN_WITH(warning_t, ...)                     \
607   ::c10::warn(::c10::Warning(                                \
608       warning_t(),                                           \
609       {__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, \
610       WARNING_MESSAGE_STRING(__VA_ARGS__),                   \
611       false));
612 #endif
613 
614 #define TORCH_WARN(...) _TORCH_WARN_WITH(::c10::UserWarning, __VA_ARGS__);
615 
616 #define TORCH_WARN_DEPRECATION(...) \
617   _TORCH_WARN_WITH(::c10::DeprecationWarning, __VA_ARGS__);
618 
619 // Report a warning to the user only once.  Accepts an arbitrary number of extra
620 // arguments which are concatenated into the warning message using operator<<
621 //
622 #define _TORCH_WARN_ONCE(...)                                             \
623   C10_UNUSED static const auto C10_ANONYMOUS_VARIABLE(torch_warn_once_) = \
624       [&] {                                                               \
625         TORCH_WARN(__VA_ARGS__);                                          \
626         return true;                                                      \
627       }()
628 
629 #ifdef DISABLE_WARN
630 #define TORCH_WARN_ONCE(...) ((void)0);
631 #else
632 #define TORCH_WARN_ONCE(...)                   \
633   if (::c10::WarningUtils::get_warnAlways()) { \
634     TORCH_WARN(__VA_ARGS__);                   \
635   } else {                                     \
636     _TORCH_WARN_ONCE(__VA_ARGS__);             \
637   }
638 #endif
639 
640 // Report an error with a specific argument
641 // NOTE: using the argument name in TORCH_CHECK's message is preferred
642 #define TORCH_CHECK_ARG(cond, argN, ...) \
643   TORCH_CHECK(cond, "invalid argument ", argN, ": ", __VA_ARGS__)
644 
645 // ----------------------------------------------------------------------------
646 // Deprecated macros
647 // ----------------------------------------------------------------------------
648 
649 namespace c10::detail {
650 
651 /*
652 // Deprecation disabled until we fix sites in our codebase
653 C10_DEPRECATED_MESSAGE("AT_ERROR(msg) is deprecated, use TORCH_CHECK(false, msg)
654 instead.")
655 */
deprecated_AT_ERROR()656 inline void deprecated_AT_ERROR() {}
657 
658 /*
659 // Deprecation disabled until we fix sites in our codebase
660 C10_DEPRECATED_MESSAGE("AT_ASSERT is deprecated, if you mean to indicate an
661 internal invariant failure, use " \
662                        "TORCH_INTERNAL_ASSERT instead; if you mean to do user
663 error checking, use " \ "TORCH_CHECK.  See
664 https://github.com/pytorch/pytorch/issues/20287 for more details.")
665 */
deprecated_AT_ASSERT()666 inline void deprecated_AT_ASSERT() {}
667 
668 /*
669 // Deprecation disabled until we fix sites in our codebase
670 C10_DEPRECATED_MESSAGE("AT_ASSERTM is deprecated, if you mean to indicate an
671 internal invariant failure, use " \
672                        "TORCH_INTERNAL_ASSERT instead; if you mean to do user
673 error checking, use " \ "TORCH_CHECK.  See
674 https://github.com/pytorch/pytorch/issues/20287 for more details.")
675 */
deprecated_AT_ASSERTM()676 inline void deprecated_AT_ASSERTM() {}
677 
678 } // namespace c10::detail
679 
680 // Deprecated alias; this alias was deprecated because people kept mistakenly
681 // using it for user error checking.  Use TORCH_INTERNAL_ASSERT or TORCH_CHECK
682 // instead. See https://github.com/pytorch/pytorch/issues/20287 for more
683 // details.
684 #define AT_ASSERT(...)                                              \
685   do {                                                              \
686     ::c10::detail::deprecated_AT_ASSERT();                          \
687     C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__)); \
688   } while (false)
689 
690 // Deprecated alias, like AT_ASSERT.  The new TORCH_INTERNAL_ASSERT macro
691 // supports both 0-ary and variadic calls, so having a separate
692 // message-accepting macro is not necessary.
693 //
694 // NB: we MUST include cond explicitly here, as MSVC will miscompile the macro
695 // expansion, shunting all of __VA_ARGS__ to cond.  An alternate workaround
696 // can be seen at
697 // https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
698 #define AT_ASSERTM(cond, ...)                                             \
699   do {                                                                    \
700     ::c10::detail::deprecated_AT_ASSERTM();                               \
701     C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(cond, __VA_ARGS__)); \
702   } while (false)
703 
704 // Deprecated alias; this alias was deprecated because it represents extra API
705 // surface that makes it hard for people to understand what macro to use.
706 // Use TORCH_CHECK(false, ...) or TORCH_INTERNAL_ASSERT(false, ...) to
707 // unconditionally fail at a line of code.
708 #define AT_ERROR(...)                                                        \
709   do {                                                                       \
710     ::c10::detail::deprecated_AT_ERROR();                                    \
711     C10_EXPAND_MSVC_WORKAROUND(TORCH_CHECK(false, ::c10::str(__VA_ARGS__))); \
712   } while (false)
713 
714 #endif // C10_UTIL_EXCEPTION_H_
715