123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- // 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
- }
|