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