I have just put something very similar to this in our code base.... extern void __attribute__((error("Smart assert always failed"))) __smartAssertAlwaysFail(void); #define smart_assert(x) do { \ if (__builtin_constant_p(x)) { \ if (!(x)) __smartAssertAlwaysFail(); \ } else { \ assert(x); \ } ...and it's working quite well. Better than I expected in that it's not just catching things that are declared const. It catches stupid things like.... if( expression) { .... assert( !expression); } It catches things that can be inlined but seen as constant at comile time. I think as gcc's optimizer get's smarter this will be quite a win. It also basically subsumes static_assert() It's not the full solution I'm looking for, but hey, it's better than before. Where people have done things like.... switch(x) { case a: case b: .... default: assert(false); } Yup, it yowls about that. But I have created another noreturn function assert_not_reached() and replaced all assert(false) by assert_not_reached(); On Wed, May 9, 2018 at 10:13 PM, David Brown <david@xxxxxxxxxxxxxxx> wrote: > On 09/05/18 10:35, Jonathan Wakely wrote: > > On 4 May 2018 at 14:34, Segher Boessenkool wrote: > >> On Fri, May 04, 2018 at 03:16:14PM +0200, Mason wrote: > >>> On 04/05/2018 01:03, John Carter wrote: > >>> > >>>> But compile with ... > >>>> gcc -O3 -W -Wall -Wextra -o a a.c > >>>> ...now results in NO warnings! > >>>> > >>>> ie. Although gcc _knows_ the assert _will_ trigger at run time... it > can't > >>>> tell me at compile time anymore. > >>>> > >>>> ie. Counter intuitively, adding asserts and error checks to my code > has > >>>> made me less safe. > >>> > >>> In the first version, gcc inlines the function call, which enables > >>> further analysis. In the second version, the assert() call makes > >>> gcc decide not to inline the function call, thus later analysis passes > >>> are no longer able to spot the out-of-bounds access. > >> > >> No, that's not it. In the second version there *is* no out of bounds > >> access! > > > > Right, the assert means that if the access would have been out of > > bounds the program terminates. So (when NDEBUG is not defined) it's > > impossible to reach the array access with an index >= 4. > > > > It doesn't hurt GCC's analysis, it just changes the program, and the > > analysis works on the new program. > > > > > What you might want here is a smarter assert: > > extern void __attribute__((error("Smart assert always failed"))) > __smartAssertAlwaysFail(void); > > #define smart_assert(x) do { \ > if (__builtin_constant_p(x)) { \ > if (!(x)) __smartAssertAlwaysFail(); \ > } else { \ > assert(x); \ > } > > > I use something similar for assertions in some of my embedded code (I > don't use normal asserts, because there is no output or way to exit the > program). > > I am sure something related could be put in the normal assert macro - > perhaps with a warning rather than an error. > > -- John Carter Phone : (64)(3) 358 6639 Tait Electronics PO Box 1645 Christchurch New Zealand -- This Communication is Confidential. We only send and receive email on the basis of the terms set out at www.taitradio.com/email_disclaimer <http://www.taitradio.com/email_disclaimer>