_Static_warning?

Martin Sebor msebor@redhat.com
Tue May 19 14:52:00 GMT 2015


On 05/18/2015 11:07 PM, Eduardo Piombino wrote:
> That's really helpful and it's very close to what I've been looking for.
> Had I figured this trick (I tried [ab]using so many other warnings
> with no gain) I may have settled for this solution, weren't it for the
> fact that in my current setup the _Static_warning is not fired from
> its own line like your example, but from a macro.
>
> $ cat h.c && ../gcc/bin/gcc -Wall -c h.c -o/dev/null
> int static_warning_dummy(char * p) __attribute__ ((nonnull(1)));
> int static_warning_dummy(char * p) { return 0; }
> #define _Static_warning(x, txt) (int) (x) ? 0 :
> static_warning_dummy((char *) x);
>
> #define foo(x) do { _Static_warning(x, errormsg); bar(x); } while(0)
>
> void bar(int p)
> {
> }
>
> int main(void)
> {
>          _Static_warning(0, "bar"); // here you see the message in the logs
>          foo(0); // here you don't
> }
>
> h.c: In function ‘main’:
> h.c:13:2: warning: null argument where non-null required (argument 1)
> [-Wnonnull]
>    _Static_warning(0, "bar"); // here you see the message in the logs
>     ^
> h.c:14:2: warning: null argument where non-null required (argument 1)
> [-Wnonnull]
>    foo(0); // here you don't
>     ^
>
> The consequence is that when the compiler prints out the line that
> triggered it, it will print out the original line of code, and not the
> one where I actually invoked the _Static_warning, losing the message
> parameter in the way.

I would consider this a bug. GCC should include in the warning
the context from which the macro was invoked just as it does in
the _Static_assert case, and just as Clang does (below).

$ cat t.c && clang -Wall -c -o/dev/null t.c
void foo (char*, ...) __attribute__ ((nonnull (1)));
#define foo(p) foo (p, "p is null")
#define bar(p) _Static_assert (p, "p is null")

void baz (void) {
     foo (0);
     bar (0);
}
t.c:6:5: warning: null passed to a callee that requires a non-null argument
       [-Wnonnull]
     foo (0);
     ^    ~
t.c:2:35: note: expanded from macro 'foo'
#define foo(p) foo (p, "p is null")
                                   ^
t.c:7:5: error: static_assert failed "p is null"
     bar (0);
     ^    ~
t.c:3:16: note: expanded from macro 'bar'
#define bar(p) _Static_assert (p, "p is null")
                ^
1 warning and 1 error generated.

> There may exist some kind of workaround to this, but I can't see it right now.

It's not pretty but this seems to work:

$ cat -n t.c && gcc -O2 -Wall -c -o/dev/null t.c
      1	#define Static_warning(x, txt) \
      2	   (void)__builtin_choose_expr (x, 0, (char[sizeof txt - 2 + 
!!x]){ txt })
      3	#define foo(x) do { Static_warning (x, "errormsg"); } while(0)
      4	
      5	
      6	void bar (void) {
      7	    Static_warning (0, "bad");
      8	    foo (0);
      9	
     10	    Static_warning (1, "good");
     11	    foo (1);
     12	}
t.c: In function ‘bar’:
t.c:2:67: warning: initializer-string for array of chars is too long
     (void)__builtin_choose_expr (x, 0, (char[sizeof txt - 2 + !!x]){ txt })
                                                                    ^
t.c:7:5: note: in expansion of macro ‘Static_warning’
      Static_warning (0, "bad");
      ^
t.c:2:67: warning: initializer-string for array of chars is too long
     (void)__builtin_choose_expr (x, 0, (char[sizeof txt - 2 + !!x]){ txt })
                                                                    ^
t.c:3:21: note: in expansion of macro ‘Static_warning’
  #define foo(x) do { Static_warning (x, "errormsg"); } while(0)
                      ^
t.c:8:5: note: in expansion of macro ‘foo’
      foo (0);
      ^

Martin



More information about the Gcc-help mailing list