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 27namespace Cody { 28 29// Location is needed regardless of checking, to make the fatal 30// handler simpler 31class Location 32{ 33protected: 34 char const *file; 35 unsigned line; 36 37public: 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 64public: 65 constexpr char const *File () const 66 { 67 return file; 68 } 69 constexpr unsigned Line () const 70 { 71 return line; 72 } 73}; 74 75void 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 87void AssertFailed [[noreturn]] (Location loc = Location ()) noexcept; 88void 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 127inline void Unreachable () noexcept 128{ 129 __builtin_unreachable (); 130} 131#endif 132 133} 134