1 | /**************************************************************************/ |
2 | /* error_macros.h */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #ifndef ERROR_MACROS_H |
32 | #define ERROR_MACROS_H |
33 | |
34 | #include "core/typedefs.h" |
35 | |
36 | #include <atomic> // We'd normally use safe_refcount.h, but that would cause circular includes. |
37 | |
38 | class String; |
39 | |
40 | enum ErrorHandlerType { |
41 | ERR_HANDLER_ERROR, |
42 | ERR_HANDLER_WARNING, |
43 | ERR_HANDLER_SCRIPT, |
44 | ERR_HANDLER_SHADER, |
45 | }; |
46 | |
47 | // Pointer to the error handler printing function. Reassign to any function to have errors printed. |
48 | // Parameters: userdata, function, file, line, error, explanation, type. |
49 | typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, bool p_editor_notify, ErrorHandlerType p_type); |
50 | |
51 | struct ErrorHandlerList { |
52 | ErrorHandlerFunc errfunc = nullptr; |
53 | void *userdata = nullptr; |
54 | |
55 | ErrorHandlerList *next = nullptr; |
56 | |
57 | ErrorHandlerList() {} |
58 | }; |
59 | |
60 | void add_error_handler(ErrorHandlerList *p_handler); |
61 | void remove_error_handler(const ErrorHandlerList *p_handler); |
62 | |
63 | // Functions used by the error macros. |
64 | void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); |
65 | void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); |
66 | void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); |
67 | void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); |
68 | void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); |
69 | void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); |
70 | void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "" , bool p_editor_notify = false, bool fatal = false); |
71 | void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false); |
72 | void _err_flush_stdout(); |
73 | |
74 | #ifdef __GNUC__ |
75 | //#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying |
76 | #define FUNCTION_STR __FUNCTION__ |
77 | #else |
78 | #define FUNCTION_STR __FUNCTION__ |
79 | #endif |
80 | |
81 | #ifdef _MSC_VER |
82 | /** |
83 | * Don't use GENERATE_TRAP() directly, should only be used be the macros below. |
84 | */ |
85 | #define GENERATE_TRAP() __debugbreak() |
86 | #else |
87 | /** |
88 | * Don't use GENERATE_TRAP() directly, should only be used be the macros below. |
89 | */ |
90 | #define GENERATE_TRAP() __builtin_trap() |
91 | #endif |
92 | |
93 | /** |
94 | * Error macros. |
95 | * WARNING: These macros work in the opposite way to assert(). |
96 | * |
97 | * Unlike exceptions and asserts, these macros try to maintain consistency and stability. |
98 | * In most cases, bugs and/or invalid data are not fatal. They should never allow a perfectly |
99 | * running application to fail or crash. |
100 | * Always try to return processable data, so the engine can keep running well. |
101 | * Use the _MSG versions to print a meaningful message to help with debugging. |
102 | * |
103 | * The `((void)0)` no-op statement is used as a trick to force us to put a semicolon after |
104 | * those macros, making them look like proper statements. |
105 | * The if wrappers are used to ensure that the macro replacement does not trigger unexpected |
106 | * issues when expanded e.g. after an `if (cond) ERR_FAIL();` without braces. |
107 | */ |
108 | |
109 | // Index out of bounds error macros. |
110 | // These macros should be used instead of `ERR_FAIL_COND` for bounds checking. |
111 | |
112 | // Integer index out of bounds error macros. |
113 | |
114 | /** |
115 | * Try using `ERR_FAIL_INDEX_MSG`. |
116 | * Only use this macro if there is no sensible error message. |
117 | * |
118 | * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. |
119 | * If not, the current function returns. |
120 | */ |
121 | #define ERR_FAIL_INDEX(m_index, m_size) \ |
122 | if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ |
123 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ |
124 | return; \ |
125 | } else \ |
126 | ((void)0) |
127 | |
128 | /** |
129 | * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. |
130 | * If not, prints `m_msg` and the current function returns. |
131 | */ |
132 | #define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \ |
133 | if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ |
134 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \ |
135 | return; \ |
136 | } else \ |
137 | ((void)0) |
138 | |
139 | /** |
140 | * Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor. |
141 | */ |
142 | #define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \ |
143 | if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ |
144 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \ |
145 | return; \ |
146 | } else \ |
147 | ((void)0) |
148 | |
149 | /** |
150 | * Try using `ERR_FAIL_INDEX_V_MSG`. |
151 | * Only use this macro if there is no sensible error message. |
152 | * |
153 | * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. |
154 | * If not, the current function returns `m_retval`. |
155 | */ |
156 | #define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \ |
157 | if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ |
158 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ |
159 | return m_retval; \ |
160 | } else \ |
161 | ((void)0) |
162 | |
163 | /** |
164 | * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. |
165 | * If not, prints `m_msg` and the current function returns `m_retval`. |
166 | */ |
167 | #define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ |
168 | if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ |
169 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \ |
170 | return m_retval; \ |
171 | } else \ |
172 | ((void)0) |
173 | |
174 | /** |
175 | * Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor. |
176 | */ |
177 | #define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \ |
178 | if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ |
179 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \ |
180 | return m_retval; \ |
181 | } else \ |
182 | ((void)0) |
183 | |
184 | /** |
185 | * Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`. |
186 | * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and |
187 | * there is no sensible error message. |
188 | * |
189 | * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. |
190 | * If not, the application crashes. |
191 | */ |
192 | #define CRASH_BAD_INDEX(m_index, m_size) \ |
193 | if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ |
194 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \ |
195 | _err_flush_stdout(); \ |
196 | GENERATE_TRAP(); \ |
197 | } else \ |
198 | ((void)0) |
199 | |
200 | /** |
201 | * Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`. |
202 | * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable. |
203 | * |
204 | * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. |
205 | * If not, prints `m_msg` and the application crashes. |
206 | */ |
207 | #define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \ |
208 | if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ |
209 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \ |
210 | _err_flush_stdout(); \ |
211 | GENERATE_TRAP(); \ |
212 | } else \ |
213 | ((void)0) |
214 | |
215 | // Unsigned integer index out of bounds error macros. |
216 | |
217 | /** |
218 | * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG`. |
219 | * Only use this macro if there is no sensible error message. |
220 | * |
221 | * Ensures an unsigned integer index `m_index` is less than `m_size`. |
222 | * If not, the current function returns. |
223 | */ |
224 | #define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \ |
225 | if (unlikely((m_index) >= (m_size))) { \ |
226 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ |
227 | return; \ |
228 | } else \ |
229 | ((void)0) |
230 | |
231 | /** |
232 | * Ensures an unsigned integer index `m_index` is less than `m_size`. |
233 | * If not, prints `m_msg` and the current function returns. |
234 | */ |
235 | #define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ |
236 | if (unlikely((m_index) >= (m_size))) { \ |
237 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \ |
238 | return; \ |
239 | } else \ |
240 | ((void)0) |
241 | |
242 | /** |
243 | * Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor. |
244 | */ |
245 | #define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \ |
246 | if (unlikely((m_index) >= (m_size))) { \ |
247 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \ |
248 | return; \ |
249 | } else \ |
250 | ((void)0) |
251 | |
252 | /** |
253 | * Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`. |
254 | * Only use this macro if there is no sensible error message. |
255 | * |
256 | * Ensures an unsigned integer index `m_index` is less than `m_size`. |
257 | * If not, the current function returns `m_retval`. |
258 | */ |
259 | #define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \ |
260 | if (unlikely((m_index) >= (m_size))) { \ |
261 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ |
262 | return m_retval; \ |
263 | } else \ |
264 | ((void)0) |
265 | |
266 | /** |
267 | * Ensures an unsigned integer index `m_index` is less than `m_size`. |
268 | * If not, prints `m_msg` and the current function returns `m_retval`. |
269 | */ |
270 | #define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ |
271 | if (unlikely((m_index) >= (m_size))) { \ |
272 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \ |
273 | return m_retval; \ |
274 | } else \ |
275 | ((void)0) |
276 | |
277 | /** |
278 | * Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor. |
279 | */ |
280 | #define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \ |
281 | if (unlikely((m_index) >= (m_size))) { \ |
282 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \ |
283 | return m_retval; \ |
284 | } else \ |
285 | ((void)0) |
286 | |
287 | /** |
288 | * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`. |
289 | * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and |
290 | * there is no sensible error message. |
291 | * |
292 | * Ensures an unsigned integer index `m_index` is less than `m_size`. |
293 | * If not, the application crashes. |
294 | */ |
295 | #define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \ |
296 | if (unlikely((m_index) >= (m_size))) { \ |
297 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \ |
298 | _err_flush_stdout(); \ |
299 | GENERATE_TRAP(); \ |
300 | } else \ |
301 | ((void)0) |
302 | |
303 | /** |
304 | * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`. |
305 | * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable. |
306 | * |
307 | * Ensures an unsigned integer index `m_index` is less than `m_size`. |
308 | * If not, prints `m_msg` and the application crashes. |
309 | */ |
310 | #define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ |
311 | if (unlikely((m_index) >= (m_size))) { \ |
312 | _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \ |
313 | _err_flush_stdout(); \ |
314 | GENERATE_TRAP(); \ |
315 | } else \ |
316 | ((void)0) |
317 | |
318 | // Null reference error macros. |
319 | |
320 | /** |
321 | * Try using `ERR_FAIL_NULL_MSG`. |
322 | * Only use this macro if there is no sensible error message. |
323 | * |
324 | * Ensures a pointer `m_param` is not null. |
325 | * If it is null, the current function returns. |
326 | */ |
327 | #define ERR_FAIL_NULL(m_param) \ |
328 | if (unlikely(m_param == nullptr)) { \ |
329 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \ |
330 | return; \ |
331 | } else \ |
332 | ((void)0) |
333 | |
334 | /** |
335 | * Ensures a pointer `m_param` is not null. |
336 | * If it is null, prints `m_msg` and the current function returns. |
337 | */ |
338 | #define ERR_FAIL_NULL_MSG(m_param, m_msg) \ |
339 | if (unlikely(m_param == nullptr)) { \ |
340 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \ |
341 | return; \ |
342 | } else \ |
343 | ((void)0) |
344 | |
345 | /** |
346 | * Same as `ERR_FAIL_NULL_MSG` but also notifies the editor. |
347 | */ |
348 | #define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \ |
349 | if (unlikely(m_param == nullptr)) { \ |
350 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \ |
351 | return; \ |
352 | } else \ |
353 | ((void)0) |
354 | |
355 | /** |
356 | * Try using `ERR_FAIL_NULL_V_MSG`. |
357 | * Only use this macro if there is no sensible error message. |
358 | * |
359 | * Ensures a pointer `m_param` is not null. |
360 | * If it is null, the current function returns `m_retval`. |
361 | */ |
362 | #define ERR_FAIL_NULL_V(m_param, m_retval) \ |
363 | if (unlikely(m_param == nullptr)) { \ |
364 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \ |
365 | return m_retval; \ |
366 | } else \ |
367 | ((void)0) |
368 | |
369 | /** |
370 | * Ensures a pointer `m_param` is not null. |
371 | * If it is null, prints `m_msg` and the current function returns `m_retval`. |
372 | */ |
373 | #define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ |
374 | if (unlikely(m_param == nullptr)) { \ |
375 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \ |
376 | return m_retval; \ |
377 | } else \ |
378 | ((void)0) |
379 | |
380 | /** |
381 | * Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor. |
382 | */ |
383 | #define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \ |
384 | if (unlikely(m_param == nullptr)) { \ |
385 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \ |
386 | return m_retval; \ |
387 | } else \ |
388 | ((void)0) |
389 | |
390 | /** |
391 | * Try using `ERR_FAIL_COND_MSG`. |
392 | * Only use this macro if there is no sensible error message. |
393 | * If checking for null use ERR_FAIL_NULL_MSG instead. |
394 | * If checking index bounds use ERR_FAIL_INDEX_MSG instead. |
395 | * |
396 | * Ensures `m_cond` is false. |
397 | * If `m_cond` is true, the current function returns. |
398 | */ |
399 | #define ERR_FAIL_COND(m_cond) \ |
400 | if (unlikely(m_cond)) { \ |
401 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \ |
402 | return; \ |
403 | } else \ |
404 | ((void)0) |
405 | |
406 | /** |
407 | * Ensures `m_cond` is false. |
408 | * If `m_cond` is true, prints `m_msg` and the current function returns. |
409 | * |
410 | * If checking for null use ERR_FAIL_NULL_MSG instead. |
411 | * If checking index bounds use ERR_FAIL_INDEX_MSG instead. |
412 | */ |
413 | #define ERR_FAIL_COND_MSG(m_cond, m_msg) \ |
414 | if (unlikely(m_cond)) { \ |
415 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \ |
416 | return; \ |
417 | } else \ |
418 | ((void)0) |
419 | |
420 | /** |
421 | * Same as `ERR_FAIL_COND_MSG` but also notifies the editor. |
422 | */ |
423 | #define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \ |
424 | if (unlikely(m_cond)) { \ |
425 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \ |
426 | return; \ |
427 | } else \ |
428 | ((void)0) |
429 | |
430 | /** |
431 | * Try using `ERR_FAIL_COND_V_MSG`. |
432 | * Only use this macro if there is no sensible error message. |
433 | * If checking for null use ERR_FAIL_NULL_V_MSG instead. |
434 | * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead. |
435 | * |
436 | * Ensures `m_cond` is false. |
437 | * If `m_cond` is true, the current function returns `m_retval`. |
438 | */ |
439 | #define ERR_FAIL_COND_V(m_cond, m_retval) \ |
440 | if (unlikely(m_cond)) { \ |
441 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval)); \ |
442 | return m_retval; \ |
443 | } else \ |
444 | ((void)0) |
445 | |
446 | /** |
447 | * Ensures `m_cond` is false. |
448 | * If `m_cond` is true, prints `m_msg` and the current function returns `m_retval`. |
449 | * |
450 | * If checking for null use ERR_FAIL_NULL_V_MSG instead. |
451 | * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead. |
452 | */ |
453 | #define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ |
454 | if (unlikely(m_cond)) { \ |
455 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \ |
456 | return m_retval; \ |
457 | } else \ |
458 | ((void)0) |
459 | |
460 | /** |
461 | * Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor. |
462 | */ |
463 | #define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \ |
464 | if (unlikely(m_cond)) { \ |
465 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \ |
466 | return m_retval; \ |
467 | } else \ |
468 | ((void)0) |
469 | |
470 | /** |
471 | * Try using `ERR_CONTINUE_MSG`. |
472 | * Only use this macro if there is no sensible error message. |
473 | * |
474 | * Ensures `m_cond` is false. |
475 | * If `m_cond` is true, the current loop continues. |
476 | */ |
477 | #define ERR_CONTINUE(m_cond) \ |
478 | if (unlikely(m_cond)) { \ |
479 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \ |
480 | continue; \ |
481 | } else \ |
482 | ((void)0) |
483 | |
484 | /** |
485 | * Ensures `m_cond` is false. |
486 | * If `m_cond` is true, prints `m_msg` and the current loop continues. |
487 | */ |
488 | #define ERR_CONTINUE_MSG(m_cond, m_msg) \ |
489 | if (unlikely(m_cond)) { \ |
490 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \ |
491 | continue; \ |
492 | } else \ |
493 | ((void)0) |
494 | |
495 | /** |
496 | * Same as `ERR_CONTINUE_MSG` but also notifies the editor. |
497 | */ |
498 | #define ERR_CONTINUE_EDMSG(m_cond, m_msg) \ |
499 | if (unlikely(m_cond)) { \ |
500 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \ |
501 | continue; \ |
502 | } else \ |
503 | ((void)0) |
504 | |
505 | /** |
506 | * Try using `ERR_BREAK_MSG`. |
507 | * Only use this macro if there is no sensible error message. |
508 | * |
509 | * Ensures `m_cond` is false. |
510 | * If `m_cond` is true, the current loop breaks. |
511 | */ |
512 | #define ERR_BREAK(m_cond) \ |
513 | if (unlikely(m_cond)) { \ |
514 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \ |
515 | break; \ |
516 | } else \ |
517 | ((void)0) |
518 | |
519 | /** |
520 | * Ensures `m_cond` is false. |
521 | * If `m_cond` is true, prints `m_msg` and the current loop breaks. |
522 | */ |
523 | #define ERR_BREAK_MSG(m_cond, m_msg) \ |
524 | if (unlikely(m_cond)) { \ |
525 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \ |
526 | break; \ |
527 | } else \ |
528 | ((void)0) |
529 | |
530 | /** |
531 | * Same as `ERR_BREAK_MSG` but also notifies the editor. |
532 | */ |
533 | #define ERR_BREAK_EDMSG(m_cond, m_msg) \ |
534 | if (unlikely(m_cond)) { \ |
535 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \ |
536 | break; \ |
537 | } else \ |
538 | ((void)0) |
539 | |
540 | /** |
541 | * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`. |
542 | * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and |
543 | * there is no sensible error message. |
544 | * |
545 | * Ensures `m_cond` is false. |
546 | * If `m_cond` is true, the application crashes. |
547 | */ |
548 | #define CRASH_COND(m_cond) \ |
549 | if (unlikely(m_cond)) { \ |
550 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \ |
551 | _err_flush_stdout(); \ |
552 | GENERATE_TRAP(); \ |
553 | } else \ |
554 | ((void)0) |
555 | |
556 | /** |
557 | * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`. |
558 | * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable. |
559 | * |
560 | * Ensures `m_cond` is false. |
561 | * If `m_cond` is true, prints `m_msg` and the application crashes. |
562 | */ |
563 | #define CRASH_COND_MSG(m_cond, m_msg) \ |
564 | if (unlikely(m_cond)) { \ |
565 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \ |
566 | _err_flush_stdout(); \ |
567 | GENERATE_TRAP(); \ |
568 | } else \ |
569 | ((void)0) |
570 | |
571 | // Generic error macros. |
572 | |
573 | /** |
574 | * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_MSG`. |
575 | * Only use this macro if more complex error detection or recovery is required, and |
576 | * there is no sensible error message. |
577 | * |
578 | * The current function returns. |
579 | */ |
580 | #define ERR_FAIL() \ |
581 | if (true) { \ |
582 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \ |
583 | return; \ |
584 | } else \ |
585 | ((void)0) |
586 | |
587 | /** |
588 | * Try using `ERR_FAIL_COND_MSG`. |
589 | * Only use this macro if more complex error detection or recovery is required. |
590 | * |
591 | * Prints `m_msg`, and the current function returns. |
592 | */ |
593 | #define ERR_FAIL_MSG(m_msg) \ |
594 | if (true) { \ |
595 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \ |
596 | return; \ |
597 | } else \ |
598 | ((void)0) |
599 | |
600 | /** |
601 | * Same as `ERR_FAIL_MSG` but also notifies the editor. |
602 | */ |
603 | #define ERR_FAIL_EDMSG(m_msg) \ |
604 | if (true) { \ |
605 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \ |
606 | return; \ |
607 | } else \ |
608 | ((void)0) |
609 | |
610 | /** |
611 | * Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`. |
612 | * Only use this macro if more complex error detection or recovery is required, and |
613 | * there is no sensible error message. |
614 | * |
615 | * The current function returns `m_retval`. |
616 | */ |
617 | #define ERR_FAIL_V(m_retval) \ |
618 | if (true) { \ |
619 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \ |
620 | return m_retval; \ |
621 | } else \ |
622 | ((void)0) |
623 | |
624 | /** |
625 | * Try using `ERR_FAIL_COND_V_MSG`. |
626 | * Only use this macro if more complex error detection or recovery is required. |
627 | * |
628 | * Prints `m_msg`, and the current function returns `m_retval`. |
629 | */ |
630 | #define ERR_FAIL_V_MSG(m_retval, m_msg) \ |
631 | if (true) { \ |
632 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \ |
633 | return m_retval; \ |
634 | } else \ |
635 | ((void)0) |
636 | |
637 | /** |
638 | * Same as `ERR_FAIL_V_MSG` but also notifies the editor. |
639 | */ |
640 | #define ERR_FAIL_V_EDMSG(m_retval, m_msg) \ |
641 | if (true) { \ |
642 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \ |
643 | return m_retval; \ |
644 | } else \ |
645 | ((void)0) |
646 | |
647 | /** |
648 | * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`. |
649 | * Only use this macro at the start of a function that has not been implemented yet, or |
650 | * if more complex error detection or recovery is required. |
651 | * |
652 | * Prints `m_msg`. |
653 | */ |
654 | #define ERR_PRINT(m_msg) \ |
655 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg) |
656 | |
657 | /** |
658 | * Same as `ERR_PRINT` but also notifies the editor. |
659 | */ |
660 | #define ERR_PRINT_ED(m_msg) \ |
661 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true) |
662 | |
663 | /** |
664 | * Prints `m_msg` once during the application lifetime. |
665 | */ |
666 | #define ERR_PRINT_ONCE(m_msg) \ |
667 | if (true) { \ |
668 | static bool first_print = true; \ |
669 | if (first_print) { \ |
670 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \ |
671 | first_print = false; \ |
672 | } \ |
673 | } else \ |
674 | ((void)0) |
675 | |
676 | /** |
677 | * Same as `ERR_PRINT_ONCE` but also notifies the editor. |
678 | */ |
679 | #define ERR_PRINT_ONCE_ED(m_msg) \ |
680 | if (true) { \ |
681 | static bool first_print = true; \ |
682 | if (first_print) { \ |
683 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \ |
684 | first_print = false; \ |
685 | } \ |
686 | } else \ |
687 | ((void)0) |
688 | |
689 | // Print warning message macros. |
690 | |
691 | /** |
692 | * Prints `m_msg`. |
693 | * |
694 | * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. |
695 | */ |
696 | #define WARN_PRINT(m_msg) \ |
697 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING) |
698 | |
699 | /** |
700 | * Same as `WARN_PRINT` but also notifies the editor. |
701 | */ |
702 | #define WARN_PRINT_ED(m_msg) \ |
703 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING) |
704 | |
705 | /** |
706 | * Prints `m_msg` once during the application lifetime. |
707 | * |
708 | * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. |
709 | */ |
710 | #define WARN_PRINT_ONCE(m_msg) \ |
711 | if (true) { \ |
712 | static bool first_print = true; \ |
713 | if (first_print) { \ |
714 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING); \ |
715 | first_print = false; \ |
716 | } \ |
717 | } else \ |
718 | ((void)0) |
719 | |
720 | /** |
721 | * Same as `WARN_PRINT_ONCE` but also notifies the editor. |
722 | */ |
723 | #define WARN_PRINT_ONCE_ED(m_msg) \ |
724 | if (true) { \ |
725 | static bool first_print = true; \ |
726 | if (first_print) { \ |
727 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING); \ |
728 | first_print = false; \ |
729 | } \ |
730 | } else \ |
731 | ((void)0) |
732 | |
733 | // Print deprecated warning message macros. |
734 | |
735 | /** |
736 | * Warns that the current function is deprecated. |
737 | */ |
738 | #define WARN_DEPRECATED \ |
739 | if (true) { \ |
740 | static std::atomic<bool> warning_shown; \ |
741 | if (!warning_shown.load()) { \ |
742 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, ERR_HANDLER_WARNING); \ |
743 | warning_shown.store(true); \ |
744 | } \ |
745 | } else \ |
746 | ((void)0) |
747 | |
748 | /** |
749 | * Warns that the current function is deprecated and prints `m_msg`. |
750 | */ |
751 | #define WARN_DEPRECATED_MSG(m_msg) \ |
752 | if (true) { \ |
753 | static std::atomic<bool> warning_shown; \ |
754 | if (!warning_shown.load()) { \ |
755 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, ERR_HANDLER_WARNING); \ |
756 | warning_shown.store(true); \ |
757 | } \ |
758 | } else \ |
759 | ((void)0) |
760 | |
761 | /** |
762 | * Do not use. |
763 | * If the application should never reach this point use CRASH_NOW_MSG(m_msg) to explain why. |
764 | * |
765 | * The application crashes. |
766 | */ |
767 | #define CRASH_NOW() \ |
768 | if (true) { \ |
769 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \ |
770 | _err_flush_stdout(); \ |
771 | GENERATE_TRAP(); \ |
772 | } else \ |
773 | ((void)0) |
774 | |
775 | /** |
776 | * Only use if the application should never reach this point. |
777 | * |
778 | * Prints `m_msg`, and then the application crashes. |
779 | */ |
780 | #define CRASH_NOW_MSG(m_msg) \ |
781 | if (true) { \ |
782 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \ |
783 | _err_flush_stdout(); \ |
784 | GENERATE_TRAP(); \ |
785 | } else \ |
786 | ((void)0) |
787 | |
788 | /** |
789 | * Note: IN MOST CASES YOU SHOULD NOT USE THIS MACRO. |
790 | * Do not use unless you understand the trade-offs. |
791 | * |
792 | * DEV macros will be compiled out in releases, they are wrapped in DEV_ENABLED. |
793 | * |
794 | * Prefer WARNINGS / ERR_FAIL macros (which fail without crashing) - ERR_FAIL should be used in most cases. |
795 | * Then CRASH_NOW_MSG macros (on rare occasions where error cannot be recovered). |
796 | * |
797 | * DEV_ASSERT should generally only be used when both of the following conditions are met: |
798 | * 1) Bottleneck code where a check in release would be too expensive. |
799 | * 2) Situations where the check would fail obviously and straight away during the maintenance of the code |
800 | * (i.e. strict conditions that should be true no matter what) |
801 | * and that can't fail for other contributors once the code is finished and merged. |
802 | */ |
803 | #ifdef DEV_ENABLED |
804 | #define DEV_ASSERT(m_cond) \ |
805 | if (unlikely(!(m_cond))) { \ |
806 | _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \ |
807 | _err_flush_stdout(); \ |
808 | GENERATE_TRAP(); \ |
809 | } else \ |
810 | ((void)0) |
811 | #else |
812 | #define DEV_ASSERT(m_cond) |
813 | #endif |
814 | |
815 | #endif // ERROR_MACROS_H |
816 | |