diff mbox

Emit -Waddress warnings for comparing address of reference against NULL

Message ID 1430096197-29836-1-git-send-email-patrick@parcs.ath.cx
State New
Headers show

Commit Message

Patrick Palka April 27, 2015, 12:56 a.m. UTC
Here is an updated version of the patch with, hopefully, all your
suggestions made.  I decided to add calls to STRIP_NOPS before emitting
the warning so that we properly warn for cases where there's a cast in
between the whole thing, e.g.

  if (!&(int &)a)

I also added guards to emit the warnings only when the stripped operand
is actually a decl so that we don't pass a non-decl argument to
warning_at() which can happen in a case like

  if (!&(int &)*(int *)0)

Does this look OK now after testing?

gcc/c-family/ChangeLog:

	PR c++/65168
	* c-common.c (c_common_truthvalue_conversion): Warn when
	converting an address of a reference to a truth value.

gcc/cp/ChangeLog:

	PR c++/65168
	* typeck.c (cp_build_binary_op): Warn when comparing an address
	of a reference against NULL.

gcc/testsuite/ChangeLog:

	PR c++/65168
	g++.dg/warn/Walways-true-3.C: New test.
---
 gcc/c-family/c-common.c                    | 14 ++++++++++
 gcc/cp/typeck.c                            | 34 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/warn/Walways-true-3.C | 45 ++++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/warn/Walways-true-3.C

Comments

Patrick Palka May 3, 2015, 9:29 p.m. UTC | #1
On Sun, Apr 26, 2015 at 8:56 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> Here is an updated version of the patch with, hopefully, all your
> suggestions made.  I decided to add calls to STRIP_NOPS before emitting
> the warning so that we properly warn for cases where there's a cast in
> between the whole thing, e.g.
>
>   if (!&(int &)a)
>
> I also added guards to emit the warnings only when the stripped operand
> is actually a decl so that we don't pass a non-decl argument to
> warning_at() which can happen in a case like
>
>   if (!&(int &)*(int *)0)
>
> Does this look OK now after testing?
>
> gcc/c-family/ChangeLog:
>
>         PR c++/65168
>         * c-common.c (c_common_truthvalue_conversion): Warn when
>         converting an address of a reference to a truth value.
>
> gcc/cp/ChangeLog:
>
>         PR c++/65168
>         * typeck.c (cp_build_binary_op): Warn when comparing an address
>         of a reference against NULL.
>
> gcc/testsuite/ChangeLog:
>
>         PR c++/65168
>         g++.dg/warn/Walways-true-3.C: New test.
> ---
>  gcc/c-family/c-common.c                    | 14 ++++++++++
>  gcc/cp/typeck.c                            | 34 ++++++++++++++++++++++
>  gcc/testsuite/g++.dg/warn/Walways-true-3.C | 45 ++++++++++++++++++++++++++++++
>  3 files changed, 93 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/warn/Walways-true-3.C
>
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index 9797e17..c353c72 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -4806,6 +4806,20 @@ c_common_truthvalue_conversion (location_t location, tree expr)
>         tree totype = TREE_TYPE (expr);
>         tree fromtype = TREE_TYPE (TREE_OPERAND (expr, 0));
>
> +       if (POINTER_TYPE_P (totype)
> +           && TREE_CODE (fromtype) == REFERENCE_TYPE)
> +         {
> +           tree inner = expr;
> +           STRIP_NOPS (inner);
> +
> +           if (DECL_P (inner))
> +             warning_at (location,
> +                         OPT_Waddress,
> +                         "the compiler can assume that the address of "
> +                         "%qD will always evaluate to %<true%>",
> +                         inner);
> +         }
> +
>         /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
>            since that affects how `default_conversion' will behave.  */
>         if (TREE_CODE (totype) == REFERENCE_TYPE
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index 91db32a..13fb401 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -4423,6 +4423,23 @@ cp_build_binary_op (location_t location,
>                 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 (OPT_Waddress,
> +                        "the compiler can assume that the address of "
> +                        "%qD will never be NULL",
> +                        inner_op0);
> +           }
>         }
>        else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
>                 && null_ptr_cst_p (op0))
> @@ -4445,6 +4462,23 @@ cp_build_binary_op (location_t location,
>                 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 (OPT_Waddress,
> +                        "the compiler can assume that the address of "
> +                        "%qD will never be NULL",
> +                        inner_op1);
> +           }
>         }
>        else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
>                || (TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P (type1)))
> diff --git a/gcc/testsuite/g++.dg/warn/Walways-true-3.C b/gcc/testsuite/g++.dg/warn/Walways-true-3.C
> new file mode 100644
> index 0000000..0d13d3f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Walways-true-3.C
> @@ -0,0 +1,45 @@
> +// { dg-options "-Waddress" }
> +
> +void foo (void);
> +
> +int d;
> +int &c = d;
> +
> +void
> +bar (int &a)
> +{
> +  int &b = a;
> +
> +  if ((int *)&a) // { dg-warning "address of" }
> +    foo ();
> +
> +  if (&b) // { dg-warning "address of" }
> +    foo ();
> +
> +  if (!&c) // { dg-warning "address of" }
> +    foo ();
> +
> +  if (!&(int &)(int &)a) // { dg-warning "address of" }
> +    foo ();
> +
> +  if (&a == 0) // { dg-warning "never be NULL" }
> +    foo ();
> +
> +  if (&b != 0) // { dg-warning "never be NULL" }
> +    foo ();
> +
> +  if (0 == &(int &)(int &)c) // { dg-warning "never be NULL" }
> +    foo ();
> +
> +  if (&a != (int *)0) // { dg-warning "never be NULL" }
> +    foo ();
> +}
> +
> +bool
> +bar_1 (int &a)
> +{
> +  if (d == 5)
> +    return &a; // { dg-warning "address of" }
> +  else
> +    return !&(int &)(int &)a; // { dg-warning "address of" }
> +}
> --
> 2.4.0.rc2.31.g7c597ef
>

Ping.
Patrick Palka June 10, 2015, 2:39 a.m. UTC | #2
On Sun, May 3, 2015 at 5:29 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> On Sun, Apr 26, 2015 at 8:56 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
>> Here is an updated version of the patch with, hopefully, all your
>> suggestions made.  I decided to add calls to STRIP_NOPS before emitting
>> the warning so that we properly warn for cases where there's a cast in
>> between the whole thing, e.g.
>>
>>   if (!&(int &)a)
>>
>> I also added guards to emit the warnings only when the stripped operand
>> is actually a decl so that we don't pass a non-decl argument to
>> warning_at() which can happen in a case like
>>
>>   if (!&(int &)*(int *)0)
>>
>> Does this look OK now after testing?
>>
>> gcc/c-family/ChangeLog:
>>
>>         PR c++/65168
>>         * c-common.c (c_common_truthvalue_conversion): Warn when
>>         converting an address of a reference to a truth value.
>>
>> gcc/cp/ChangeLog:
>>
>>         PR c++/65168
>>         * typeck.c (cp_build_binary_op): Warn when comparing an address
>>         of a reference against NULL.
>>
>> gcc/testsuite/ChangeLog:
>>
>>         PR c++/65168
>>         g++.dg/warn/Walways-true-3.C: New test.
>> ---
>>  gcc/c-family/c-common.c                    | 14 ++++++++++
>>  gcc/cp/typeck.c                            | 34 ++++++++++++++++++++++
>>  gcc/testsuite/g++.dg/warn/Walways-true-3.C | 45 ++++++++++++++++++++++++++++++
>>  3 files changed, 93 insertions(+)
>>  create mode 100644 gcc/testsuite/g++.dg/warn/Walways-true-3.C
>>
>> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
>> index 9797e17..c353c72 100644
>> --- a/gcc/c-family/c-common.c
>> +++ b/gcc/c-family/c-common.c
>> @@ -4806,6 +4806,20 @@ c_common_truthvalue_conversion (location_t location, tree expr)
>>         tree totype = TREE_TYPE (expr);
>>         tree fromtype = TREE_TYPE (TREE_OPERAND (expr, 0));
>>
>> +       if (POINTER_TYPE_P (totype)
>> +           && TREE_CODE (fromtype) == REFERENCE_TYPE)
>> +         {
>> +           tree inner = expr;
>> +           STRIP_NOPS (inner);
>> +
>> +           if (DECL_P (inner))
>> +             warning_at (location,
>> +                         OPT_Waddress,
>> +                         "the compiler can assume that the address of "
>> +                         "%qD will always evaluate to %<true%>",
>> +                         inner);
>> +         }
>> +
>>         /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
>>            since that affects how `default_conversion' will behave.  */
>>         if (TREE_CODE (totype) == REFERENCE_TYPE
>> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
>> index 91db32a..13fb401 100644
>> --- a/gcc/cp/typeck.c
>> +++ b/gcc/cp/typeck.c
>> @@ -4423,6 +4423,23 @@ cp_build_binary_op (location_t location,
>>                 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 (OPT_Waddress,
>> +                        "the compiler can assume that the address of "
>> +                        "%qD will never be NULL",
>> +                        inner_op0);
>> +           }
>>         }
>>        else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
>>                 && null_ptr_cst_p (op0))
>> @@ -4445,6 +4462,23 @@ cp_build_binary_op (location_t location,
>>                 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 (OPT_Waddress,
>> +                        "the compiler can assume that the address of "
>> +                        "%qD will never be NULL",
>> +                        inner_op1);
>> +           }
>>         }
>>        else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
>>                || (TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P (type1)))
>> diff --git a/gcc/testsuite/g++.dg/warn/Walways-true-3.C b/gcc/testsuite/g++.dg/warn/Walways-true-3.C
>> new file mode 100644
>> index 0000000..0d13d3f
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/warn/Walways-true-3.C
>> @@ -0,0 +1,45 @@
>> +// { dg-options "-Waddress" }
>> +
>> +void foo (void);
>> +
>> +int d;
>> +int &c = d;
>> +
>> +void
>> +bar (int &a)
>> +{
>> +  int &b = a;
>> +
>> +  if ((int *)&a) // { dg-warning "address of" }
>> +    foo ();
>> +
>> +  if (&b) // { dg-warning "address of" }
>> +    foo ();
>> +
>> +  if (!&c) // { dg-warning "address of" }
>> +    foo ();
>> +
>> +  if (!&(int &)(int &)a) // { dg-warning "address of" }
>> +    foo ();
>> +
>> +  if (&a == 0) // { dg-warning "never be NULL" }
>> +    foo ();
>> +
>> +  if (&b != 0) // { dg-warning "never be NULL" }
>> +    foo ();
>> +
>> +  if (0 == &(int &)(int &)c) // { dg-warning "never be NULL" }
>> +    foo ();
>> +
>> +  if (&a != (int *)0) // { dg-warning "never be NULL" }
>> +    foo ();
>> +}
>> +
>> +bool
>> +bar_1 (int &a)
>> +{
>> +  if (d == 5)
>> +    return &a; // { dg-warning "address of" }
>> +  else
>> +    return !&(int &)(int &)a; // { dg-warning "address of" }
>> +}
>> --
>> 2.4.0.rc2.31.g7c597ef
>>
>
> Ping.

Ping.
Jason Merrill June 11, 2015, 8:45 p.m. UTC | #3
Let's use explicit location for the C++ front end warnings, too.  OK 
with that change.

Jason
diff mbox

Patch

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 9797e17..c353c72 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -4806,6 +4806,20 @@  c_common_truthvalue_conversion (location_t location, tree expr)
 	tree totype = TREE_TYPE (expr);
 	tree fromtype = TREE_TYPE (TREE_OPERAND (expr, 0));
 
+	if (POINTER_TYPE_P (totype)
+	    && TREE_CODE (fromtype) == REFERENCE_TYPE)
+	  {
+	    tree inner = expr;
+	    STRIP_NOPS (inner);
+
+	    if (DECL_P (inner))
+	      warning_at (location,
+			  OPT_Waddress,
+			  "the compiler can assume that the address of "
+			  "%qD will always evaluate to %<true%>",
+			  inner);
+	  }
+
 	/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
 	   since that affects how `default_conversion' will behave.  */
 	if (TREE_CODE (totype) == REFERENCE_TYPE
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 91db32a..13fb401 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4423,6 +4423,23 @@  cp_build_binary_op (location_t location,
 		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 (OPT_Waddress,
+			 "the compiler can assume that the address of "
+			 "%qD will never be NULL",
+			 inner_op0);
+	    }
 	}
       else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
 		&& null_ptr_cst_p (op0))
@@ -4445,6 +4462,23 @@  cp_build_binary_op (location_t location,
 		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 (OPT_Waddress,
+			 "the compiler can assume that the address of "
+			 "%qD will never be NULL",
+			 inner_op1);
+	    }
 	}
       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	       || (TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P (type1)))
diff --git a/gcc/testsuite/g++.dg/warn/Walways-true-3.C b/gcc/testsuite/g++.dg/warn/Walways-true-3.C
new file mode 100644
index 0000000..0d13d3f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Walways-true-3.C
@@ -0,0 +1,45 @@ 
+// { dg-options "-Waddress" }
+
+void foo (void);
+
+int d;
+int &c = d;
+
+void
+bar (int &a)
+{
+  int &b = a;
+
+  if ((int *)&a) // { dg-warning "address of" }
+    foo ();
+
+  if (&b) // { dg-warning "address of" }
+    foo ();
+
+  if (!&c) // { dg-warning "address of" }
+    foo ();
+
+  if (!&(int &)(int &)a) // { dg-warning "address of" }
+    foo ();
+
+  if (&a == 0) // { dg-warning "never be NULL" }
+    foo ();
+
+  if (&b != 0) // { dg-warning "never be NULL" }
+    foo ();
+
+  if (0 == &(int &)(int &)c) // { dg-warning "never be NULL" }
+    foo ();
+
+  if (&a != (int *)0) // { dg-warning "never be NULL" }
+    foo ();
+}
+
+bool
+bar_1 (int &a)
+{
+  if (d == 5)
+    return &a; // { dg-warning "address of" }
+  else
+    return !&(int &)(int &)a; // { dg-warning "address of" }
+}