From a4d963e00b0b506bd8562acd406d90e5714a1761 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 17 May 2019 10:48:29 +1000 Subject: [PATCH] debug: move panic related calls to a distinct unit This will allow us to reduce the required headers and avoid some circular dependencies in some client libraries. --- CMakeLists.txt | 2 + debug.hpp | 133 +------------------------------------------- debug/panic.cpp | 1 + debug/panic.hpp | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 131 deletions(-) create mode 100644 debug/panic.cpp create mode 100644 debug/panic.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 641dbc30..4f6a8226 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,6 +278,8 @@ list ( cpuid.hpp debug.cpp debug.hpp + debug/panic.cpp + debug/panic.hpp encode/number.hpp encode/base.cpp encode/base.hpp diff --git a/debug.hpp b/debug.hpp index 4265f3f1..28098e77 100644 --- a/debug.hpp +++ b/debug.hpp @@ -3,12 +3,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2010-2017 Danny Robson + * Copyright 2010-2019 Danny Robson */ #pragma once #include "platform.hpp" +#include "debug/panic.hpp" //#include "maths.hpp" // XXX: See notes at the end of file for maths.hpp inclusion #include @@ -435,136 +436,6 @@ namespace cruft::debug { void breakpoint (void); -/////////////////////////////////////////////////////////////////////////////// -// We define an identity macro for panic so that TCL and GCC don't decide to -// fuck us over by redefine the symbol. -// -// Apparently this can't be taken care of via a '-Dpanic=panic' argument, -// because it just ignores it for reasons I can't figure out. -#ifdef panic -#undef panic -#endif - -#define panic panic - - -//----------------------------------------------------------------------------- -namespace cruft::debug::detail { - void - panic [[noreturn]] (const char *msg); - - - void not_implemented [[noreturn]] (const char *msg); - - - void unreachable [[noreturn]] (const char *msg); -} - - -//----------------------------------------------------------------------------- -constexpr void -panic [[noreturn]] (const char *msg) -{ - ! msg - ? panic (msg) - : cruft::debug::detail::panic (msg); -} - - -//----------------------------------------------------------------------------- -inline void -panic [[noreturn]] (const std::string &msg) -{ - panic (msg.c_str ()); -} - - -/////////////////////////////////////////////////////////////////////////////// -// not_implemented/unreachable/panic must be callable from constexpr contexts. -// but they rely on functions that aren't constexpr to perform the controlled -// abort. -// -// we can work around this in the same way assert does by using a conditional -// that hides an extern function that actually does the work. as we can't -// utilise external state this has to be the message variable which will -// assume isn't ever null. -// -// to avoid warnings about a return from a noreturn function we recurse into -// ourself in the alternate case. this branch shouldn't ever be taken, but if -// it is we were planning on crashing anyway... - -/////////////////////////////////////////////////////////////////////////////// -constexpr void -not_implemented [[noreturn]] (const char *msg) -{ - ! msg - ? not_implemented (msg) - : cruft::debug::detail::not_implemented (msg); -} - - -constexpr void -not_implemented [[noreturn]] (void) -{ - not_implemented ("operation not implemented"); -} - - -constexpr void unimplemented [[noreturn]] (void) { not_implemented (); } - - -constexpr void unimplemented [[noreturn]] (const char *msg) { not_implemented (msg); } - - -/////////////////////////////////////////////////////////////////////////////// -constexpr void -unreachable [[noreturn]] (const char *msg) -{ - ! msg - ? unreachable (msg) - : cruft::debug::detail::unreachable (msg); -} - - -constexpr void -unreachable [[noreturn]] (void) -{ - unreachable ("unreachable code isn't"); -} - - -/////////////////////////////////////////////////////////////////////////////// -/// report a fatal error induced by an unhandled value, especially in switch -/// statements. will almost invariably abort the application. -namespace cruft::debug::detail { - template - T - unhandled [[noreturn]] (T &&t) noexcept - { - // If we've been given an enum we should handle it like its underlying - // type so that when we end up logging it we don't accidentally - // trigger an infinite loop of calls to `unhandled` within the - // ostream operator. It doesn't have to be pretty, just functional. - using base_type = std::remove_reference_t>; - if constexpr (std::is_enum_v) { - unhandled (static_cast> (t)); - } else { - std::ostringstream os; - os << "unhandled value: " << t << '\n'; - ::panic (os.str ()); - } - } -} - - -template -constexpr T -unhandled [[noreturn]] (T &&t) noexcept -{ - cruft::debug::detail::unhandled (std::forward (t)); -} - - /////////////////////////////////////////////////////////////////////////////// void warn (void); void warn (const std::string&); diff --git a/debug/panic.cpp b/debug/panic.cpp new file mode 100644 index 00000000..e01d71f3 --- /dev/null +++ b/debug/panic.cpp @@ -0,0 +1 @@ +#include "panic.hpp" \ No newline at end of file diff --git a/debug/panic.hpp b/debug/panic.hpp new file mode 100644 index 00000000..4334469b --- /dev/null +++ b/debug/panic.hpp @@ -0,0 +1,143 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2010-2019 Danny Robson + */ + +#pragma once + +#include +#include +#include + + +/////////////////////////////////////////////////////////////////////////////// +// We define an identity macro for panic so that TCL and GCC don't decide to +// fuck us over by redefine the symbol. +// +// Apparently this can't be taken care of via a '-Dpanic=panic' argument, +// because it just ignores it for reasons I can't figure out. +#ifdef panic +#undef panic +#endif + +#define panic panic + + +//----------------------------------------------------------------------------- +namespace cruft::debug::detail { + void + panic [[noreturn]] (const char *msg); + + + void not_implemented [[noreturn]] (const char *msg); + + + void unreachable [[noreturn]] (const char *msg); +} + + +//----------------------------------------------------------------------------- +constexpr void +panic [[noreturn]] (const char *msg) +{ + ! msg + ? panic (msg) + : cruft::debug::detail::panic (msg); +} + + +//----------------------------------------------------------------------------- +inline void +panic [[noreturn]] (const std::string &msg) +{ + panic (msg.c_str ()); +} + + +/////////////////////////////////////////////////////////////////////////////// +// not_implemented/unreachable/panic must be callable from constexpr contexts. +// but they rely on functions that aren't constexpr to perform the controlled +// abort. +// +// we can work around this in the same way assert does by using a conditional +// that hides an extern function that actually does the work. as we can't +// utilise external state this has to be the message variable which will +// assume isn't ever null. +// +// to avoid warnings about a return from a noreturn function we recurse into +// ourself in the alternate case. this branch shouldn't ever be taken, but if +// it is we were planning on crashing anyway... + +/////////////////////////////////////////////////////////////////////////////// +constexpr void +not_implemented [[noreturn]] (const char *msg) +{ + ! msg + ? not_implemented (msg) + : cruft::debug::detail::not_implemented (msg); +} + + +constexpr void +not_implemented [[noreturn]] (void) +{ + not_implemented ("operation not implemented"); +} + + +constexpr void unimplemented [[noreturn]] (void) { not_implemented (); } + + +constexpr void unimplemented [[noreturn]] (const char *msg) { not_implemented (msg); } + + +/////////////////////////////////////////////////////////////////////////////// +constexpr void +unreachable [[noreturn]] (const char *msg) +{ + ! msg + ? unreachable (msg) + : cruft::debug::detail::unreachable (msg); +} + + +constexpr void +unreachable [[noreturn]] (void) +{ + unreachable ("unreachable code isn't"); +} + + +/////////////////////////////////////////////////////////////////////////////// +/// report a fatal error induced by an unhandled value, especially in switch +/// statements. will almost invariably abort the application. +namespace cruft::debug::detail { + template + T + unhandled [[noreturn]] (T &&t) noexcept + { + // If we've been given an enum we should handle it like its underlying + // type so that when we end up logging it we don't accidentally + // trigger an infinite loop of calls to `unhandled` within the + // ostream operator. It doesn't have to be pretty, just functional. + using base_type = std::remove_reference_t>; + if constexpr (std::is_enum_v) { + unhandled (static_cast> (t)); + } else { + std::ostringstream os; + os << "unhandled value: " << t << '\n'; + ::panic (os.str ()); + } + } +} + + +template +constexpr T +unhandled [[noreturn]] (T &&t) noexcept +{ + cruft::debug::detail::unhandled (std::forward (t)); +}