re PR c++/64767 (Could GCC warn when a pointer is compared against '\0'?)
authorMarek Polacek <polacek@redhat.com>
Wed, 4 Jan 2017 21:47:04 +0000 (21:47 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Wed, 4 Jan 2017 21:47:04 +0000 (21:47 +0000)
PR c++/64767
* c.opt (Wpointer-compare): New option.

* c-parser.c (c_parser_postfix_expression): Mark zero character
constants by setting original_type in c_expr.
* c-typeck.c (parser_build_binary_op): Warn when a pointer is compared
with a zero character constant.
(char_type_p): New function.

* typeck.c (cp_build_binary_op): Warn when a pointer is compared with
a zero character literal.

* doc/invoke.texi: Document -Wpointer-compare.

* c-c++-common/Wpointer-compare-1.c: New test.

From-SVN: r244076

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c.opt
gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/c/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Wpointer-compare-1.c [new file with mode: 0644]

index 5181fe80e06a620976c4cbe09b6bd94a87afed7b..45efbb47c864c6977a65e377f49f5841d8a48028 100644 (file)
@@ -1,3 +1,8 @@
+2017-01-04  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/64767
+       * doc/invoke.texi: Document -Wpointer-compare.
+
 2017-01-04  Jakub Jelinek  <jakub@redhat.com>
 
        * optc-gen.awk: Emit #error for -W*/-f*/-m* Enum without
index 468b7dde8f5944868b078bd2552c08a936830e2e..b9bb5fe59a3d8bce0863200a585b06b85e4e8691 100644 (file)
@@ -1,3 +1,8 @@
+2017-01-04  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/64767
+       * c.opt (Wpointer-compare): New option.
+
 2017-01-04  Jakub Jelinek  <jakub@redhat.com>
 
        PR driver/78957
index 3f6c67fbc7e042627c83bba424641aa2cc701e30..714ce3a34f0052956dc872095b332d20f1137fc6 100644 (file)
@@ -870,6 +870,10 @@ Wpointer-sign
 C ObjC Var(warn_pointer_sign) Warning LangEnabledBy(C ObjC,Wall || Wpedantic)
 Warn when a pointer differs in signedness in an assignment.
 
+Wpointer-compare
+C ObjC C++ ObjC++ Var(warn_pointer_compare) Init(1) Warning
+Warn when a pointer is compared with a zero character constant.
+
 Wpointer-to-int-cast
 C ObjC Var(warn_pointer_to_int_cast) Init(1) Warning
 Warn when a pointer is cast to an integer of a different size.
index 6f8cf00a1da1a3202523c9e1c394ad8623e577a7..6e1c985701681da2c68a14b6d4f5c4460480dd33 100644 (file)
@@ -1,3 +1,12 @@
+2017-01-04  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/64767
+       * c-parser.c (c_parser_postfix_expression): Mark zero character
+       constants by setting original_type in c_expr.
+       * c-typeck.c (parser_build_binary_op): Warn when a pointer is compared
+       with a zero character constant.
+       (char_type_p): New function.
+
 2017-01-04  David Malcolm  <dmalcolm@redhat.com>
 
        * c-parser.c (c_parser_declaration_or_fndef): Create a
index c7679c2644a1004beffb43978337c1c51b77c855..a3504d3eec9dd0f6c70372a3f209142cab9519dd 100644 (file)
@@ -7540,6 +7540,9 @@ c_parser_postfix_expression (c_parser *parser)
     case CPP_CHAR32:
     case CPP_WCHAR:
       expr.value = c_parser_peek_token (parser)->value;
+      /* For the purpose of warning when a pointer is compared with
+        a zero character constant.  */
+      expr.original_type = char_type_node;
       set_c_expr_source_range (&expr, tok_range);
       c_parser_consume_token (parser);
       break;
index 63e0dc6b29898105794aa1bd24e2c985e137a0cb..96e7351bf4580788ed2383e26d0aec0d2d6c4fae 100644 (file)
@@ -3595,6 +3595,18 @@ parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg)
   return result;
 }
 
+/* Returns true if TYPE is a character type, *not* including wchar_t.  */
+
+static bool
+char_type_p (tree type)
+{
+  return (type == char_type_node
+         || type == unsigned_char_type_node
+         || type == signed_char_type_node
+         || type == char16_type_node
+         || type == char32_type_node);
+}
+
 /* This is the entry point used by the parser to build binary operators
    in the input.  CODE, a tree_code, specifies the binary operator, and
    ARG1 and ARG2 are the operands.  In addition to constructing the
@@ -3714,6 +3726,21 @@ parser_build_binary_op (location_t location, enum tree_code code,
              && !integer_zerop (tree_strip_nop_conversions (arg1.value))))
        warning_at (location, OPT_Waddress,
                    "comparison with string literal results in unspecified behavior");
+      /* Warn for ptr == '\0', it's likely that it should've been ptr[0].  */
+      if (POINTER_TYPE_P (type1)
+          && null_pointer_constant_p (arg2.value)
+          && char_type_p (type2)
+          && warning_at (location, OPT_Wpointer_compare,
+                         "comparison between pointer and zero character "
+                         "constant"))
+       inform (arg1.get_start (), "did you mean to dereference the pointer?");
+      else if (POINTER_TYPE_P (type2)
+              && null_pointer_constant_p (arg1.value)
+              && char_type_p (type1)
+              && warning_at (location, OPT_Wpointer_compare,
+                             "comparison between pointer and zero character "
+                             "constant"))
+       inform (arg2.get_start (), "did you mean to dereference the pointer?");
     }
   else if (TREE_CODE_CLASS (code) == tcc_comparison
           && (code1 == STRING_CST || code2 == STRING_CST))
index 8dc6588ec31ce1b09b42abed0d6bb9d019ca7fbe..8e723be3eba8f8fbf89b02494a4b833278c5da1c 100644 (file)
@@ -1,3 +1,9 @@
+2017-01-04  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/64767
+       * typeck.c (cp_build_binary_op): Warn when a pointer is compared with
+       a zero character literal.
+
 2017-01-04  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/78949
index 6da98f65bdd3d150396db1dd8af0b38b9324a637..b84f8beef53ee2fb39fdbc13a2d004f92a82b17b 100644 (file)
@@ -4604,6 +4604,12 @@ cp_build_binary_op (location_t location,
          else
            result_type = type0;
 
+         if (char_type_p (TREE_TYPE (orig_op1))
+             && warning (OPT_Wpointer_compare,
+                         "comparison between pointer and zero character "
+                         "constant"))
+           inform (input_location,
+                   "did you mean to dereference the pointer?");
          warn_for_null_address (location, op0, complain);
        }
       else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
@@ -4618,6 +4624,12 @@ cp_build_binary_op (location_t location,
          else
            result_type = type1;
 
+         if (char_type_p (TREE_TYPE (orig_op0))
+             && warning (OPT_Wpointer_compare,
+                         "comparison between pointer and zero character "
+                         "constant"))
+           inform (input_location,
+                   "did you mean to dereference the pointer?");
          warn_for_null_address (location, op1, complain);
        }
       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
index 2bd105a867f2955ebc9c17ff6904afecd776baab..a6ea4259f522293f9de42f18c216d14eb3c350b1 100644 (file)
@@ -295,7 +295,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wpacked  -Wpacked-bitfield-compat  -Wpadded @gol
 -Wparentheses -Wno-pedantic-ms-format @gol
 -Wplacement-new -Wplacement-new=@var{n} @gol
--Wpointer-arith  -Wno-pointer-to-int-cast @gol
+-Wpointer-arith  -Wpointer-compare  -Wno-pointer-to-int-cast @gol
 -Wno-pragmas -Wredundant-decls -Wrestrict  -Wno-return-local-addr @gol
 -Wreturn-type  -Wsequence-point  -Wshadow  -Wno-shadow-ivar @gol
 -Wshadow=global, -Wshadow=local, -Wshadow=compatible-local @gol
@@ -5637,6 +5637,22 @@ convenience in calculations with @code{void *} pointers and pointers
 to functions.  In C++, warn also when an arithmetic operation involves
 @code{NULL}.  This warning is also enabled by @option{-Wpedantic}.
 
+@item -Wpointer-compare
+@opindex Wpointer-compare
+@opindex Wno-pointer-compare
+Warn if a pointer is compared with a zero character constant.  This usually
+means that the pointer was meant to be dereferenced.  For example:
+
+@smallexample
+const char *p = foo ();
+if (p == '\0')
+  return 42;
+@end smallexample
+
+Note that the code above is invalid in C++11.
+
+This warning is enabled by default.
+
 @item -Wtype-limits
 @opindex Wtype-limits
 @opindex Wno-type-limits
index f56c11b957f9005200d95329709bb4f26eb07ee8..9b44a4a5843a67074855e2678ec8ec87d93986d8 100644 (file)
@@ -1,3 +1,8 @@
+2017-01-04  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/64767
+       * c-c++-common/Wpointer-compare-1.c: New test.
+
 2017-01-04  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/78949
diff --git a/gcc/testsuite/c-c++-common/Wpointer-compare-1.c b/gcc/testsuite/c-c++-common/Wpointer-compare-1.c
new file mode 100644 (file)
index 0000000..440341e
--- /dev/null
@@ -0,0 +1,65 @@
+/* PR c++/64767 */
+/* { dg-do compile } */
+/* { dg-options "-Wpointer-compare" } */
+/* { dg-additional-options "-std=c++03" { target c++ } } */
+
+int
+f1 (int *p, int **q)
+{
+  int r = 0;
+
+  r += p == '\0'; /* { dg-warning "comparison between pointer and zero character" } */
+  r += p == L'\0'; /* { dg-warning "comparison between pointer and zero character" } */
+  r += p != '\0'; /* { dg-warning "comparison between pointer and zero character" } */
+  r += p != L'\0'; /* { dg-warning "comparison between pointer and zero character" } */
+
+  r += '\0' == p; /* { dg-warning "comparison between pointer and zero character" } */
+  r += L'\0' == p; /* { dg-warning "comparison between pointer and zero character" } */
+  r += '\0' != p; /* { dg-warning "comparison between pointer and zero character" } */
+  r += L'\0' != p; /* { dg-warning "comparison between pointer and zero character" } */
+
+  r += q == '\0'; /* { dg-warning "comparison between pointer and zero character" } */
+  r += q == L'\0'; /* { dg-warning "comparison between pointer and zero character" } */
+  r += q != '\0'; /* { dg-warning "comparison between pointer and zero character" } */
+  r += q != L'\0'; /* { dg-warning "comparison between pointer and zero character" } */
+
+  r += '\0' == q; /* { dg-warning "comparison between pointer and zero character" } */
+  r += L'\0' == q; /* { dg-warning "comparison between pointer and zero character" } */
+  r += '\0' != q; /* { dg-warning "comparison between pointer and zero character" } */
+  r += L'\0' != q; /* { dg-warning "comparison between pointer and zero character" } */
+
+  return r;
+}
+
+int
+f2 (int *p)
+{
+  int r = 0;
+
+  /* Keep quiet.  */
+  r += p == (void *) 0;
+  r += p != (void *) 0;
+  r += (void *) 0 == p;
+  r += (void *) 0 != p;
+
+  r += p == 0;
+  r += p != 0;
+  r += 0 == p;
+  r += 0 != p;
+
+  return r;
+}
+
+int
+f3 (int *p)
+{
+  int r = 0;
+
+  r += p == (char) 0; /* { dg-warning "comparison between pointer and zero character" } */
+  r += p != (char) 0; /* { dg-warning "comparison between pointer and zero character" } */
+
+  r += (char) 0 == p; /* { dg-warning "comparison between pointer and zero character" } */
+  r += (char) 0 != p; /* { dg-warning "comparison between pointer and zero character" } */
+
+  return r;
+}