Bug 36299

Summary: spurious and undocumented warning with -Waddress for a == 0 when a is an array
Product: gcc Reporter: Vincent Lefèvre <vincent-gcc>
Component: cAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: gcc-bugs, manu
Priority: P3    
Version: 4.3.1   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2011-03-02 17:06:47

Description Vincent Lefèvre 2008-05-22 09:04:50 UTC
With -Waddress (implied by -Wall), I get the following warning when I use the test a == 0 where a is an array: the address of 'a' will never be NULL. This behavior is undocumented and inconsistent (see below). Here's a testcase:

int main (void)
{
  char a[1], *b;
  b = a;
  if (a == 0)
    return 1;
  else if (a == (void *) 0)
    return 2;
  else if (b == 0)
    return 3;
  else if (b == (void *) 0)
    return 4;
  return 0;
}

gcc warns only for a == 0 (and this is OK to use 0 instead of (void *) 0 because it is a valid form for a null pointer constant).

Moreover this is very similar to code like
  if (1) ...
or code given in bug 12963, for which gcc no longer emits warnings: indeed such kind of correct and useful code is typically used in macros.
Comment 1 Andrew Pinski 2008-05-22 20:00:48 UTC
  if (a == 0)
    return 1;
  else if (a == (void *) 0)

Those two should warn about being address being zero.  "a" decays to a pointer type and really &a[0].

-- Pinski
Comment 2 Manuel López-Ibáñez 2008-08-23 12:53:51 UTC
Andrew, how could we detect that it is a decayed array?

I think we would like to warn for 

if (a == (void *) 0) 

but not for

if ((void *)a == 0) 

or even if possible not for 

if (&a[0] == 0) 

Vincent, 
this warning was added on purpose, because probably someone requested it. I don't see that it is very different from the documented case of using the address of a function in a conditional.

You should be able to work-around the macro case by casting the array to (char *) or perhaps casting to (void *) ? That said, we would like to not warn within macros for a wide range of warnings but we don't have the infrastructure to do that yet.

Comment 3 Vincent Lefèvre 2008-08-23 20:00:31 UTC
(In reply to comment #2)
> this warning was added on purpose, because probably someone requested it. I
> don't see that it is very different from the documented case of using the
> address of a function in a conditional.

The documentation should be improved anyway (the word "suspicious" is very subjective).

> You should be able to work-around the macro case by casting the array to (char
> *) or perhaps casting to (void *) ?

Yes, this makes sense. Perhaps this should be documented.

> That said, we would like to not warn within
> macros for a wide range of warnings but we don't have the infrastructure to do
> that yet.

How about something like __extension__, e.g. __no_warnings__ would disable the warnings for the following statement or expression? If expression, one could still use __no_warnings__ with ({ ... }). Keywords for individual warnings or warning groups would even be better. At the same time, it would be nice to have some macro defined, declaring that such a keyword is available (that would be much better than testing the GCC version).
Comment 4 Manuel López-Ibáñez 2011-03-01 09:14:27 UTC
(In reply to comment #3)
> 
> The documentation should be improved anyway (the word "suspicious" is very
> subjective).
> 

Please propose a patch.

> > You should be able to work-around the macro case by casting the array to (char
> > *) or perhaps casting to (void *) ?
> 
> Yes, this makes sense. Perhaps this should be documented.

Is it working? I meant to say "ideally" one should be able to do this but I don't think it is working right now (and probably there are not testcases testing this).

> 
> How about something like __extension__, e.g. __no_warnings__ would disable the
> warnings for the following statement or expression? If expression, one could

There was a patch floating around in gcc-patches to implement that but since GCC location info is far from perfect (especially on macro expansions), I think it won't work well in practice. Moreover, the preferred way is to use the existing diagnostic pragmas. http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
Comment 5 Vincent Lefèvre 2011-03-01 15:05:19 UTC
Under Debian, I can no longer reproduce the problem with GCC 4.5.2:

$ gcc-4.5 -Wall warn-nulladdress.c
$ gcc-4.5 -Waddress warn-nulladdress.c
$ gcc-4.4 -Wall warn-nulladdress.c
warn-nulladdress.c: In function ‘main’:
warn-nulladdress.c:14: warning: the address of ‘a’ will never be NULL
$ gcc-4.4 -Waddress warn-nulladdress.c
warn-nulladdress.c: In function ‘main’:
warn-nulladdress.c:14: warning: the address of ‘a’ will never be NULL

So, I assume that it has been fixed anyway. Do you confirm?
Comment 6 Manuel López-Ibáñez 2011-03-01 15:37:25 UTC
(In reply to comment #5)
> 
> So, I assume that it has been fixed anyway. Do you confirm?

I think the intention is to warn, at least for a == (void *)0, since the address of a cannot be zero or null. So I would say that this is a regression.
Comment 7 Vincent Lefèvre 2011-03-02 01:15:23 UTC
(In reply to comment #6)
> I think the intention is to warn, at least for a == (void *)0, since the
> address of a cannot be zero or null. So I would say that this is a regression.

But this is valid in C, and in practice, such a test can occur in macro expansions: a macro can check whether some pointer is null before doing something with it. There shouldn't be a warning in such a case.
Comment 8 Manuel López-Ibáñez 2011-03-02 10:51:51 UTC
(In reply to comment #7)
> (In reply to comment #6)
> > I think the intention is to warn, at least for a == (void *)0, since the
> > address of a cannot be zero or null. So I would say that this is a regression.
> 
> But this is valid in C, and in practice, such a test can occur in macro
> expansions: a macro can check whether some pointer is null before doing
> something with it. There shouldn't be a warning in such a case.

Every warning warns about something valid in C, otherwise it would be an error not a warning.
Comment 9 Vincent Lefèvre 2011-03-02 15:17:33 UTC
(In reply to comment #8)
> Every warning warns about something valid in C, otherwise it would be an error
> not a warning.

No, for instance:

int main(void)
{
  int i;
  return i;
}

This is undefined behavior and detected by GCC, but one gets only a warning:

tst.c: In function ‘main’:
tst.c:4: warning: ‘i’ is used uninitialized in this function

Compare to a == 0 in the above testcase, which has a well-defined behavior.
Comment 10 Manuel López-Ibáñez 2011-03-02 17:06:47 UTC
(In reply to comment #9)
> This is undefined behavior and detected by GCC, but one gets only a warning:

I am not going to waste time discussing the fine-points of what is a valid C program. If you don't want this warning, please contribute a testcase to gcc-patches@gcc.gnu.org, so this warning won't reappear in the future:

http://gcc.gnu.org/wiki/HowToPrepareATestcase

Otherwise, someone will come who thinks that this should be warned and they will "fix it".
Comment 11 Vincent Lefèvre 2011-03-11 15:15:16 UTC
(In reply to comment #10)
> If you don't want this warning, please contribute a testcase to
> gcc-patches@gcc.gnu.org, so this warning won't reappear in the future:

Done: http://gcc.gnu.org/ml/gcc-patches/2011-03/msg00624.html
Comment 12 Joseph S. Myers 2011-04-01 19:36:27 UTC
Author: jsm28
Date: Fri Apr  1 19:36:23 2011
New Revision: 171850

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=171850
Log:
2011-04-01  Vincent Lefevre  <vincent+gcc@vinc17.org>

	PR c/36299
	* gcc.dg/Waddress.c: New test.

Added:
    trunk/gcc/testsuite/gcc.dg/Waddress.c
Modified:
    trunk/gcc/testsuite/ChangeLog
Comment 13 Marek Polacek 2014-06-30 19:37:50 UTC
So fixed.