// CODYlib -*- mode:c++ -*- // Copyright (C) 2020 Nathan Sidwell, nathan@acm.org // License: Apache v2.0 #include "cody.hh" #ifndef __has_builtin #define __has_builtin(X) 0 #endif #ifndef __has_include #define __has_include(X) 0 #endif // C++ #if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE) #define CODY_LOC_BUILTIN 1 #elif __has_include () #include #ifdef __cpp_lib_source_location #define CODY_LOC_SOURCE 1 #endif #endif // C #include namespace Cody { // Location is needed regardless of checking, to make the fatal // handler simpler class Location { protected: char const *file; unsigned line; public: constexpr Location (char const *file_ #if CODY_LOC_BUILTIN = __builtin_FILE () #elif !CODY_LOC_SOURCE = nullptr #endif , unsigned line_ #if CODY_LOC_BUILTIN = __builtin_LINE () #elif !CODY_LOC_SOURCE = 0 #endif ) :file (file_), line (line_) { } #if !CODY_LOC_BUILTIN && CODY_LOC_SOURCE using source_location = std::source_location; constexpr Location (source_location loc = source_location::current ()) : Location (loc.file (), loc.line ()) { } #endif public: constexpr char const *File () const { return file; } constexpr unsigned Line () const { return line; } }; void HCF [[noreturn]] ( char const *msg #if NMS_CHECKING , Location const = Location () #if !CODY_LOC_BUILTIN && !CODY_LOC_SOURCE #define HCF(M) HCF ((M), Cody::Location (__FILE__, __LINE__)) #endif #endif ) noexcept; #if NMS_CHECKING void AssertFailed [[noreturn]] (Location loc = Location ()) noexcept; void Unreachable [[noreturn]] (Location loc = Location ()) noexcept; #if !CODY_LOC_BUILTIN && !CODY_LOC_SOURCE #define AssertFailed() AssertFailed (Cody::Location (__FILE__, __LINE__)) #define Unreachable() Unreachable (Cody::Location (__FILE__, __LINE__)) #endif // Do we have __VA_OPT__, alas no specific feature macro for it :( // From stack overflow // https://stackoverflow.com/questions/48045470/portably-detect-va-opt-support // Relies on having variadic macros, but they're a C++11 thing, so // we're good #define HAVE_ARG_3(a,b,c,...) c #define HAVE_VA_OPT_(...) HAVE_ARG_3(__VA_OPT__(,),true,false,) #define HAVE_VA_OPT HAVE_VA_OPT_(?) // Oh, for lazily evaluated function parameters #if HAVE_VA_OPT // Assert is variadic, so you can write Assert (TPL(C)) without // extraneous parens. I don't think we need that though. #define Assert(EXPR, ...) \ (__builtin_expect (bool (EXPR __VA_OPT__ (, __VA_ARGS__)), true) \ ? (void)0 : AssertFailed ()) #else // If you don't have the GNU ,##__VA_ARGS__ pasting extension, we'll // need another fallback #define Assert(EXPR, ...) \ (__builtin_expect (bool (EXPR, ##__VA_ARGS__), true) \ ? (void)0 : AssertFailed ()) #endif #else // Not asserting, use EXPR in an unevaluated context #if HAVE_VA_OPT #define Assert(EXPR, ...) \ ((void)sizeof (bool (EXPR __VA_OPT__ (, __VA_ARGS__))), (void)0) #else #define Assert(EXPR, ...) \ ((void)sizeof (bool (EXPR, ##__VA_ARGS__)), (void)0) #endif inline void Unreachable () noexcept { __builtin_unreachable (); } #endif }