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