| // 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 (<source_location>) |
| #include <source_location> |
| #ifdef __cpp_lib_source_location |
| #define CODY_LOC_SOURCE 1 |
| #endif |
| #endif |
| |
| // C |
| #include <cstdio> |
| |
| 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<A,B>(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 |
| |
| } |