Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/rapidyaml/include/c4/error.hpp
4261 views
1
#ifndef _C4_ERROR_HPP_
2
#define _C4_ERROR_HPP_
3
4
/** @file error.hpp Facilities for error reporting and runtime assertions. */
5
6
/** @defgroup error_checking Error checking */
7
8
#include "c4/config.hpp"
9
10
#ifdef _DOXYGEN_
11
/** if this is defined and exceptions are enabled, then calls to C4_ERROR()
12
* will throw an exception
13
* @ingroup error_checking */
14
# define C4_EXCEPTIONS_ENABLED
15
/** if this is defined and exceptions are enabled, then calls to C4_ERROR()
16
* will throw an exception
17
* @see C4_EXCEPTIONS_ENABLED
18
* @ingroup error_checking */
19
# define C4_ERROR_THROWS_EXCEPTION
20
/** evaluates to noexcept when C4_ERROR might be called and
21
* exceptions are disabled. Otherwise, defaults to nothing.
22
* @ingroup error_checking */
23
# define C4_NOEXCEPT
24
#endif // _DOXYGEN_
25
26
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
27
# define C4_NOEXCEPT
28
#else
29
# define C4_NOEXCEPT noexcept
30
#endif
31
32
33
namespace c4 {
34
namespace detail {
35
struct fail_type__ {};
36
} // detail
37
} // c4
38
#define C4_STATIC_ERROR(dummy_type, errmsg) \
39
static_assert(std::is_same<dummy_type, c4::detail::fail_type__>::value, errmsg)
40
41
42
//-----------------------------------------------------------------------------
43
44
#define C4_ASSERT_SAME_TYPE(ty1, ty2) \
45
C4_STATIC_ASSERT(std::is_same<ty1 C4_COMMA_X ty2>::value)
46
47
#define C4_ASSERT_DIFF_TYPE(ty1, ty2) \
48
C4_STATIC_ASSERT( ! std::is_same<ty1 C4_COMMA_X ty2>::value)
49
50
51
//-----------------------------------------------------------------------------
52
53
#ifdef _DOXYGEN_
54
/** utility macro that triggers a breakpoint when
55
* the debugger is attached and NDEBUG is not defined.
56
* @ingroup error_checking */
57
# define C4_DEBUG_BREAK()
58
#endif // _DOXYGEN_
59
60
61
#if defined(NDEBUG) || defined(C4_NO_DEBUG_BREAK)
62
# define C4_DEBUG_BREAK()
63
#else
64
# ifdef __clang__
65
# pragma clang diagnostic push
66
# if !defined(__APPLE_CC__)
67
# if __clang_major__ >= 10
68
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
69
# endif
70
# else
71
# if __clang_major__ >= 13
72
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
73
# endif
74
# endif
75
# elif defined(__GNUC__)
76
# endif
77
# include <c4/ext/debugbreak/debugbreak.h>
78
# define C4_DEBUG_BREAK() if(c4::is_debugger_attached()) { ::debug_break(); }
79
# ifdef __clang__
80
# pragma clang diagnostic pop
81
# elif defined(__GNUC__)
82
# endif
83
#endif
84
85
namespace c4 {
86
C4CORE_EXPORT bool is_debugger_attached();
87
} // namespace c4
88
89
90
//-----------------------------------------------------------------------------
91
92
#ifdef __clang__
93
/* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
94
* variadic macros is not portable, but works in clang, gcc, msvc, icc.
95
* clang requires switching off compiler warnings for pedantic mode.
96
* @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
97
# pragma clang diagnostic push
98
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
99
#elif defined(__GNUC__)
100
/* GCC also issues a warning for zero-args calls to variadic macros.
101
* This warning is switched on with -pedantic and apparently there is no
102
* easy way to turn it off as with clang. But marking this as a system
103
* header works.
104
* @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
105
* @see http://stackoverflow.com/questions/35587137/ */
106
# pragma GCC system_header
107
#endif
108
109
110
//-----------------------------------------------------------------------------
111
112
namespace c4 {
113
114
typedef enum : uint32_t {
115
/** when an error happens and the debugger is attached, call C4_DEBUG_BREAK().
116
* Without effect otherwise. */
117
ON_ERROR_DEBUGBREAK = 0x01 << 0,
118
/** when an error happens log a message. */
119
ON_ERROR_LOG = 0x01 << 1,
120
/** when an error happens invoke a callback if it was set with
121
* set_error_callback(). */
122
ON_ERROR_CALLBACK = 0x01 << 2,
123
/** when an error happens call std::terminate(). */
124
ON_ERROR_ABORT = 0x01 << 3,
125
/** when an error happens and exceptions are enabled throw an exception.
126
* Without effect otherwise. */
127
ON_ERROR_THROW = 0x01 << 4,
128
/** the default flags. */
129
ON_ERROR_DEFAULTS = ON_ERROR_DEBUGBREAK|ON_ERROR_LOG|ON_ERROR_CALLBACK|ON_ERROR_ABORT
130
} ErrorFlags_e;
131
using error_flags = uint32_t;
132
C4CORE_EXPORT void set_error_flags(error_flags f);
133
C4CORE_EXPORT error_flags get_error_flags();
134
135
136
using error_callback_type = void (*)(const char* msg, size_t msg_size);
137
C4CORE_EXPORT void set_error_callback(error_callback_type cb);
138
C4CORE_EXPORT error_callback_type get_error_callback();
139
140
141
//-----------------------------------------------------------------------------
142
/** RAII class controling the error settings inside a scope. */
143
struct ScopedErrorSettings
144
{
145
error_flags m_flags;
146
error_callback_type m_callback;
147
148
explicit ScopedErrorSettings(error_callback_type cb)
149
: m_flags(get_error_flags()),
150
m_callback(get_error_callback())
151
{
152
set_error_callback(cb);
153
}
154
explicit ScopedErrorSettings(error_flags flags)
155
: m_flags(get_error_flags()),
156
m_callback(get_error_callback())
157
{
158
set_error_flags(flags);
159
}
160
explicit ScopedErrorSettings(error_flags flags, error_callback_type cb)
161
: m_flags(get_error_flags()),
162
m_callback(get_error_callback())
163
{
164
set_error_flags(flags);
165
set_error_callback(cb);
166
}
167
~ScopedErrorSettings()
168
{
169
set_error_flags(m_flags);
170
set_error_callback(m_callback);
171
}
172
};
173
174
175
//-----------------------------------------------------------------------------
176
177
/** source location */
178
struct srcloc;
179
180
C4CORE_EXPORT void handle_error(srcloc s, const char *fmt, ...);
181
C4CORE_EXPORT void handle_warning(srcloc s, const char *fmt, ...);
182
183
184
# define C4_ERROR(msg, ...) \
185
do { \
186
if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
187
{ \
188
C4_DEBUG_BREAK() \
189
} \
190
c4::handle_error(C4_SRCLOC(), msg, ## __VA_ARGS__); \
191
} while(0)
192
193
194
# define C4_WARNING(msg, ...) \
195
c4::handle_warning(C4_SRCLOC(), msg, ## __VA_ARGS__)
196
197
198
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
199
200
struct srcloc
201
{
202
const char *file = "";
203
const char *func = "";
204
int line = 0;
205
};
206
#define C4_SRCLOC() c4::srcloc{__FILE__, C4_PRETTY_FUNC, __LINE__}
207
208
#elif defined(C4_ERROR_SHOWS_FILELINE)
209
210
struct srcloc
211
{
212
const char *file;
213
int line;
214
};
215
#define C4_SRCLOC() c4::srcloc{__FILE__, __LINE__}
216
217
#elif ! defined(C4_ERROR_SHOWS_FUNC)
218
219
struct srcloc
220
{
221
};
222
#define C4_SRCLOC() c4::srcloc()
223
224
#else
225
# error not implemented
226
#endif
227
228
229
//-----------------------------------------------------------------------------
230
// assertions
231
232
// Doxygen needs this so that only one definition counts
233
#ifdef _DOXYGEN_
234
/** Explicitly enables assertions, independently of NDEBUG status.
235
* This is meant to allow enabling assertions even when NDEBUG is defined.
236
* Defaults to undefined.
237
* @ingroup error_checking */
238
# define C4_USE_ASSERT
239
/** assert that a condition is true; this is turned off when NDEBUG
240
* is defined and C4_USE_ASSERT is not true.
241
* @ingroup error_checking */
242
# define C4_ASSERT
243
/** same as C4_ASSERT(), additionally prints a printf-formatted message
244
* @ingroup error_checking */
245
# define C4_ASSERT_MSG
246
/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults
247
* to noexcept
248
* @ingroup error_checking */
249
# define C4_NOEXCEPT_A
250
#endif // _DOXYGEN_
251
252
#ifndef C4_USE_ASSERT
253
# ifdef NDEBUG
254
# define C4_USE_ASSERT 0
255
# else
256
# define C4_USE_ASSERT 1
257
# endif
258
#endif
259
260
#if C4_USE_ASSERT
261
# define C4_ASSERT(cond) C4_CHECK(cond)
262
# define C4_ASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)
263
# define C4_ASSERT_IF(predicate, cond) if(predicate) { C4_ASSERT(cond); }
264
# define C4_NOEXCEPT_A C4_NOEXCEPT
265
#else
266
# define C4_ASSERT(cond)
267
# define C4_ASSERT_MSG(cond, /*fmt, */...)
268
# define C4_ASSERT_IF(predicate, cond)
269
# define C4_NOEXCEPT_A noexcept
270
#endif
271
272
273
//-----------------------------------------------------------------------------
274
// extreme assertions
275
276
// Doxygen needs this so that only one definition counts
277
#ifdef _DOXYGEN_
278
/** Explicitly enables extreme assertions; this is meant to allow enabling
279
* assertions even when NDEBUG is defined. Defaults to undefined.
280
* @ingroup error_checking */
281
# define C4_USE_XASSERT
282
/** extreme assertion: can be switched off independently of
283
* the regular assertion; use for example for bounds checking in hot code.
284
* Turned on only when C4_USE_XASSERT is defined
285
* @ingroup error_checking */
286
# define C4_XASSERT
287
/** same as C4_XASSERT(), and additionally prints a printf-formatted message
288
* @ingroup error_checking */
289
# define C4_XASSERT_MSG
290
/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults to noexcept
291
* @ingroup error_checking */
292
# define C4_NOEXCEPT_X
293
#endif // _DOXYGEN_
294
295
#ifndef C4_USE_XASSERT
296
# define C4_USE_XASSERT C4_USE_ASSERT
297
#endif
298
299
#if C4_USE_XASSERT
300
# define C4_XASSERT(cond) C4_CHECK(cond)
301
# define C4_XASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)
302
# define C4_XASSERT_IF(predicate, cond) if(predicate) { C4_XASSERT(cond); }
303
# define C4_NOEXCEPT_X C4_NOEXCEPT
304
#else
305
# define C4_XASSERT(cond)
306
# define C4_XASSERT_MSG(cond, /*fmt, */...)
307
# define C4_XASSERT_IF(predicate, cond)
308
# define C4_NOEXCEPT_X noexcept
309
#endif
310
311
312
//-----------------------------------------------------------------------------
313
// checks: never switched-off
314
315
/** Check that a condition is true, or raise an error when not
316
* true. Unlike C4_ASSERT(), this check is not disabled in non-debug
317
* builds.
318
* @see C4_ASSERT
319
* @ingroup error_checking
320
*
321
* @todo add constexpr-compatible compile-time assert:
322
* https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
323
*/
324
#define C4_CHECK(cond) \
325
do { \
326
if(C4_UNLIKELY(!(cond))) \
327
{ \
328
C4_ERROR("check failed: %s", #cond); \
329
} \
330
} while(0)
331
332
333
/** like C4_CHECK(), and additionally log a printf-style message.
334
* @see C4_CHECK
335
* @ingroup error_checking */
336
#define C4_CHECK_MSG(cond, fmt, ...) \
337
do { \
338
if(C4_UNLIKELY(!(cond))) \
339
{ \
340
C4_ERROR("check failed: " #cond "\n" fmt, ## __VA_ARGS__); \
341
} \
342
} while(0)
343
344
345
//-----------------------------------------------------------------------------
346
// Common error conditions
347
348
#define C4_NOT_IMPLEMENTED() C4_ERROR("NOT IMPLEMENTED")
349
#define C4_NOT_IMPLEMENTED_MSG(/*msg, */...) C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__)
350
#define C4_NOT_IMPLEMENTED_IF(condition) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED"); } } while(0)
351
#define C4_NOT_IMPLEMENTED_IF_MSG(condition, /*msg, */...) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__); } } while(0)
352
353
#define C4_NEVER_REACH() do { C4_ERROR("never reach this point"); C4_UNREACHABLE(); } while(0)
354
#define C4_NEVER_REACH_MSG(/*msg, */...) do { C4_ERROR("never reach this point: " __VA_ARGS__); C4_UNREACHABLE(); } while(0)
355
356
357
358
//-----------------------------------------------------------------------------
359
// helpers for warning suppression
360
// idea adapted from https://github.com/onqtam/doctest/
361
362
// TODO: add C4_MESSAGE() https://stackoverflow.com/questions/18252351/custom-preprocessor-macro-for-a-conditional-pragma-message-xxx?rq=1
363
364
365
#ifdef C4_MSVC
366
#define C4_SUPPRESS_WARNING_MSVC_PUSH __pragma(warning(push))
367
#define C4_SUPPRESS_WARNING_MSVC(w) __pragma(warning(disable : w))
368
#define C4_SUPPRESS_WARNING_MSVC_POP __pragma(warning(pop))
369
#else // C4_MSVC
370
#define C4_SUPPRESS_WARNING_MSVC_PUSH
371
#define C4_SUPPRESS_WARNING_MSVC(w)
372
#define C4_SUPPRESS_WARNING_MSVC_POP
373
#endif // C4_MSVC
374
375
376
#ifdef C4_CLANG
377
#define C4_PRAGMA_TO_STR(x) _Pragma(#x)
378
#define C4_SUPPRESS_WARNING_CLANG_PUSH _Pragma("clang diagnostic push")
379
#define C4_SUPPRESS_WARNING_CLANG(w) C4_PRAGMA_TO_STR(clang diagnostic ignored w)
380
#define C4_SUPPRESS_WARNING_CLANG_POP _Pragma("clang diagnostic pop")
381
#else // C4_CLANG
382
#define C4_SUPPRESS_WARNING_CLANG_PUSH
383
#define C4_SUPPRESS_WARNING_CLANG(w)
384
#define C4_SUPPRESS_WARNING_CLANG_POP
385
#endif // C4_CLANG
386
387
388
#ifdef C4_GCC
389
#define C4_PRAGMA_TO_STR(x) _Pragma(#x)
390
#define C4_SUPPRESS_WARNING_GCC_PUSH _Pragma("GCC diagnostic push")
391
#define C4_SUPPRESS_WARNING_GCC(w) C4_PRAGMA_TO_STR(GCC diagnostic ignored w)
392
#define C4_SUPPRESS_WARNING_GCC_POP _Pragma("GCC diagnostic pop")
393
#else // C4_GCC
394
#define C4_SUPPRESS_WARNING_GCC_PUSH
395
#define C4_SUPPRESS_WARNING_GCC(w)
396
#define C4_SUPPRESS_WARNING_GCC_POP
397
#endif // C4_GCC
398
399
400
#define C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(w) \
401
C4_SUPPRESS_WARNING_MSVC_PUSH \
402
C4_SUPPRESS_WARNING_MSVC(w)
403
404
#define C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w) \
405
C4_SUPPRESS_WARNING_CLANG_PUSH \
406
C4_SUPPRESS_WARNING_CLANG(w)
407
408
#define C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \
409
C4_SUPPRESS_WARNING_GCC_PUSH \
410
C4_SUPPRESS_WARNING_GCC(w)
411
412
413
#define C4_SUPPRESS_WARNING_GCC_CLANG_PUSH \
414
C4_SUPPRESS_WARNING_GCC_PUSH \
415
C4_SUPPRESS_WARNING_CLANG_PUSH
416
417
#define C4_SUPPRESS_WARNING_GCC_CLANG(w) \
418
C4_SUPPRESS_WARNING_GCC(w) \
419
C4_SUPPRESS_WARNING_CLANG(w)
420
421
#define C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(w) \
422
C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \
423
C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w)
424
425
#define C4_SUPPRESS_WARNING_GCC_CLANG_POP \
426
C4_SUPPRESS_WARNING_GCC_POP \
427
C4_SUPPRESS_WARNING_CLANG_POP
428
429
} // namespace c4
430
431
#ifdef __clang__
432
# pragma clang diagnostic pop
433
#endif
434
435
#endif /* _C4_ERROR_HPP_ */
436
437