1 // CODYlib -*- mode:c++ -*- 2 // Copyright (C) 2020 Nathan Sidwell, nathan@acm.org 3 // License: Apache v2.0 4 5 #include "cody.hh" 6 7 #ifndef __has_builtin 8 #define __has_builtin(X) 0 9 #endif 10 #ifndef __has_include 11 #define __has_include(X) 0 12 #endif 13 14 // C++ 15 #if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE) 16 #define CODY_LOC_BUILTIN 1 17 #elif __has_include (<source_location>) 18 #include <source_location> 19 #ifdef __cpp_lib_source_location 20 #define CODY_LOC_SOURCE 1 21 #endif 22 #endif 23 24 // C 25 #include <cstdio> 26 27 namespace Cody { 28 29 // Location is needed regardless of checking, to make the fatal 30 // handler simpler 31 class Location 32 { 33 protected: 34 char const *file; 35 unsigned line; 36 37 public: 38 constexpr Location (char const *file_ 39 #if CODY_LOC_BUILTIN 40 = __builtin_FILE () 41 #elif !CODY_LOC_SOURCE 42 = nullptr 43 #endif 44 , unsigned line_ 45 #if CODY_LOC_BUILTIN 46 = __builtin_LINE () 47 #elif !CODY_LOC_SOURCE 48 = 0 49 #endif 50 ) 51 :file (file_), line (line_) 52 { 53 } 54 55 #if !CODY_LOC_BUILTIN && CODY_LOC_SOURCE 56 using source_location = std::source_location; 57 58 constexpr Location (source_location loc = source_location::current ()) 59 : Location (loc.file (), loc.line ()) 60 { 61 } 62 #endif 63 64 public: 65 constexpr char const *File () const 66 { 67 return file; 68 } 69 constexpr unsigned Line () const 70 { 71 return line; 72 } 73 }; 74 75 void HCF [[noreturn]] 76 ( 77 char const *msg 78 #if NMS_CHECKING 79 , Location const = Location () 80 #if !CODY_LOC_BUILTIN && !CODY_LOC_SOURCE 81 #define HCF(M) HCF ((M), Cody::Location (__FILE__, __LINE__)) 82 #endif 83 #endif 84 ) noexcept; 85 86 #if NMS_CHECKING 87 void AssertFailed [[noreturn]] (Location loc = Location ()) noexcept; 88 void Unreachable [[noreturn]] (Location loc = Location ()) noexcept; 89 #if !CODY_LOC_BUILTIN && !CODY_LOC_SOURCE 90 #define AssertFailed() AssertFailed (Cody::Location (__FILE__, __LINE__)) 91 #define Unreachable() Unreachable (Cody::Location (__FILE__, __LINE__)) 92 #endif 93 94 // Do we have __VA_OPT__, alas no specific feature macro for it :( 95 // From stack overflow 96 // https://stackoverflow.com/questions/48045470/portably-detect-va-opt-support 97 // Relies on having variadic macros, but they're a C++11 thing, so 98 // we're good 99 #define HAVE_ARG_3(a,b,c,...) c 100 #define HAVE_VA_OPT_(...) HAVE_ARG_3(__VA_OPT__(,),true,false,) 101 #define HAVE_VA_OPT HAVE_VA_OPT_(?) 102 103 // Oh, for lazily evaluated function parameters 104 #if HAVE_VA_OPT 105 // Assert is variadic, so you can write Assert (TPL<A,B>(C)) without 106 // extraneous parens. I don't think we need that though. 107 #define Assert(EXPR, ...) \ 108 (__builtin_expect (bool (EXPR __VA_OPT__ (, __VA_ARGS__)), true) \ 109 ? (void)0 : AssertFailed ()) 110 #else 111 // If you don't have the GNU ,##__VA_ARGS__ pasting extension, we'll 112 // need another fallback 113 #define Assert(EXPR, ...) \ 114 (__builtin_expect (bool (EXPR, ##__VA_ARGS__), true) \ 115 ? (void)0 : AssertFailed ()) 116 #endif 117 #else 118 // Not asserting, use EXPR in an unevaluated context 119 #if HAVE_VA_OPT 120 #define Assert(EXPR, ...) \ 121 ((void)sizeof (bool (EXPR __VA_OPT__ (, __VA_ARGS__))), (void)0) 122 #else 123 #define Assert(EXPR, ...) \ 124 ((void)sizeof (bool (EXPR, ##__VA_ARGS__)), (void)0) 125 #endif 126 127 inline void Unreachable () noexcept 128 { 129 __builtin_unreachable (); 130 } 131 #endif 132 133 } 134