From 7f2640686401c087210073de0631caa0a1ee4fbe Mon Sep 17 00:00:00 2001 From: Francis Deslauriers Date: Fri, 24 Apr 2020 15:58:26 -0400 Subject: [PATCH] Implement compile time assertion macro wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Starting from C++11[1] and C11[2] both C++ and C standards implement the `static_assert()` macro that allows the compile time evaluation of an expression and emitting of a compiler error when the expression evaluates to false. This commit implements a wrapper for compile time assertions on C compilers implementing C standards prior C11. On such compilers, we emulate a static assert by typedef'ing an array of negative size in case of predicate failure. The downside of this method is that error messages are a bit cryptic as it mentions the negative-sized array. We overcome this issue by using a user-provided message as part of variable name that gets printed on error. For this reason, we decide to require 2 different messages in addition of the predicate. Here is the signature of the macro: #define lttng_static_assert(predicate, msg, c_identifier_msg) The first message, `msg`, is the used with C++/C11 compilers can be any string. The second message, `c_identifier_msg`, is used with older standards and MUST be a valid C identifier as it's will be concatenated to a typedef name. For example: If the user uses the macro such as: lttng_static_assert(false, "My assert message", MY_ASSERT_MSG); The C99 user will get an error looking like this: error: size of array ‘lttng_static_assert_MY_ASSERT_MSG’ is negative The C11 or C++ user will get an error looking like this: error: static assertion failed: "My assert message" [1] https://en.cppreference.com/w/cpp/language/static_assert [2] https://en.cppreference.com/w/c/language/_Static_assert Signed-off-by: Francis Deslauriers Signed-off-by: Mathieu Desnoyers Change-Id: I725f6e77f1858b8d88ffae781b648ac5b5c64b28 --- include/lttng/ust-compiler.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/lttng/ust-compiler.h b/include/lttng/ust-compiler.h index c2896285..e7d72e0d 100644 --- a/include/lttng/ust-compiler.h +++ b/include/lttng/ust-compiler.h @@ -24,6 +24,8 @@ * SOFTWARE. */ +#include + #define lttng_ust_notrace __attribute__((no_instrument_function)) #define LTTNG_PACKED __attribute__((__packed__)) @@ -71,4 +73,31 @@ #define __LTTNG_COMPOUND_LITERAL(type, ...) (type[]) { __VA_ARGS__ } #endif +/* + * Compile time assertion. + * - predicate: boolean expression to evaluate, + * - msg: string to print to the user on failure when `static_assert()` is + * supported, + * - c_identifier_msg: message to be included in the typedef to emulate a + * static assertion. This parameter must be a valid C identifier as it will + * be used as a typedef name. + */ +#if defined (__cplusplus) || __STDC_VERSION__ >= 201112L +#define lttng_static_assert(predicate, msg, c_identifier_msg) \ + static_assert(predicate, msg) +#else +/* + * Evaluates the predicate and emit a compilation error on failure. + * + * If the predicate evaluates to true, this macro emits a typedef of an array + * of size 0. + * + * If the predicate evaluates to false, this macro emits a typedef of an array + * of negative size which is invalid in C and forces a compiler error. The msg + * parameter is used in the tentative typedef so it is printed to the user. + */ +#define lttng_static_assert(predicate, msg, c_identifier_msg) \ + typedef char lttng_static_assert_##c_identifier_msg[2*!!(predicate)-1]; +#endif + #endif /* _LTTNG_UST_COMPILER_H */ -- 2.34.1