Spicy
exception.h
1 // Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <optional>
6 #include <ostream>
7 #include <stdexcept>
8 #include <string>
9 #include <string_view>
10 #include <utility>
11 
12 #include <hilti/rt/backtrace.h>
13 #include <hilti/rt/extension-points.h>
14 #include <hilti/rt/fmt.h>
15 
16 namespace hilti::rt {
17 
18 class String;
19 
24 class Exception : public std::runtime_error {
25 public:
29  Exception(std::string_view desc) : Exception(Internal(), "Exception", desc) {
30 #ifndef NDEBUG
31  _backtrace = Backtrace();
32 #endif
33  }
34 
39  Exception(std::string_view desc, std::string_view location) : Exception(Internal(), "Exception", desc, location) {
40 #ifndef NDEBUG
41  _backtrace = Backtrace();
42 #endif
43  }
44 
45  Exception();
46 
47  Exception(const Exception& other)
48  : std::runtime_error(other),
49  _description(other._description),
50  _location(other._location),
51  _backtrace(other._backtrace) {}
52 
53  Exception(Exception&&) noexcept = default;
54  Exception& operator=(const Exception& other) = default;
55 
56  Exception& operator=(Exception&&) noexcept = default;
57 
58  // Empty, but required to make exception handling work between library
59  // and host application. See:
60  // http://www.toptip.ca/2012/06/c-exceptions-thrown-from-shared-library.html
61  ~Exception() override;
62 
64  std::string_view description() const { return _description; }
65 
67  std::string_view location() const { return _location; }
68 
73  const Backtrace* backtrace() const {
74  if ( ! _backtrace )
75  return nullptr;
76 
77  return &*_backtrace;
78  }
79 
80 protected:
81  enum Internal {};
82 
83  Exception(Internal, const char* type, std::string_view desc);
84  Exception(Internal, const char* type, std::string_view desc, std::string_view location);
85 
86 private:
87  Exception(Internal, const char* type, std::string_view what, std::string_view desc, std::string_view location);
88 
89  std::string _description;
90  std::string _location;
91  std::optional<Backtrace> _backtrace; // null if unavailable.
92 };
93 
94 inline std::ostream& operator<<(std::ostream& stream, const Exception& e) { return stream << e.what(); }
95 
96 #define HILTI_EXCEPTION(name, base) \
97  class name : public ::hilti::rt::base { \
98  public: \
99  name(std::string_view desc) : base(Internal(), #name, desc) {} \
100  name(std::string_view desc, std::string_view location) : base(Internal(), #name, desc, location) {} \
101  virtual ~name(); /* required to create vtable, see hilti::rt::Exception */ \
102  \
103  name(const name&) = default; \
104  name(name&&) = default; \
105  \
106  name& operator=(const name&) = default; \
107  name& operator=(name&&) = default; \
108  \
109  protected: \
110  using base::base; \
111  }; // namespace hilti::rt
112 
113 #define HILTI_EXCEPTION_NS(name, ns, base) \
114  class name : public ns::base { \
115  public: \
116  name(std::string_view desc) : base(Internal(), #name, desc) {} \
117  name(std::string_view desc, std::string_view location) : base(Internal(), #name, desc, location) {} \
118  virtual ~name(); /* required to create vtable, see hilti::rt::Exception */ \
119  \
120  protected: \
121  using base::base; \
122  };
123 
124 #define HILTI_EXCEPTION_IMPL(name) name::name::~name() = default;
125 
127 HILTI_EXCEPTION(RuntimeError, Exception)
128 
129 
130 HILTI_EXCEPTION(UsageError, Exception)
131 
132 
133 HILTI_EXCEPTION(RecoverableFailure, RuntimeError)
134 
135 
136 HILTI_EXCEPTION(AssertionFailure, RuntimeError)
137 
138 /*
139  * Exception triggered y the ".?" operator to signal to host applications that
140  * a struct attribute isn't set.
141  */
142 HILTI_EXCEPTION(AttributeNotSet, RuntimeError)
143 
144 
147 HILTI_EXCEPTION(DivisionByZero, RuntimeError)
148 
149 
150 HILTI_EXCEPTION(EnvironmentError, UsageError)
151 
152 
153 HILTI_EXCEPTION(ExpiredReference, RuntimeError)
154 
155 
158 HILTI_EXCEPTION(Frozen, RuntimeError)
159 
160 
161 HILTI_EXCEPTION(IllegalReference, RuntimeError)
162 
163 
164 HILTI_EXCEPTION(IndexError, RuntimeError)
165 
166 
167 HILTI_EXCEPTION(InvalidArgument, RuntimeError);
168 
170 HILTI_EXCEPTION(InvalidIterator, RuntimeError)
171 
173 HILTI_EXCEPTION(InvalidValue, RuntimeError);
174 
176 HILTI_EXCEPTION(MatchStateReuse, RuntimeError)
177 
179 HILTI_EXCEPTION(MissingData, RecoverableFailure);
180 
182 HILTI_EXCEPTION(NotSupported, RuntimeError)
183 
185 HILTI_EXCEPTION(NullReference, RuntimeError)
186 
188 HILTI_EXCEPTION(OutOfRange, RuntimeError)
189 
193 HILTI_EXCEPTION(Overflow, RuntimeError)
194 
196 HILTI_EXCEPTION(PatternError, RuntimeError)
197 
199 HILTI_EXCEPTION(UnhandledSwitchCase, RuntimeError)
200 
202 HILTI_EXCEPTION(UnicodeError, RuntimeError)
203 
207 HILTI_EXCEPTION(UnsetOptional, RuntimeError)
208 
212 HILTI_EXCEPTION(UnsetTupleElement, RuntimeError)
213 
217 HILTI_EXCEPTION(UnsetUnionMember, RuntimeError)
218 
222 HILTI_EXCEPTION(StackSizeExceeded, RuntimeError)
223 
225 class FormattingError : public RuntimeError {
226 public:
227  FormattingError(std::string desc) : RuntimeError(_sanitize(std::move(desc))) {}
228 
229 private:
230  std::string _sanitize(std::string desc) {
231  if ( auto pos = desc.find("tinyformat: "); pos != std::string::npos )
232  desc.erase(pos, 12);
233 
234  return desc;
235  }
236 };
237 
246 class WouldBlock : public std::runtime_error {
247 public:
248  using std::runtime_error::runtime_error;
249 
254  WouldBlock(std::string_view desc, std::string_view location);
255 };
256 
257 namespace exception {
258 
259 // Disables `Configuration::abort_on_exception` during its lifetime.
261 public:
264 
267  DisableAbortOnExceptions& operator=(const DisableAbortOnExceptions&) = delete;
268  DisableAbortOnExceptions& operator=(DisableAbortOnExceptions&&) noexcept = delete;
269 };
270 
272 void printUncaught(const Exception& e);
273 
275 void printUncaught(const Exception& e, std::ostream& out);
276 
281 String what(const Exception& e);
282 
287 String what(const std::exception& e);
288 
290 String where(const Exception& e);
291 
292 } // namespace exception
293 
294 namespace detail::adl {
295 inline std::string to_string(const Exception& e, adl::tag /*unused*/) { return fmt("<exception: %s>", e.what()); }
296 inline std::string to_string(const WouldBlock& e, adl::tag /*unused*/) { return fmt("<exception: %s>", e.what()); }
297 } // namespace detail::adl
298 
299 } // namespace hilti::rt
Definition: backtrace.h:17
Definition: exception.h:24
std::string_view description() const
Definition: exception.h:64
Exception(std::string_view desc, std::string_view location)
Definition: exception.h:39
const Backtrace * backtrace() const
Definition: exception.h:73
Exception(std::string_view desc)
Definition: exception.h:29
std::string_view location() const
Definition: exception.h:67
Definition: exception.h:225
Definition: string.h:31
Definition: exception.h:246
WouldBlock(std::string_view desc, std::string_view location)
Definition: exception.cc:98
Definition: any.h:7
HILTI_EXCEPTION(InvalidArgument, RuntimeError)
void location(const char *x)
Definition: logging.h:126
std::string fmt(const char *fmt, const Args &... args)
Definition: fmt.h:17
std::string to_string(T &&x)
Definition: extension-points.h:26