From c15f029a7108117ab62d3275b77cddd8d77e0b81 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 21 Feb 2024 00:32:59 +0000 Subject: [PATCH] init.h: restore designated initializers in SYS_INIT_NAMED() As seen in the PR #68125 discussion, commit 19a33c788413 ("init: adjust the SYS_INIT dev field init to play nice with older compilers") entirely threw away designated initializers in SYS_INIT_NAMED() to avoid compatibility issues across toolchains. One key aspect that was probably missed at the time: C and C++ are two different languages and this is especially true with respect to designated initializers. Designated initializers provide safer and more readable code, especially in their much stricter C++ version. So use an #ifdef to restore them in SYS_INIT_NAMED() thanks to a small braces difference between C and C++. Signed-off-by: Marc Herbert --- include/zephyr/init.h | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 2788dc01afd7fe..512ea9f67bea67 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -151,6 +151,39 @@ struct init_entry { __attribute__((__section__( \ ".z_init_" #level STRINGIFY(prio)"_" STRINGIFY(sub_prio)"_"))) + +/* Designated initializers where added to C in C99. There were added to + * C++ 20 years later in a much more restricted form. C99 allows many + * variations: out of order, mix of designated and not, overlap, + * override,... but C++ allows none of these. See differences detailed + * in the P0329R0.pdf C++ proposal. + * Note __STDC_VERSION__ is undefined when compiling C++. + */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__) < 201100 + +/* Anonymous unions require C11. Some pre-C11 gcc versions have early + * support for anonymous unions but they require these braces when + * combined with C99 designated initializers, see longer discussion in + * #69411. + * These braces are compatible with any C version but not with C++20. + */ +# define Z_INIT_SYS_INIT_DEV_NULL { .dev = NULL } + +#else + +/* When using -std=c++20 or higher, g++ (v12.2.0) reject braces for + * initializing anonymous unions because it is technically a mix of + * designated and not designated initializers which is not allowed in + * C++. Interestingly, the _same_ g++ version does accept the braces above + * when using -std=c++17 or lower! + * The tests/lib/cpp/cxx/ added by commit 3d9c428d57bf invoke the C++ + * compiler with a range of different `-std=...` parameters without needing + * any manual configuration. + */ +# define Z_INIT_SYS_INIT_DEV_NULL .dev = NULL + +#endif + /** @endcond */ /** @@ -205,7 +238,8 @@ struct init_entry { #define SYS_INIT_NAMED(name, init_fn_, level, prio) \ static const Z_DECL_ALIGN(struct init_entry) \ Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ - Z_INIT_ENTRY_NAME(name) = {{ (init_fn_) }, { NULL } } + Z_INIT_ENTRY_NAME(name) = {.init_fn = {.sys = (init_fn_)}, \ + Z_INIT_SYS_INIT_DEV_NULL} /** @} */