diff --git a/CMakeLists.txt b/CMakeLists.txt index e3762ee..e5ba873 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,8 @@ if(MSVC) # they have their own __inline; this breaks `static inline` functions. # We do not want to care and so we fix this with a definition. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline") + # Same for the (C99) __func__ special variable; we use it only in C++ code. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D__func__=__FUNCTION__") endif() if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) diff --git a/src/platform/unixutil.cpp b/src/platform/unixutil.cpp index 83c0774..ef1a86a 100644 --- a/src/platform/unixutil.cpp +++ b/src/platform/unixutil.cpp @@ -8,6 +8,7 @@ // Copyright 2013 Daniel Richard G. //----------------------------------------------------------------------------- #include +#include #include "solvespace.h" @@ -25,6 +26,29 @@ void dbp(const char *str, ...) fputc('\n', stderr); } +void assert_failure(const char *file, unsigned line, const char *function, + const char *condition, const char *message) { + fprintf(stderr, "File %s, line %u, function %s:\n", file, line, function); + fprintf(stderr, "Assertion '%s' failed: ((%s) == false).\n", message, condition); + + static void *ptrs[1024] = {}; + size_t nptrs = backtrace(ptrs, sizeof(ptrs) / sizeof(ptrs[0])); + char **syms = backtrace_symbols(ptrs, nptrs); + + fprintf(stderr, "Backtrace:\n"); + if(syms != NULL) { + for(size_t i = 0; i < nptrs; i++) { + fprintf(stderr, "%2zu: %s\n", i, syms[i]); + } + } else { + for(size_t i = 0; i < nptrs; i++) { + fprintf(stderr, "%2zu: %p\n", i, ptrs[i]); + } + } + + abort(); +} + FILE *ssfopen(const std::string &filename, const char *mode) { if(filename.length() != strlen(filename.c_str())) oops(); diff --git a/src/platform/w32util.cpp b/src/platform/w32util.cpp index 20f3ec6..588e04d 100644 --- a/src/platform/w32util.cpp +++ b/src/platform/w32util.cpp @@ -24,6 +24,17 @@ void dbp(const char *str, ...) OutputDebugStringA(buf); } +void assert_failure(const char *file, unsigned line, const char *function, + const char *condition, const char *message) { + dbp("File %s, line %u, function %s:\n", file, line, function); + dbp("Assertion '%s' failed: ((%s) == false).\n", message, condition); +#ifdef NDEBUG + _exit(1); +#else + abort(); +#endif +} + std::string Narrow(const wchar_t *in) { std::string out; diff --git a/src/solvespace.h b/src/solvespace.h index 1e7d306..40fe7cf 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -56,14 +56,26 @@ struct FT_FaceRec_; #endif // Debugging functions -#ifdef NDEBUG -#define oops() do { dbp("oops at line %d, file %s\n", __LINE__, __FILE__); \ - exit(-1); } while(0) +#if defined(__GNUC__) +#define ssassert(condition, message) \ + do { \ + if(__builtin_expect((condition), true) == false) { \ + SolveSpace::assert_failure(__FILE__, __LINE__, __func__, #condition, message); \ + __builtin_unreachable(); \ + } \ + } while(0) #else -#define oops() do { dbp("oops at line %d, file %s\n", __LINE__, __FILE__); \ - abort(); } while(0) +#define ssassert(condition, message) \ + do { \ + if((condition) == false) { \ + SolveSpace::assert_failure(__FILE__, __LINE__, __func__, #condition, message); \ + abort(); \ + } \ + } while(0) #endif +#define oops() ssassert(false, "oops() called") + #ifndef isnan # define isnan(x) (((x) != (x)) || (x > 1e11) || (x < -1e11)) #endif @@ -74,6 +86,12 @@ using std::min; using std::max; using std::swap; +#if defined(__GNUC__) +__attribute__((noreturn)) +#endif +void assert_failure(const char *file, unsigned line, const char *function, + const char *condition, const char *message); + #if defined(__GNUC__) __attribute__((__format__ (__printf__, 1, 2))) #endif