diff mbox

C++ PATCH to fix missing warning (PR c++/70194)

Message ID 20160316144552.GG10006@redhat.com
State New
Headers show

Commit Message

Marek Polacek March 16, 2016, 2:45 p.m. UTC
On Tue, Mar 15, 2016 at 03:41:52PM -0400, Jason Merrill wrote:
> Let's factor out that duplicated code into a separate function.

Sure.  It also allowed me to hoist the cheap tests for both warnings, and
while at it, I used 'location' for the first warning.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2016-03-16  Marek Polacek  <polacek@redhat.com>

	PR c++/70194
	* typeck.c (warn_for_null_address): New function.
	(cp_build_binary_op): Call it.

	* g++.dg/warn/constexpr-70194.C: New test.


	Marek

Comments

Jason Merrill March 16, 2016, 7:44 p.m. UTC | #1
OK.

Jason
Martin Sebor March 17, 2016, 12:43 a.m. UTC | #2
> @@ -3974,6 +3974,38 @@ build_vec_cmp (tree_code code, tree type,
>     return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
>   }
>
> +/* Possibly warn about an address never being NULL.  */
> +
> +static void
> +warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
> +{
...
> +  if (TREE_CODE (cop) == ADDR_EXPR
> +      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
> +      && !TREE_NO_WARNING (cop))
> +    warning_at (location, OPT_Waddress, "the address of %qD will never "
> +		"be NULL", TREE_OPERAND (cop, 0));
> +
> +  if (CONVERT_EXPR_P (op)
> +      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == REFERENCE_TYPE)
> +    {
> +      tree inner_op = op;
> +      STRIP_NOPS (inner_op);
> +
> +      if (DECL_P (inner_op))
> +	warning_at (location, OPT_Waddress,
> +		    "the compiler can assume that the address of "
> +		    "%qD will never be NULL", inner_op);

Since I noted the subtle differences between the phrasing of
the various -Waddress warnings in the bug, I have to ask: what is
the significance of the difference between the two warnings here?

Would it not be appropriate to issue the first warning in the latter
case?  Or perhaps even use the same text as is already used elsewhere:
"the address of %qD will always evaluate as ‘true’" (since it may not
be the macro NULL that's mentioned in the expression).

Martin
Jeff Law March 17, 2016, 4:27 p.m. UTC | #3
On 03/16/2016 06:43 PM, Martin Sebor wrote:
>> @@ -3974,6 +3974,38 @@ build_vec_cmp (tree_code code, tree type,
>>     return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
>>   }
>>
>> +/* Possibly warn about an address never being NULL.  */
>> +
>> +static void
>> +warn_for_null_address (location_t location, tree op, tsubst_flags_t
>> complain)
>> +{
> ...
>> +  if (TREE_CODE (cop) == ADDR_EXPR
>> +      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
>> +      && !TREE_NO_WARNING (cop))
>> +    warning_at (location, OPT_Waddress, "the address of %qD will never "
>> +        "be NULL", TREE_OPERAND (cop, 0));
>> +
>> +  if (CONVERT_EXPR_P (op)
>> +      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == REFERENCE_TYPE)
>> +    {
>> +      tree inner_op = op;
>> +      STRIP_NOPS (inner_op);
>> +
>> +      if (DECL_P (inner_op))
>> +    warning_at (location, OPT_Waddress,
>> +            "the compiler can assume that the address of "
>> +            "%qD will never be NULL", inner_op);
>
> Since I noted the subtle differences between the phrasing of
> the various -Waddress warnings in the bug, I have to ask: what is
> the significance of the difference between the two warnings here?
>
> Would it not be appropriate to issue the first warning in the latter
> case?  Or perhaps even use the same text as is already used elsewhere:
> "the address of %qD will always evaluate as ‘true’" (since it may not
> be the macro NULL that's mentioned in the expression).
They were added at different times AFAICT.  The former is fairly old 
(Douglas Gregor, 2008) at this point.  The latter was added by Patrick 
Palka for 65168 about a year ago.

You could directly ask Patrick about motivations for a different message.

Jeff
Marek Polacek March 17, 2016, 4:41 p.m. UTC | #4
On Wed, Mar 16, 2016 at 06:43:39PM -0600, Martin Sebor wrote:
> >@@ -3974,6 +3974,38 @@ build_vec_cmp (tree_code code, tree type,
> >    return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
> >  }
> >
> >+/* Possibly warn about an address never being NULL.  */
> >+
> >+static void
> >+warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
> >+{
> ...
> >+  if (TREE_CODE (cop) == ADDR_EXPR
> >+      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
> >+      && !TREE_NO_WARNING (cop))
> >+    warning_at (location, OPT_Waddress, "the address of %qD will never "
> >+		"be NULL", TREE_OPERAND (cop, 0));
> >+
> >+  if (CONVERT_EXPR_P (op)
> >+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == REFERENCE_TYPE)
> >+    {
> >+      tree inner_op = op;
> >+      STRIP_NOPS (inner_op);
> >+
> >+      if (DECL_P (inner_op))
> >+	warning_at (location, OPT_Waddress,
> >+		    "the compiler can assume that the address of "
> >+		    "%qD will never be NULL", inner_op);
> 
> Since I noted the subtle differences between the phrasing of
> the various -Waddress warnings in the bug, I have to ask: what is
> the significance of the difference between the two warnings here?
 
Quite frankly, I don't know.

> Would it not be appropriate to issue the first warning in the latter
> case?  Or perhaps even use the same text as is already used elsewhere:
> "the address of %qD will always evaluate as ‘true’" (since it may not
> be the macro NULL that's mentioned in the expression).

There are more discrepancies in the front ends wrt error/warning messages.
Perhaps we should try to unify them some more, but I don't think this has
a big priority, if the message is clear enough for the users.

	Marek
Jason Merrill March 17, 2016, 4:45 p.m. UTC | #5
On 03/16/2016 08:43 PM, Martin Sebor wrote:
>> @@ -3974,6 +3974,38 @@ build_vec_cmp (tree_code code, tree type,
>>     return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
>>   }
>>
>> +/* Possibly warn about an address never being NULL.  */
>> +
>> +static void
>> +warn_for_null_address (location_t location, tree op, tsubst_flags_t
>> complain)
>> +{
> ...
>> +  if (TREE_CODE (cop) == ADDR_EXPR
>> +      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
>> +      && !TREE_NO_WARNING (cop))
>> +    warning_at (location, OPT_Waddress, "the address of %qD will never "
>> +        "be NULL", TREE_OPERAND (cop, 0));
>> +
>> +  if (CONVERT_EXPR_P (op)
>> +      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == REFERENCE_TYPE)
>> +    {
>> +      tree inner_op = op;
>> +      STRIP_NOPS (inner_op);
>> +
>> +      if (DECL_P (inner_op))
>> +    warning_at (location, OPT_Waddress,
>> +            "the compiler can assume that the address of "
>> +            "%qD will never be NULL", inner_op);
>
> Since I noted the subtle differences between the phrasing of
> the various -Waddress warnings in the bug, I have to ask: what is
> the significance of the difference between the two warnings here?

The difference is that in the second case, a reference could be bound to 
a null address, but that has undefined behavior, so the compiler can 
assume it won't happen.

Jason
Jeff Law March 17, 2016, 4:47 p.m. UTC | #6
On 03/17/2016 10:45 AM, Jason Merrill wrote:
> On 03/16/2016 08:43 PM, Martin Sebor wrote:
>>> @@ -3974,6 +3974,38 @@ build_vec_cmp (tree_code code, tree type,
>>>     return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
>>>   }
>>>
>>> +/* Possibly warn about an address never being NULL.  */
>>> +
>>> +static void
>>> +warn_for_null_address (location_t location, tree op, tsubst_flags_t
>>> complain)
>>> +{
>> ...
>>> +  if (TREE_CODE (cop) == ADDR_EXPR
>>> +      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
>>> +      && !TREE_NO_WARNING (cop))
>>> +    warning_at (location, OPT_Waddress, "the address of %qD will
>>> never "
>>> +        "be NULL", TREE_OPERAND (cop, 0));
>>> +
>>> +  if (CONVERT_EXPR_P (op)
>>> +      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) ==
>>> REFERENCE_TYPE)
>>> +    {
>>> +      tree inner_op = op;
>>> +      STRIP_NOPS (inner_op);
>>> +
>>> +      if (DECL_P (inner_op))
>>> +    warning_at (location, OPT_Waddress,
>>> +            "the compiler can assume that the address of "
>>> +            "%qD will never be NULL", inner_op);
>>
>> Since I noted the subtle differences between the phrasing of
>> the various -Waddress warnings in the bug, I have to ask: what is
>> the significance of the difference between the two warnings here?
>
> The difference is that in the second case, a reference could be bound to
> a null address, but that has undefined behavior, so the compiler can
> assume it won't happen.
So the first can't happen, the second could, but would be considered 
undefined behavior.

jeff
Patrick Palka March 17, 2016, 4:48 p.m. UTC | #7
On Thu, Mar 17, 2016 at 12:27 PM, Jeff Law <law@redhat.com> wrote:
> On 03/16/2016 06:43 PM, Martin Sebor wrote:
>>>
>>> @@ -3974,6 +3974,38 @@ build_vec_cmp (tree_code code, tree type,
>>>     return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
>>>   }
>>>
>>> +/* Possibly warn about an address never being NULL.  */
>>> +
>>> +static void
>>> +warn_for_null_address (location_t location, tree op, tsubst_flags_t
>>> complain)
>>> +{
>>
>> ...
>>>
>>> +  if (TREE_CODE (cop) == ADDR_EXPR
>>> +      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
>>> +      && !TREE_NO_WARNING (cop))
>>> +    warning_at (location, OPT_Waddress, "the address of %qD will never "
>>> +        "be NULL", TREE_OPERAND (cop, 0));
>>> +
>>> +  if (CONVERT_EXPR_P (op)
>>> +      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == REFERENCE_TYPE)
>>> +    {
>>> +      tree inner_op = op;
>>> +      STRIP_NOPS (inner_op);
>>> +
>>> +      if (DECL_P (inner_op))
>>> +    warning_at (location, OPT_Waddress,
>>> +            "the compiler can assume that the address of "
>>> +            "%qD will never be NULL", inner_op);
>>
>>
>> Since I noted the subtle differences between the phrasing of
>> the various -Waddress warnings in the bug, I have to ask: what is
>> the significance of the difference between the two warnings here?
>>
>> Would it not be appropriate to issue the first warning in the latter
>> case?  Or perhaps even use the same text as is already used elsewhere:
>> "the address of %qD will always evaluate as ‘true’" (since it may not
>> be the macro NULL that's mentioned in the expression).
>
> They were added at different times AFAICT.  The former is fairly old
> (Douglas Gregor, 2008) at this point.  The latter was added by Patrick Palka
> for 65168 about a year ago.
>
> You could directly ask Patrick about motivations for a different message.

There is no plausible way for the address of a non-reference variable
to be NULL even in code with UB (aside from __attribute__ ((weak)) in
which case the warning is suppressed).  But the address of a reference
can easily seem to be NULL if one performs UB and assigns to it *(int
*)NULL or something like that.  I think that was my motivation, anyway
:)
Martin Sebor March 17, 2016, 6:51 p.m. UTC | #8
On 03/17/2016 10:48 AM, Patrick Palka wrote:
> On Thu, Mar 17, 2016 at 12:27 PM, Jeff Law <law@redhat.com> wrote:
>> On 03/16/2016 06:43 PM, Martin Sebor wrote:
>>>>
>>>> @@ -3974,6 +3974,38 @@ build_vec_cmp (tree_code code, tree type,
>>>>      return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
>>>>    }
>>>>
>>>> +/* Possibly warn about an address never being NULL.  */
>>>> +
>>>> +static void
>>>> +warn_for_null_address (location_t location, tree op, tsubst_flags_t
>>>> complain)
>>>> +{
>>>
>>> ...
>>>>
>>>> +  if (TREE_CODE (cop) == ADDR_EXPR
>>>> +      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
>>>> +      && !TREE_NO_WARNING (cop))
>>>> +    warning_at (location, OPT_Waddress, "the address of %qD will never "
>>>> +        "be NULL", TREE_OPERAND (cop, 0));
>>>> +
>>>> +  if (CONVERT_EXPR_P (op)
>>>> +      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == REFERENCE_TYPE)
>>>> +    {
>>>> +      tree inner_op = op;
>>>> +      STRIP_NOPS (inner_op);
>>>> +
>>>> +      if (DECL_P (inner_op))
>>>> +    warning_at (location, OPT_Waddress,
>>>> +            "the compiler can assume that the address of "
>>>> +            "%qD will never be NULL", inner_op);
>>>
>>>
>>> Since I noted the subtle differences between the phrasing of
>>> the various -Waddress warnings in the bug, I have to ask: what is
>>> the significance of the difference between the two warnings here?
>>>
>>> Would it not be appropriate to issue the first warning in the latter
>>> case?  Or perhaps even use the same text as is already used elsewhere:
>>> "the address of %qD will always evaluate as ‘true’" (since it may not
>>> be the macro NULL that's mentioned in the expression).
>>
>> They were added at different times AFAICT.  The former is fairly old
>> (Douglas Gregor, 2008) at this point.  The latter was added by Patrick Palka
>> for 65168 about a year ago.
>>
>> You could directly ask Patrick about motivations for a different message.
>
> There is no plausible way for the address of a non-reference variable
> to be NULL even in code with UB (aside from __attribute__ ((weak)) in
> which case the warning is suppressed).  But the address of a reference
> can easily seem to be NULL if one performs UB and assigns to it *(int
> *)NULL or something like that.  I think that was my motivation, anyway
> :)

Thanks (everyone) for the explanation.

I actually think the warning Patrick added is the most accurate
and would be appropriate in all cases.

I suppose what bothers me besides the mention of NULL even when
there is no NULL in the code, is that a) the text of the warnings
is misleading (contradictory) in some interesting cases, and b)
I can't think of a way in which the difference between the three
phrasings of the diagnostic could be useful to a user.  All three
imply the same thing: compilers can and GCC is some cases does
assume that the address of an ordinary (non weak) function, object,
or reference is not null.

To see (a), consider the invalid test program below, in which
GCC makes this assumption about the address of i even though
the warning doesn't mention it (but it makes a claim that's
contrary to the actual address), yet doesn't make the same
assumption about the address of the reference even though
the diagnostic says it can.

While I would find the warning less misleading if it simply said
in all three cases: "the address of 'x' will always evaluate as
‘true’" I think it would be even more accurate if it said
"the address of 'x' may be assumed to evaluate to ‘true’"  That
avoids making claims about whether or not it actually is null,
doesn't talk about the NULL macro when one isn't used in the
code, and by saying "may assume" it allows for both making
the assumption as well as not making one.

I'm happy to submit a patch to make this change in stage 1 if
no one objects to it.

Martin

$ cat x.c && /home/msebor/build/gcc-trunk-svn/gcc/xgcc 
-B/home/msebor/build/gcc-trunk-svn/gcc -c -xc++ x.c && 
/home/msebor/build/gcc-trunk-svn/gcc/xgcc 
-B/home/msebor/build/gcc-trunk-svn/gcc -DMAIN -Wall -Wextra -Wpedantic 
x.o -xc++ x.c && ./a.out
#if MAIN

extern int i;
extern int &r;

extern void f ();

int main ()
{
     f ();

#define TEST(x) __builtin_printf ("%s is %s\n", #x, (x) ? "true" : "false")

     TEST (&i != 0);
     TEST (&r != 0);
     TEST (&i);
}

#else
extern __attribute__ ((weak)) int i;
int &r = i;

void f ()
{
     __builtin_printf ("&i = %p\n&r = %p\n", &i, &r);
}

#endif
x.c: In function ‘int main()’:
x.c:14:17: warning: the address of ‘i’ will never be NULL [-Waddress]
      TEST (&i != 0);
                  ^
x.c:12:54: note: in definition of macro ‘TEST’
  #define TEST(x) __builtin_printf ("%s is %s\n", #x, (x) ? "true" : 
"false")
                                                       ^
x.c:15:14: warning: the compiler can assume that the address of ‘r’ will 
never be NULL [-Waddress]
      TEST (&r != 0);
            ~~~^~~~
x.c:12:54: note: in definition of macro ‘TEST’
  #define TEST(x) __builtin_printf ("%s is %s\n", #x, (x) ? "true" : 
"false")
                                                       ^
x.c:12:68: warning: the address of ‘i’ will always evaluate as ‘true’ 
[-Waddres]
  #define TEST(x) __builtin_printf ("%s is %s\n", #x, (x) ? "true" : 
"false")
                                                                     ^
x.c:16:5: note: in expansion of macro ‘TEST’
      TEST (&i);
      ^~~~
&i = (nil)
&r = (nil)
&i != 0 is true
&r != 0 is false
&i is true
Jason Merrill March 17, 2016, 7 p.m. UTC | #9
On 03/17/2016 02:51 PM, Martin Sebor wrote:
> On 03/17/2016 10:48 AM, Patrick Palka wrote:
>> On Thu, Mar 17, 2016 at 12:27 PM, Jeff Law <law@redhat.com> wrote:
>>> On 03/16/2016 06:43 PM, Martin Sebor wrote:
>>>>>
>>>>> @@ -3974,6 +3974,38 @@ build_vec_cmp (tree_code code, tree type,
>>>>>      return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec,
>>>>> zero_vec);
>>>>>    }
>>>>>
>>>>> +/* Possibly warn about an address never being NULL.  */
>>>>> +
>>>>> +static void
>>>>> +warn_for_null_address (location_t location, tree op, tsubst_flags_t
>>>>> complain)
>>>>> +{
>>>>
>>>> ...
>>>>>
>>>>> +  if (TREE_CODE (cop) == ADDR_EXPR
>>>>> +      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
>>>>> +      && !TREE_NO_WARNING (cop))
>>>>> +    warning_at (location, OPT_Waddress, "the address of %qD will
>>>>> never "
>>>>> +        "be NULL", TREE_OPERAND (cop, 0));
>>>>> +
>>>>> +  if (CONVERT_EXPR_P (op)
>>>>> +      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) ==
>>>>> REFERENCE_TYPE)
>>>>> +    {
>>>>> +      tree inner_op = op;
>>>>> +      STRIP_NOPS (inner_op);
>>>>> +
>>>>> +      if (DECL_P (inner_op))
>>>>> +    warning_at (location, OPT_Waddress,
>>>>> +            "the compiler can assume that the address of "
>>>>> +            "%qD will never be NULL", inner_op);
>>>>
>>>>
>>>> Since I noted the subtle differences between the phrasing of
>>>> the various -Waddress warnings in the bug, I have to ask: what is
>>>> the significance of the difference between the two warnings here?
>>>>
>>>> Would it not be appropriate to issue the first warning in the latter
>>>> case?  Or perhaps even use the same text as is already used elsewhere:
>>>> "the address of %qD will always evaluate as ‘true’" (since it may not
>>>> be the macro NULL that's mentioned in the expression).
>>>
>>> They were added at different times AFAICT.  The former is fairly old
>>> (Douglas Gregor, 2008) at this point.  The latter was added by
>>> Patrick Palka
>>> for 65168 about a year ago.
>>>
>>> You could directly ask Patrick about motivations for a different
>>> message.
>>
>> There is no plausible way for the address of a non-reference variable
>> to be NULL even in code with UB (aside from __attribute__ ((weak)) in
>> which case the warning is suppressed).  But the address of a reference
>> can easily seem to be NULL if one performs UB and assigns to it *(int
>> *)NULL or something like that.  I think that was my motivation, anyway
>> :)
>
> Thanks (everyone) for the explanation.
>
> I actually think the warning Patrick added is the most accurate
> and would be appropriate in all cases.
>
> I suppose what bothers me besides the mention of NULL even when
> there is no NULL in the code, is that a) the text of the warnings
> is misleading (contradictory) in some interesting cases, and b)
> I can't think of a way in which the difference between the three
> phrasings of the diagnostic could be useful to a user.  All three
> imply the same thing: compilers can and GCC is some cases does
> assume that the address of an ordinary (non weak) function, object,
> or reference is not null.
>
> To see (a), consider the invalid test program below, in which
> GCC makes this assumption about the address of i even though
> the warning doesn't mention it (but it makes a claim that's
> contrary to the actual address), yet doesn't make the same
> assumption about the address of the reference even though
> the diagnostic says it can.
>
> While I would find the warning less misleading if it simply said
> in all three cases: "the address of 'x' will always evaluate as
> ‘true’" I think it would be even more accurate if it said
> "the address of 'x' may be assumed to evaluate to ‘true’"  That
> avoids making claims about whether or not it actually is null,
> doesn't talk about the NULL macro when one isn't used in the
> code, and by saying "may assume" it allows for both making
> the assumption as well as not making one.

That sounds good except that talking about 'true' is wrong when there is 
an explicit comparison to a null pointer constant.  I'd be fine with 
changing "NULL" to "null" or similar.

> I'm happy to submit a patch to make this change in stage 1 if
> no one objects to it.
>
> Martin
>
> $ cat x.c && /home/msebor/build/gcc-trunk-svn/gcc/xgcc
> -B/home/msebor/build/gcc-trunk-svn/gcc -c -xc++ x.c &&
> /home/msebor/build/gcc-trunk-svn/gcc/xgcc
> -B/home/msebor/build/gcc-trunk-svn/gcc -DMAIN -Wall -Wextra -Wpedantic
> x.o -xc++ x.c && ./a.out
> #if MAIN
>
> extern int i;
> extern int &r;
>
> extern void f ();
>
> int main ()
> {
>      f ();
>
> #define TEST(x) __builtin_printf ("%s is %s\n", #x, (x) ? "true" : "false")
>
>      TEST (&i != 0);
>      TEST (&r != 0);
>      TEST (&i);
> }
>
> #else
> extern __attribute__ ((weak)) int i;
> int &r = i;
>
> void f ()
> {
>      __builtin_printf ("&i = %p\n&r = %p\n", &i, &r);
> }
>
> #endif
> x.c: In function ‘int main()’:
> x.c:14:17: warning: the address of ‘i’ will never be NULL [-Waddress]
>       TEST (&i != 0);
>                   ^
> x.c:12:54: note: in definition of macro ‘TEST’
>   #define TEST(x) __builtin_printf ("%s is %s\n", #x, (x) ? "true" :
> "false")
>                                                        ^
> x.c:15:14: warning: the compiler can assume that the address of ‘r’ will
> never be NULL [-Waddress]
>       TEST (&r != 0);
>             ~~~^~~~
> x.c:12:54: note: in definition of macro ‘TEST’
>   #define TEST(x) __builtin_printf ("%s is %s\n", #x, (x) ? "true" :
> "false")
>                                                        ^
> x.c:12:68: warning: the address of ‘i’ will always evaluate as ‘true’
> [-Waddres]
>   #define TEST(x) __builtin_printf ("%s is %s\n", #x, (x) ? "true" :
> "false")
>                                                                      ^
> x.c:16:5: note: in expansion of macro ‘TEST’
>       TEST (&i);
>       ^~~~
> &i = (nil)
> &r = (nil)
> &i != 0 is true
> &r != 0 is false
> &i is true
>
Martin Sebor March 18, 2016, 12:19 a.m. UTC | #10
>> While I would find the warning less misleading if it simply said
>> in all three cases: "the address of 'x' will always evaluate as
>> ‘true’" I think it would be even more accurate if it said
>> "the address of 'x' may be assumed to evaluate to ‘true’"  That
>> avoids making claims about whether or not it actually is null,
>> doesn't talk about the NULL macro when one isn't used in the
>> code, and by saying "may assume" it allows for both making
>> the assumption as well as not making one.
>
> That sounds good except that talking about 'true' is wrong when there is
> an explicit comparison to a null pointer constant.  I'd be fine with
> changing "NULL" to "null" or similar.

Sounds good.  I will use bug 47931 - missing -Waddress warning
for comparison with NULL, to take care of the outstanding cases
where a warning still isn't issued (in either C++ or C) and also
adjust the text of the warning.

Martin

PS It seems that just adding STRIP_NOPS (op) to Marek's patch
significantly increases the number of successfully diagnosed
cases.  (The small patch I attached to 47931 covers nearly all
the remaining cases I could think of.)
diff mbox

Patch

diff --git gcc/cp/typeck.c gcc/cp/typeck.c
index 20f0afc..447006c 100644
--- gcc/cp/typeck.c
+++ gcc/cp/typeck.c
@@ -3974,6 +3974,38 @@  build_vec_cmp (tree_code code, tree type,
   return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
 }
 
+/* Possibly warn about an address never being NULL.  */
+
+static void
+warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
+{
+  if (!warn_address
+      || (complain & tf_warning) == 0
+      || c_inhibit_evaluation_warnings != 0
+      || TREE_NO_WARNING (op))
+    return;
+
+  tree cop = fold_non_dependent_expr (op);
+
+  if (TREE_CODE (cop) == ADDR_EXPR
+      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
+      && !TREE_NO_WARNING (cop))
+    warning_at (location, OPT_Waddress, "the address of %qD will never "
+		"be NULL", TREE_OPERAND (cop, 0));
+
+  if (CONVERT_EXPR_P (op)
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == REFERENCE_TYPE)
+    {
+      tree inner_op = op;
+      STRIP_NOPS (inner_op);
+
+      if (DECL_P (inner_op))
+	warning_at (location, OPT_Waddress,
+		    "the compiler can assume that the address of "
+		    "%qD will never be NULL", inner_op);
+    }
+}
+
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    LOCATION is the location_t of the operator in the source code.
@@ -4520,32 +4552,7 @@  cp_build_binary_op (location_t location,
 	  else
 	    result_type = type0;
 
-	  if (TREE_CODE (op0) == ADDR_EXPR
-	      && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
-	    {
-	      if ((complain & tf_warning)
-		  && c_inhibit_evaluation_warnings == 0
-		  && !TREE_NO_WARNING (op0))
-		warning (OPT_Waddress, "the address of %qD will never be NULL",
-			 TREE_OPERAND (op0, 0));
-	    }
-
-	  if (CONVERT_EXPR_P (op0)
-	      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0)))
-		 == REFERENCE_TYPE)
-	    {
-	      tree inner_op0 = op0;
-	      STRIP_NOPS (inner_op0);
-
-	      if ((complain & tf_warning)
-		  && c_inhibit_evaluation_warnings == 0
-		  && !TREE_NO_WARNING (op0)
-		  && DECL_P (inner_op0))
-		warning_at (location, OPT_Waddress,
-			    "the compiler can assume that the address of "
-			    "%qD will never be NULL",
-			    inner_op0);
-	    }
+	  warn_for_null_address (location, op0, complain);
 	}
       else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
 		&& null_ptr_cst_p (op0))
@@ -4559,32 +4566,7 @@  cp_build_binary_op (location_t location,
 	  else
 	    result_type = type1;
 
-	  if (TREE_CODE (op1) == ADDR_EXPR 
-	      && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
-	    {
-	      if ((complain & tf_warning)
-		  && c_inhibit_evaluation_warnings == 0
-		  && !TREE_NO_WARNING (op1))
-		warning (OPT_Waddress, "the address of %qD will never be NULL",
-			 TREE_OPERAND (op1, 0));
-	    }
-
-	  if (CONVERT_EXPR_P (op1)
-	      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op1, 0)))
-		 == REFERENCE_TYPE)
-	    {
-	      tree inner_op1 = op1;
-	      STRIP_NOPS (inner_op1);
-
-	      if ((complain & tf_warning)
-		  && c_inhibit_evaluation_warnings == 0
-		  && !TREE_NO_WARNING (op1)
-		  && DECL_P (inner_op1))
-		warning_at (location, OPT_Waddress,
-			    "the compiler can assume that the address of "
-			    "%qD will never be NULL",
-			    inner_op1);
-	    }
+	  warn_for_null_address (location, op1, complain);
 	}
       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	       || (TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P (type1)))
diff --git gcc/testsuite/g++.dg/warn/constexpr-70194.C gcc/testsuite/g++.dg/warn/constexpr-70194.C
index e69de29..cdc56c0 100644
--- gcc/testsuite/g++.dg/warn/constexpr-70194.C
+++ gcc/testsuite/g++.dg/warn/constexpr-70194.C
@@ -0,0 +1,12 @@ 
+// PR c++/70194
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wall" }
+
+int i;
+
+const bool b0 = &i == 0; // { dg-warning "the address of .i. will never be NULL" }
+constexpr int *p = &i;
+const bool b1 = p == 0; // { dg-warning "the address of .i. will never be NULL" }
+const bool b2 = 0 == p; // { dg-warning "the address of .i. will never be NULL" }
+const bool b3 = p != 0; // { dg-warning "the address of .i. will never be NULL" }
+const bool b4 = 0 != p; // { dg-warning "the address of .i. will never be NULL" }