From 54c68e129014a5bb0ad7e8c301adce9569fb62c4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 16 Dec 2022 13:46:58 +0100 Subject: [PATCH] Squashed 'src/c-stdaux/' changes from c37722ff2f55..eceefe959250 eceefe959250 doc: update README.md for typography df7e0ac7a792 build: release v1.3.0 293d76aded19 test-basic: use `non_constant_expr` 12f8380286f3 generic: handle compile time expression in _c_boolean_expr_(),_c_likely_()/_c_unlikely_() 92b25e384e3b test/basic: add tests for _c_boolean_expr_ 4c1765bc0b4d test/api: move _c_always_inline_ test to generic group fe95c7a78fe9 test/api: add missing test for _c_boolean_expr_ git-subtree-dir: src/c-stdaux git-subtree-split: eceefe9592501bce485db62966853b361e90ec2f --- AUTHORS | 1 + NEWS.md | 33 +++++++++++++++++++++ README.md | 12 ++++---- meson.build | 2 +- src/c-stdaux-generic.h | 32 ++++++++++++--------- src/test-api.c | 17 +++++++---- src/test-basic.c | 65 ++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 132 insertions(+), 30 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4b108f1901..0f2a73fd51 100644 --- a/AUTHORS +++ b/AUTHORS @@ -35,6 +35,7 @@ COPYRIGHT: (ordered alphabetically) AUTHORS: (ordered alphabetically) David Rheinsberg Evgeny Vereshchagin + Jan Engelhardt Lorenzo Arena Michele Dionisio Thomas Haller diff --git a/NEWS.md b/NEWS.md index be824d664c..0cae9c5671 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 diff --git a/README.md b/README.md index d56fbc05c5..985193c5fd 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/meson.build b/meson.build index bf0da130fc..e41fd5f3e1 100644 --- a/meson.build +++ b/meson.build @@ -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' diff --git a/src/c-stdaux-generic.h b/src/c-stdaux-generic.h index 86be1d317a..4848617a79 100644 --- a/src/c-stdaux-generic.h +++ b/src/c-stdaux-generic.h @@ -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 diff --git a/src/test-api.c b/src/test-api.c index b2f7ab1163..ca78c602d4 100644 --- a/src/test-api.c +++ b/src/test-api.c @@ -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; diff --git a/src/test-basic.c b/src/test-basic.c index 0cb656e0cf..ffb4bf6086 100644 --- a/src/test-basic.c +++ b/src/test-basic.c @@ -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;