#ifndef HALIDE_ERROR_H #define HALIDE_ERROR_H #include #include #include "Debug.h" #include "Introspection.h" #include "runtime/HalideRuntime.h" // for HALIDE_ALWAYS_INLINE namespace Halide { /** Query whether Halide was compiled with exceptions. */ EXPORT bool exceptions_enabled(); /** A base class for Halide errors. */ struct Error : public std::runtime_error { // Give each class a non-inlined constructor so that the type // doesn't get separately instantiated in each compilation unit. EXPORT Error(const std::string &msg); }; /** An error that occurs while running a JIT-compiled Halide pipeline. */ struct RuntimeError : public Error { EXPORT RuntimeError(const std::string &msg); }; /** An error that occurs while compiling a Halide pipeline that Halide * attributes to a user error. */ struct CompileError : public Error { EXPORT CompileError(const std::string &msg); }; /** An error that occurs while compiling a Halide pipeline that Halide * attributes to an internal compiler bug, or to an invalid use of * Halide's internals. */ struct InternalError : public Error { EXPORT InternalError(const std::string &msg); }; /** CompileTimeErrorReporter is used at compile time (*not* runtime) when * an error or warning is generated by Halide. Note that error() is called * a fatal error has occurred, and returning to Halide may cause a crash; * implementations of CompileTimeErrorReporter::error() should never return. * (Implementations of CompileTimeErrorReporter::warning() may return but * may also abort(), exit(), etc.) */ class CompileTimeErrorReporter { public: virtual ~CompileTimeErrorReporter() {} virtual void warning(const char* msg) = 0; virtual void error(const char* msg) = 0; }; /** The default error reporter logs to stderr, then throws an exception * (if WITH_EXCEPTIONS) or calls abort (if not). This allows customization * of that behavior if a more gentle response to error reporting is desired. * Note that error_reporter is expected to remain valid across all Halide usage; * it is up to the caller to ensure that this is the case (and to do any * cleanup necessary). */ EXPORT void set_custom_compile_time_error_reporter(CompileTimeErrorReporter* error_reporter); namespace Internal { struct ErrorReport { enum { User = 0x0001, Warning = 0x0002, Runtime = 0x0004 }; std::ostringstream msg; const int flags; EXPORT ErrorReport(const char *f, int l, const char *cs, int flags); // Just a trick used to convert RValue into LValue HALIDE_ALWAYS_INLINE ErrorReport& ref() { return *this; } template ErrorReport &operator<<(const T &x) { msg << x; return *this; } /** When you're done using << on the object, and let it fall out of * scope, this errors out, or throws an exception if they are * enabled. This is a little dangerous because the destructor will * also be called if there's an exception in flight due to an * error in one of the arguments passed to operator<<. We handle * this by only actually throwing if there isn't an exception in * flight already. */ #if __cplusplus >= 201100 || _MSC_VER >= 1900 EXPORT ~ErrorReport() noexcept(false); #else EXPORT ~ErrorReport(); #endif }; // This uses operator precedence as a trick to avoid argument evaluation if // an assertion is true: it is intended to be used as part of the // _halide_internal_assertion macro, to coerce the result of the stream // expression to void (to match the condition-is-false case). class Voidifier { public: HALIDE_ALWAYS_INLINE Voidifier() {} // This has to be an operator with a precedence lower than << but // higher than ?: HALIDE_ALWAYS_INLINE void operator&(ErrorReport&) {} }; /** * _halide_internal_assertion is used to implement our assertion macros * in such a way that the messages output for the assertion are only * evaluated if the assertion's value is false. * * Note that this macro intentionally has no parens internally; in actual * use, the implicit grouping will end up being * * condition ? (void) : (Voidifier() & (ErrorReport << arg1 << arg2 ... << argN)) * * This (regrettably) requires a macro to work, but has the highly desirable * effect that all assertion parameters are totally skipped (not ever evaluated) * when the assertion is true. */ #define _halide_internal_assertion(condition, flags) \ (condition) \ ? (void)0 \ : ::Halide::Internal::Voidifier() & \ ::Halide::Internal::ErrorReport(__FILE__, __LINE__, #condition, flags).ref() #define internal_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, 0) #define user_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User) #define user_warning Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User | Halide::Internal::ErrorReport::Warning) #define halide_runtime_error Halide::Internal::ErrorReport(__FILE__, __LINE__, nullptr, Halide::Internal::ErrorReport::User | Halide::Internal::ErrorReport::Runtime) #define internal_assert(c) _halide_internal_assertion(c, 0) #define user_assert(c) _halide_internal_assertion(c, Halide::Internal::ErrorReport::User) // The nicely named versions get cleaned up at the end of Halide.h, // but user code might want to do halide-style user_asserts (e.g. the // Extern macros introduce calls to user_assert), so for that purpose // we define an equivalent macro that can be used outside of Halide.h #define _halide_user_assert(c) _halide_internal_assertion(c, Halide::Internal::ErrorReport::User) // N.B. Any function that might throw a user_assert or user_error may // not be inlined into the user's code, or the line number will be // misattributed to Halide.h. Either make such functions internal to // libHalide, or mark them as NO_INLINE. } } #endif