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