0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-27 07:54:05 +01:00

ircd: Add ircd::assertion and exception suite for assertive errors.

This commit is contained in:
Jason Volk 2018-01-08 13:26:29 -08:00
parent c8aaeb491f
commit 9e086e9acd
2 changed files with 75 additions and 2 deletions

View file

@ -28,6 +28,7 @@
namespace ircd namespace ircd
{ {
// Root exception
struct exception; struct exception;
// Prefer ircd::terminate() to std::terminate() if possible. // Prefer ircd::terminate() to std::terminate() if possible.
@ -35,6 +36,11 @@ namespace ircd
[[noreturn]] void terminate(std::exception_ptr) noexcept; [[noreturn]] void terminate(std::exception_ptr) noexcept;
[[noreturn]] void terminate() noexcept; [[noreturn]] void terminate() noexcept;
// Terminates in debug mode; throws in release mode; always logs critical.
[[noreturn]] void assertion(const std::exception &) noexcept(RB_DEBUG);
[[noreturn]] void assertion(std::exception_ptr) noexcept(RB_DEBUG);
[[noreturn]] void assertion() noexcept(RB_DEBUG);
// Can be used to clobber the std::terminate_handler // Can be used to clobber the std::terminate_handler
void aborting() noexcept; void aborting() noexcept;
} }
@ -147,6 +153,31 @@ struct name \
} \ } \
}; };
/// Creates an assertion-type exception.
///
/// Throwable exception which will terminate on construction in debug mode
/// but throw normally in release mode. Ideally this should never be thrown
/// in release mode because the termination in debug means a test can never
/// pass and the triggering callsite should be eliminated. Nevertheless it
/// throws normally in release mode.
#define IRCD_ASSERTION(parent, name) \
struct name \
:parent \
{ \
template<class... args> \
name(const char *const &fmt = " ", args&&... ap) noexcept(RB_DEBUG) \
:parent{generate_skip} \
{ \
generate(#name, fmt, va_rtti{std::forward<args>(ap)...}); \
ircd::assertion(*this); \
} \
\
name(generate_skip_t) noexcept(RB_DEBUG) \
:parent{generate_skip} \
{ \
} \
}; \
namespace ircd namespace ircd
{ {
/// Root error exception type. Inherit from this. /// Root error exception type. Inherit from this.
@ -157,4 +188,8 @@ namespace ircd
/// ///
IRCD_EXCEPTION(exception, error) // throw ircd::error("something bad") IRCD_EXCEPTION(exception, error) // throw ircd::error("something bad")
IRCD_EXCEPTION(error, user_error) // throw ircd::user_error("something silly") IRCD_EXCEPTION(error, user_error) // throw ircd::user_error("something silly")
// Assertion errors; see IRCD_ASSERTION docs.
IRCD_ASSERTION(exception, assertive)
IRCD_ASSERTION(assertive, not_implemented)
} }

View file

@ -47,6 +47,44 @@ noexcept
return size; return size;
} }
void
ircd::assertion()
noexcept(RB_DEBUG)
{
if(std::uncaught_exceptions())
{
assertion(std::current_exception());
} else {
log::critical("IRCd Assertion without active exception.");
assert(0);
throw assertive{};
}
}
void
ircd::assertion(std::exception_ptr eptr)
noexcept(RB_DEBUG) try
{
std::rethrow_exception(eptr);
}
catch(const std::exception &e)
{
assertion(e);
}
void
ircd::assertion(const std::exception &e)
noexcept(RB_DEBUG)
{
log::critical("IRCd Assertion %s", e.what());
#ifdef RB_DEBUG
terminate(e);
#else
throw e;
#endif
}
void void
ircd::terminate() ircd::terminate()
noexcept noexcept
@ -76,7 +114,7 @@ ircd::terminate(const std::exception &e)
noexcept noexcept
{ {
log::critical("IRCd Terminated: %s", e.what()); log::critical("IRCd Terminated: %s", e.what());
std::terminate(); throw e;
} }
[[noreturn]] static void [[noreturn]] static void