util/assert: add optional message to assert, assume, and static_assert

Removed static_assert_nomsg, since static_assert's message argument is
optional now. In C2X mode this uses the native _Static_assert
functionality, otherwise it falls back to a macro-based overload.

Additionally, rewrote the assert macro so it correctly marks the failing
branch as a dead end.
This commit is contained in:
Andrei Alexeyev 2023-03-26 01:52:41 +01:00
parent 7c19322940
commit 711edc218f
No known key found for this signature in database
GPG key ID: 72D26128040B9690
8 changed files with 83 additions and 31 deletions

View file

@ -334,6 +334,16 @@ config.set('TAISEI_BUILDCONF_HAVE_ATTR_MALLOC_WITH_ARGS', cc.compiles(
args : ['-Wattributes', '-Werror']
))
config.set('TAISEI_BUILDCONF_HAVE_STATIC_ASSERT_WITHOUT_MSG', cc.compiles(
'''
#include <assert.h>
static_assert(1, "with message");
static_assert(1);
''',
name : 'static_assert() without message',
args : ['-Werror']
))
prefer_relpath_systems = [
'windows',
]

View file

@ -68,7 +68,7 @@ typedef enum {
NUM_EPRIOS = EPRIO_LAST - EPRIO_FIRST + 1,
} EventPriority;
static_assert_nomsg(EPRIO_DEFAULT == 0);
static_assert(EPRIO_DEFAULT == 0);
typedef enum {
EFLAG_MENU = (1 << 0),

View file

@ -150,11 +150,11 @@ typedef enum PixmapFormat {
} PixmapFormat;
// sanity check
static_assert_nomsg(_impl_pixmap_format_layout(PIXMAP_FORMAT_ETC2_EAC_RG11) == PIXMAP_LAYOUT_RG);
static_assert_nomsg(_impl_pixmap_format_compression(PIXMAP_FORMAT_ASTC_4x4_RGBA) == PIXMAP_COMPRESSION_ASTC_4x4_RGBA);
static_assert_nomsg(_impl_pixmap_format_depth(PIXMAP_FORMAT_RGB16F) == 16);
static_assert_nomsg(_impl_pixmap_format_depth(PIXMAP_FORMAT_RGB8) == 8);
static_assert_nomsg(_impl_pixmap_format_layout(PIXMAP_FORMAT_RGB8) == PIXMAP_LAYOUT_RGB);
static_assert(_impl_pixmap_format_layout(PIXMAP_FORMAT_ETC2_EAC_RG11) == PIXMAP_LAYOUT_RG);
static_assert(_impl_pixmap_format_compression(PIXMAP_FORMAT_ASTC_4x4_RGBA) == PIXMAP_COMPRESSION_ASTC_4x4_RGBA);
static_assert(_impl_pixmap_format_depth(PIXMAP_FORMAT_RGB16F) == 16);
static_assert(_impl_pixmap_format_depth(PIXMAP_FORMAT_RGB8) == 8);
static_assert(_impl_pixmap_format_layout(PIXMAP_FORMAT_RGB8) == PIXMAP_LAYOUT_RGB);
INLINE bool pixmap_format_is_compressed(PixmapFormat fmt) {
return _impl_pixmap_format_is_compressed(fmt);

View file

@ -167,7 +167,7 @@ static MagicUniformSpec magic_unfiroms[] = {
[UMAGIC_COLOR_OUT_SIZES] = { "r_colorOutputSizes[0]", "vec2", UNIFORM_VEC2 },
[UMAGIC_DEPTH_OUT_SIZE] = { "r_depthOutputSize", "vec2", UNIFORM_VEC2 },
};
static_assert_nomsg(ARRAY_SIZE(magic_unfiroms) == NUM_MAGIC_UNIFORMS);
static_assert(ARRAY_SIZE(magic_unfiroms) == NUM_MAGIC_UNIFORMS);
static void gl33_update_uniform(Uniform *uniform, uint offset, uint count, const void *data) {
// these are validated properly in gl33_uniform

View file

@ -186,7 +186,7 @@ static GLenum target_from_class_and_layer(TextureClass cls, uint layer) {
[CUBEMAP_FACE_POS_Z] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
[CUBEMAP_FACE_NEG_Z] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
};
static_assert_nomsg(ARRAY_SIZE(facemap) == 6);
static_assert(ARRAY_SIZE(facemap) == 6);
assert(layer < ARRAY_SIZE(facemap));
return facemap[layer];
} else if(target == GL_TEXTURE_2D) {

View file

@ -479,7 +479,7 @@ static bool load_pixmap(
static void texture_loader_cubemap_from_pixmaps(TextureLoadData *ld) {
ResourceLoadState *st = ld->st;
static_assert_nomsg(sizeof(*ld->cubemaps)/sizeof(*ld->pixmaps) == ARRAY_SIZE(ld->src_paths.cubemap));
static_assert(sizeof(*ld->cubemaps)/sizeof(*ld->pixmaps) == ARRAY_SIZE(ld->src_paths.cubemap));
const int nsides = sizeof(*ld->cubemaps)/sizeof(*ld->pixmaps);
ld->num_pixmaps = nsides;
ld->cubemaps = ALLOC_ARRAY(1, typeof(*ld->cubemaps));

View file

@ -12,14 +12,31 @@
#include "util.h"
#include "log.h"
void _ts_assert_fail(const char *cond, const char *func, const char *file, int line, bool use_log) {
void _ts_assert_fail(
const char *cond, const char *msg, const char *func, const char *file, int line, bool use_log
) {
use_log = use_log && log_initialized();
if(use_log) {
_taisei_log(LOG_FAKEFATAL, func, file, line, "%s:%i: assertion `%s` failed", file, line, cond);
if(msg) {
_taisei_log(LOG_FAKEFATAL, func, file, line,
"%s:%i: assertion `%s` failed: %s", file, line, cond, msg);
} else {
_taisei_log(LOG_FAKEFATAL, func, file, line,
"%s:%i: assertion `%s` failed", file, line, cond);
}
log_sync(true);
} else {
tsfprintf(stderr, "%s:%i: %s(): assertion `%s` failed\n", file, line, func, cond);
if(msg) {
tsfprintf(stderr,
"%s:%i: %s(): assertion `%s` failed: %s\n", file, line, func, cond, msg);
} else {
tsfprintf(stderr,
"%s:%i: %s(): assertion `%s` failed\n", file, line, func, cond);
}
fflush(stderr);
}
}

View file

@ -9,21 +9,26 @@
#pragma once
#include "taisei.h"
#if __has_attribute(analyzer_noreturn)
#define attr_analyzer_noreturn \
__attribute__ ((analyzer_noreturn))
#else
#define attr_analyzer_noreturn
#include "util/macrohax.h"
#ifndef TAISEI_BUILDCONF_HAVE_STATIC_ASSERT_WITHOUT_MSG
#undef static_assert
#define _static_assert_0(cond) _Static_assert(cond, #cond)
#define _static_assert_1(cond, msg) _Static_assert(cond, msg)
#define static_assert(cond, ...) \
MACROHAX_OVERLOAD_NARGS(_static_assert_, __VA_ARGS__)(cond, ##__VA_ARGS__)
#endif
attr_analyzer_noreturn
void _ts_assert_fail(const char *cond, const char *func, const char *file, int line, bool use_log);
void _ts_assert_fail(
const char *cond,
const char *msg,
const char *func,
const char *file,
int line,
bool use_log
);
#undef assert
#undef static_assert
#define static_assert _Static_assert
#define static_assert_nomsg(x) static_assert(x, #x)
#if defined(__EMSCRIPTEN__)
void _emscripten_trap(void);
@ -42,15 +47,35 @@ void _ts_assert_fail(const char *cond, const char *func, const char *file, int l
#endif
#ifdef NDEBUG
#define _assert(cond, uselog)
#define _assume(cond, uselog) ASSUME(cond)
#define _assert(cond, msg, uselog)
#define _assume(cond, msg, uselog) ASSUME(cond)
#else
#define _assert(cond, uselog) (LIKELY(cond) ? (void)0 : (_ts_assert_fail(#cond, __func__, _TAISEI_SRC_FILE, __LINE__, uselog), TRAP()))
#define _assume(cond, uselog) _assert(cond, uselog)
#define _assert(cond, msg, uselog) ({ \
if(UNLIKELY(!(cond))) { \
_ts_assert_fail(#cond, msg, __func__, _TAISEI_SRC_FILE, __LINE__, uselog); \
TRAP(); \
__builtin_unreachable(); \
} \
})
#define _assume(cond, msg, uselog) _assert(cond, msg, uselog)
#endif
#define assert(cond) _assert(cond, true)
#define assert_nolog(cond) _assert(cond, false)
#define _assert_0(cond) _assert(cond, NULL, true)
#define _assert_1(cond, msg) _assert(cond, msg, true)
#define assert(cond, ...) \
MACROHAX_OVERLOAD_NARGS(_assert_, __VA_ARGS__)(cond, ##__VA_ARGS__)
#define assume(cond) _assume(cond, true)
#define assume_nolog(cond) _assume(cond, false)
#define _assert_nolog_0(cond) _assert(cond, NULL, false)
#define _assert_nolog_1(cond, msg) _assert(cond, msg, false)
#define assert_nolog(cond, ...) \
MACROHAX_OVERLOAD_NARGS(_assert_nolog_, __VA_ARGS__)(cond, ##__VA_ARGS__)
#define _assume_0(cond) _assume(cond, NULL, true)
#define _assume_1(cond, msg) _assume(cond, msg, true)
#define assume(cond, ...) \
MACROHAX_OVERLOAD_NARGS(_assume_, __VA_ARGS__)(cond, ##__VA_ARGS__)
#define _assume_nolog_0(cond) _assume(cond, NULL, false)
#define _assume_nolog_1(cond, msg) _assume(cond, msg, false)
#define assume_nolog(cond, ...) \
MACROHAX_OVERLOAD_NARGS(_assume_nolog_, __VA_ARGS__)(cond, ##__VA_ARGS__)