1 #ifndef HALIDE_ERROR_H 2 #define HALIDE_ERROR_H 3 4 #include <sstream> 5 #include <stdexcept> 6 7 #include "Debug.h" 8 #include "runtime/HalideRuntime.h" // for HALIDE_ALWAYS_INLINE 9 10 namespace Halide { 11 12 /** Query whether Halide was compiled with exceptions. */ 13 bool exceptions_enabled(); 14 15 /** A base class for Halide errors. */ 16 struct Error : public std::runtime_error { 17 // Give each class a non-inlined constructor so that the type 18 // doesn't get separately instantiated in each compilation unit. 19 Error(const std::string &msg); 20 }; 21 22 /** An error that occurs while running a JIT-compiled Halide pipeline. */ 23 struct RuntimeError : public Error { 24 RuntimeError(const std::string &msg); 25 }; 26 27 /** An error that occurs while compiling a Halide pipeline that Halide 28 * attributes to a user error. */ 29 struct CompileError : public Error { 30 CompileError(const std::string &msg); 31 }; 32 33 /** An error that occurs while compiling a Halide pipeline that Halide 34 * attributes to an internal compiler bug, or to an invalid use of 35 * Halide's internals. */ 36 struct InternalError : public Error { 37 InternalError(const std::string &msg); 38 }; 39 40 /** CompileTimeErrorReporter is used at compile time (*not* runtime) when 41 * an error or warning is generated by Halide. Note that error() is called 42 * a fatal error has occurred, and returning to Halide may cause a crash; 43 * implementations of CompileTimeErrorReporter::error() should never return. 44 * (Implementations of CompileTimeErrorReporter::warning() may return but 45 * may also abort(), exit(), etc.) 46 */ 47 class CompileTimeErrorReporter { 48 public: 49 virtual ~CompileTimeErrorReporter() = default; 50 virtual void warning(const char *msg) = 0; 51 virtual void error(const char *msg) = 0; 52 }; 53 54 /** The default error reporter logs to stderr, then throws an exception 55 * (if HALIDE_WITH_EXCEPTIONS) or calls abort (if not). This allows customization 56 * of that behavior if a more gentle response to error reporting is desired. 57 * Note that error_reporter is expected to remain valid across all Halide usage; 58 * it is up to the caller to ensure that this is the case (and to do any 59 * cleanup necessary). 60 */ 61 void set_custom_compile_time_error_reporter(CompileTimeErrorReporter *error_reporter); 62 63 namespace Internal { 64 65 struct ErrorReport { 66 enum { 67 User = 0x0001, 68 Warning = 0x0002, 69 Runtime = 0x0004 70 }; 71 72 std::ostringstream msg; 73 const int flags; 74 75 ErrorReport(const char *f, int l, const char *cs, int flags); 76 77 // Just a trick used to convert RValue into LValue refErrorReport78 HALIDE_ALWAYS_INLINE ErrorReport &ref() { 79 return *this; 80 } 81 82 template<typename T> 83 ErrorReport &operator<<(const T &x) { 84 msg << x; 85 return *this; 86 } 87 88 /** When you're done using << on the object, and let it fall out of 89 * scope, this errors out, or throws an exception if they are 90 * enabled. This is a little dangerous because the destructor will 91 * also be called if there's an exception in flight due to an 92 * error in one of the arguments passed to operator<<. We handle 93 * this by only actually throwing if there isn't an exception in 94 * flight already. 95 */ 96 #if __cplusplus >= 201100 || _MSC_VER >= 1900 97 ~ErrorReport() noexcept(false); 98 #else 99 ~ErrorReport(); 100 #endif 101 }; 102 103 // This uses operator precedence as a trick to avoid argument evaluation if 104 // an assertion is true: it is intended to be used as part of the 105 // _halide_internal_assertion macro, to coerce the result of the stream 106 // expression to void (to match the condition-is-false case). 107 class Voidifier { 108 public: 109 HALIDE_ALWAYS_INLINE Voidifier() = default; 110 // This has to be an operator with a precedence lower than << but 111 // higher than ?: 112 HALIDE_ALWAYS_INLINE void operator&(ErrorReport &) { 113 } 114 }; 115 116 /** 117 * _halide_internal_assertion is used to implement our assertion macros 118 * in such a way that the messages output for the assertion are only 119 * evaluated if the assertion's value is false. 120 * 121 * Note that this macro intentionally has no parens internally; in actual 122 * use, the implicit grouping will end up being 123 * 124 * condition ? (void) : (Voidifier() & (ErrorReport << arg1 << arg2 ... << argN)) 125 * 126 * This (regrettably) requires a macro to work, but has the highly desirable 127 * effect that all assertion parameters are totally skipped (not ever evaluated) 128 * when the assertion is true. 129 */ 130 #define _halide_internal_assertion(condition, flags) \ 131 (condition) ? (void)0 : ::Halide::Internal::Voidifier() & ::Halide::Internal::ErrorReport(__FILE__, __LINE__, #condition, flags).ref() 132 133 #define internal_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, 0) 134 #define user_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User) 135 #define user_warning Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User | Halide::Internal::ErrorReport::Warning) 136 #define halide_runtime_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User | Halide::Internal::ErrorReport::Runtime) 137 138 #define internal_assert(c) _halide_internal_assertion(c, 0) 139 #define user_assert(c) _halide_internal_assertion(c, Halide::Internal::ErrorReport::User) 140 141 // The nicely named versions get cleaned up at the end of Halide.h, 142 // but user code might want to do halide-style user_asserts (e.g. the 143 // Extern macros introduce calls to user_assert), so for that purpose 144 // we define an equivalent macro that can be used outside of Halide.h 145 #define _halide_user_assert(c) _halide_internal_assertion(c, Halide::Internal::ErrorReport::User) 146 147 // N.B. Any function that might throw a user_assert or user_error may 148 // not be inlined into the user's code, or the line number will be 149 // misattributed to Halide.h. Either make such functions internal to 150 // libHalide, or mark them as HALIDE_NO_USER_CODE_INLINE. 151 152 } // namespace Internal 153 154 } // namespace Halide 155 156 #endif 157