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:
Location(char const * file_=__builtin_FILE (),unsigned line_=__builtin_LINE ())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 
Location(source_location loc=source_location::current ())58   constexpr Location (source_location loc = source_location::current ())
59     : Location (loc.file (), loc.line ())
60   {
61   }
62 #endif
63 
64 public:
File() const65   constexpr char const *File () const
66   {
67     return file;
68   }
Line() const69   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 
Unreachable()127 inline void Unreachable () noexcept
128 {
129   __builtin_unreachable ();
130 }
131 #endif
132 
133 }
134