Implement compile time assertion macro wrapper
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Fri, 24 Apr 2020 19:58:26 +0000 (15:58 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 24 Apr 2020 23:47:56 +0000 (19:47 -0400)
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 <francis.deslauriers@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I725f6e77f1858b8d88ffae781b648ac5b5c64b28

include/lttng/ust-compiler.h

index c289628580ee420346a24e6e72bc9f7fa9299ebd..e7d72e0da3fd21843b8caa0879200a4c43c38f21 100644 (file)
@@ -24,6 +24,8 @@
  * SOFTWARE.
  */
 
+#include <assert.h>
+
 #define lttng_ust_notrace __attribute__((no_instrument_function))
 #define LTTNG_PACKED   __attribute__((__packed__))
 
 #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 */
This page took 0.027053 seconds and 4 git commands to generate.