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

source code of libcody/internal.hh