public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
@ 2016-09-10 15:06 Marek Polacek
  2016-09-10 15:13 ` Jakub Jelinek
  2016-09-14  5:56 ` Jason Merrill
  0 siblings, 2 replies; 18+ messages in thread
From: Marek Polacek @ 2016-09-10 15:06 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill, Joseph Myers

Spurred by the recent <http://www.viva64.com/en/b/0425/> findings, I decided to
implement a warning that warns when a pointer is compared with a zero character
literal (constant), because this isn't likely to be intended.  So e.g.

  ptr == L'\0'

is probably wrong and should've been written as

  ptr[0] == L'\0'

Jonathan pointed out that this would actually be invalid C++11 since pointer
conversions are only allowed for integer literals, not char literals.
There's -Wzero-as-null-pointer-constant to catch other cases such as

  void *o = '\0';

This patch deals strictly with ==/!=.

Now, I'm not exactly sure how to name this, -Wpointer-compare seems pretty
general.  So maybe as a followup I could use this option for C's
"comparison between pointer and integer" (that's a pedwarn)?

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

2016-09-10  Marek Polacek  <polacek@redhat.com>

	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.

	* cp-tree.h (class cp_expr): Add char_literal_p member.  Update the
	constructors and the copy constructor.
	* parser.c (cp_parser_primary_expression): Mark zero character
	literals.
	(cp_parser_binary_expression): 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.

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index a5358ed..ac299b6 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -776,6 +776,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.
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 0aba51c..46ca08a 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -7520,6 +7520,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;
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index d56c3d6..6426ae6 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -3709,6 +3709,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)
+	   && arg2.original_type == char_type_node
+	   && 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)
+	       && arg1.original_type == char_type_node
+	       && 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))
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 5bcb98b..a29905b 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -51,16 +51,21 @@ class cp_expr
 {
 public:
   cp_expr () :
-    m_value (NULL), m_loc (UNKNOWN_LOCATION) {}
+    m_value (NULL), m_loc (UNKNOWN_LOCATION), m_char_literal_p (false) {}
 
   cp_expr (tree value) :
-    m_value (value), m_loc (EXPR_LOCATION (m_value)) {}
+    m_value (value), m_loc (EXPR_LOCATION (m_value)),
+    m_char_literal_p (false) {}
 
   cp_expr (tree value, location_t loc):
-    m_value (value), m_loc (loc) {}
+    m_value (value), m_loc (loc), m_char_literal_p (false) {}
+
+  cp_expr (tree value, location_t loc, bool char_literal_p):
+    m_value (value), m_loc (loc), m_char_literal_p (char_literal_p) {}
 
   cp_expr (const cp_expr &other) :
-    m_value (other.m_value), m_loc (other.m_loc) {}
+    m_value (other.m_value), m_loc (other.m_loc),
+    m_char_literal_p (other.m_char_literal_p) {}
 
   /* Implicit conversions to tree.  */
   operator tree () const { return m_value; }
@@ -91,9 +96,12 @@ public:
     set_location (make_location (m_loc, start, finish));
   }
 
+  bool is_char_literal_p () const { return m_char_literal_p; }
+
  private:
   tree m_value;
   location_t m_loc;
+  bool m_char_literal_p;
 };
 
 inline bool
diff --git gcc/cp/parser.c gcc/cp/parser.c
index ca9f8b9..fc916a0 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -4756,6 +4756,7 @@ cp_parser_primary_expression (cp_parser *parser,
 			      cp_id_kind *idk)
 {
   cp_token *token = NULL;
+  bool char_literal_p = false;
 
   /* Assume the primary expression is not an id-expression.  */
   *idk = CP_ID_KIND_NONE;
@@ -4777,6 +4778,7 @@ cp_parser_primary_expression (cp_parser *parser,
     case CPP_CHAR32:
     case CPP_WCHAR:
     case CPP_UTF8CHAR:
+      char_literal_p = true;
     case CPP_NUMBER:
     case CPP_PREPARSED_EXPR:
       if (TREE_CODE (token->u.value) == USERDEF_LITERAL)
@@ -4832,7 +4834,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	  if (!cast_p)
 	    cp_parser_non_integral_constant_expression (parser, NIC_FLOAT);
 	}
-      return cp_expr (token->u.value, token->location);
+      return cp_expr (token->u.value, token->location, char_literal_p);
 
     case CPP_CHAR_USERDEF:
     case CPP_CHAR16_USERDEF:
@@ -8924,6 +8926,31 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 	warn_logical_not_parentheses (current.loc, current.tree_type,
 				      current.lhs, maybe_constant_value (rhs));
 
+      /* Warn for ptr == '\0', it's likely that it should've been ptr[0].  */
+      if (current.tree_type == EQ_EXPR || current.tree_type == NE_EXPR)
+	{
+	  if (TREE_TYPE (current.lhs.get_value ())
+	      && POINTER_TYPE_P (TREE_TYPE (current.lhs.get_value ()))
+	      && integer_zerop (rhs.get_value ())
+	      && !TREE_OVERFLOW (rhs.get_value ())
+	      && rhs.is_char_literal_p ()
+	      && warning_at (current.loc, OPT_Wpointer_compare,
+			     "comparison between pointer and zero character "
+			     "literal"))
+	    inform (current.lhs.get_location (),
+		    "did you mean to dereference the pointer?");
+	  else if (TREE_TYPE (rhs.get_value ())
+		   && POINTER_TYPE_P (TREE_TYPE (rhs.get_value ()))
+		   && integer_zerop (current.lhs.get_value ())
+		   && !TREE_OVERFLOW (current.lhs.get_value ())
+		   && current.lhs.is_char_literal_p ()
+		   && warning_at (current.loc, OPT_Wpointer_compare,
+				  "comparison between pointer and zero "
+				  "character literal"))
+	    inform (rhs.get_location (),
+		    "did you mean to dereference the pointer?");
+
+	}
       overload = NULL;
 
       location_t combined_loc = make_location (current.loc,
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 20be9b7..cc19874 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -287,7 +287,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  -Wno-return-local-addr @gol
 -Wreturn-type  -Wsequence-point  -Wshadow  -Wno-shadow-ivar @gol
 -Wshift-overflow -Wshift-overflow=@var{n} @gol
@@ -5115,6 +5115,20 @@ 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
+
+This warning is enabled by default.
+
 @item -Wtype-limits
 @opindex Wtype-limits
 @opindex Wno-type-limits
diff --git gcc/testsuite/c-c++-common/Wpointer-compare-1.c gcc/testsuite/c-c++-common/Wpointer-compare-1.c
index e69de29..80da85a 100644
--- gcc/testsuite/c-c++-common/Wpointer-compare-1.c
+++ gcc/testsuite/c-c++-common/Wpointer-compare-1.c
@@ -0,0 +1,81 @@
+/* PR c++/64767 */
+/* { dg-do compile } */
+/* { dg-options "-Wpointer-compare" } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+
+int
+f1 (int *p, int **q)
+{
+  int r = 0;
+
+  r += p == '\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p == L'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p == u'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p == U'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p != '\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p != L'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p != u'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p != U'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+
+  r += '\0' == p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += L'\0' == p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += u'\0' == p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += U'\0' == p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += '\0' != p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += L'\0' != p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += u'\0' != p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += U'\0' != p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+
+  r += q == '\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q == L'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q == u'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q == U'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q != '\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q != L'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q != u'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q != U'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+
+  r += '\0' == q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += L'\0' == q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += u'\0' == q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += U'\0' == q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += '\0' != q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += L'\0' != q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += u'\0' != q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += U'\0' != q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+
+  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;
+  r += p != (char) 0;
+
+  r += (char) 0 == p;
+  r += (char) 0 != p;
+
+  return r;
+}

	Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-10 15:06 C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767) Marek Polacek
@ 2016-09-10 15:13 ` Jakub Jelinek
  2016-09-10 15:48   ` Marek Polacek
  2016-09-14  5:56 ` Jason Merrill
  1 sibling, 1 reply; 18+ messages in thread
From: Jakub Jelinek @ 2016-09-10 15:13 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill, Joseph Myers

Hi!

Just a minor nit:

On Sat, Sep 10, 2016 at 04:58:43PM +0200, Marek Polacek wrote:
> Spurred by the recent <http://www.viva64.com/en/b/0425/> findings, I decided to
> implement a warning that warns when a pointer is compared with a zero character
> literal (constant), because this isn't likely to be intended.  So e.g.

> @@ -4777,6 +4778,7 @@ cp_parser_primary_expression (cp_parser *parser,
>      case CPP_CHAR32:
>      case CPP_WCHAR:
>      case CPP_UTF8CHAR:
> +      char_literal_p = true;
>      case CPP_NUMBER:
>      case CPP_PREPARSED_EXPR:
>        if (TREE_CODE (token->u.value) == USERDEF_LITERAL)

No /* FALLTHRU */ ?

	Jakub

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-10 15:13 ` Jakub Jelinek
@ 2016-09-10 15:48   ` Marek Polacek
  0 siblings, 0 replies; 18+ messages in thread
From: Marek Polacek @ 2016-09-10 15:48 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: GCC Patches, Jason Merrill, Joseph Myers

On Sat, Sep 10, 2016 at 05:07:51PM +0200, Jakub Jelinek wrote:
> Hi!
> 
> Just a minor nit:
> 
> On Sat, Sep 10, 2016 at 04:58:43PM +0200, Marek Polacek wrote:
> > Spurred by the recent <http://www.viva64.com/en/b/0425/> findings, I decided to
> > implement a warning that warns when a pointer is compared with a zero character
> > literal (constant), because this isn't likely to be intended.  So e.g.
> 
> > @@ -4777,6 +4778,7 @@ cp_parser_primary_expression (cp_parser *parser,
> >      case CPP_CHAR32:
> >      case CPP_WCHAR:
> >      case CPP_UTF8CHAR:
> > +      char_literal_p = true;
> >      case CPP_NUMBER:
> >      case CPP_PREPARSED_EXPR:
> >        if (TREE_CODE (token->u.value) == USERDEF_LITERAL)
> 
> No /* FALLTHRU */ ?

Oh yeah, I'd completely forgotten.  Didn't mean to make the guy implementing
-Wimplicit-fallthrough sad...

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

2016-09-10  Marek Polacek  <polacek@redhat.com>

	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.

	* cp-tree.h (class cp_expr): Add char_literal_p member.  Update the
	constructors and the copy constructor.
	* parser.c (cp_parser_primary_expression): Mark zero character
	literals.
	(cp_parser_binary_expression): 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.

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index c55c7c3..a93c07e 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -796,6 +796,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.
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 0aba51c..46ca08a 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -7520,6 +7520,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;
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index d56c3d6..6426ae6 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -3709,6 +3709,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)
+	   && arg2.original_type == char_type_node
+	   && 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)
+	       && arg1.original_type == char_type_node
+	       && 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))
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index d4bfb26..218c5a7 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -51,16 +51,21 @@ class cp_expr
 {
 public:
   cp_expr () :
-    m_value (NULL), m_loc (UNKNOWN_LOCATION) {}
+    m_value (NULL), m_loc (UNKNOWN_LOCATION), m_char_literal_p (false) {}
 
   cp_expr (tree value) :
-    m_value (value), m_loc (EXPR_LOCATION (m_value)) {}
+    m_value (value), m_loc (EXPR_LOCATION (m_value)),
+    m_char_literal_p (false) {}
 
   cp_expr (tree value, location_t loc):
-    m_value (value), m_loc (loc) {}
+    m_value (value), m_loc (loc), m_char_literal_p (false) {}
+
+  cp_expr (tree value, location_t loc, bool char_literal_p):
+    m_value (value), m_loc (loc), m_char_literal_p (char_literal_p) {}
 
   cp_expr (const cp_expr &other) :
-    m_value (other.m_value), m_loc (other.m_loc) {}
+    m_value (other.m_value), m_loc (other.m_loc),
+    m_char_literal_p (other.m_char_literal_p) {}
 
   /* Implicit conversions to tree.  */
   operator tree () const { return m_value; }
@@ -91,9 +96,12 @@ public:
     set_location (make_location (m_loc, start, finish));
   }
 
+  bool is_char_literal_p () const { return m_char_literal_p; }
+
  private:
   tree m_value;
   location_t m_loc;
+  bool m_char_literal_p;
 };
 
 inline bool
diff --git gcc/cp/parser.c gcc/cp/parser.c
index ca9f8b9..405ba14 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -4756,6 +4756,7 @@ cp_parser_primary_expression (cp_parser *parser,
 			      cp_id_kind *idk)
 {
   cp_token *token = NULL;
+  bool char_literal_p = false;
 
   /* Assume the primary expression is not an id-expression.  */
   *idk = CP_ID_KIND_NONE;
@@ -4777,6 +4778,8 @@ cp_parser_primary_expression (cp_parser *parser,
     case CPP_CHAR32:
     case CPP_WCHAR:
     case CPP_UTF8CHAR:
+      char_literal_p = true;
+      /* FALLTHRU */
     case CPP_NUMBER:
     case CPP_PREPARSED_EXPR:
       if (TREE_CODE (token->u.value) == USERDEF_LITERAL)
@@ -4832,7 +4835,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	  if (!cast_p)
 	    cp_parser_non_integral_constant_expression (parser, NIC_FLOAT);
 	}
-      return cp_expr (token->u.value, token->location);
+      return cp_expr (token->u.value, token->location, char_literal_p);
 
     case CPP_CHAR_USERDEF:
     case CPP_CHAR16_USERDEF:
@@ -8924,6 +8927,31 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 	warn_logical_not_parentheses (current.loc, current.tree_type,
 				      current.lhs, maybe_constant_value (rhs));
 
+      /* Warn for ptr == '\0', it's likely that it should've been ptr[0].  */
+      if (current.tree_type == EQ_EXPR || current.tree_type == NE_EXPR)
+	{
+	  if (TREE_TYPE (current.lhs.get_value ())
+	      && POINTER_TYPE_P (TREE_TYPE (current.lhs.get_value ()))
+	      && integer_zerop (rhs.get_value ())
+	      && !TREE_OVERFLOW (rhs.get_value ())
+	      && rhs.is_char_literal_p ()
+	      && warning_at (current.loc, OPT_Wpointer_compare,
+			     "comparison between pointer and zero character "
+			     "literal"))
+	    inform (current.lhs.get_location (),
+		    "did you mean to dereference the pointer?");
+	  else if (TREE_TYPE (rhs.get_value ())
+		   && POINTER_TYPE_P (TREE_TYPE (rhs.get_value ()))
+		   && integer_zerop (current.lhs.get_value ())
+		   && !TREE_OVERFLOW (current.lhs.get_value ())
+		   && current.lhs.is_char_literal_p ()
+		   && warning_at (current.loc, OPT_Wpointer_compare,
+				  "comparison between pointer and zero "
+				  "character literal"))
+	    inform (rhs.get_location (),
+		    "did you mean to dereference the pointer?");
+
+	}
       overload = NULL;
 
       location_t combined_loc = make_location (current.loc,
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index b2eaea7..734dcbc 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -287,7 +287,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  -Wno-return-local-addr @gol
 -Wreturn-type  -Wsequence-point  -Wshadow  -Wno-shadow-ivar @gol
 -Wshift-overflow -Wshift-overflow=@var{n} @gol
@@ -5136,6 +5136,20 @@ 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
+
+This warning is enabled by default.
+
 @item -Wtype-limits
 @opindex Wtype-limits
 @opindex Wno-type-limits
diff --git gcc/testsuite/c-c++-common/Wpointer-compare-1.c gcc/testsuite/c-c++-common/Wpointer-compare-1.c
index e69de29..80da85a 100644
--- gcc/testsuite/c-c++-common/Wpointer-compare-1.c
+++ gcc/testsuite/c-c++-common/Wpointer-compare-1.c
@@ -0,0 +1,81 @@
+/* PR c++/64767 */
+/* { dg-do compile } */
+/* { dg-options "-Wpointer-compare" } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+
+int
+f1 (int *p, int **q)
+{
+  int r = 0;
+
+  r += p == '\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p == L'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p == u'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p == U'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p != '\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p != L'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p != u'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += p != U'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+
+  r += '\0' == p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += L'\0' == p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += u'\0' == p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += U'\0' == p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += '\0' != p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += L'\0' != p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += u'\0' != p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += U'\0' != p; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+
+  r += q == '\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q == L'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q == u'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q == U'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q != '\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q != L'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q != u'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += q != U'\0'; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+
+  r += '\0' == q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += L'\0' == q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += u'\0' == q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += U'\0' == q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += '\0' != q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += L'\0' != q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += u'\0' != q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+  r += U'\0' != q; /* { dg-warning "comparison between pointer and zero character (literal|constant)" } */
+
+  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;
+  r += p != (char) 0;
+
+  r += (char) 0 == p;
+  r += (char) 0 != p;
+
+  return r;
+}

	Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-10 15:06 C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767) Marek Polacek
  2016-09-10 15:13 ` Jakub Jelinek
@ 2016-09-14  5:56 ` Jason Merrill
  2016-09-15 12:31   ` Marek Polacek
  1 sibling, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2016-09-14  5:56 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Joseph Myers

On Sat, Sep 10, 2016 at 10:58 AM, Marek Polacek <polacek@redhat.com> wrote:
> Spurred by the recent <http://www.viva64.com/en/b/0425/> findings, I decided to
> implement a warning that warns when a pointer is compared with a zero character
> literal (constant), because this isn't likely to be intended.  So e.g.
>
>   ptr == L'\0'
>
> is probably wrong and should've been written as
>
>   ptr[0] == L'\0'
>
> Jonathan pointed out that this would actually be invalid C++11 since pointer
> conversions are only allowed for integer literals, not char literals.

Ah, indeed.  And if we fix that, we get an error rather than a
warning.  Maybe let's handle this by wrapping character literals in a
redundant NOP_EXPR?

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-14  5:56 ` Jason Merrill
@ 2016-09-15 12:31   ` Marek Polacek
  2016-09-19 19:51     ` Jason Merrill
  0 siblings, 1 reply; 18+ messages in thread
From: Marek Polacek @ 2016-09-15 12:31 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Joseph Myers

On Wed, Sep 14, 2016 at 12:07:49AM -0400, Jason Merrill wrote:
> On Sat, Sep 10, 2016 at 10:58 AM, Marek Polacek <polacek@redhat.com> wrote:
> > Spurred by the recent <http://www.viva64.com/en/b/0425/> findings, I decided to
> > implement a warning that warns when a pointer is compared with a zero character
> > literal (constant), because this isn't likely to be intended.  So e.g.
> >
> >   ptr == L'\0'
> >
> > is probably wrong and should've been written as
> >
> >   ptr[0] == L'\0'
> >
> > Jonathan pointed out that this would actually be invalid C++11 since pointer
> > conversions are only allowed for integer literals, not char literals.
> 
> Ah, indeed.  And if we fix that, we get an error rather than a
> warning.  Maybe let's handle this by wrapping character literals in a
> redundant NOP_EXPR?

So I've tried.  Wrapping character literals in a NOP_EXPR would make us
error on that comparison (good), but it breaks -Wchar-subscripts, which
could be solved by adding STRIP_NOPS, but unfortunately it breaks even
-Wmemset-transposed-args: '\0' would become (char) '\0', which is not a
literal zero anymore.  And if I do sth like
+       if (TREE_CODE (arg2) == NOP_EXPR
+           && TREE_TYPE (arg2) == TREE_TYPE (TREE_OPERAND (arg2, 0)))
+         arg2 = TREE_OPERAND (arg2, 0);
then (int) 0 would became a literal zero and we'd warn when not appropriate.

We should also error for e.g. void *p = '\0'; but the problem with the
NOP_EXPR cast is that convert_for_init strips nops, so we wouldn't reject
this code.

So it seems we may need some CHARACTER_CST or somesuch?

Note that we should also take boolean-literals into account.

	Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-15 12:31   ` Marek Polacek
@ 2016-09-19 19:51     ` Jason Merrill
  2016-09-21 19:55       ` Jason Merrill
  0 siblings, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2016-09-19 19:51 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Joseph Myers

On Thu, Sep 15, 2016 at 8:16 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Wed, Sep 14, 2016 at 12:07:49AM -0400, Jason Merrill wrote:
>> On Sat, Sep 10, 2016 at 10:58 AM, Marek Polacek <polacek@redhat.com> wrote:
>> > Spurred by the recent <http://www.viva64.com/en/b/0425/> findings, I decided to
>> > implement a warning that warns when a pointer is compared with a zero character
>> > literal (constant), because this isn't likely to be intended.  So e.g.
>> >
>> >   ptr == L'\0'
>> >
>> > is probably wrong and should've been written as
>> >
>> >   ptr[0] == L'\0'
>> >
>> > Jonathan pointed out that this would actually be invalid C++11 since pointer
>> > conversions are only allowed for integer literals, not char literals.
>>
>> Ah, indeed.  And if we fix that, we get an error rather than a
>> warning.  Maybe let's handle this by wrapping character literals in a
>> redundant NOP_EXPR?
>
> So I've tried.  Wrapping character literals in a NOP_EXPR would make us
> error on that comparison (good), but it breaks -Wchar-subscripts, which
> could be solved by adding STRIP_NOPS, but unfortunately it breaks even
> -Wmemset-transposed-args: '\0' would become (char) '\0', which is not a
> literal zero anymore.  And if I do sth like
> +       if (TREE_CODE (arg2) == NOP_EXPR
> +           && TREE_TYPE (arg2) == TREE_TYPE (TREE_OPERAND (arg2, 0)))
> +         arg2 = TREE_OPERAND (arg2, 0);
> then (int) 0 would became a literal zero and we'd warn when not appropriate.
>
> We should also error for e.g. void *p = '\0'; but the problem with the
> NOP_EXPR cast is that convert_for_init strips nops, so we wouldn't reject
> this code.

Good point.

> So it seems we may need some CHARACTER_CST or somesuch?

I suppose that an INTEGER_CST of character type is necessarily a
character constant, so adding a check for !char_type_p ought to do the
trick.

> Note that we should also take boolean-literals into account.

We already check for INTEGER_TYPE, so boolean literals should already
be excluded.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-19 19:51     ` Jason Merrill
@ 2016-09-21 19:55       ` Jason Merrill
  2016-09-23 13:29         ` Marek Polacek
  0 siblings, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2016-09-21 19:55 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Joseph Myers

[-- Attachment #1: Type: text/plain, Size: 262 bytes --]

On Mon, Sep 19, 2016 at 2:49 PM, Jason Merrill <jason@redhat.com> wrote:
> I suppose that an INTEGER_CST of character type is necessarily a
> character constant, so adding a check for !char_type_p ought to do the
> trick.

Indeed it does.  I'm checking this in:

[-- Attachment #2: char903.diff --]
[-- Type: text/x-patch, Size: 918 bytes --]

commit d2f237ef0f63b3ee3da79bcbfad08fedb325d554
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Sep 21 10:58:39 2016 -0400

            Core 903
            * call.c (null_ptr_cst_p): Check char_type_p.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 393aab9..2804bd8 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -527,6 +527,7 @@ null_ptr_cst_p (tree t)
     {
       /* Core issue 903 says only literal 0 is a null pointer constant.  */
       if (TREE_CODE (type) == INTEGER_TYPE
+	  && !char_type_p (type)
 	  && TREE_CODE (t) == INTEGER_CST
 	  && integer_zerop (t)
 	  && !TREE_OVERFLOW (t))
diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr36.C b/gcc/testsuite/g++.dg/cpp0x/nullptr36.C
new file mode 100644
index 0000000..5f43881
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nullptr36.C
@@ -0,0 +1,3 @@
+// { dg-do compile { target c++11 } }
+
+void *p = '\0';			// { dg-error "invalid conversion" }

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-21 19:55       ` Jason Merrill
@ 2016-09-23 13:29         ` Marek Polacek
  2016-09-23 14:37           ` Jason Merrill
  0 siblings, 1 reply; 18+ messages in thread
From: Marek Polacek @ 2016-09-23 13:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Joseph Myers

On Wed, Sep 21, 2016 at 03:52:09PM -0400, Jason Merrill wrote:
> On Mon, Sep 19, 2016 at 2:49 PM, Jason Merrill <jason@redhat.com> wrote:
> > I suppose that an INTEGER_CST of character type is necessarily a
> > character constant, so adding a check for !char_type_p ought to do the
> > trick.
> 
> Indeed it does.  I'm checking this in:

Nice, thanks.  What about the original patch?  We still need to warn
(or error for C++11) for pointer comparisons.

	Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-23 13:29         ` Marek Polacek
@ 2016-09-23 14:37           ` Jason Merrill
  2016-09-30 16:52             ` Marek Polacek
  0 siblings, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2016-09-23 14:37 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Joseph Myers

On Fri, Sep 23, 2016 at 9:15 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Wed, Sep 21, 2016 at 03:52:09PM -0400, Jason Merrill wrote:
>> On Mon, Sep 19, 2016 at 2:49 PM, Jason Merrill <jason@redhat.com> wrote:
>> > I suppose that an INTEGER_CST of character type is necessarily a
>> > character constant, so adding a check for !char_type_p ought to do the
>> > trick.
>>
>> Indeed it does.  I'm checking this in:
>
> Nice, thanks.  What about the original patch?  We still need to warn
> (or error for C++11) for pointer comparisons.

If we still accept pointer comparisons in C++, that's another bug with
treating \0 as a null pointer constant.  This seems to be because
ocp_convert of \0 to int produces an INTEGER_CST indistinguishable
from literal 0.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-23 14:37           ` Jason Merrill
@ 2016-09-30 16:52             ` Marek Polacek
  2016-09-30 17:22               ` Martin Sebor
  2016-09-30 22:16               ` Jason Merrill
  0 siblings, 2 replies; 18+ messages in thread
From: Marek Polacek @ 2016-09-30 16:52 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Fri, Sep 23, 2016 at 10:31:33AM -0400, Jason Merrill wrote:
> On Fri, Sep 23, 2016 at 9:15 AM, Marek Polacek <polacek@redhat.com> wrote:
> > On Wed, Sep 21, 2016 at 03:52:09PM -0400, Jason Merrill wrote:
> >> On Mon, Sep 19, 2016 at 2:49 PM, Jason Merrill <jason@redhat.com> wrote:
> >> > I suppose that an INTEGER_CST of character type is necessarily a
> >> > character constant, so adding a check for !char_type_p ought to do the
> >> > trick.
> >>
> >> Indeed it does.  I'm checking this in:
> >
> > Nice, thanks.  What about the original patch?  We still need to warn
> > (or error for C++11) for pointer comparisons.
> 
> If we still accept pointer comparisons in C++, that's another bug with
> treating \0 as a null pointer constant.  This seems to be because
> ocp_convert of \0 to int produces an INTEGER_CST indistinguishable
> from literal 0.

I was trying to fix this in ocp_convert, by using NOP_EXPRs, but that wasn't
successful.  But since we're interested in ==/!=, I think this can be fixed
easily in cp_build_binary_op.  Actually, all that seems to be needed is using
orig_op as the argument to null_ptr_cst_p, but that wouldn't give the correct
diagnostics, so I did this.  By checking orig_op we can see if the operands are
character literals or not, because orig_op is an operand before the default
conversions.

Curiously, nothing in the testsuite broke.

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

2016-09-30  Marek Polacek  <polacek@redhat.com>

	Core 903
	* typeck.c (cp_build_binary_op) [EQ_EXPR]: Diagnose invalid pointer
	conversions.

	* g++.dg/cpp0x/nullptr37.C: New test.

diff --git gcc/cp/typeck.c gcc/cp/typeck.c
index 617ca55..2e6f44e 100644
--- gcc/cp/typeck.c
+++ gcc/cp/typeck.c
@@ -4584,6 +4584,14 @@ cp_build_binary_op (location_t location,
 	  else
 	    result_type = type0;
 
+	  if (null_ptr_cst_p (op1) && !null_ptr_cst_p (orig_op1))
+	    {
+	      if (complain & tf_error)
+		permerror (input_location, "ISO C++11 only allows pointer "
+			   "conversions for integer literals");
+	      else
+		return error_mark_node;
+	    }
 	  warn_for_null_address (location, op0, complain);
 	}
       else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
@@ -4598,6 +4606,14 @@ cp_build_binary_op (location_t location,
 	  else
 	    result_type = type1;
 
+	  if (null_ptr_cst_p (op0) && !null_ptr_cst_p (orig_op0))
+	    {
+	      if (complain & tf_error)
+		permerror (input_location, "ISO C++11 only allows pointer "
+			   "conversions for integer literals");
+	      else
+		return error_mark_node;
+	    }
 	  warn_for_null_address (location, op1, complain);
 	}
       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
diff --git gcc/testsuite/g++.dg/cpp0x/nullptr37.C gcc/testsuite/g++.dg/cpp0x/nullptr37.C
index e69de29..17c33d1 100644
--- gcc/testsuite/g++.dg/cpp0x/nullptr37.C
+++ gcc/testsuite/g++.dg/cpp0x/nullptr37.C
@@ -0,0 +1,78 @@
+/* PR c++/64767 */
+// { dg-do compile { target c++11 } }
+
+int
+f1 (int *p, int **q)
+{
+  int r = 0;
+
+  r += p == '\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += p == L'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += p == u'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += p == U'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += p != '\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += p != L'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += p != u'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += p != U'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+
+  r += '\0' == p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += L'\0' == p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += u'\0' == p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += U'\0' == p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += '\0' != p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += L'\0' != p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += u'\0' != p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += U'\0' != p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+
+  r += q == '\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += q == L'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += q == u'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += q == U'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += q != '\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += q != L'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += q != u'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += q != U'\0'; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+
+  r += '\0' == q; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += L'\0' == q; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += u'\0' == q; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += U'\0' == q; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += '\0' != q; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += L'\0' != q; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += u'\0' != q; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += U'\0' != q; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+
+  return r;
+}
+
+int
+f2 (int *p)
+{
+  int r = 0;
+
+  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-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += p != (char) 0; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+
+  r += (char) 0 == p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+  r += (char) 0 != p; /* { dg-error "ISO C\\+\\+11 only allows pointer conversions for integer literals" } */
+
+  return r;
+}


	Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-30 16:52             ` Marek Polacek
@ 2016-09-30 17:22               ` Martin Sebor
  2016-09-30 19:52                 ` Martin Sebor
  2016-09-30 22:16               ` Jason Merrill
  1 sibling, 1 reply; 18+ messages in thread
From: Martin Sebor @ 2016-09-30 17:22 UTC (permalink / raw)
  To: Marek Polacek, Jason Merrill; +Cc: GCC Patches

> +		permerror (input_location, "ISO C++11 only allows pointer "
> +			   "conversions for integer literals");

FWIW, I think it would be clearer to either mention the currently
selected language version or leave it out completely rather than
hardcoding C++11.  When the user specifies -std=c++14 (or later),
or when that's the current version used by the compiler, a warning
that tells them what C++ 11 allows isn't really relevant (or
meaningful), and becomes less so as time goes on.

Martin

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-30 17:22               ` Martin Sebor
@ 2016-09-30 19:52                 ` Martin Sebor
  2016-09-30 20:02                   ` Marek Polacek
  0 siblings, 1 reply; 18+ messages in thread
From: Martin Sebor @ 2016-09-30 19:52 UTC (permalink / raw)
  To: Marek Polacek, Jason Merrill; +Cc: GCC Patches

On 09/30/2016 11:05 AM, Martin Sebor wrote:
>> +        permerror (input_location, "ISO C++11 only allows pointer "
>> +               "conversions for integer literals");
>
> FWIW, I think it would be clearer to either mention the currently
> selected language version or leave it out completely rather than
> hardcoding C++11.  When the user specifies -std=c++14 (or later),
> or when that's the current version used by the compiler, a warning
> that tells them what C++ 11 allows isn't really relevant (or
> meaningful), and becomes less so as time goes on.

Btw., I realize there are other instances where the C++ version
has been hardcoded and so I should have made it clear that I meant
my comment as a general suggestion, not as an objection to the patch.
Sorry if that wasn't apparent.

I've quickly surveyed some of the existing messages that mention
a C++ version and found instances where it applies only to the
referenced version of the standard and prior but not later versions. 
For example:

   msgid "in C++98 %q+D may not be static because it is a member of a union"
   msgid "in C++03 a class-key must be used when declaring a friend"

But I also came across another form that may resolve the concern
I raised: mentioning the version along with whether it's the first
or last that supports (or doesn't support) the construct, such as
"C++11 and above."  Here's one example of it:

   msgid "in C++11 and above a default constructor can be explicit"

It might be worth to come up with a convention to adopt in new
messages and (gradually) change what's already there to use it.

Martin

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-30 19:52                 ` Martin Sebor
@ 2016-09-30 20:02                   ` Marek Polacek
  2016-09-30 22:16                     ` Martin Sebor
  0 siblings, 1 reply; 18+ messages in thread
From: Marek Polacek @ 2016-09-30 20:02 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, GCC Patches

On Fri, Sep 30, 2016 at 01:08:19PM -0600, Martin Sebor wrote:
> On 09/30/2016 11:05 AM, Martin Sebor wrote:
> > > +        permerror (input_location, "ISO C++11 only allows pointer "
> > > +               "conversions for integer literals");
> > 
> > FWIW, I think it would be clearer to either mention the currently
> > selected language version or leave it out completely rather than
> > hardcoding C++11.  When the user specifies -std=c++14 (or later),
> > or when that's the current version used by the compiler, a warning
> > that tells them what C++ 11 allows isn't really relevant (or
> > meaningful), and becomes less so as time goes on.
> 
> Btw., I realize there are other instances where the C++ version
> has been hardcoded and so I should have made it clear that I meant
> my comment as a general suggestion, not as an objection to the patch.
> Sorry if that wasn't apparent.
> 
> I've quickly surveyed some of the existing messages that mention
> a C++ version and found instances where it applies only to the
> referenced version of the standard and prior but not later versions. For
> example:
> 
>   msgid "in C++98 %q+D may not be static because it is a member of a union"
>   msgid "in C++03 a class-key must be used when declaring a friend"
> 
> But I also came across another form that may resolve the concern
> I raised: mentioning the version along with whether it's the first
> or last that supports (or doesn't support) the construct, such as
> "C++11 and above."  Here's one example of it:
> 
>   msgid "in C++11 and above a default constructor can be explicit"
> 
> It might be worth to come up with a convention to adopt in new
> messages and (gradually) change what's already there to use it.

Maybe, no strong opinions, I'll just go with whatever people prefer here.
Though I guess I like those explicit versions because you know when a
particular thing changed.  And when you're using -std=c++14 and the
compiler says C++11, I think that's ok, because C++14 implies C++11.

	Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-30 20:02                   ` Marek Polacek
@ 2016-09-30 22:16                     ` Martin Sebor
  0 siblings, 0 replies; 18+ messages in thread
From: Martin Sebor @ 2016-09-30 22:16 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jason Merrill, GCC Patches

On 09/30/2016 01:40 PM, Marek Polacek wrote:
> On Fri, Sep 30, 2016 at 01:08:19PM -0600, Martin Sebor wrote:
>> On 09/30/2016 11:05 AM, Martin Sebor wrote:
>>>> +        permerror (input_location, "ISO C++11 only allows pointer "
>>>> +               "conversions for integer literals");
>>>
>>> FWIW, I think it would be clearer to either mention the currently
>>> selected language version or leave it out completely rather than
>>> hardcoding C++11.  When the user specifies -std=c++14 (or later),
>>> or when that's the current version used by the compiler, a warning
>>> that tells them what C++ 11 allows isn't really relevant (or
>>> meaningful), and becomes less so as time goes on.
>>
>> Btw., I realize there are other instances where the C++ version
>> has been hardcoded and so I should have made it clear that I meant
>> my comment as a general suggestion, not as an objection to the patch.
>> Sorry if that wasn't apparent.
>>
>> I've quickly surveyed some of the existing messages that mention
>> a C++ version and found instances where it applies only to the
>> referenced version of the standard and prior but not later versions. For
>> example:
>>
>>   msgid "in C++98 %q+D may not be static because it is a member of a union"
>>   msgid "in C++03 a class-key must be used when declaring a friend"
>>
>> But I also came across another form that may resolve the concern
>> I raised: mentioning the version along with whether it's the first
>> or last that supports (or doesn't support) the construct, such as
>> "C++11 and above."  Here's one example of it:
>>
>>   msgid "in C++11 and above a default constructor can be explicit"
>>
>> It might be worth to come up with a convention to adopt in new
>> messages and (gradually) change what's already there to use it.
>
> Maybe, no strong opinions, I'll just go with whatever people prefer here.
> Though I guess I like those explicit versions because you know when a
> particular thing changed.  And when you're using -std=c++14 and the
> compiler says C++11, I think that's ok, because C++14 implies C++11.

I agree that mentioning the (first or last) version can be helpful.
Does adopting the "C++11 and later" and "C++11 and earlier" phrasing
sound good then?  If no one objects I'll add it to the Guidelines for
C/C++ FE diagnostics on the Wiki.

(I changed "above" to "later" because it pairs better with "earlier"
than "below" would , and because it seems to be more natural when
referring to the year the version a standard was ratified.)

Martin

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-30 16:52             ` Marek Polacek
  2016-09-30 17:22               ` Martin Sebor
@ 2016-09-30 22:16               ` Jason Merrill
  2016-10-01 14:41                 ` Marek Polacek
  1 sibling, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2016-09-30 22:16 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Fri, Sep 30, 2016 at 12:43 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Fri, Sep 23, 2016 at 10:31:33AM -0400, Jason Merrill wrote:
>> On Fri, Sep 23, 2016 at 9:15 AM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Wed, Sep 21, 2016 at 03:52:09PM -0400, Jason Merrill wrote:
>> >> On Mon, Sep 19, 2016 at 2:49 PM, Jason Merrill <jason@redhat.com> wrote:
>> >> > I suppose that an INTEGER_CST of character type is necessarily a
>> >> > character constant, so adding a check for !char_type_p ought to do the
>> >> > trick.
>> >>
>> >> Indeed it does.  I'm checking this in:
>> >
>> > Nice, thanks.  What about the original patch?  We still need to warn
>> > (or error for C++11) for pointer comparisons.
>>
>> If we still accept pointer comparisons in C++, that's another bug with
>> treating \0 as a null pointer constant.  This seems to be because
>> ocp_convert of \0 to int produces an INTEGER_CST indistinguishable
>> from literal 0.
>
> I was trying to fix this in ocp_convert, by using NOP_EXPRs, but that wasn't
> successful.  But since we're interested in ==/!=, I think this can be fixed
> easily in cp_build_binary_op.  Actually, all that seems to be needed is using
> orig_op as the argument to null_ptr_cst_p, but that wouldn't give the correct
> diagnostics, so I did this.  By checking orig_op we can see if the operands are
> character literals or not, because orig_op is an operand before the default
> conversions.

What is wrong about the diagnostic from just using orig_op?  "ISO C++
forbids comparison between pointer and integer" seems fine to me, and
will help the user to realize that they need to index off the pointer.

I see that some of the calls to null_ptr_cst_p in cp_build_binary_op
have already been changed to check orig_op*, but not all.  Let's
update the remaining calls, that should do the trick without adding a
new error.

Jason

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-09-30 22:16               ` Jason Merrill
@ 2016-10-01 14:41                 ` Marek Polacek
  2016-10-02 18:43                   ` Jason Merrill
  0 siblings, 1 reply; 18+ messages in thread
From: Marek Polacek @ 2016-10-01 14:41 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Fri, Sep 30, 2016 at 05:48:03PM -0400, Jason Merrill wrote:
> On Fri, Sep 30, 2016 at 12:43 PM, Marek Polacek <polacek@redhat.com> wrote:
> > On Fri, Sep 23, 2016 at 10:31:33AM -0400, Jason Merrill wrote:
> >> On Fri, Sep 23, 2016 at 9:15 AM, Marek Polacek <polacek@redhat.com> wrote:
> >> > On Wed, Sep 21, 2016 at 03:52:09PM -0400, Jason Merrill wrote:
> >> >> On Mon, Sep 19, 2016 at 2:49 PM, Jason Merrill <jason@redhat.com> wrote:
> >> >> > I suppose that an INTEGER_CST of character type is necessarily a
> >> >> > character constant, so adding a check for !char_type_p ought to do the
> >> >> > trick.
> >> >>
> >> >> Indeed it does.  I'm checking this in:
> >> >
> >> > Nice, thanks.  What about the original patch?  We still need to warn
> >> > (or error for C++11) for pointer comparisons.
> >>
> >> If we still accept pointer comparisons in C++, that's another bug with
> >> treating \0 as a null pointer constant.  This seems to be because
> >> ocp_convert of \0 to int produces an INTEGER_CST indistinguishable
> >> from literal 0.
> >
> > I was trying to fix this in ocp_convert, by using NOP_EXPRs, but that wasn't
> > successful.  But since we're interested in ==/!=, I think this can be fixed
> > easily in cp_build_binary_op.  Actually, all that seems to be needed is using
> > orig_op as the argument to null_ptr_cst_p, but that wouldn't give the correct
> > diagnostics, so I did this.  By checking orig_op we can see if the operands are
> > character literals or not, because orig_op is an operand before the default
> > conversions.
> 
> What is wrong about the diagnostic from just using orig_op?  "ISO C++
> forbids comparison between pointer and integer" seems fine to me, and
> will help the user to realize that they need to index off the pointer.
> 
> I see that some of the calls to null_ptr_cst_p in cp_build_binary_op
> have already been changed to check orig_op*, but not all.  Let's
> update the remaining calls, that should do the trick without adding a
> new error.

Here you go:

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

2016-10-01  Marek Polacek  <polacek@redhat.com>

	Core 903
	* typeck.c (cp_build_binary_op): Pass original operands to
	null_ptr_cst_p, not those after the default conversions.

	* g++.dg/cpp0x/nullptr37.C: New test.

diff --git gcc/cp/typeck.c gcc/cp/typeck.c
index 617ca55..8b780be 100644
--- gcc/cp/typeck.c
+++ gcc/cp/typeck.c
@@ -4573,7 +4573,7 @@ cp_build_binary_op (location_t location,
 	      || code1 == COMPLEX_TYPE || code1 == ENUMERAL_TYPE))
 	short_compare = 1;
       else if (((code0 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type0))
-		&& null_ptr_cst_p (op1))
+		&& null_ptr_cst_p (orig_op1))
 	       /* Handle, eg, (void*)0 (c++/43906), and more.  */
 	       || (code0 == POINTER_TYPE
 		   && TYPE_PTR_P (type1) && integer_zerop (op1)))
@@ -4587,7 +4587,7 @@ cp_build_binary_op (location_t location,
 	  warn_for_null_address (location, op0, complain);
 	}
       else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
-		&& null_ptr_cst_p (op0))
+		&& null_ptr_cst_p (orig_op0))
 	       /* Handle, eg, (void*)0 (c++/43906), and more.  */
 	       || (code1 == POINTER_TYPE
 		   && TYPE_PTR_P (type0) && integer_zerop (op0)))
@@ -4604,7 +4604,7 @@ cp_build_binary_op (location_t location,
 	       || (TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P (type1)))
 	result_type = composite_pointer_type (type0, type1, op0, op1,
 					      CPO_COMPARISON, complain);
-      else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
+      else if (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1))
 	/* One of the operands must be of nullptr_t type.  */
         result_type = TREE_TYPE (nullptr_node);
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
@@ -4623,7 +4623,7 @@ cp_build_binary_op (location_t location,
           else
             return error_mark_node;
 	}
-      else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
+      else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (orig_op1))
 	{
 	  if (TARGET_PTRMEMFUNC_VBIT_LOCATION
 	      == ptrmemfunc_vbit_in_delta)
@@ -4664,7 +4664,7 @@ cp_build_binary_op (location_t location,
 	    }
 	  result_type = TREE_TYPE (op0);
 	}
-      else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
+      else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (orig_op0))
 	return cp_build_binary_op (location, code, op1, op0, complain);
       else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1))
 	{
@@ -4877,21 +4877,21 @@ cp_build_binary_op (location_t location,
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	result_type = composite_pointer_type (type0, type1, op0, op1,
 					      CPO_COMPARISON, complain);
-      else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
+      else if (code0 == POINTER_TYPE && null_ptr_cst_p (orig_op1))
 	{
 	  result_type = type0;
 	  if (extra_warnings && (complain & tf_warning))
 	    warning (OPT_Wextra,
 		     "ordered comparison of pointer with integer zero");
 	}
-      else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
+      else if (code1 == POINTER_TYPE && null_ptr_cst_p (orig_op0))
 	{
 	  result_type = type1;
 	  if (extra_warnings && (complain & tf_warning))
 	    warning (OPT_Wextra,
 		     "ordered comparison of pointer with integer zero");
 	}
-      else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
+      else if (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1))
 	/* One of the operands must be of nullptr_t type.  */
         result_type = TREE_TYPE (nullptr_node);
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
diff --git gcc/testsuite/g++.dg/cpp0x/nullptr37.C gcc/testsuite/g++.dg/cpp0x/nullptr37.C
index e69de29..e746a28 100644
--- gcc/testsuite/g++.dg/cpp0x/nullptr37.C
+++ gcc/testsuite/g++.dg/cpp0x/nullptr37.C
@@ -0,0 +1,78 @@
+/* PR c++/64767 */
+// { dg-do compile { target c++11 } }
+
+int
+f1 (int *p, int **q)
+{
+  int r = 0;
+
+  r += p == '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += p == L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += p == u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += p == U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += p != '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += p != L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += p != u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += p != U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+
+  r += '\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += L'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += u'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += U'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += '\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += L'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += u'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += U'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+
+  r += q == '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += q == L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += q == u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += q == U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += q != '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += q != L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += q != u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += q != U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+
+  r += '\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += L'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += u'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += U'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += '\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += L'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += u'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += U'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+
+  return r;
+}
+
+int
+f2 (int *p)
+{
+  int r = 0;
+
+  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-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += p != (char) 0; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+
+  r += (char) 0 == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+  r += (char) 0 != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+
+  return r;
+}

	Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-10-01 14:41                 ` Marek Polacek
@ 2016-10-02 18:43                   ` Jason Merrill
  2017-01-04  6:56                     ` Eric Gallager
  0 siblings, 1 reply; 18+ messages in thread
From: Jason Merrill @ 2016-10-02 18:43 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

OK, thanks.

On Sat, Oct 1, 2016 at 10:16 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Fri, Sep 30, 2016 at 05:48:03PM -0400, Jason Merrill wrote:
>> On Fri, Sep 30, 2016 at 12:43 PM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Fri, Sep 23, 2016 at 10:31:33AM -0400, Jason Merrill wrote:
>> >> On Fri, Sep 23, 2016 at 9:15 AM, Marek Polacek <polacek@redhat.com> wrote:
>> >> > On Wed, Sep 21, 2016 at 03:52:09PM -0400, Jason Merrill wrote:
>> >> >> On Mon, Sep 19, 2016 at 2:49 PM, Jason Merrill <jason@redhat.com> wrote:
>> >> >> > I suppose that an INTEGER_CST of character type is necessarily a
>> >> >> > character constant, so adding a check for !char_type_p ought to do the
>> >> >> > trick.
>> >> >>
>> >> >> Indeed it does.  I'm checking this in:
>> >> >
>> >> > Nice, thanks.  What about the original patch?  We still need to warn
>> >> > (or error for C++11) for pointer comparisons.
>> >>
>> >> If we still accept pointer comparisons in C++, that's another bug with
>> >> treating \0 as a null pointer constant.  This seems to be because
>> >> ocp_convert of \0 to int produces an INTEGER_CST indistinguishable
>> >> from literal 0.
>> >
>> > I was trying to fix this in ocp_convert, by using NOP_EXPRs, but that wasn't
>> > successful.  But since we're interested in ==/!=, I think this can be fixed
>> > easily in cp_build_binary_op.  Actually, all that seems to be needed is using
>> > orig_op as the argument to null_ptr_cst_p, but that wouldn't give the correct
>> > diagnostics, so I did this.  By checking orig_op we can see if the operands are
>> > character literals or not, because orig_op is an operand before the default
>> > conversions.
>>
>> What is wrong about the diagnostic from just using orig_op?  "ISO C++
>> forbids comparison between pointer and integer" seems fine to me, and
>> will help the user to realize that they need to index off the pointer.
>>
>> I see that some of the calls to null_ptr_cst_p in cp_build_binary_op
>> have already been changed to check orig_op*, but not all.  Let's
>> update the remaining calls, that should do the trick without adding a
>> new error.
>
> Here you go:
>
> Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk?
>
> 2016-10-01  Marek Polacek  <polacek@redhat.com>
>
>         Core 903
>         * typeck.c (cp_build_binary_op): Pass original operands to
>         null_ptr_cst_p, not those after the default conversions.
>
>         * g++.dg/cpp0x/nullptr37.C: New test.
>
> diff --git gcc/cp/typeck.c gcc/cp/typeck.c
> index 617ca55..8b780be 100644
> --- gcc/cp/typeck.c
> +++ gcc/cp/typeck.c
> @@ -4573,7 +4573,7 @@ cp_build_binary_op (location_t location,
>               || code1 == COMPLEX_TYPE || code1 == ENUMERAL_TYPE))
>         short_compare = 1;
>        else if (((code0 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type0))
> -               && null_ptr_cst_p (op1))
> +               && null_ptr_cst_p (orig_op1))
>                /* Handle, eg, (void*)0 (c++/43906), and more.  */
>                || (code0 == POINTER_TYPE
>                    && TYPE_PTR_P (type1) && integer_zerop (op1)))
> @@ -4587,7 +4587,7 @@ cp_build_binary_op (location_t location,
>           warn_for_null_address (location, op0, complain);
>         }
>        else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
> -               && null_ptr_cst_p (op0))
> +               && null_ptr_cst_p (orig_op0))
>                /* Handle, eg, (void*)0 (c++/43906), and more.  */
>                || (code1 == POINTER_TYPE
>                    && TYPE_PTR_P (type0) && integer_zerop (op0)))
> @@ -4604,7 +4604,7 @@ cp_build_binary_op (location_t location,
>                || (TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P (type1)))
>         result_type = composite_pointer_type (type0, type1, op0, op1,
>                                               CPO_COMPARISON, complain);
> -      else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
> +      else if (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1))
>         /* One of the operands must be of nullptr_t type.  */
>          result_type = TREE_TYPE (nullptr_node);
>        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
> @@ -4623,7 +4623,7 @@ cp_build_binary_op (location_t location,
>            else
>              return error_mark_node;
>         }
> -      else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
> +      else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (orig_op1))
>         {
>           if (TARGET_PTRMEMFUNC_VBIT_LOCATION
>               == ptrmemfunc_vbit_in_delta)
> @@ -4664,7 +4664,7 @@ cp_build_binary_op (location_t location,
>             }
>           result_type = TREE_TYPE (op0);
>         }
> -      else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
> +      else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (orig_op0))
>         return cp_build_binary_op (location, code, op1, op0, complain);
>        else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1))
>         {
> @@ -4877,21 +4877,21 @@ cp_build_binary_op (location_t location,
>        else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
>         result_type = composite_pointer_type (type0, type1, op0, op1,
>                                               CPO_COMPARISON, complain);
> -      else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
> +      else if (code0 == POINTER_TYPE && null_ptr_cst_p (orig_op1))
>         {
>           result_type = type0;
>           if (extra_warnings && (complain & tf_warning))
>             warning (OPT_Wextra,
>                      "ordered comparison of pointer with integer zero");
>         }
> -      else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
> +      else if (code1 == POINTER_TYPE && null_ptr_cst_p (orig_op0))
>         {
>           result_type = type1;
>           if (extra_warnings && (complain & tf_warning))
>             warning (OPT_Wextra,
>                      "ordered comparison of pointer with integer zero");
>         }
> -      else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
> +      else if (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1))
>         /* One of the operands must be of nullptr_t type.  */
>          result_type = TREE_TYPE (nullptr_node);
>        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
> diff --git gcc/testsuite/g++.dg/cpp0x/nullptr37.C gcc/testsuite/g++.dg/cpp0x/nullptr37.C
> index e69de29..e746a28 100644
> --- gcc/testsuite/g++.dg/cpp0x/nullptr37.C
> +++ gcc/testsuite/g++.dg/cpp0x/nullptr37.C
> @@ -0,0 +1,78 @@
> +/* PR c++/64767 */
> +// { dg-do compile { target c++11 } }
> +
> +int
> +f1 (int *p, int **q)
> +{
> +  int r = 0;
> +
> +  r += p == '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += p == L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += p == u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += p == U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += p != '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += p != L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += p != u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += p != U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +
> +  r += '\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += L'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += u'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += U'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += '\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += L'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += u'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += U'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +
> +  r += q == '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += q == L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += q == u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += q == U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += q != '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += q != L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += q != u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += q != U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +
> +  r += '\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += L'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += u'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += U'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += '\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += L'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += u'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += U'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +
> +  return r;
> +}
> +
> +int
> +f2 (int *p)
> +{
> +  int r = 0;
> +
> +  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-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += p != (char) 0; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +
> +  r += (char) 0 == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +  r += (char) 0 != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
> +
> +  return r;
> +}
>
>         Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767)
  2016-10-02 18:43                   ` Jason Merrill
@ 2017-01-04  6:56                     ` Eric Gallager
  0 siblings, 0 replies; 18+ messages in thread
From: Eric Gallager @ 2017-01-04  6:56 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Marek Polacek, GCC Patches

On 10/2/16, Jason Merrill <jason@redhat.com> wrote:
> OK, thanks.
>
> On Sat, Oct 1, 2016 at 10:16 AM, Marek Polacek <polacek@redhat.com> wrote:
>> On Fri, Sep 30, 2016 at 05:48:03PM -0400, Jason Merrill wrote:
>>> On Fri, Sep 30, 2016 at 12:43 PM, Marek Polacek <polacek@redhat.com>
>>> wrote:
>>> > On Fri, Sep 23, 2016 at 10:31:33AM -0400, Jason Merrill wrote:
>>> >> On Fri, Sep 23, 2016 at 9:15 AM, Marek Polacek <polacek@redhat.com>
>>> >> wrote:
>>> >> > On Wed, Sep 21, 2016 at 03:52:09PM -0400, Jason Merrill wrote:
>>> >> >> On Mon, Sep 19, 2016 at 2:49 PM, Jason Merrill <jason@redhat.com>
>>> >> >> wrote:
>>> >> >> > I suppose that an INTEGER_CST of character type is necessarily a
>>> >> >> > character constant, so adding a check for !char_type_p ought to
>>> >> >> > do the
>>> >> >> > trick.
>>> >> >>
>>> >> >> Indeed it does.  I'm checking this in:
>>> >> >
>>> >> > Nice, thanks.  What about the original patch?  We still need to
>>> >> > warn
>>> >> > (or error for C++11) for pointer comparisons.
>>> >>
>>> >> If we still accept pointer comparisons in C++, that's another bug
>>> >> with
>>> >> treating \0 as a null pointer constant.  This seems to be because
>>> >> ocp_convert of \0 to int produces an INTEGER_CST indistinguishable
>>> >> from literal 0.
>>> >
>>> > I was trying to fix this in ocp_convert, by using NOP_EXPRs, but that
>>> > wasn't
>>> > successful.  But since we're interested in ==/!=, I think this can be
>>> > fixed
>>> > easily in cp_build_binary_op.  Actually, all that seems to be needed is
>>> > using
>>> > orig_op as the argument to null_ptr_cst_p, but that wouldn't give the
>>> > correct
>>> > diagnostics, so I did this.  By checking orig_op we can see if the
>>> > operands are
>>> > character literals or not, because orig_op is an operand before the
>>> > default
>>> > conversions.
>>>
>>> What is wrong about the diagnostic from just using orig_op?  "ISO C++
>>> forbids comparison between pointer and integer" seems fine to me, and
>>> will help the user to realize that they need to index off the pointer.
>>>
>>> I see that some of the calls to null_ptr_cst_p in cp_build_binary_op
>>> have already been changed to check orig_op*, but not all.  Let's
>>> update the remaining calls, that should do the trick without adding a
>>> new error.
>>
>> Here you go:
>>
>> Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk?
>>
>> 2016-10-01  Marek Polacek  <polacek@redhat.com>
>>
>>         Core 903
>>         * typeck.c (cp_build_binary_op): Pass original operands to
>>         null_ptr_cst_p, not those after the default conversions.
>>
>>         * g++.dg/cpp0x/nullptr37.C: New test.
>>
>> diff --git gcc/cp/typeck.c gcc/cp/typeck.c
>> index 617ca55..8b780be 100644
>> --- gcc/cp/typeck.c
>> +++ gcc/cp/typeck.c
>> @@ -4573,7 +4573,7 @@ cp_build_binary_op (location_t location,
>>               || code1 == COMPLEX_TYPE || code1 == ENUMERAL_TYPE))
>>         short_compare = 1;
>>        else if (((code0 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type0))
>> -               && null_ptr_cst_p (op1))
>> +               && null_ptr_cst_p (orig_op1))
>>                /* Handle, eg, (void*)0 (c++/43906), and more.  */
>>                || (code0 == POINTER_TYPE
>>                    && TYPE_PTR_P (type1) && integer_zerop (op1)))
>> @@ -4587,7 +4587,7 @@ cp_build_binary_op (location_t location,
>>           warn_for_null_address (location, op0, complain);
>>         }
>>        else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
>> -               && null_ptr_cst_p (op0))
>> +               && null_ptr_cst_p (orig_op0))
>>                /* Handle, eg, (void*)0 (c++/43906), and more.  */
>>                || (code1 == POINTER_TYPE
>>                    && TYPE_PTR_P (type0) && integer_zerop (op0)))
>> @@ -4604,7 +4604,7 @@ cp_build_binary_op (location_t location,
>>                || (TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P
>> (type1)))
>>         result_type = composite_pointer_type (type0, type1, op0, op1,
>>                                               CPO_COMPARISON, complain);
>> -      else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
>> +      else if (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1))
>>         /* One of the operands must be of nullptr_t type.  */
>>          result_type = TREE_TYPE (nullptr_node);
>>        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
>> @@ -4623,7 +4623,7 @@ cp_build_binary_op (location_t location,
>>            else
>>              return error_mark_node;
>>         }
>> -      else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
>> +      else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (orig_op1))
>>         {
>>           if (TARGET_PTRMEMFUNC_VBIT_LOCATION
>>               == ptrmemfunc_vbit_in_delta)
>> @@ -4664,7 +4664,7 @@ cp_build_binary_op (location_t location,
>>             }
>>           result_type = TREE_TYPE (op0);
>>         }
>> -      else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
>> +      else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (orig_op0))
>>         return cp_build_binary_op (location, code, op1, op0, complain);
>>        else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1))
>>         {
>> @@ -4877,21 +4877,21 @@ cp_build_binary_op (location_t location,
>>        else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
>>         result_type = composite_pointer_type (type0, type1, op0, op1,
>>                                               CPO_COMPARISON, complain);
>> -      else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
>> +      else if (code0 == POINTER_TYPE && null_ptr_cst_p (orig_op1))
>>         {
>>           result_type = type0;
>>           if (extra_warnings && (complain & tf_warning))
>>             warning (OPT_Wextra,
>>                      "ordered comparison of pointer with integer zero");
>>         }
>> -      else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
>> +      else if (code1 == POINTER_TYPE && null_ptr_cst_p (orig_op0))
>>         {
>>           result_type = type1;
>>           if (extra_warnings && (complain & tf_warning))
>>             warning (OPT_Wextra,
>>                      "ordered comparison of pointer with integer zero");
>>         }
>> -      else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
>> +      else if (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1))
>>         /* One of the operands must be of nullptr_t type.  */
>>          result_type = TREE_TYPE (nullptr_node);
>>        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
>> diff --git gcc/testsuite/g++.dg/cpp0x/nullptr37.C
>> gcc/testsuite/g++.dg/cpp0x/nullptr37.C
>> index e69de29..e746a28 100644
>> --- gcc/testsuite/g++.dg/cpp0x/nullptr37.C
>> +++ gcc/testsuite/g++.dg/cpp0x/nullptr37.C
>> @@ -0,0 +1,78 @@
>> +/* PR c++/64767 */
>> +// { dg-do compile { target c++11 } }
>> +
>> +int
>> +f1 (int *p, int **q)
>> +{
>> +  int r = 0;
>> +
>> +  r += p == '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += p == L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += p == u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += p == U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += p != '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += p != L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += p != u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += p != U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +
>> +  r += '\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += L'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += u'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += U'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += '\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += L'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += u'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += U'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +
>> +  r += q == '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += q == L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += q == u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += q == U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += q != '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += q != L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += q != u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += q != U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +
>> +  r += '\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += L'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += u'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += U'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += '\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += L'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += u'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +  r += U'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between
>> pointer and integer" }
>> +
>> +  return r;
>> +}
>> +
>> +int
>> +f2 (int *p)
>> +{
>> +  int r = 0;
>> +
>> +  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-error "ISO C\\+\\+ forbids comparison
>> between pointer and integer" }
>> +  r += p != (char) 0; // { dg-error "ISO C\\+\\+ forbids comparison
>> between pointer and integer" }
>> +
>> +  r += (char) 0 == p; // { dg-error "ISO C\\+\\+ forbids comparison
>> between pointer and integer" }
>> +  r += (char) 0 != p; // { dg-error "ISO C\\+\\+ forbids comparison
>> between pointer and integer" }
>> +
>> +  return r;
>> +}
>>
>>         Marek
>

So I'm still kind of unclear as to what got committed as a result of
this thread. It seems like there's a new diagnostic for C++11, but
what about other language standards? Is there still going to be a
separate -Wpointer-compare flag usable in plain C? When I tried with
trunk from yesterday, it still didn't work:

$ /usr/local/bin/gcc -Wpointer-compare -c unexmacosx.c
gcc: error: unrecognized command line option ‘-Wpointer-compare’; did
you mean ‘-Wnonnull-compare’?
$

I hope a separate -Wpointer-compare flag can make it in in time for GCC 7.

Thanks,
Eric

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2017-01-04  6:56 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-10 15:06 C/C++ PATCH to implement -Wpointer-compare warning (PR c++/64767) Marek Polacek
2016-09-10 15:13 ` Jakub Jelinek
2016-09-10 15:48   ` Marek Polacek
2016-09-14  5:56 ` Jason Merrill
2016-09-15 12:31   ` Marek Polacek
2016-09-19 19:51     ` Jason Merrill
2016-09-21 19:55       ` Jason Merrill
2016-09-23 13:29         ` Marek Polacek
2016-09-23 14:37           ` Jason Merrill
2016-09-30 16:52             ` Marek Polacek
2016-09-30 17:22               ` Martin Sebor
2016-09-30 19:52                 ` Martin Sebor
2016-09-30 20:02                   ` Marek Polacek
2016-09-30 22:16                     ` Martin Sebor
2016-09-30 22:16               ` Jason Merrill
2016-10-01 14:41                 ` Marek Polacek
2016-10-02 18:43                   ` Jason Merrill
2017-01-04  6:56                     ` Eric Gallager

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).