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 
22 class Exception : public std::runtime_error {
23 public:
27  Exception(std::string_view desc) : Exception(Internal(), "Exception", desc) {
28 #ifndef NDEBUG
29  _backtrace = Backtrace();
30 #endif
31  }
32 
37  Exception(std::string_view desc, std::string_view location) : Exception(Internal(), "Exception", desc, location) {
38 #ifndef NDEBUG
39  _backtrace = Backtrace();
40 #endif
41  }
42 
43  Exception();
44 
45  Exception(const Exception& other)
46  : std::runtime_error(other),
47  _description(other._description),
48  _location(other._location),
49  _backtrace(other._backtrace) {}
50 
51  Exception(Exception&&) noexcept = default;
52  Exception& operator=(const Exception& other) = default;
53 
54  Exception& operator=(Exception&&) noexcept = default;
55 
56  // Empty, but required to make exception handling work between library
57  // and host application. See:
58  // http://www.toptip.ca/2012/06/c-exceptions-thrown-from-shared-library.html
59  ~Exception() override;
60 
62  const auto& description() const { return _description; }
63 
65  const auto& location() const { return _location; }
66 
71  const Backtrace* backtrace() const {
72  if ( ! _backtrace )
73  return nullptr;
74 
75  return &*_backtrace;
76  }
77 
78 protected:
79  enum Internal {};
80 
81  Exception(Internal, const char* type, std::string_view desc);
82  Exception(Internal, const char* type, std::string_view desc, std::string_view location);
83 
84 private:
85  Exception(Internal, const char* type, std::string_view what, std::string_view desc, std::string_view location);
86 
87  std::string _description;
88  std::string _location;
89  std::optional<Backtrace> _backtrace; // null if unavailable.
90 };
91 
92 inline std::ostream& operator<<(std::ostream& stream, const Exception& e) { return stream << e.what(); }
93 
94 #define HILTI_EXCEPTION(name, base) \
95  class name : public ::hilti::rt::base { \
96  public: \
97  name(std::string_view desc) : base(Internal(), #name, desc) {} \
98  name(std::string_view desc, std::string_view location) : base(Internal(), #name, desc, location) {} \
99  virtual ~name(); /* required to create vtable, see hilti::rt::Exception */ \
100  protected: \
101  using base::base; \
102  }; // namespace hilti::rt
103 
104 #define HILTI_EXCEPTION_NS(name, ns, base) \
105  class name : public ns::base { \
106  public: \
107  name(std::string_view desc) : base(Internal(), #name, desc) {} \
108  name(std::string_view desc, std::string_view location) : base(Internal(), #name, desc, location) {} \
109  virtual ~name(); /* required to create vtable, see hilti::rt::Exception */ \
110  protected: \
111  using base::base; \
112  };
113 
114 #define HILTI_EXCEPTION_IMPL(name) name::name::~name() = default;
115 
117 HILTI_EXCEPTION(RuntimeError, Exception)
118 
119 
120 HILTI_EXCEPTION(UsageError, Exception)
121 
122 
123 HILTI_EXCEPTION(RecoverableFailure, RuntimeError)
124 
125 
126 HILTI_EXCEPTION(AssertionFailure, RuntimeError)
127 
128 /*
129  * Exception triggered y the ".?" operator to signal to host applications that
130  * a struct attribute isn't set.
131  */
132 HILTI_EXCEPTION(AttributeNotSet, RuntimeError)
133 
134 
137 HILTI_EXCEPTION(DivisionByZero, RuntimeError)
138 
139 
140 HILTI_EXCEPTION(EnvironmentError, UsageError)
141 
142 
143 HILTI_EXCEPTION(ExpiredReference, RuntimeError)
144 
145 
148 HILTI_EXCEPTION(Frozen, RuntimeError)
149 
150 
151 HILTI_EXCEPTION(IllegalReference, RuntimeError)
152 
153 
154 HILTI_EXCEPTION(IndexError, RuntimeError)
155 
156 
157 HILTI_EXCEPTION(InvalidArgument, RuntimeError);
158 
160 HILTI_EXCEPTION(InvalidIterator, RuntimeError)
161 
163 HILTI_EXCEPTION(InvalidValue, RuntimeError);
164 
166 HILTI_EXCEPTION(MatchStateReuse, RuntimeError)
167 
169 HILTI_EXCEPTION(MissingData, RecoverableFailure);
170 
172 HILTI_EXCEPTION(NotSupported, RuntimeError)
173 
175 HILTI_EXCEPTION(NullReference, RuntimeError)
176 
178 HILTI_EXCEPTION(OutOfRange, RuntimeError)
179 
183 HILTI_EXCEPTION(Overflow, RuntimeError)
184 
186 HILTI_EXCEPTION(PatternError, RuntimeError)
187 
189 HILTI_EXCEPTION(UnhandledSwitchCase, RuntimeError)
190 
192 HILTI_EXCEPTION(UnicodeError, RuntimeError)
193 
197 HILTI_EXCEPTION(UnsetOptional, RuntimeError)
198 
202 HILTI_EXCEPTION(UnsetTupleElement, RuntimeError)
203 
207 HILTI_EXCEPTION(UnsetUnionMember, RuntimeError)
208 
212 HILTI_EXCEPTION(StackSizeExceeded, RuntimeError)
213 
215 class FormattingError : public RuntimeError {
216 public:
217  FormattingError(std::string desc) : RuntimeError(_sanitize(std::move(desc))) {}
218 
219 private:
220  std::string _sanitize(std::string desc) {
221  if ( auto pos = desc.find("tinyformat: "); pos != std::string::npos )
222  desc.erase(pos, 12);
223 
224  return desc;
225  }
226 };
227 
236 class WouldBlock : public std::runtime_error {
237 public:
238  using std::runtime_error::runtime_error;
239 
244  WouldBlock(std::string_view desc, std::string_view location);
245 };
246 
247 namespace exception {
248 
249 // Disables `Configuration::abort_on_exception` during its lifetime.
251 public:
254 
257  DisableAbortOnExceptions& operator=(const DisableAbortOnExceptions&) = delete;
258  DisableAbortOnExceptions& operator=(DisableAbortOnExceptions&&) noexcept = delete;
259 };
260 
262 void printUncaught(const Exception& e);
263 
265 void printUncaught(const Exception& e, std::ostream& out);
266 
271 inline std::string what(const Exception& e) { return e.description(); }
272 
277 inline std::string what(const std::exception& e) { return e.what(); }
278 
280 inline std::string where(const Exception& e) { return e.location(); }
281 
282 } // namespace exception
283 
284 namespace detail::adl {
285 inline std::string to_string(const Exception& e, adl::tag /*unused*/) { return fmt("<exception: %s>", e.what()); }
286 inline std::string to_string(const WouldBlock& e, adl::tag /*unused*/) { return fmt("<exception: %s>", e.what()); }
287 } // namespace detail::adl
288 
289 } // namespace hilti::rt
Definition: backtrace.h:15
Definition: exception.h:22
Exception(std::string_view desc, std::string_view location)
Definition: exception.h:37
const auto & description() const
Definition: exception.h:62
const auto & location() const
Definition: exception.h:65
const Backtrace * backtrace() const
Definition: exception.h:71
Exception(std::string_view desc)
Definition: exception.h:27
Definition: exception.h:215
Definition: exception.h:236
WouldBlock(std::string_view desc, std::string_view location)
Definition: exception.cc:88
Definition: any.h:7
HILTI_EXCEPTION(InvalidArgument, RuntimeError)
std::string fmt(const char *fmt, const Args &... args)
Definition: fmt.h:13
std::string to_string(T &&x)
Definition: extension-points.h:26