Abandon standard C conformance and require GNU extensions

Removed the use_gnu_ext option as well as fallback paths for compilers
that don't support GNU extensions. To my knowledge, none of those
compilers support C11 to a sufficient extent to compile Taisei anyway,
and those fallbacks are very poorly tested.

Pedantic warnings are now disabled, and extensions that are common to
reasonably recent versions of GCC and clang are permitted to be relied
on (list of allowed extensions TBA).
This commit is contained in:
Andrei Alexeyev 2021-08-12 17:12:40 +03:00
parent f3fcec70f6
commit f73b1d6891
No known key found for this signature in database
GPG key ID: 72D26128040B9690
10 changed files with 112 additions and 164 deletions

View file

@ -3,7 +3,6 @@ project('taisei', 'c',
version : 'v1.4-dev',
meson_version : '>=0.53.0',
default_options : [
# Should really be c11, but gnu11 is a safer default because everything is terrible.
'c_std=gnu11',
'default_library=static',
@ -60,7 +59,6 @@ config = configuration_data()
taisei_c_args = [
'-Wall',
'-Wpedantic',
'-Werror=assume',
'-Werror=implicit-function-declaration',
@ -81,10 +79,8 @@ taisei_c_args = [
'-Wfloat-overflow-conversion',
'-Wfloat-zero-conversion',
'-Wfor-loop-analysis',
'-Wformat-pedantic',
'-Wformat-security',
'-Wgcc-compat',
'-Wgnu',
'-Wignored-qualifiers',
'-Winit-self',
'-Wlogical-op',
@ -272,7 +268,6 @@ else
config.set('TAISEI_BUILDCONF_HAVE_MAX_ALIGN_T', malloc_alignment > 0)
endif
config.set('TAISEI_BUILDCONF_USE_GNU_EXTENSIONS', get_option('use_gnu_ext'))
config.set('TAISEI_BUILDCONF_HAVE_BUILTIN_POPCOUNTLL', cc.has_function('__builtin_popcountll'))
config.set('TAISEI_BUILDCONF_HAVE_BUILTIN_POPCOUNT', cc.has_function('__builtin_popcount'))
config.set('TAISEI_BUILDCONF_HAVE_BUILTIN_AVAILABLE', cc.has_function('__builtin_available'))

View file

@ -190,10 +190,3 @@ option(
value : false,
description : 'Build shaderc and spirv-cross CLI tools from subprojects even if system versions exist'
)
option(
'use_gnu_ext',
type : 'boolean',
value : true,
description : 'Allow use of some GNU C extensions (if supported by compiler)'
)

View file

@ -33,43 +33,26 @@ typedef DYNAMIC_ARRAY_BASE(void) DynamicArray;
DynamicArray dyn_array; \
}
#ifdef USE_GNU_EXTENSIONS
#define DYNARRAY_ASSERT_VALID(darr) do { \
static_assert( \
__builtin_types_compatible_p(DynamicArray, __typeof__((darr)->dyn_array)), \
"x->dyn_array must be of DynamicArray type"); \
static_assert( \
__builtin_offsetof(__typeof__(*(darr)), dyn_array) == 0, \
"x->dyn_array must be the first member in struct"); \
} while(0)
#else
#define DYNARRAY_ASSERT_VALID(darr) ((void)0)
#endif
#define DYNARRAY_ASSERT_VALID(darr) do { \
static_assert( \
__builtin_types_compatible_p(DynamicArray, __typeof__((darr)->dyn_array)), \
"x->dyn_array must be of DynamicArray type"); \
static_assert( \
__builtin_offsetof(__typeof__(*(darr)), dyn_array) == 0, \
"x->dyn_array must be the first member in struct"); \
} while(0)
#ifdef USE_GNU_EXTENSIONS
#define DYNARRAY_CAST_TO_BASE(darr) (__extension__ ({ \
DYNARRAY_ASSERT_VALID(darr); \
&NOT_NULL(darr)->dyn_array; \
}))
#else
#define DYNARRAY_CAST_TO_BASE(darr) (&(darr)->dyn_array)
#endif
#define DYNARRAY_CAST_TO_BASE(darr) ({ \
DYNARRAY_ASSERT_VALID(darr); \
&NOT_NULL(darr)->dyn_array; \
})
#ifdef USE_GNU_EXTENSIONS
#define DYNARRAY_CHECK_ELEMENT_TYPE(darr, elem) do { \
static_assert( \
__builtin_types_compatible_p(__typeof__(elem), __typeof__(*(darr)->data)), \
"Dynamic array element type mismatch" \
); \
} while(0)
#else
#define DYNARRAY_CHECK_ELEMENT_TYPE(darr, elem) do { \
static_assert( \
sizeof(elem) == sizeof(*(darr)->data), \
"Dynamic array element size mismatch" \
); \
} while(0)
#endif
#define DYNARRAY_CHECK_ELEMENT_TYPE(darr, elem) do { \
static_assert( \
__builtin_types_compatible_p(__typeof__(elem), __typeof__(*(darr)->data)), \
"Dynamic array element type mismatch" \
); \
} while(0)
#define DYNARRAY_ELEM_SIZE(darr) sizeof(*(darr)->data)
@ -97,15 +80,10 @@ dynarray_size_t _dynarray_prepare_append_with_min_capacity(dynarray_size_t sizeo
#define _dynarray_append_with_min_capacity(darr, min_capacity) \
dynarray_get_ptr(darr, _dynarray_dispatch_func(prepare_append_with_min_capacity, darr, min_capacity))
#ifdef USE_GNU_EXTENSIONS
#define dynarray_append_with_min_capacity(darr, min_capacity) (__extension__ ({ \
assume((darr) != NULL); \
_dynarray_append_with_min_capacity((darr), min_capacity); \
}))
#else
#define dynarray_append_with_min_capacity(darr, min_capacity) \
_dynarray_append_with_min_capacity((darr), min_capacity)
#endif
#define dynarray_append_with_min_capacity(darr, min_capacity) ({ \
__auto_type _darr2 = NOT_NULL(darr); \
dynarray_get_ptr(_darr2, _dynarray_dispatch_func(prepare_append_with_min_capacity, _darr2, min_capacity)); \
})
#define dynarray_append(darr) \
dynarray_append_with_min_capacity(darr, 2)
@ -121,23 +99,22 @@ void _dynarray_compact(dynarray_size_t sizeof_element, DynamicArray *darr) attr_
} \
} while(0)
#ifdef USE_GNU_EXTENSIONS
#define dynarray_get_ptr(darr, idx) (__extension__ ({ \
DYNARRAY_ASSERT_VALID(darr); \
__auto_type _darr = NOT_NULL(darr); \
dynarray_size_t _darr_idx = (idx); \
assume(_darr_idx >= 0); \
assume(_darr_idx < _darr->num_elements); \
NOT_NULL((darr)->data + _darr_idx); \
}))
#else
#define dynarray_get_ptr(darr, idx) ((darr)->data + (idx))
#endif
#define dynarray_get_ptr(darr, idx) ({ \
DYNARRAY_ASSERT_VALID(darr); \
__auto_type _darr = NOT_NULL(darr); \
dynarray_size_t _darr_idx = (idx); \
assume(_darr_idx >= 0); \
assume(_darr_idx < _darr->num_elements); \
NOT_NULL((darr)->data + _darr_idx); \
})
#define dynarray_get(darr, idx) (*dynarray_get_ptr(darr, idx))
#define dynarray_get(darr, idx) (*dynarray_get_ptr(darr, idx))
#define dynarray_set(darr, idx, ...) ((*dynarray_get_ptr(darr, idx)) = (__VA_ARGS__))
void _dynarray_set_elements(dynarray_size_t sizeof_element, DynamicArray *darr, dynarray_size_t num_elements, void *elements) attr_nonnull_all;
void _dynarray_set_elements(
dynarray_size_t sizeof_element, DynamicArray *darr,
dynarray_size_t num_elements, void *elements
) attr_nonnull_all;
#define dynarray_set_elements(darr, num_elements, elements) do { \
DYNARRAY_ASSERT_VALID(darr); \
DYNARRAY_CHECK_ELEMENT_TYPE(darr, *(elements)); \
@ -145,24 +122,23 @@ void _dynarray_set_elements(dynarray_size_t sizeof_element, DynamicArray *darr,
} while(0)
typedef bool (*dynarray_filter_predicate_t)(const void *pelem, void *userdata);
void _dynarray_filter(dynarray_size_t sizeof_element, DynamicArray *darr, dynarray_filter_predicate_t predicate, void *userdata) attr_nonnull(2, 3);
void _dynarray_filter(
dynarray_size_t sizeof_element, DynamicArray *darr,
dynarray_filter_predicate_t predicate, void *userdata
) attr_nonnull(2, 3);
#define dynarray_filter(darr, predicate, userdata) \
_dynarray_dispatch_func(filter, darr, predicate, userdata)
#ifdef USE_GNU_EXTENSIONS
#define dynarray_indexof(darr, pelem) (__extension__ ({ \
DYNARRAY_ASSERT_VALID(darr); \
__auto_type _darr = NOT_NULL(darr); \
__auto_type _darr_pelem = NOT_NULL(pelem); \
DYNARRAY_CHECK_ELEMENT_TYPE(_darr, *(_darr_pelem)); \
intptr_t _darr_idx = (intptr_t)(_darr_pelem - _darr->data); \
assume(_darr_idx >= 0); \
assume(_darr_idx < _darr->num_elements); \
(dynarray_size_t)_darr_idx; \
}))
#else
#define dynarray_indexof(darr, pelem) ((intptr_t)((pelem) - (darr)->data))
#endif
#define dynarray_indexof(darr, pelem) ({ \
DYNARRAY_ASSERT_VALID(darr); \
__auto_type _darr = NOT_NULL(darr); \
__auto_type _darr_pelem = NOT_NULL(pelem); \
DYNARRAY_CHECK_ELEMENT_TYPE(_darr, *(_darr_pelem)); \
intptr_t _darr_idx = (intptr_t)(_darr_pelem - _darr->data); \
assume(_darr_idx >= 0); \
assume(_darr_idx < _darr->num_elements); \
(dynarray_size_t)_darr_idx; \
})
#define _dynarray_foreach_iter MACROHAX_ADDLINENUM(_dynarray_foreach_iter)
#define _dynarray_foreach_ignored MACROHAX_ADDLINENUM(_dynarray_foreach_ignored)
@ -179,9 +155,18 @@ void _dynarray_filter(dynarray_size_t sizeof_element, DynamicArray *darr, dynarr
} while(0)
#define dynarray_foreach_elem(_darr, _pelem_var, ...) \
dynarray_foreach(_darr, attr_unused dynarray_size_t _dynarray_foreach_ignored, _pelem_var, __VA_ARGS__)
dynarray_foreach( \
_darr, \
attr_unused dynarray_size_t _dynarray_foreach_ignored, \
_pelem_var, \
__VA_ARGS__ \
)
#define dynarray_foreach_idx(_darr, _cntr_var, ...) \
dynarray_foreach(_darr, _cntr_var, attr_unused void *_dynarray_foreach_ignored, __VA_ARGS__)
dynarray_foreach(_darr, \
_cntr_var, \
attr_unused void *_dynarray_foreach_ignored, \
__VA_ARGS__ \
)
#endif // IGUARD_dynarray_h

View file

@ -125,15 +125,11 @@ INLINE const char *ent_type_name(EntityType type) {
}
}
#ifdef USE_GNU_EXTENSIONS
#define ENT_CAST(ent, typename) (__extension__ ({ \
__auto_type _ent = ent; \
assert(_ent->type == ENT_TYPE_ID(typename)); \
UNION_CAST(EntityInterface*, typename*, _ent); \
}))
#else
#define ENT_CAST(ent, typename) UNION_CAST(EntityInterface*, typename*, (ent));
#endif
#define ENT_CAST(ent, typename) ({ \
__auto_type _ent = ent; \
assert(_ent->type == ENT_TYPE_ID(typename)); \
UNION_CAST(EntityInterface*, typename*, _ent); \
})
void ent_init(void);
void ent_shutdown(void);

View file

@ -79,7 +79,7 @@ void eventloop_run(void) {
em_handle_resize_event, NULL, EPRIO_SYSTEM, MAKE_TAISEI_EVENT(TE_VIDEO_MODE_CHANGED)
});
(__extension__ EM_ASM({
EM_ASM({
Module['onFirstFrame']();
}));
});
}

View file

@ -101,42 +101,36 @@ ListContainer* list_wrap_container(void *data) attr_returns_allocated;
// type-generic macros
#ifdef USE_GNU_EXTENSIONS
// thorough safeguard
#define LIST_CAST(expr) ({ \
static_assert(__builtin_types_compatible_p( \
ListInterface, __typeof__((*(expr)).list_interface)), \
"struct must implement ListInterface (use the LIST_INTERFACE macro)"); \
static_assert(__builtin_offsetof(__typeof__(*(expr)), list_interface) == 0, \
"list_interface must be the first member in struct"); \
CASTPTR_ASSUME_ALIGNED((expr), List); \
})
#define LIST_CAST(expr) (__extension__ ({ \
static_assert(__builtin_types_compatible_p(ListInterface, __typeof__((*(expr)).list_interface)), \
"struct must implement ListInterface (use the LIST_INTERFACE macro)"); \
static_assert(__builtin_offsetof(__typeof__(*(expr)), list_interface) == 0, \
"list_interface must be the first member in struct"); \
CASTPTR_ASSUME_ALIGNED((expr), List); \
}))
#define LIST_CAST_2(expr) ({ \
static_assert(__builtin_types_compatible_p(\
ListInterface, __typeof__((**(expr)).list_interface)), \
"struct must implement ListInterface (use the LIST_INTERFACE macro)"); \
static_assert(__builtin_offsetof(__typeof__(**(expr)), list_interface) == 0, \
"list_interface must be the first member in struct"); \
(void)ASSUME_ALIGNED(*(expr), alignof(List)); \
(List**)(expr); \
})
#define LIST_CAST_2(expr) (__extension__ ({ \
static_assert(__builtin_types_compatible_p(ListInterface, __typeof__((**(expr)).list_interface)), \
"struct must implement ListInterface (use the LIST_INTERFACE macro)"); \
static_assert(__builtin_offsetof(__typeof__(**(expr)), list_interface) == 0, \
"list_interface must be the first member in struct"); \
(void)ASSUME_ALIGNED(*(expr), alignof(List)); \
(List**)(expr); \
}))
#define LIST_ANCHOR_CAST(expr) ({ \
static_assert(__builtin_types_compatible_p(\
ListAnchorInterface, __typeof__((*(expr)).list_anchor_interface)), \
"struct must implement ListAnchorInterface (use the LIST_ANCHOR_INTERFACE macro)"); \
static_assert(__builtin_offsetof(__typeof__(*(expr)), list_anchor_interface) == 0, \
"list_anchor_interface must be the first member in struct"); \
CASTPTR_ASSUME_ALIGNED((expr), ListAnchor); \
})
#define LIST_ANCHOR_CAST(expr) (__extension__ ({ \
static_assert(__builtin_types_compatible_p(ListAnchorInterface, __typeof__((*(expr)).list_anchor_interface)), \
"struct must implement ListAnchorInterface (use the LIST_ANCHOR_INTERFACE macro)"); \
static_assert(__builtin_offsetof(__typeof__(*(expr)), list_anchor_interface) == 0, \
"list_anchor_interface must be the first member in struct"); \
CASTPTR_ASSUME_ALIGNED((expr), ListAnchor); \
}))
#define LIST_CAST_RETURN(e_typekey, e_return) CASTPTR_ASSUME_ALIGNED((e_return), __typeof__(*(e_typekey)))
#else
// basic safeguard
#define LIST_CAST(expr) ((void)sizeof((*(expr)).list_interface), (List*)(expr))
#define LIST_CAST_2(expr) ((void)sizeof((**(expr)).list_interface), (List**)(expr))
#define LIST_ANCHOR_CAST(expr) ((void)sizeof((*(expr)).list_anchor_interface), (ListAnchor*)(expr))
#define LIST_CAST_RETURN(e_typekey, e_return) (void*)(e_return)
#endif
#define LIST_CAST_RETURN(e_typekey, e_return) \
CASTPTR_ASSUME_ALIGNED((e_return), __typeof__(*(e_typekey)))
#define list_insert(dest,elem) \
(LIST_CAST_RETURN(elem, list_insert(LIST_CAST_2(dest), LIST_CAST(elem))))

View file

@ -26,8 +26,8 @@ void _ts_assert_fail(const char *cond, const char *func, const char *file, int l
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
void _emscripten_trap(void) {
(__extension__ EM_ASM({
EM_ASM({
throw new Error("You just activated my trap card!");
}));
});
}
#endif

View file

@ -76,12 +76,9 @@
#define PRAGMA(p) _Pragma(#p)
#ifdef RNG_API_CHECK
#undef TAISEI_BUILDCONF_USE_GNU_EXTENSIONS
#undef USE_GNU_EXTENSIONS
#endif
#ifndef __GNUC__ // clang defines this too
#pragma Unsupported compiler, expect nothing to work
#define __attribute__(...)
#define __extension__
#define UNREACHABLE
@ -91,9 +88,6 @@
#define LIKELY(x) (bool)(x)
#define UNLIKELY(x) (bool)(x)
#else
#ifdef TAISEI_BUILDCONF_USE_GNU_EXTENSIONS
#define USE_GNU_EXTENSIONS
#endif
#define UNREACHABLE __builtin_unreachable()
#define DIAGNOSTIC(x) PRAGMA(GCC diagnostic x)
@ -292,32 +286,23 @@ typedef _Complex double cmplx;
#define INLINE static inline attr_must_inline __attribute__((gnu_inline))
#ifdef USE_GNU_EXTENSIONS
#define ASSUME_ALIGNED(expr, alignment) (__extension__ ({ \
static_assert(__builtin_constant_p(alignment), ""); \
__auto_type _assume_aligned_ptr = (expr); \
assert(((uintptr_t)_assume_aligned_ptr & ((alignment) - 1)) == 0); \
__builtin_assume_aligned(_assume_aligned_ptr, (alignment)); \
}))
#else
#define ASSUME_ALIGNED(expr, alignment) (expr)
#endif
#define ASSUME_ALIGNED(expr, alignment) ({ \
static_assert(__builtin_constant_p(alignment), ""); \
__auto_type _assume_aligned_ptr = (expr); \
assert(((uintptr_t)_assume_aligned_ptr & ((alignment) - 1)) == 0); \
__builtin_assume_aligned(_assume_aligned_ptr, (alignment)); \
})
#define UNION_CAST(_from_type, _to_type, _expr) \
((union { _from_type f; _to_type t; }) { .f = (_expr) }).t
// #define CASTPTR_ASSUME_ALIGNED(expr, type) UNION_CAST(void*, type*, ASSUME_ALIGNED(expr, alignof(type)))
#define CASTPTR_ASSUME_ALIGNED(expr, type) ((type*)ASSUME_ALIGNED((expr), alignof(type)))
#ifdef USE_GNU_EXTENSIONS
#define NOT_NULL(expr) (__extension__ ({ \
__auto_type _assume_not_null_ptr = (expr); \
assume(_assume_not_null_ptr != NULL); \
_assume_not_null_ptr; \
}))
#else
#define NOT_NULL(expr) (expr)
#endif
#define NOT_NULL(expr) ({ \
__auto_type _assume_not_null_ptr = (expr); \
assume(_assume_not_null_ptr != NULL); \
_assume_not_null_ptr; \
})
#ifdef __SWITCH__
#include "../arch_switch.h"

View file

@ -506,7 +506,7 @@ uint64_t _umuldiv64_slow(uint64_t x, uint64_t multiplier, uint64_t divisor) {
INLINE
uint64_t _umuldiv64(uint64_t x, uint64_t multiplier, uint64_t divisor) {
#if defined(TAISEI_BUILDCONF_HAVE_INT128)
__extension__ typedef unsigned __int128 uint128_t;
typedef unsigned __int128 uint128_t;
return ((uint128_t)x * (uint128_t)multiplier) / divisor;
#elif defined(TAISEI_BUILDCONF_HAVE_LONG_DOUBLE)
#define UMULDIV64_SANITY_CHECK

View file

@ -36,7 +36,7 @@ void vfs_sync_callback(bool is_load, char *error, CallChain *next) {
void vfs_sync(VFSSyncMode mode, CallChain next) {
CallChain *cc = memdup(&next, sizeof(next));
__extension__ (EM_ASM({
EM_ASM({
SyncFS($0, $1);
}, (mode == VFS_SYNC_LOAD), cc));
}, (mode == VFS_SYNC_LOAD), cc);
}