internal.hh 3.1 KB

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