Path: blob/master/dep/rapidyaml/include/c4/error.hpp
4261 views
#ifndef _C4_ERROR_HPP_1#define _C4_ERROR_HPP_23/** @file error.hpp Facilities for error reporting and runtime assertions. */45/** @defgroup error_checking Error checking */67#include "c4/config.hpp"89#ifdef _DOXYGEN_10/** if this is defined and exceptions are enabled, then calls to C4_ERROR()11* will throw an exception12* @ingroup error_checking */13# define C4_EXCEPTIONS_ENABLED14/** if this is defined and exceptions are enabled, then calls to C4_ERROR()15* will throw an exception16* @see C4_EXCEPTIONS_ENABLED17* @ingroup error_checking */18# define C4_ERROR_THROWS_EXCEPTION19/** evaluates to noexcept when C4_ERROR might be called and20* exceptions are disabled. Otherwise, defaults to nothing.21* @ingroup error_checking */22# define C4_NOEXCEPT23#endif // _DOXYGEN_2425#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)26# define C4_NOEXCEPT27#else28# define C4_NOEXCEPT noexcept29#endif303132namespace c4 {33namespace detail {34struct fail_type__ {};35} // detail36} // c437#define C4_STATIC_ERROR(dummy_type, errmsg) \38static_assert(std::is_same<dummy_type, c4::detail::fail_type__>::value, errmsg)394041//-----------------------------------------------------------------------------4243#define C4_ASSERT_SAME_TYPE(ty1, ty2) \44C4_STATIC_ASSERT(std::is_same<ty1 C4_COMMA_X ty2>::value)4546#define C4_ASSERT_DIFF_TYPE(ty1, ty2) \47C4_STATIC_ASSERT( ! std::is_same<ty1 C4_COMMA_X ty2>::value)484950//-----------------------------------------------------------------------------5152#ifdef _DOXYGEN_53/** utility macro that triggers a breakpoint when54* the debugger is attached and NDEBUG is not defined.55* @ingroup error_checking */56# define C4_DEBUG_BREAK()57#endif // _DOXYGEN_585960#if defined(NDEBUG) || defined(C4_NO_DEBUG_BREAK)61# define C4_DEBUG_BREAK()62#else63# ifdef __clang__64# pragma clang diagnostic push65# if !defined(__APPLE_CC__)66# if __clang_major__ >= 1067# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]68# endif69# else70# if __clang_major__ >= 1371# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]72# endif73# endif74# elif defined(__GNUC__)75# endif76# include <c4/ext/debugbreak/debugbreak.h>77# define C4_DEBUG_BREAK() if(c4::is_debugger_attached()) { ::debug_break(); }78# ifdef __clang__79# pragma clang diagnostic pop80# elif defined(__GNUC__)81# endif82#endif8384namespace c4 {85C4CORE_EXPORT bool is_debugger_attached();86} // namespace c4878889//-----------------------------------------------------------------------------9091#ifdef __clang__92/* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to93* variadic macros is not portable, but works in clang, gcc, msvc, icc.94* clang requires switching off compiler warnings for pedantic mode.95* @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */96# pragma clang diagnostic push97# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension98#elif defined(__GNUC__)99/* GCC also issues a warning for zero-args calls to variadic macros.100* This warning is switched on with -pedantic and apparently there is no101* easy way to turn it off as with clang. But marking this as a system102* header works.103* @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html104* @see http://stackoverflow.com/questions/35587137/ */105# pragma GCC system_header106#endif107108109//-----------------------------------------------------------------------------110111namespace c4 {112113typedef enum : uint32_t {114/** when an error happens and the debugger is attached, call C4_DEBUG_BREAK().115* Without effect otherwise. */116ON_ERROR_DEBUGBREAK = 0x01 << 0,117/** when an error happens log a message. */118ON_ERROR_LOG = 0x01 << 1,119/** when an error happens invoke a callback if it was set with120* set_error_callback(). */121ON_ERROR_CALLBACK = 0x01 << 2,122/** when an error happens call std::terminate(). */123ON_ERROR_ABORT = 0x01 << 3,124/** when an error happens and exceptions are enabled throw an exception.125* Without effect otherwise. */126ON_ERROR_THROW = 0x01 << 4,127/** the default flags. */128ON_ERROR_DEFAULTS = ON_ERROR_DEBUGBREAK|ON_ERROR_LOG|ON_ERROR_CALLBACK|ON_ERROR_ABORT129} ErrorFlags_e;130using error_flags = uint32_t;131C4CORE_EXPORT void set_error_flags(error_flags f);132C4CORE_EXPORT error_flags get_error_flags();133134135using error_callback_type = void (*)(const char* msg, size_t msg_size);136C4CORE_EXPORT void set_error_callback(error_callback_type cb);137C4CORE_EXPORT error_callback_type get_error_callback();138139140//-----------------------------------------------------------------------------141/** RAII class controling the error settings inside a scope. */142struct ScopedErrorSettings143{144error_flags m_flags;145error_callback_type m_callback;146147explicit ScopedErrorSettings(error_callback_type cb)148: m_flags(get_error_flags()),149m_callback(get_error_callback())150{151set_error_callback(cb);152}153explicit ScopedErrorSettings(error_flags flags)154: m_flags(get_error_flags()),155m_callback(get_error_callback())156{157set_error_flags(flags);158}159explicit ScopedErrorSettings(error_flags flags, error_callback_type cb)160: m_flags(get_error_flags()),161m_callback(get_error_callback())162{163set_error_flags(flags);164set_error_callback(cb);165}166~ScopedErrorSettings()167{168set_error_flags(m_flags);169set_error_callback(m_callback);170}171};172173174//-----------------------------------------------------------------------------175176/** source location */177struct srcloc;178179C4CORE_EXPORT void handle_error(srcloc s, const char *fmt, ...);180C4CORE_EXPORT void handle_warning(srcloc s, const char *fmt, ...);181182183# define C4_ERROR(msg, ...) \184do { \185if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \186{ \187C4_DEBUG_BREAK() \188} \189c4::handle_error(C4_SRCLOC(), msg, ## __VA_ARGS__); \190} while(0)191192193# define C4_WARNING(msg, ...) \194c4::handle_warning(C4_SRCLOC(), msg, ## __VA_ARGS__)195196197#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)198199struct srcloc200{201const char *file = "";202const char *func = "";203int line = 0;204};205#define C4_SRCLOC() c4::srcloc{__FILE__, C4_PRETTY_FUNC, __LINE__}206207#elif defined(C4_ERROR_SHOWS_FILELINE)208209struct srcloc210{211const char *file;212int line;213};214#define C4_SRCLOC() c4::srcloc{__FILE__, __LINE__}215216#elif ! defined(C4_ERROR_SHOWS_FUNC)217218struct srcloc219{220};221#define C4_SRCLOC() c4::srcloc()222223#else224# error not implemented225#endif226227228//-----------------------------------------------------------------------------229// assertions230231// Doxygen needs this so that only one definition counts232#ifdef _DOXYGEN_233/** Explicitly enables assertions, independently of NDEBUG status.234* This is meant to allow enabling assertions even when NDEBUG is defined.235* Defaults to undefined.236* @ingroup error_checking */237# define C4_USE_ASSERT238/** assert that a condition is true; this is turned off when NDEBUG239* is defined and C4_USE_ASSERT is not true.240* @ingroup error_checking */241# define C4_ASSERT242/** same as C4_ASSERT(), additionally prints a printf-formatted message243* @ingroup error_checking */244# define C4_ASSERT_MSG245/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults246* to noexcept247* @ingroup error_checking */248# define C4_NOEXCEPT_A249#endif // _DOXYGEN_250251#ifndef C4_USE_ASSERT252# ifdef NDEBUG253# define C4_USE_ASSERT 0254# else255# define C4_USE_ASSERT 1256# endif257#endif258259#if C4_USE_ASSERT260# define C4_ASSERT(cond) C4_CHECK(cond)261# define C4_ASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)262# define C4_ASSERT_IF(predicate, cond) if(predicate) { C4_ASSERT(cond); }263# define C4_NOEXCEPT_A C4_NOEXCEPT264#else265# define C4_ASSERT(cond)266# define C4_ASSERT_MSG(cond, /*fmt, */...)267# define C4_ASSERT_IF(predicate, cond)268# define C4_NOEXCEPT_A noexcept269#endif270271272//-----------------------------------------------------------------------------273// extreme assertions274275// Doxygen needs this so that only one definition counts276#ifdef _DOXYGEN_277/** Explicitly enables extreme assertions; this is meant to allow enabling278* assertions even when NDEBUG is defined. Defaults to undefined.279* @ingroup error_checking */280# define C4_USE_XASSERT281/** extreme assertion: can be switched off independently of282* the regular assertion; use for example for bounds checking in hot code.283* Turned on only when C4_USE_XASSERT is defined284* @ingroup error_checking */285# define C4_XASSERT286/** same as C4_XASSERT(), and additionally prints a printf-formatted message287* @ingroup error_checking */288# define C4_XASSERT_MSG289/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults to noexcept290* @ingroup error_checking */291# define C4_NOEXCEPT_X292#endif // _DOXYGEN_293294#ifndef C4_USE_XASSERT295# define C4_USE_XASSERT C4_USE_ASSERT296#endif297298#if C4_USE_XASSERT299# define C4_XASSERT(cond) C4_CHECK(cond)300# define C4_XASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)301# define C4_XASSERT_IF(predicate, cond) if(predicate) { C4_XASSERT(cond); }302# define C4_NOEXCEPT_X C4_NOEXCEPT303#else304# define C4_XASSERT(cond)305# define C4_XASSERT_MSG(cond, /*fmt, */...)306# define C4_XASSERT_IF(predicate, cond)307# define C4_NOEXCEPT_X noexcept308#endif309310311//-----------------------------------------------------------------------------312// checks: never switched-off313314/** Check that a condition is true, or raise an error when not315* true. Unlike C4_ASSERT(), this check is not disabled in non-debug316* builds.317* @see C4_ASSERT318* @ingroup error_checking319*320* @todo add constexpr-compatible compile-time assert:321* https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/322*/323#define C4_CHECK(cond) \324do { \325if(C4_UNLIKELY(!(cond))) \326{ \327C4_ERROR("check failed: %s", #cond); \328} \329} while(0)330331332/** like C4_CHECK(), and additionally log a printf-style message.333* @see C4_CHECK334* @ingroup error_checking */335#define C4_CHECK_MSG(cond, fmt, ...) \336do { \337if(C4_UNLIKELY(!(cond))) \338{ \339C4_ERROR("check failed: " #cond "\n" fmt, ## __VA_ARGS__); \340} \341} while(0)342343344//-----------------------------------------------------------------------------345// Common error conditions346347#define C4_NOT_IMPLEMENTED() C4_ERROR("NOT IMPLEMENTED")348#define C4_NOT_IMPLEMENTED_MSG(/*msg, */...) C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__)349#define C4_NOT_IMPLEMENTED_IF(condition) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED"); } } while(0)350#define C4_NOT_IMPLEMENTED_IF_MSG(condition, /*msg, */...) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__); } } while(0)351352#define C4_NEVER_REACH() do { C4_ERROR("never reach this point"); C4_UNREACHABLE(); } while(0)353#define C4_NEVER_REACH_MSG(/*msg, */...) do { C4_ERROR("never reach this point: " __VA_ARGS__); C4_UNREACHABLE(); } while(0)354355356357//-----------------------------------------------------------------------------358// helpers for warning suppression359// idea adapted from https://github.com/onqtam/doctest/360361// TODO: add C4_MESSAGE() https://stackoverflow.com/questions/18252351/custom-preprocessor-macro-for-a-conditional-pragma-message-xxx?rq=1362363364#ifdef C4_MSVC365#define C4_SUPPRESS_WARNING_MSVC_PUSH __pragma(warning(push))366#define C4_SUPPRESS_WARNING_MSVC(w) __pragma(warning(disable : w))367#define C4_SUPPRESS_WARNING_MSVC_POP __pragma(warning(pop))368#else // C4_MSVC369#define C4_SUPPRESS_WARNING_MSVC_PUSH370#define C4_SUPPRESS_WARNING_MSVC(w)371#define C4_SUPPRESS_WARNING_MSVC_POP372#endif // C4_MSVC373374375#ifdef C4_CLANG376#define C4_PRAGMA_TO_STR(x) _Pragma(#x)377#define C4_SUPPRESS_WARNING_CLANG_PUSH _Pragma("clang diagnostic push")378#define C4_SUPPRESS_WARNING_CLANG(w) C4_PRAGMA_TO_STR(clang diagnostic ignored w)379#define C4_SUPPRESS_WARNING_CLANG_POP _Pragma("clang diagnostic pop")380#else // C4_CLANG381#define C4_SUPPRESS_WARNING_CLANG_PUSH382#define C4_SUPPRESS_WARNING_CLANG(w)383#define C4_SUPPRESS_WARNING_CLANG_POP384#endif // C4_CLANG385386387#ifdef C4_GCC388#define C4_PRAGMA_TO_STR(x) _Pragma(#x)389#define C4_SUPPRESS_WARNING_GCC_PUSH _Pragma("GCC diagnostic push")390#define C4_SUPPRESS_WARNING_GCC(w) C4_PRAGMA_TO_STR(GCC diagnostic ignored w)391#define C4_SUPPRESS_WARNING_GCC_POP _Pragma("GCC diagnostic pop")392#else // C4_GCC393#define C4_SUPPRESS_WARNING_GCC_PUSH394#define C4_SUPPRESS_WARNING_GCC(w)395#define C4_SUPPRESS_WARNING_GCC_POP396#endif // C4_GCC397398399#define C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(w) \400C4_SUPPRESS_WARNING_MSVC_PUSH \401C4_SUPPRESS_WARNING_MSVC(w)402403#define C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w) \404C4_SUPPRESS_WARNING_CLANG_PUSH \405C4_SUPPRESS_WARNING_CLANG(w)406407#define C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \408C4_SUPPRESS_WARNING_GCC_PUSH \409C4_SUPPRESS_WARNING_GCC(w)410411412#define C4_SUPPRESS_WARNING_GCC_CLANG_PUSH \413C4_SUPPRESS_WARNING_GCC_PUSH \414C4_SUPPRESS_WARNING_CLANG_PUSH415416#define C4_SUPPRESS_WARNING_GCC_CLANG(w) \417C4_SUPPRESS_WARNING_GCC(w) \418C4_SUPPRESS_WARNING_CLANG(w)419420#define C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(w) \421C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \422C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w)423424#define C4_SUPPRESS_WARNING_GCC_CLANG_POP \425C4_SUPPRESS_WARNING_GCC_POP \426C4_SUPPRESS_WARNING_CLANG_POP427428} // namespace c4429430#ifdef __clang__431# pragma clang diagnostic pop432#endif433434#endif /* _C4_ERROR_HPP_ */435436437