Loading...
Searching...
No Matches
Error.h
Go to the documentation of this file.
#ifndef HALIDE_ERROR_H
#define HALIDE_ERROR_H
#include <sstream>
#include <stdexcept>
#include "Debug.h"
#include "runtime/HalideRuntime.h" // for HALIDE_ALWAYS_INLINE
namespace Halide {
/** Query whether Halide was compiled with exceptions. */
bool exceptions_enabled();
/** A base class for Halide errors.
*
* Note that this deliberately does *not* descend from std::runtime_error, or
* even std::exception; unfortunately, std::runtime_error is not marked as
* DLLEXPORT on Windows, but Error needs to be marked as such, and mismatching
* DLLEXPORT annotations in a class inheritance hierarchy in this way can lead
* to ODR violations. Instead, we just attempt to replicate the API of
* runtime_error here. */
struct HALIDE_EXPORT_SYMBOL Error {
Error() = delete;
// Give each class a non-inlined constructor so that the type
// doesn't get separately instantiated in each compilation unit.
explicit Error(const char *msg);
explicit Error(const std::string &msg);
Error(const Error &);
Error &operator=(const Error &);
Error(Error &&) noexcept;
Error &operator=(Error &&) noexcept;
virtual ~Error();
virtual const char *what() const noexcept;
private:
// Using a std::string here will cause MSVC to complain about the fact
// that class std::string isn't declared DLLEXPORT, even though the
// field is private; rather than suppress the warning, we'll just use
// an old-fashioned new-and-delete to keep it nice and clean.
char *what_;
};
/** An error that occurs while running a JIT-compiled Halide pipeline. */
struct HALIDE_EXPORT_SYMBOL RuntimeError final : Error {
static constexpr auto error_name = "Runtime error";
explicit RuntimeError(const char *msg);
explicit RuntimeError(const std::string &msg);
};
/** An error that occurs while compiling a Halide pipeline that Halide
* attributes to a user error. */
struct HALIDE_EXPORT_SYMBOL CompileError final : Error {
static constexpr auto error_name = "User error";
explicit CompileError(const char *msg);
explicit 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 HALIDE_EXPORT_SYMBOL InternalError final : Error {
static constexpr auto error_name = "Internal error";
explicit InternalError(const char *msg);
explicit 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() = default;
virtual void warning(const char *msg) = 0;
[[noreturn]] virtual void error(const char *msg) = 0;
};
/** The default error reporter logs to stderr, then throws an exception
* (if HALIDE_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).
*/
void set_custom_compile_time_error_reporter(CompileTimeErrorReporter *error_reporter);
namespace Internal {
/**
* If a custom error reporter is configured, notifies the reporter by calling
* its error() function with the value of \p e.what()
*
* Otherwise, if Halide was built with exceptions, throw \p e unless an
* existing exception is in flight. On the other hand, if Halide was built
* without exceptions, print the error message to stderr and abort().
*
* @param e The error to throw or report
*/
/// @{
[[noreturn]] void throw_error(const RuntimeError &e);
[[noreturn]] void throw_error(const CompileError &e);
[[noreturn]] void throw_error(const InternalError &e);
/// @}
/**
* If a custom error reporter is configured, notifies the reporter by calling
* its warning() function. Otherwise, prints the warning to stderr.
*
* @param warning The warning to issue
*/
void issue_warning(const char *warning);
template<typename T>
struct ReportBase {
template<typename S>
HALIDE_ALWAYS_INLINE T &operator<<(const S &x) {
msg << x;
return *static_cast<T *>(this);
}
HALIDE_ALWAYS_INLINE operator bool() const {
return !finalized;
}
protected:
std::ostringstream msg{};
bool finalized{false};
// This function is called as part of issue() below. We can't use a
// virtual function because issue() needs to be marked [[noreturn]]
// for errors and be left alone for warnings (i.e., they have
// different signatures).
std::string finalize_message() {
if (!msg.str().empty() && msg.str().back() != '\n') {
msg << "\n";
}
finalized = true;
return msg.str();
}
T &init(const char *file, const char *function, const int line, const char *condition_string, const char *prefix) {
if (debug_is_active_impl(1, file, function, line)) {
msg << prefix << " at " << file << ":" << line << ' ';
if (condition_string) {
msg << "Condition failed: " << condition_string << ' ';
}
}
return *static_cast<T *>(this);
}
};
template<typename Exception>
struct ErrorReport final : ReportBase<ErrorReport<Exception>> {
ErrorReport &init(const char *file, const char *function, const int line, const char *condition_string) {
return ReportBase<ErrorReport>::init(file, function, line, condition_string, Exception::error_name) << "Error: ";
}
[[noreturn]] void issue() noexcept(false) {
throw_error(Exception(this->finalize_message()));
}
};
struct WarningReport final : ReportBase<WarningReport> {
WarningReport &init(const char *file, const char *function, const int line, const char *condition_string) {
return ReportBase::init(file, function, line, condition_string, "Warning") << "Warning: ";
}
void issue() {
issue_warning(this->finalize_message().c_str());
}
};
/**
* The following three diagnostic macros are implemented such that the
* message is evaluated only if the assertion's value is false.
*
* 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.
*
* The macros work by deferring the call to issue() until after the stream
* has been evaluated. This previously used a trick where ErrorReport would
* throw in the destructor, but throwing in a destructor is UB in a lot of
* scenarios, and it was easy to break things by mistake.
*/
/// @{
#define _halide_error_impl(type) \
for (Halide::Internal::ErrorReport<type> _err; 1; _err.issue()) \
/**/ _err.init(__FILE__, __FUNCTION__, __LINE__, nullptr)
#define _halide_assert_impl(condition, type) \
if (!(condition)) \
for (Halide::Internal::ErrorReport<type> _err; 1; _err.issue()) \
/*****/ _err.init(__FILE__, __FUNCTION__, __LINE__, #condition)
#define _halide_user_warning \
for (Halide::Internal::WarningReport _err; _err; _err.issue()) \
/**/ _err.init(__FILE__, __FUNCTION__, __LINE__, nullptr)
/// @}
#define user_warning _halide_user_warning
#define user_error _halide_error_impl(Halide::CompileError)
#define internal_error _halide_error_impl(Halide::InternalError)
#define halide_runtime_error _halide_error_impl(Halide::RuntimeError)
#define internal_assert(c) _halide_assert_impl(c, Halide::InternalError)
#define user_assert(c) _halide_assert_impl(c, Halide::CompileError)
// 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_error _halide_error_impl(Halide::CompileError)
#define _halide_internal_error _halide_error_impl(Halide::InternalError)
#define _halide_runtime_error _halide_error_impl(Halide::RuntimeError)
#define _halide_internal_assert(c) _halide_assert_impl(c, Halide::InternalError)
#define _halide_user_assert(c) _halide_assert_impl(c, Halide::CompileError)
// 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 HALIDE_NO_USER_CODE_INLINE.
// handler suitable for use with std::terminate; it will catch unhandled exceptions
// and log the `what()` to stderr, then abort. Exposed as a function to minimize
// the need for external code to need to know the definition of Halide::Error.
HALIDE_EXPORT_SYMBOL void unhandled_exception_handler();
} // namespace Internal
} // namespace Halide
#endif
Debug.h
Defines functions for debug logging during code generation.
HalideRuntime.h
This file declares the routines used by Halide internally in its runtime.
HALIDE_EXPORT_SYMBOL
#define HALIDE_EXPORT_SYMBOL
Definition HalideRuntime.h:83
HALIDE_ALWAYS_INLINE
#define HALIDE_ALWAYS_INLINE
Definition HalideRuntime.h:49
Halide::CompileTimeErrorReporter
CompileTimeErrorReporter is used at compile time (not runtime) when an error or warning is generated ...
Definition Error.h:82
Halide::CompileTimeErrorReporter::warning
virtual void warning(const char *msg)=0
Halide::CompileTimeErrorReporter::error
virtual void error(const char *msg)=0
Halide::CompileTimeErrorReporter::~CompileTimeErrorReporter
virtual ~CompileTimeErrorReporter()=default
Halide::Internal
Definition AbstractGenerator.h:24
Halide::Internal::throw_error
void throw_error(const RuntimeError &e)
If a custom error reporter is configured, notifies the reporter by calling its error() function with ...
Halide::Internal::issue_warning
void issue_warning(const char *warning)
If a custom error reporter is configured, notifies the reporter by calling its warning() function.
Halide::Internal::unhandled_exception_handler
HALIDE_EXPORT_SYMBOL void unhandled_exception_handler()
Halide::Internal::debug_is_active_impl
bool debug_is_active_impl(int verbosity, const char *file, const char *function, int line)
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition AbstractGenerator.h:19
Halide::exceptions_enabled
bool exceptions_enabled()
Query whether Halide was compiled with exceptions.
Halide::set_custom_compile_time_error_reporter
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...
Halide::CompileError
An error that occurs while compiling a Halide pipeline that Halide attributes to a user error.
Definition Error.h:58
Halide::CompileError::error_name
static constexpr auto error_name
Definition Error.h:59
Halide::CompileError::CompileError
CompileError(const char *msg)
Halide::CompileError::CompileError
CompileError(const std::string &msg)
Halide::Error::Error
Error(Error &&) noexcept
Halide::Error::Error
Error(const std::string &msg)
Halide::Error::Error
Error(const char *msg)
Halide::Error::Error
Error()=delete
Halide::Error::operator=
Error & operator=(const Error &)
Halide::Error::Error
Error(const Error &)
Halide::Error::what
virtual const char * what() const noexcept
Halide::Internal::ErrorReport
Definition Error.h:164
Halide::Internal::ErrorReport::issue
void issue() noexcept(false)
Definition Error.h:169
Halide::Internal::ErrorReport::init
ErrorReport & init(const char *file, const char *function, const int line, const char *condition_string)
Definition Error.h:165
Halide::Internal::ReportBase
Definition Error.h:125
Halide::Internal::ReportBase::finalize_message
std::string finalize_message()
Definition Error.h:144
Halide::Internal::ReportBase::msg
std::ostringstream msg
Definition Error.h:137
Halide::Internal::ReportBase::finalized
bool finalized
Definition Error.h:138
Halide::Internal::ReportBase::init
T & init(const char *file, const char *function, const int line, const char *condition_string, const char *prefix)
Definition Error.h:152
Halide::Internal::ReportBase::operator<<
HALIDE_ALWAYS_INLINE T & operator<<(const S &x)
Definition Error.h:127
Halide::Internal::WarningReport
Definition Error.h:174
Halide::Internal::WarningReport::issue
void issue()
Definition Error.h:179
Halide::Internal::WarningReport::init
WarningReport & init(const char *file, const char *function, const int line, const char *condition_string)
Definition Error.h:175
Halide::InternalError
An error that occurs while compiling a Halide pipeline that Halide attributes to an internal compiler...
Definition Error.h:68
Halide::InternalError::error_name
static constexpr auto error_name
Definition Error.h:69
Halide::InternalError::InternalError
InternalError(const std::string &msg)
Halide::InternalError::InternalError
InternalError(const char *msg)
Halide::RuntimeError
An error that occurs while running a JIT-compiled Halide pipeline.
Definition Error.h:49
Halide::RuntimeError::error_name
static constexpr auto error_name
Definition Error.h:50
Halide::RuntimeError::RuntimeError
RuntimeError(const char *msg)
Halide::RuntimeError::RuntimeError
RuntimeError(const std::string &msg)