/src/Error.h
C Header | 169 lines | 102 code | 26 blank | 41 comment | 15 complexity | 0f24ba4af3a59a334e62328ce7c228c7 MD5 | raw file
- #ifndef HALIDE_ERROR_H
- #define HALIDE_ERROR_H
- #include <string>
- #include <sstream>
- #include <stdexcept>
- #include "Debug.h"
- #include "Introspection.h"
- 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 {
- std::ostringstream *msg;
- const char *file;
- const char *condition_string;
- int line;
- bool condition;
- bool user;
- bool warning;
- bool runtime;
- ErrorReport(const char *f, int l, const char *cs, bool c, bool u, bool w, bool r) :
- msg(NULL), file(f), condition_string(cs), line(l), condition(c), user(u), warning(w), runtime(r) {
- if (condition) return;
- msg = new std::ostringstream;
- const std::string &source_loc = Introspection::get_source_location();
- if (user) {
- // Only mention where inside of libHalide the error tripped if we have debug level > 0
- debug(1) << "User error triggered at " << f << ":" << l << "\n";
- if (condition_string) {
- debug(1) << "Condition failed: " << condition_string << "\n";
- }
- if (warning) {
- (*msg) << "Warning";
- } else {
- (*msg) << "Error";
- }
- if (source_loc.empty()) {
- (*msg) << ":\n";
- } else {
- (*msg) << " at " << source_loc << ":\n";
- }
- } else {
- (*msg) << "Internal ";
- if (warning) {
- (*msg) << "warning";
- } else {
- (*msg) << "error";
- }
- (*msg) << " at " << f << ":" << l;
- if (!source_loc.empty()) {
- (*msg) << " triggered by user code at " << source_loc << ":\n";
- } else {
- (*msg) << "\n";
- }
- if (condition_string) {
- (*msg) << "Condition failed: " << condition_string << "\n";
- }
- }
- }
- template<typename T>
- ErrorReport &operator<<(T x) {
- if (condition) return *this;
- (*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
- ~ErrorReport() noexcept(false) {
- #else
- ~ErrorReport() {
- #endif
- if (condition) return;
- explode();
- }
- EXPORT void explode();
- };
- #define internal_error Halide::Internal::ErrorReport(__FILE__, __LINE__, NULL, false, false, false, false)
- #define internal_assert(c) Halide::Internal::ErrorReport(__FILE__, __LINE__, #c, c, false, false, false)
- #define user_error Halide::Internal::ErrorReport(__FILE__, __LINE__, NULL, false, true, false, false)
- #define user_assert(c) Halide::Internal::ErrorReport(__FILE__, __LINE__, #c, c, true, false, false)
- #define user_warning Halide::Internal::ErrorReport(__FILE__, __LINE__, NULL, false, true, true, false)
- #define halide_runtime_error Halide::Internal::ErrorReport(__FILE__, __LINE__, NULL, false, true, false, true)
- // 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::ErrorReport(__FILE__, __LINE__, #c, c, true, false, false)
- // 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