Halide 20.0.0
Halide compiler and libraries
Loading...
Searching...
No Matches
Error.h
Go to the documentation of this file.
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
10namespace Halide {
11
12/** Query whether Halide was compiled with exceptions. */
14
15/** A base class for Halide errors.
16 *
17 * Note that this deliberately does *not* descend from std::runtime_error, or
18 * even std::exception; unfortunately, std::runtime_error is not marked as
19 * DLLEXPORT on Windows, but Error needs to be marked as such, and mismatching
20 * DLLEXPORT annotations in a class inheritance hierarchy in this way can lead
21 * to ODR violations. Instead, we just attempt to replicate the API of
22 * runtime_error here. */
24 Error() = delete;
25
26 // Give each class a non-inlined constructor so that the type
27 // doesn't get separately instantiated in each compilation unit.
28 explicit Error(const char *msg);
29 explicit Error(const std::string &msg);
30
31 Error(const Error &);
33 Error(Error &&) noexcept;
34 Error &operator=(Error &&) noexcept;
35
36 virtual ~Error();
37
38 virtual const char *what() const noexcept;
39
40private:
41 // Using a std::string here will cause MSVC to complain about the fact
42 // that class std::string isn't declared DLLEXPORT, even though the
43 // field is private; rather than suppress the warning, we'll just use
44 // an old-fashioned new-and-delete to keep it nice and clean.
45 char *what_;
46};
47
48/** An error that occurs while running a JIT-compiled Halide pipeline. */
50 static constexpr auto error_name = "Runtime error";
51
52 explicit RuntimeError(const char *msg);
53 explicit RuntimeError(const std::string &msg);
54};
55
56/** An error that occurs while compiling a Halide pipeline that Halide
57 * attributes to a user error. */
59 static constexpr auto error_name = "User error";
60
61 explicit CompileError(const char *msg);
62 explicit CompileError(const std::string &msg);
63};
64
65/** An error that occurs while compiling a Halide pipeline that Halide
66 * attributes to an internal compiler bug, or to an invalid use of
67 * Halide's internals. */
69 static constexpr auto error_name = "Internal error";
70
71 explicit InternalError(const char *msg);
72 explicit InternalError(const std::string &msg);
73};
74
75/** CompileTimeErrorReporter is used at compile time (*not* runtime) when
76 * an error or warning is generated by Halide. Note that error() is called
77 * a fatal error has occurred, and returning to Halide may cause a crash;
78 * implementations of CompileTimeErrorReporter::error() should never return.
79 * (Implementations of CompileTimeErrorReporter::warning() may return but
80 * may also abort(), exit(), etc.)
81 */
83public:
84 virtual ~CompileTimeErrorReporter() = default;
85 virtual void warning(const char *msg) = 0;
86 [[noreturn]] virtual void error(const char *msg) = 0;
87};
88
89/** The default error reporter logs to stderr, then throws an exception
90 * (if HALIDE_WITH_EXCEPTIONS) or calls abort (if not). This allows customization
91 * of that behavior if a more gentle response to error reporting is desired.
92 * Note that error_reporter is expected to remain valid across all Halide usage;
93 * it is up to the caller to ensure that this is the case (and to do any
94 * cleanup necessary).
95 */
97
98namespace Internal {
99
100/**
101 * If a custom error reporter is configured, notifies the reporter by calling
102 * its error() function with the value of \p e.what()
103 *
104 * Otherwise, if Halide was built with exceptions, throw \p e unless an
105 * existing exception is in flight. On the other hand, if Halide was built
106 * without exceptions, print the error message to stderr and abort().
107 *
108 * @param e The error to throw or report
109 */
110/// @{
111[[noreturn]] void throw_error(const RuntimeError &e);
112[[noreturn]] void throw_error(const CompileError &e);
113[[noreturn]] void throw_error(const InternalError &e);
114/// @}
115
116/**
117 * If a custom error reporter is configured, notifies the reporter by calling
118 * its warning() function. Otherwise, prints the warning to stderr.
119 *
120 * @param warning The warning to issue
121 */
122void issue_warning(const char *warning);
123
124template<typename T>
126 std::ostringstream msg;
127
128 ReportBase(const char *file, const char *function, int line, const char *condition_string, const char *prefix) {
129 if (debug_is_active_impl(1, file, function, line)) {
130 msg << prefix << " at " << file << ":" << line << ' ';
131 if (condition_string) {
132 msg << "Condition failed: " << condition_string << ' ';
133 }
134 }
135 }
136
137 // Just a trick used to convert RValue into LValue
139 return *static_cast<T *>(this);
140 }
141
142 template<typename S>
144 msg << x;
145 return *static_cast<T *>(this);
146 }
147
148protected:
149 std::string finalize_message() {
150 if (!msg.str().empty() && msg.str().back() != '\n') {
151 msg << "\n";
152 }
153 return msg.str();
154 }
155};
156
157template<typename Exception>
158struct ErrorReport : ReportBase<ErrorReport<Exception>> {
160
161 ErrorReport(const char *file, const char *function, int line, const char *condition_string)
162 : Base(file, function, line, condition_string, Exception::error_name) {
163 this->msg << "Error: ";
164 }
165
166 /** When you're done using << on the object, and let it fall out of
167 * scope, this errors out, or throws an exception if they are
168 * enabled. This is a little dangerous because the destructor will
169 * also be called if there's an exception in flight due to an
170 * error in one of the arguments passed to operator<<. We handle
171 * this by only actually throwing if there isn't an exception in
172 * flight already.
173 */
174 [[noreturn]] ~ErrorReport() noexcept(false) {
175 throw_error(Exception(this->finalize_message()));
176 }
177};
178
179struct WarningReport : ReportBase<WarningReport> {
180 WarningReport(const char *file, const char *function, int line, const char *condition_string)
181 : ReportBase(file, function, line, condition_string, "Warning") {
182 this->msg << "Warning: ";
183 }
184
185 /** When you're done using << on the object, and let it fall out of
186 * scope, this prints the computed warning message.
187 */
189 issue_warning(this->finalize_message().c_str());
190 }
191};
192
193// This uses operator precedence as a trick to avoid argument evaluation if
194// an assertion is true: it is intended to be used as part of the
195// _halide_internal_assertion macro, to coerce the result of the stream
196// expression to void (to match the condition-is-false case).
197struct Voidifier {
198 // This has to be an operator with a precedence lower than << but
199 // higher than ?:
200 template<typename T>
203};
204
205/**
206 * _halide_internal_assertion is used to implement our assertion macros
207 * in such a way that the messages output for the assertion are only
208 * evaluated if the assertion's value is false.
209 *
210 * Note that this macro intentionally has no parens internally; in actual
211 * use, the implicit grouping will end up being
212 *
213 * condition ? (void) : (Voidifier() & (ErrorReport << arg1 << arg2 ... << argN))
214 *
215 * This (regrettably) requires a macro to work, but has the highly desirable
216 * effect that all assertion parameters are totally skipped (not ever evaluated)
217 * when the assertion is true.
218 */
219#define _halide_internal_assertion(condition, type) \
220 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
221 (condition) ? (void)0 : ::Halide::Internal::Voidifier() & ::Halide::Internal::ErrorReport<type>(__FILE__, __FUNCTION__, __LINE__, #condition).ref()
222
223#define internal_error Halide::Internal::ErrorReport<Halide::InternalError>(__FILE__, __FUNCTION__, __LINE__, nullptr)
224#define user_error Halide::Internal::ErrorReport<Halide::CompileError>(__FILE__, __FUNCTION__, __LINE__, nullptr)
225#define user_warning Halide::Internal::WarningReport(__FILE__, __FUNCTION__, __LINE__, nullptr)
226#define halide_runtime_error Halide::Internal::ErrorReport<Halide::RuntimeError>(__FILE__, __FUNCTION__, __LINE__, nullptr)
227
228#define internal_assert(c) _halide_internal_assertion(c, Halide::InternalError)
229#define user_assert(c) _halide_internal_assertion(c, Halide::CompileError)
230
231// The nicely named versions get cleaned up at the end of Halide.h,
232// but user code might want to do halide-style user_asserts (e.g. the
233// Extern macros introduce calls to user_assert), so for that purpose
234// we define an equivalent macro that can be used outside of Halide.h
235#define _halide_internal_assert(c) _halide_internal_assertion(c, Halide::InternalError)
236#define _halide_user_assert(c) _halide_internal_assertion(c, Halide::CompileError)
237
238// N.B. Any function that might throw a user_assert or user_error may
239// not be inlined into the user's code, or the line number will be
240// misattributed to Halide.h. Either make such functions internal to
241// libHalide, or mark them as HALIDE_NO_USER_CODE_INLINE.
242
243// handler suitable for use with std::terminate; it will catch unhandled exceptions
244// and log the `what()` to stderr, then abort. Exposed as a function to minimize
245// the need for external code to need to know the definition of Halide::Error.
247
248} // namespace Internal
249
250} // namespace Halide
251
252#endif
Defines functions for debug logging during code generation.
This file declares the routines used by Halide internally in its runtime.
#define HALIDE_EXPORT_SYMBOL
#define HALIDE_ALWAYS_INLINE
CompileTimeErrorReporter is used at compile time (not runtime) when an error or warning is generated ...
Definition Error.h:82
virtual void warning(const char *msg)=0
virtual void error(const char *msg)=0
virtual ~CompileTimeErrorReporter()=default
void throw_error(const RuntimeError &e)
If a custom error reporter is configured, notifies the reporter by calling its error() function with ...
void issue_warning(const char *warning)
If a custom error reporter is configured, notifies the reporter by calling its warning() function.
HALIDE_EXPORT_SYMBOL void unhandled_exception_handler()
bool debug_is_active_impl(int verbosity, const char *file, const char *function, int line)
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
bool exceptions_enabled()
Query whether Halide was compiled with exceptions.
void set_custom_compile_time_error_reporter(CompileTimeErrorReporter *error_reporter)
The default error reporter logs to stderr, then throws an exception (if HALIDE_WITH_EXCEPTIONS) or ca...
An error that occurs while compiling a Halide pipeline that Halide attributes to a user error.
Definition Error.h:58
CompileError(const char *msg)
CompileError(const std::string &msg)
A base class for Halide errors.
Definition Error.h:23
Error(Error &&) noexcept
Error(const std::string &msg)
Error(const char *msg)
Error()=delete
Error & operator=(const Error &)
Error(const Error &)
ErrorReport(const char *file, const char *function, int line, const char *condition_string)
Definition Error.h:161
~ErrorReport() noexcept(false)
When you're done using << on the object, and let it fall out of scope, this errors out,...
Definition Error.h:174
std::string finalize_message()
Definition Error.h:149
ReportBase(const char *file, const char *function, int line, const char *condition_string, const char *prefix)
Definition Error.h:128
std::ostringstream msg
Definition Error.h:126
HALIDE_ALWAYS_INLINE T & ref()
Definition Error.h:138
HALIDE_ALWAYS_INLINE T & operator<<(const S &x)
Definition Error.h:143
HALIDE_ALWAYS_INLINE void operator&(T &)
Definition Error.h:201
WarningReport(const char *file, const char *function, int line, const char *condition_string)
Definition Error.h:180
~WarningReport()
When you're done using << on the object, and let it fall out of scope, this prints the computed warni...
Definition Error.h:188
An error that occurs while compiling a Halide pipeline that Halide attributes to an internal compiler...
Definition Error.h:68
InternalError(const std::string &msg)
InternalError(const char *msg)
An error that occurs while running a JIT-compiled Halide pipeline.
Definition Error.h:49
RuntimeError(const char *msg)
RuntimeError(const std::string &msg)