debug: make panic and friends constexpr

This commit is contained in:
Danny Robson 2015-10-29 10:43:41 +11:00
parent ba9a8f8b35
commit 2702c53df4
3 changed files with 148 additions and 47 deletions

View File

@ -22,33 +22,31 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
using namespace std; using namespace util::debug;
//------------------------------------------------------------------------------ ////////////////////////////////////////////////////////////////////////////////
void void
panic (const std::string& what) { detail::panic (const char *msg)
cerr << "PANIC: " << what << "\n" << debug::backtrace () << endl; {
std::cerr << "PANIC: " << msg << "\n" << ::debug::backtrace () << std::endl;
breakpoint (); breakpoint ();
abort (); abort ();
} }
void ////////////////////////////////////////////////////////////////////////////////
panic (void)
{ panic ("NFI"); }
//------------------------------------------------------------------------------
#if defined(PLATFORM_WIN32) #if defined(PLATFORM_WIN32)
#include <windows.h> #include <windows.h>
void void
breakpoint (void) { breakpoint (void)
{
DebugBreak (); DebugBreak ();
} }
#else #else
void void
breakpoint (void) { breakpoint (void)
{
#if defined (__x86_64) || defined (__i386) #if defined (__x86_64) || defined (__i386)
__asm__ ("int $3;"); __asm__ ("int $3;");
#else #else
@ -58,39 +56,31 @@ breakpoint (void) {
#endif #endif
//------------------------------------------------------------------------------ //-----------------------------------------------------------------------------
void void
not_implemented (void) { detail::not_implemented (const char *msg)
not_implemented ("Function not implemented"); {
panic (msg);
} }
//-----------------------------------------------------------------------------
void void
not_implemented (const char *msg) detail::unreachable (const char *msg)
{ panic (msg); } {
panic (msg);
//------------------------------------------------------------------------------
void
unreachable (void) {
panic ("Unreachable code executed");
} }
////////////////////////////////////////////////////////////////////////////////
void void
unreachable (const std::string& what) { unusual (void)
panic (" Unreachable code executed: " + what); {
}
//------------------------------------------------------------------------------
void
unusual (void) {
panic ("Unusual code path found."); panic ("Unusual code path found.");
} }
//------------------------------------------------------------------------------ ////////////////////////////////////////////////////////////////////////////////
#if defined(PLATFORM_LINUX) #if defined(PLATFORM_LINUX)
#include <fenv.h> #include <fenv.h>
void void
@ -100,6 +90,7 @@ enable_fpe (void)
} }
//-----------------------------------------------------------------------------
void void
disable_fpe (void) disable_fpe (void)
{ {
@ -108,8 +99,11 @@ disable_fpe (void)
#else #else
// contropfp is not defined supposedly due to a regression in GCC include behaviours. // contropfp is not defined supposedly due to a regression in GCC include behaviours.
//-----------------------------------------------------------------------------
void void
enable_fpe (void) { enable_fpe (void)
{
LOG_WARN ("Non-Linux exception code is broken under current GCC."); LOG_WARN ("Non-Linux exception code is broken under current GCC.");
// _clearfp(); // _clearfp();
// unsigned int ignored; // unsigned int ignored;
@ -117,8 +111,10 @@ enable_fpe (void) {
} }
//-----------------------------------------------------------------------------
void void
disable_fpe (void) { disable_fpe (void)
{
LOG_WARN ("Non-Linux exception code is broken under current GCC."); LOG_WARN ("Non-Linux exception code is broken under current GCC.");
// _clearfp(); // _clearfp();
// unsigned int ignored; // unsigned int ignored;
@ -127,13 +123,14 @@ disable_fpe (void) {
#endif #endif
//------------------------------------------------------------------------------ ////////////////////////////////////////////////////////////////////////////////
#if defined(PLATFORM_WIN32) #if defined(PLATFORM_WIN32)
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
void void
force_console (void) { force_console (void)
{
if (!AttachConsole (ATTACH_PARENT_PROCESS)) if (!AttachConsole (ATTACH_PARENT_PROCESS))
return; return;
@ -169,9 +166,10 @@ force_console (void) {
#endif #endif
//------------------------------------------------------------------------------ ////////////////////////////////////////////////////////////////////////////////
void void
debug::init (void) { util::debug::init (void)
{
#if defined(PLATFORM_WIN32) #if defined(PLATFORM_WIN32)
force_console (); force_console ();

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* *
* Copyright 2010-2012 Danny Robson <danny@nerdcruft.net> * Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __DEBUG_HPP #ifndef __DEBUG_HPP
@ -289,18 +289,21 @@ class panic_error {
}; };
///////////////////////////////////////////////////////////////////////////////
void panic [[noreturn]] (const std::string&); void panic [[noreturn]] (const std::string&);
void panic [[noreturn]] (void); constexpr void panic [[noreturn]] (const char*);
constexpr void panic [[noreturn]] (void);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void not_implemented [[noreturn]] (void); constexpr void not_implemented [[noreturn]] (void);
void not_implemented [[noreturn]] (const char*); constexpr void not_implemented [[noreturn]] (const char *msg);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void unreachable [[noreturn]] (void); constexpr void unreachable [[noreturn]] (void);
void unreachable [[noreturn]] (const std::string&); constexpr void unreachable [[noreturn]] (const char*);
void unusual (void); void unusual (void);
@ -314,7 +317,7 @@ void disable_fpe (void);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace debug { namespace util { namespace debug {
void init (void); void init (void);
@ -358,13 +361,15 @@ namespace debug {
(void)t; (void)t;
CHECK (valid (t)); CHECK (valid (t));
} }
} } }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// XXX: maths needs to be included so that CHECK_EQ/NEQ can call almost_equal, // XXX: maths needs to be included so that CHECK_EQ/NEQ can call almost_equal,
// but maths.hpp might be using CHECK_ macros so we must include maths.hpp // but maths.hpp might be using CHECK_ macros so we must include maths.hpp
// after we define the CHECK_ macros so the preprocessor can resolve them. // after we define the CHECK_ macros so the preprocessor can resolve them.
#include "maths.hpp" #include "./maths.hpp"
#include "./debug.ipp"
#endif // __DEBUG_HPP #endif // __DEBUG_HPP

98
debug.ipp Normal file
View File

@ -0,0 +1,98 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_DEBUG_IPP
#error
#endif
#define __UTIL_DEBUG_IPP
#include <limits>
///////////////////////////////////////////////////////////////////////////////
namespace util { namespace debug { namespace detail {
void panic [[noreturn]] (const char *msg);
void not_implemented [[noreturn]] (const char *msg);
void unreachable [[noreturn]] (const char *msg);
} } }
// 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]] (void)
{
not_implemented ("operation not implemented");
}
//-----------------------------------------------------------------------------
constexpr void not_implemented [[noreturn]] (const char *msg)
{
! msg
? not_implemented (msg)
: util::debug::detail::not_implemented (msg);
}
///////////////////////////////////////////////////////////////////////////////
constexpr void unreachable [[noreturn]] (void)
{
unreachable ("unreachable code executed");
}
//-----------------------------------------------------------------------------
constexpr void unreachable [[noreturn]] (const char *msg)
{
! msg
? unreachable (msg)
: util::debug::detail::unreachable (msg);
}
///////////////////////////////////////////////////////////////////////////////
inline void panic [[noreturn]] (const std::string &msg)
{
util::debug::detail::panic (msg.c_str ());
}
//-----------------------------------------------------------------------------
constexpr void panic [[noreturn]] (void)
{
panic ("nfi");
}
//-----------------------------------------------------------------------------
constexpr void panic [[noreturn]] (const char *msg)
{
! msg
? panic (msg)
: util::debug::detail::panic (msg);
}