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 | |
20 | namespace 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 |
29 | class 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 | |
116 | class 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 | |
161 | using UserWarning = Warning::UserWarning; |
162 | using DeprecationWarning = Warning::DeprecationWarning; |
163 | |
164 | // Issue a warning with a given message. Dispatched to the current |
165 | // warning handler. |
166 | void C10_API warn(const Warning& warning); |
167 | |
168 | class 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 | |
175 | namespace 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. |
195 | C10_API void set_warning_handler(WarningHandler* handler) noexcept(true); |
196 | /// Gets the global warning handler. |
197 | C10_API WarningHandler* get_warning_handler() noexcept(true); |
198 | |
199 | class 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. |
215 | C10_API void set_warnAlways(bool) noexcept(true); |
216 | C10_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. |
220 | struct 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. |
234 | class 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. |
240 | class 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. |
246 | class 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. |
252 | class 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. |
258 | class 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. |
264 | class 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. |
270 | class C10_API LinAlgError : public Error { |
271 | using Error::Error; |
272 | }; |
273 | |
274 | class 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. |
280 | class 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 |
286 | C10_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 |
421 | namespace c10 { |
422 | namespace detail { |
423 | template <typename... Args> |
424 | decltype(auto) torchCheckMsgImpl(const char* /*msg*/, const Args&... args) { |
425 | return ::c10::str(args...); |
426 | } |
427 | inline 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. |
431 | inline 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 | |
452 | namespace c10 { |
453 | namespace 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 | |
617 | namespace c10 { |
618 | namespace detail { |
619 | |
620 | /* |
621 | // Deprecation disabled until we fix sites in our codebase |
622 | C10_DEPRECATED_MESSAGE("AT_ERROR(msg) is deprecated, use TORCH_CHECK(false, msg) |
623 | instead.") |
624 | */ |
625 | inline void deprecated_AT_ERROR() {} |
626 | |
627 | /* |
628 | // Deprecation disabled until we fix sites in our codebase |
629 | C10_DEPRECATED_MESSAGE("AT_ASSERT is deprecated, if you mean to indicate an |
630 | internal invariant failure, use " \ |
631 | "TORCH_INTERNAL_ASSERT instead; if you mean to do user |
632 | error checking, use " \ "TORCH_CHECK. See |
633 | https://github.com/pytorch/pytorch/issues/20287 for more details.") |
634 | */ |
635 | inline void deprecated_AT_ASSERT() {} |
636 | |
637 | /* |
638 | // Deprecation disabled until we fix sites in our codebase |
639 | C10_DEPRECATED_MESSAGE("AT_ASSERTM is deprecated, if you mean to indicate an |
640 | internal invariant failure, use " \ |
641 | "TORCH_INTERNAL_ASSERT instead; if you mean to do user |
642 | error checking, use " \ "TORCH_CHECK. See |
643 | https://github.com/pytorch/pytorch/issues/20287 for more details.") |
644 | */ |
645 | inline 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 | |