c-stdaux: re-import git-subtree for 'src/c-stdaux'

git subtree pull --prefix src/c-stdaux git@github.com:c-util/c-stdaux.git main --squash
This commit is contained in:
Thomas Haller 2022-12-16 13:46:58 +01:00
commit 5e0b867a49
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
7 changed files with 133 additions and 31 deletions

View file

@ -35,6 +35,7 @@ COPYRIGHT: (ordered alphabetically)
AUTHORS: (ordered alphabetically)
David Rheinsberg <david.rheinsberg@gmail.com>
Evgeny Vereshchagin <evvers@ya.ru>
Jan Engelhardt <jengelh@inai.de>
Lorenzo Arena <lorenzo.arena@powersoft.com>
Michele Dionisio <michele.dionisio@gmail.com>
Thomas Haller <thaller@redhat.com>

View file

@ -1,5 +1,38 @@
# c-stdaux - Auxiliary macros and functions for the C standard library
## CHANGES WITH 1.3.0:
* Microsoft Windows is now supported as a target platform.
* The `C_COMPILER_*` and `C_OS_*` pre-processor constants now
allow identifying the used compiler as well as the target OS.
* The new `_c_always_inline_` annotation allows telling compilers
to inline a function unless technically not possible.
* Split c-stdaux.h into modules and include them from the root
header for backwards compatibility. Inclusion of the new modules
is guarded by the `C_COMPILER_*` and `C_OS_*` macros to prevent
them from being used on unspported platforms. A direct include
of the respective modules allows overriding that behavior.
The new modules provide the same functionality as before on the
previously supported linux platforms. With the support of other
platforms, individual modules might not be available, or generic
functions might provide a stub that provides the same runtime
behavior, but possibly with fewer diagnostics.
* Rework `c_assert()` to avoid context-expressions and instead use
the ternary-operator to check for the assertion.
* Improve `c_{un,}likely()` to support constant-folding as well as
-Wparantheses diagnostics if supported by the compiler. This adds
`_c_boolean_expr_()` as a helper to achieve this.
Contributions from: David Rheinsberg, Thomas Haller
- Dußlingen, 2022-12-15
## CHANGES WITH 1.2.0:
* Add c_memcmp() as a safe wrapper around memcmp(3) that supports

View file

@ -3,10 +3,10 @@ c-stdaux
Auxiliary macros and functions for the C standard library
The c-stdaux project contains support-macros and auxiliary functions around the
The c-stdaux project contains support macros and auxiliary functions around the
functionality of common C standard libraries. This includes helpers for the
ISO-C Standard Library, but also other common specifications like POSIX or
common extended features of wide-spread compilers like gcc and clang.
ISO C Standard Library, but also other common specifications like POSIX or
common extended features of widespread compilers like gcc and clang.
### Project
@ -20,15 +20,15 @@ The requirements for this project are:
* `libc` (e.g., `glibc >= 2.16`)
At build-time, the following software is required:
At build time, the following software is required:
* `meson >= 0.60`
* `pkg-config >= 0.29`
### Build
The meson build-system is used for this project. Contact upstream
documentation for detailed help. In most situations the following
The meson build system is used for this project. Contact upstream
documentation for detailed help. In most situations, the following
commands are sufficient to build and install from source:
```sh

View file

@ -10,7 +10,7 @@ project(
],
license: 'Apache',
meson_version: '>=0.60.0',
version: '1.2.0',
version: '1.3.0',
)
major = meson.project_version().split('.')[0]
project_description = 'Auxiliary macros and functions for the C standard library'

View file

@ -132,24 +132,28 @@ extern "C" {
* Return: Evaluates to the value of ``!!_x``.
*/
#define _c_boolean_expr_(_x) _c_internal_boolean_expr_(__COUNTER__, _x)
#if defined(C_COMPILER_GNUC)
#if defined(C_COMPILER_GNUC) && __GNUC__ > 4
# define _c_internal_boolean_expr_(_uniq, _x) \
__extension__ ({ \
int C_VAR(b, _uniq); \
__builtin_choose_expr( \
__builtin_constant_p(_x), \
(!!(_x)), \
(__extension__ ({ \
int C_VAR(b, _uniq); \
\
/* \
* Avoid any extra parentheses around the evaluation of `_x` to \
* allow `-Wparentheses` to warn about use of `x = ...` and \
* instead suggest `(x = ...)` or `x == ...`. \
*/ \
/* \
* Avoid any extra parentheses around the evaluation of \
* `_x` to allow `-Wparentheses` to warn about use of \
* `x = ...` and instead suggest `(x = ...)` or \
* `x == ...`. \
*/ \
\
if (_x) \
C_VAR(b, _uniq) = 1; \
else \
C_VAR(b, _uniq) = 0; \
if (_x) \
C_VAR(b, _uniq) = 1; \
else \
C_VAR(b, _uniq) = 0; \
\
C_VAR(b, _uniq); \
})
C_VAR(b, _uniq); \
})))
#else
# define _c_internal_boolean_expr_(_uniq, _x) (!!(_x))
#endif
@ -299,7 +303,7 @@ extern "C" {
* optimize it away.
*/
#define c_assert(_x) ( \
(bool)(_x) \
_c_likely_(_x) \
? assert(true && #_x) \
: assert(false && #_x) \
)

View file

@ -11,6 +11,7 @@
#if defined(C_MODULE_GENERIC)
static inline _c_always_inline_ int always_inline_fn(void) { return 0; }
_c_public_ int c_internal_public_fn(void);
_c_public_ int c_internal_public_fn(void) { return 0; }
@ -46,6 +47,16 @@ static void test_api_generic(void) {
#endif
}
/* _c_always_inline_ */
{
c_assert(!always_inline_fn());
}
/* _c_boolean_expr_ */
{
c_assert(_c_boolean_expr_(true));
}
/* _c_likely_ */
{
c_assert(_c_likely_(true));
@ -128,7 +139,6 @@ static void test_api_generic(void) {
#if defined(C_MODULE_GNUC)
static inline _c_always_inline_ int always_inline_fn(void) { return 0; }
static _c_const_ int const_fn(void) { return 0; }
static _c_deprecated_ _c_unused_ int deprecated_fn(void) { return 0; }
_c_hidden_ int c_internal_hidden_fn(void);
@ -139,11 +149,6 @@ static _c_sentinel_ int sentinel_fn(const _c_unused_ char *f, ...) { return 0; }
static _c_unused_ int unused_fn(void) { return 0; }
static void test_api_gnuc(void) {
/* _c_always_inline_ */
{
c_assert(!always_inline_fn());
}
/* _c_cleanup_ */
{
_c_cleanup_(c_freep) void *foo = NULL;

View file

@ -11,7 +11,57 @@
#if defined(C_MODULE_GENERIC)
static void test_basic_generic(void) {
static int check_cassert_unreachable(int switch_val) {
int result;
/* Check whether this triggers a "-Wsometimes-uninitialized" warning or
* whether the compiler recognizes c_assert(0) as unreachable code. */
switch (switch_val) {
case 1: result = 1; break;
case 2: result = 2; break;
default: c_assert(0);
}
return result;
}
static void test_basic_generic(int non_constant_expr) {
/*
* Verify `_c_boolean_expr_` evaluates expressions to a boolean value
* and correctly works on all platforms.
*/
{
int v = 0;
c_assert(_c_boolean_expr_(0) == 0);
c_assert(_c_boolean_expr_(1) == 1);
c_assert(_c_boolean_expr_(2) == 1);
c_assert(_c_boolean_expr_(INT_MIN) == 1);
c_assert(_c_boolean_expr_(INT_MAX) == 1);
/* verify no double-evaluation takes place */
c_assert(_c_boolean_expr_(v++) == 0);
c_assert(_c_boolean_expr_(v) == 1);
#if defined(C_COMPILER_GNUC)
c_assert(__builtin_constant_p(_c_boolean_expr_(1)));
c_assert(!__builtin_constant_p(_c_boolean_expr_(non_constant_expr)));
#endif
}
/*
* Test that _c_likely_() and _c_unlikely_() can deal with constant
* expressions.
*/
{
#if defined(C_COMPILER_GNUC)
c_assert(__builtin_constant_p(_c_likely_(1)));
c_assert(__builtin_constant_p(_c_unlikely_(1)));
c_assert(!__builtin_constant_p(_c_likely_(non_constant_expr)));
c_assert(!__builtin_constant_p(_c_unlikely_(non_constant_expr)));
#endif
}
/*
* Test stringify/concatenation helpers. Also make sure to test that
* the passed arguments are evaluated first, before they're stringified
@ -184,6 +234,14 @@ static void test_basic_generic(void) {
c_assert(++v2);
if (v2 != 1)
abort();
/*
* Use the `check_cassert_unreachable()` helper to verify the
* compiler does not complain about unreachable code when
* `c_assert(0)` is used.
*/
c_assert(check_cassert_unreachable(1) == 1);
c_assert(check_cassert_unreachable(2) == 2);
}
/*
@ -267,7 +325,8 @@ static void test_basic_generic(void) {
#else /* C_MODULE_GENERIC */
static void test_basic_generic(void) {
static void test_basic_generic(int non_constant_expr) {
(void)non_constant_expr;
}
#endif /* C_MODULE_GENERIC */
@ -531,7 +590,7 @@ static void test_basic_unix(void) {
int main(int argc, char **argv) {
(void)argv;
test_basic_generic();
test_basic_generic(argc);
test_basic_gnuc(argc);
test_basic_unix();
return 0;