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
38class String;
39
40enum 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.
49typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, bool p_editor_notify, ErrorHandlerType p_type);
50
51struct ErrorHandlerList {
52 ErrorHandlerFunc errfunc = nullptr;
53 void *userdata = nullptr;
54
55 ErrorHandlerList *next = nullptr;
56
57 ErrorHandlerList() {}
58};
59
60void add_error_handler(ErrorHandlerList *p_handler);
61void remove_error_handler(const ErrorHandlerList *p_handler);
62
63// Functions used by the error macros.
64void _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);
65void _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);
66void _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);
67void _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);
68void _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);
69void _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);
70void _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);
71void _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);
72void _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