M_STATIC_ASSERT: provide expression compatible

macro even in pure C11 mode
(Remove GCC extension)

Add M_OPL_AS_STR to display the oplist conditionnaly as the generated string may be too big for some compilers.

Translate some M_STATIC_FAILURE into M_STATIC_ASSERT
as M_STATIC_FAILURE is not an expression whereas M_STATIC_ASSERT is an expression.
This commit is contained in:
Patrick Pelissier committed 2023-11-04 18:48:13 +01:00
1 parent 703ab6ff9c
commit 3a057fc319
2 files changed
+32 -19

No files matched your search

+3
View File
@@ -8562,6 +8562,9 @@ M\_USE\_DECL / M\_USE\_DEF shall be defined without effective value.
See M\_USE\_DECL for more details. See M\_USE\_DECL for more details.
#### M\_USE\_PRINT\_OPLIST
If defined, it displays the oplist associated to the static assert.
#### M\_MEMORY\_ALLOC #### M\_MEMORY\_ALLOC
+29 -19
View File
@@ -450,14 +450,13 @@ M_BEGIN_PROTECTED_CODE
/* Terminate the compilation of the current unit with an error message. /* Terminate the compilation of the current unit with an error message.
The error parameter is a C token which classifies the error The error parameter is a C token which classifies the error
with an optional message detailling the error. with an optional message detailling the error.
Either use C11 to get a proper message, or at least a good hint in C99. It is not an expression and shall not be used in an expression.
error shall be a C name, msg a string. It shall be used outside of a function, therefore it is not an expression.
In C99, it uses a bitfield to be compatible with most compilers
(so that it properly displays 'error' on the command line
Quite usefull to terminate with a proper error message rather than Quite usefull to terminate with a proper error message rather than
a garbage of error due to incorrect code generation in the methods a garbage of error due to incorrect code generation in the methods
expansion. expansion.
NOTE: Some implementation claims to be C11 (default mode) but fails
to deliver a working assert.h with static_assert so we test for the
explicity precense of the macro static_assert.
*/ */
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(static_assert)) || defined(__cplusplus) #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(static_assert)) || defined(__cplusplus)
# define M_STATIC_FAILURE(error, msg) static_assert(false, #error ": " msg); # define M_STATIC_FAILURE(error, msg) static_assert(false, #error ": " msg);
@@ -469,19 +468,22 @@ M_BEGIN_PROTECTED_CODE
/* Test at compile time if the given condition is true. /* Test at compile time if the given condition is true.
The error parameter is a C token which classifies the error The error parameter is a C token which classifies the error
with an optional message detailling the error. with an optional message detailling the error.
NOTE: Use bitfield to be compatible with most compilers In C99, it uses a bitfield to be compatible with most compilers
(so that it properly displays 'error' on the command line (so that it properly displays 'error' on the command line
It cannot use C11 Static Assert as is not usable in expression. C11 static Assert is not usable in expression,
NOTE: In C++, use of lambda to encapsulate static_assert in but is usable in struct declaration. Therefore we create
an expression. a dummy struct, define the static assert within it
NOTE: For GNU compatible compilers, uses of a GNU extension. compute its size and cast it to void.
NOTE: Some implementation claims to be C11 (default mode) but fails
to deliver a working assert.h with static_assert so we test for the
explicity precense of the macro static_assert.
*/ */
#if defined(__cplusplus) #ifdef __cplusplus
# define M_STATIC_ASSERT(cond, error, msg) \ # define M_STATIC_ASSERT(cond, error, msg) \
([] { static_assert(cond, #error ": " msg); } ()) ([] { static_assert(cond, #error ": " msg); } ())
#elif defined(__GNUC__) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(static_assert) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(static_assert)
# define M_STATIC_ASSERT(cond, error, msg) \ # define M_STATIC_ASSERT(cond, error, msg) \
M_ATTR_EXTENSION ({ static_assert(cond, #error ": " msg); }) ((void) sizeof(struct { int error; static_assert(cond, #error ": " msg);}))
#else #else
# define M_STATIC_ASSERT(cond, error, msg) \ # define M_STATIC_ASSERT(cond, error, msg) \
((void) sizeof(struct { int error : !!(cond);})) ((void) sizeof(struct { int error : !!(cond);}))
@@ -2513,6 +2515,14 @@ done
#define M_AS_STR(x) M_AS_STRI(x) #define M_AS_STR(x) M_AS_STRI(x)
#define M_AS_STRI(x) #x #define M_AS_STRI(x) #x
/* Convert an oplist into a string. It may generate a very long string,
which generates warning (string length greater than 4095).
So the conversion is optional */
#ifdef M_USE_PRINT_OPLIST
# define M_OPL_AS_STR(x) M_AS_STR(x)
#else
# define M_OPL_AS_STR(x)
#endif
/* C11 MACROS */ /* C11 MACROS */
@@ -3610,7 +3620,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
NOTE: It starts by a comma, to ack the success of the transformation. NOTE: It starts by a comma, to ack the success of the transformation.
*/ */
#define M_OPLAPI_ERROR(method, oplist, ...) , M_STATIC_FAILURE(M_LIB_DISABLED_METHOD, "The method has been explictly disabled for the requested operator, yet it has been called by the container") #define M_OPLAPI_ERROR(method, oplist, ...) , M_STATIC_ASSERT(false, M_LIB_DISABLED_METHOD, "The method has been explictly disabled for the requested operator, yet it has been called by the container")
#define M_OPLAPI_0(method, oplist, ...) , M_DELAY3(method)(__VA_ARGS__) #define M_OPLAPI_0(method, oplist, ...) , M_DELAY3(method)(__VA_ARGS__)
#define M_OPLAPI_1(method, oplist, ...) , M_DELAY3(method)(oplist, __VA_ARGS__) #define M_OPLAPI_1(method, oplist, ...) , M_DELAY3(method)(oplist, __VA_ARGS__)
#define M_OPLAPI_2(method, oplist, ...) , M_DELAY3(method)(& __VA_ARGS__) #define M_OPLAPI_2(method, oplist, ...) , M_DELAY3(method)(& __VA_ARGS__)
@@ -3730,11 +3740,11 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
if the method is expanded. if the method is expanded.
*/ */
#define M_NO_DEFAULT(...) \ #define M_NO_DEFAULT(...) \
M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \ M_STATIC_ASSERT(false, M_LIB_MISSING_METHOD, \
"The requested operator has no method registered in the given OPLIST. ") "The requested operator has no method registered in the given OPLIST. ")
#define M_NO_DEF_TYPE \ #define M_NO_DEF_TYPE \
M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \ M_STATIC_ASSERT(false, M_LIB_MISSING_METHOD, \
"The requested operator has no type/subtype/suboplist registered in the given OPLIST. ") "The requested operator has no type/subtype/suboplist registered in the given OPLIST. ")
/* Test if the given variable is a basic C variable: /* Test if the given variable is a basic C variable:
@@ -3800,7 +3810,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
M_LIB_TYPE_MISTMACH, \ M_LIB_TYPE_MISTMACH, \
"The given type " M_AS_STR(type) \ "The given type " M_AS_STR(type) \
" and the type of the oplist does not match: " \ " and the type of the oplist does not match: " \
M_AS_STR(oplist) ); \ M_OPL_AS_STR(oplist) ); \
} \ } \
, /* End of TYPE */) , /* End of TYPE */)
#else #else
@@ -3814,7 +3824,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
M_LIB_TYPE_MISTMACH, \ M_LIB_TYPE_MISTMACH, \
"The given type " M_AS_STR(type) \ "The given type " M_AS_STR(type) \
" and the type of the oplist does not match: " \ " and the type of the oplist does not match: " \
M_AS_STR(oplist) ); \ M_OPL_AS_STR(oplist) ); \
} \ } \
, /* End of TYPE */) , /* End of TYPE */)
#endif #endif
@@ -4310,7 +4320,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
M_IF_OPLIST(oplist)(M_LETI3, M_LETI2_FAILURE)(cont, oplist, __VA_ARGS__) M_IF_OPLIST(oplist)(M_LETI3, M_LETI2_FAILURE)(cont, oplist, __VA_ARGS__)
// Stop with a failure (invalid oplist) // Stop with a failure (invalid oplist)
#define M_LETI2_FAILURE(cont, oplist, ...) \ #define M_LETI2_FAILURE(cont, oplist, ...) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist)) M_STATIC_ASSERT(false, M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist))
// 4. Map all variables to their own LET // 4. Map all variables to their own LET
#define M_LETI3(cont, oplist, ...) \ #define M_LETI3(cont, oplist, ...) \
for(bool cont = true; cont ; /* unused */) \ for(bool cont = true; cont ; /* unused */) \