MP_STATIC_ASSERT: Use _Static_assert or c++ static_assert#18145
MP_STATIC_ASSERT: Use _Static_assert or c++ static_assert#18145jepler wants to merge 4 commits intomicropython:masterfrom
Conversation
Signed-off-by: Angus Gratton <angus@redyak.com.au>
.. or c++ static_assert where possible. For the same reasons that C++ has trouble with "nonconstexpr" static assertions, _Static_assert rejects such expression as well. So, fall back to the old sizeof-array based implementation in that case. When _Static_assert can be used, the diagnostic quality is improved: ``` ../py/objint.c: In function ‘mp_obj_int_make_new’: ../py/misc.h:67:32: error: static assertion failed: "37 == 42" ../py/objint.c:45:5: note: in expansion of macro ‘MP_STATIC_ASSERT’ ``` As compared to a diagnostic about ``` ../py/misc.h:71:50: error: size of unnamed array is negative ``` Testing on godbolt indicated that this actually works back to gcc 4.5, but it's easier to use GNUC >= 5 as the test; Hypothetical users of 4.5, 4.6, or 4.7 will just get slightly worse diagnostics. Related: micropython#18116 Signed-off-by: Jeff Epler <jepler@unpythonic.net>
|
Code size report: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #18145 +/- ##
=======================================
Coverage 98.38% 98.38%
=======================================
Files 171 171
Lines 22287 22287
=======================================
Hits 21928 21928
Misses 359 359 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…/micropython into use-compiler-static-assert
This warning was enabled by default on clang 17.0.0 on macOS 26. Disable it, because we want to make these checks at compile-time even if it requires an extension. Signed-off-by: Jeff Epler <jepler@unpythonic.net>
|
Based on some testing in godbolt, the pragma to disable the warning flag is accepted without complaint (under -Werror) even in extremely old clang versions. |
|
[the commit message check is failing because there's the merge commit for #18129 testing] |
|
This fixes #18116 for me. |
projectgus
left a comment
There was a problem hiding this comment.
Thanks @jepler, I started down the same path as you but got stuck on what to do about the MP_STATIC_ASSERT_NONCONSTEXPR case. I think this is the right way forward.
I wonder if we should leave macos-26 in place, presumably at some point this will become macos-latest anyway?
|
There's also a few other tests that should probably be added --- for the I did something very similar to this for #18148, with the C23 |
| #define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x) | ||
|
|
||
| // Static assertion macro | ||
| #if __cplusplus |
There was a problem hiding this comment.
| #if __cplusplus | |
| #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L)) || (defined(__cplusplus) && (__cplusplus >= 201103L)) || __has_feature(cxx_static_assert) || defined(static_assert) | |
| // C23 keyword: https://en.cppreference.com/w/c/language/static_assert.html | |
| // C++11 declaration: https://en.cppreference.com/w/cpp/language/static_assert.html | |
| // Clang feature: https://clang.llvm.org/docs/LanguageExtensions.html#c-11-static-assert | |
| // assert.h macro: https://en.cppreference.com/w/c/error/static_assert.html |
| // Static assertion macro | ||
| #if __cplusplus | ||
| #define MP_STATIC_ASSERT(cond) static_assert((cond), #cond) | ||
| #elif __GNUC__ >= 5 || __STDC_VERSION__ >= 201112L |
There was a problem hiding this comment.
| #elif __GNUC__ >= 5 || __STDC_VERSION__ >= 201112L | |
| #elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || (defined(__GNUC__) && __GNUC__ >= 5) || __has_feature(c_static_assert) | |
| // C11 keyword: https://en.cppreference.com/w/c/language/static_assert.html | |
| // GCC feature: https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Static-Assertions.html | |
| // Clang feature: https://clang.llvm.org/docs/LanguageExtensions.html#c11-static-assert |
|
I'll also note that MSVC has the macro |
|
@AJMansfield I gently disagree with your proposed change to the enabling condition, but I also feel like we've discussed it before and I don't mean to rehash old settled topics. If this rings a bell do you recall specifics or have a link to the old discussion? I only found #17735 (review) in my search. gcc (actually cpp) documentation says that " As an extension, gcc has long offered support for Similar to how we ended up using version checks for MP_GCC_HAS_BUILTIN_OVERFLOW (but supplemented it with some I'm also not sure if To check my theories I tried this on godbolt across a range of gcc versions with -std=c99: gcc 4.7, 5.1, ..., 12.5, 13.4 build with no diagnostics. So, I actually didn't find any compiler versions where the The other positive thing I see your version doing is fixing how things work under |
I don't believe it's a conversation I've had --- glad for the reference on how MicroPython usually conducts things though.
Indeed, my proposal was a bit premature, I should've spent a bit more time reading and testing things first 🙃. The only (possible) benefit there might be to do with clang support. Also useful note on the
Agreed --- and it's not that I'd expect anyone with a stupid-mode compiler that actually breaks on undefined macros, but if there's anywhere to do belt-and-braces on that it's the macros designed to bridge compatibility gaps between different compiler versions. |
Yes, there was a discussion about this somewhere. I'd be happy if we were able to turn that warning on (although I guess it might require quite a few changes...). |
|
We also had to do this in CircuitPython: adafruit#10656. But |
Summary
When _Static_assert can be used, the diagnostic quality is improved:
As compared to a diagnostic about
Related: #18116
Testing
I built the unix coverage build locally. Since this is a compile-time only test, CI will be a good test.
Trade-offs and Alternatives
Testing on godbolt indicated that this actually works back to gcc 4.5, but it's easier to use GNUC >= 5 as the test; Hypothetical users of 4.5, 4.6, or 4.7 will just get slightly worse diagnostics.
For "nonconstant" static asserts, the array trick still needs to be used; _Static_assert rejects these expressions just like C++ static_assert does.