From 79f925ed078e633914daa2ba9e23b9a827d89264 Mon Sep 17 00:00:00 2001
From: jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Sun, 4 Dec 2005 23:04:59 +0000
Subject: [PATCH] 	* c-typeck.c (null_pointer_constant_p): New function. 
 (build_conditional_expr, build_c_cast, convert_for_assignment, 
 build_binary_op): Use it.

testsuite:
	* gcc.dg/c90-const-expr-5.c, gcc.dg/c99-const-expr-5.c: New tests.


git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@108022 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                           |  6 +++
 gcc/c-typeck.c                          | 50 ++++++++++++++++---------
 gcc/testsuite/ChangeLog                 |  4 ++
 gcc/testsuite/gcc.dg/c90-const-expr-5.c | 39 +++++++++++++++++++
 gcc/testsuite/gcc.dg/c99-const-expr-5.c | 39 +++++++++++++++++++
 5 files changed, 120 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c90-const-expr-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c99-const-expr-5.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 31ac7608d96f..15da7d4a1421 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2005-12-04  Joseph S. Myers  <joseph@codesourcery.com>
+
+	* c-typeck.c (null_pointer_constant_p): New function.
+	(build_conditional_expr, build_c_cast, convert_for_assignment,
+	build_binary_op): Use it.
+
 2005-12-04  Joseph S. Myers  <joseph@codesourcery.com>
 
 	* c-common.c (binary_op_error): Do not allow NOP_EXPR.
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index e4e21dc101d3..36c9bc0702c8 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -74,6 +74,7 @@ static int missing_braces_mentioned;
 static int require_constant_value;
 static int require_constant_elements;
 
+static bool null_pointer_constant_p (tree);
 static tree qualify_type (tree, tree);
 static int tagged_types_tu_compatible_p (tree, tree);
 static int comp_target_types (tree, tree);
@@ -106,6 +107,23 @@ static int lvalue_or_else (tree, enum lvalue_use);
 static int lvalue_p (tree);
 static void record_maybe_used_decl (tree);
 static int comptypes_internal (tree, tree);
+
+/* Return true if EXP is a null pointer constant, false otherwise.  */
+
+static bool
+null_pointer_constant_p (tree expr)
+{
+  /* This should really operate on c_expr structures, but they aren't
+     yet available everywhere required.  */
+  tree type = TREE_TYPE (expr);
+  return (TREE_CODE (expr) == INTEGER_CST
+	  && !TREE_CONSTANT_OVERFLOW (expr)
+	  && integer_zerop (expr)
+	  && (INTEGRAL_TYPE_P (type)
+	      || (TREE_CODE (type) == POINTER_TYPE
+		  && VOID_TYPE_P (TREE_TYPE (type))
+		  && TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED)));
+}
 /* This is a cache to hold if two types are compatible or not.  */
 
 struct tagged_tu_seen_cache {
@@ -3205,9 +3223,9 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
     {
       if (comp_target_types (type1, type2))
 	result_type = common_pointer_type (type1, type2);
-      else if (integer_zerop (orig_op1) && TREE_TYPE (type1) == void_type_node)
+      else if (null_pointer_constant_p (orig_op1))
 	result_type = qualify_type (type2, type1);
-      else if (integer_zerop (orig_op2) && TREE_TYPE (type2) == void_type_node)
+      else if (null_pointer_constant_p (orig_op2))
 	result_type = qualify_type (type1, type2);
       else if (VOID_TYPE_P (TREE_TYPE (type1)))
 	{
@@ -3233,7 +3251,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
     }
   else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
     {
-      if (!integer_zerop (op2))
+      if (!null_pointer_constant_p (orig_op2))
 	pedwarn ("pointer/integer type mismatch in conditional expression");
       else
 	{
@@ -3243,7 +3261,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
     }
   else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
     {
-      if (!integer_zerop (op1))
+      if (!null_pointer_constant_p (orig_op1))
 	pedwarn ("pointer/integer type mismatch in conditional expression");
       else
 	{
@@ -3481,7 +3499,7 @@ build_c_cast (tree type, tree expr)
 	  && TREE_CODE (otype) == POINTER_TYPE
 	  && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
 	  && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
-	  && !(integer_zerop (value) && TREE_TYPE (otype) == void_type_node))
+	  && !null_pointer_constant_p (value))
 	pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
 
       ovalue = value;
@@ -3834,7 +3852,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
 	    }
 
 	  /* Can convert integer zero to any pointer type.  */
-	  if (integer_zerop (rhs))
+	  if (null_pointer_constant_p (rhs))
 	    {
 	      rhs = null_pointer_node;
 	      break;
@@ -3972,7 +3990,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
 	      && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
 		  ||
 		  (VOID_TYPE_P (ttr)
-		   && !integer_zerop (rhs)
+		   && !null_pointer_constant_p (rhs)
 		   && TREE_CODE (ttl) == FUNCTION_TYPE)))
 	    WARN_FOR_ASSIGNMENT (G_("ISO C forbids passing argument %d of "
 				    "%qE between function pointer "
@@ -4062,7 +4080,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
       /* An explicit constant 0 can convert to a pointer,
 	 or one that results from arithmetic, even including
 	 a cast to integer type.  */
-      if (!integer_zerop (rhs))
+      if (!null_pointer_constant_p (rhs))
 	WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
 				"pointer from integer without a cast"),
 			     G_("assignment makes pointer from integer "
@@ -7900,14 +7918,14 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 	    {
 	      /* op0 != orig_op0 detects the case of something
 		 whose value is 0 but which isn't a valid null ptr const.  */
-	      if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
+	      if (pedantic && !null_pointer_constant_p (orig_op0)
 		  && TREE_CODE (tt1) == FUNCTION_TYPE)
 		pedwarn ("ISO C forbids comparison of %<void *%>"
 			 " with function pointer");
 	    }
 	  else if (VOID_TYPE_P (tt1))
 	    {
-	      if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
+	      if (pedantic && !null_pointer_constant_p (orig_op1)
 		  && TREE_CODE (tt0) == FUNCTION_TYPE)
 		pedwarn ("ISO C forbids comparison of %<void *%>"
 			 " with function pointer");
@@ -7920,11 +7938,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 	  if (result_type == NULL_TREE)
 	    result_type = ptr_type_node;
 	}
-      else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
-	       && integer_zerop (op1))
+      else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
 	result_type = type0;
-      else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
-	       && integer_zerop (op0))
+      else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
 	result_type = type1;
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
 	{
@@ -7964,15 +7980,13 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 	      pedwarn ("comparison of distinct pointer types lacks a cast");
 	    }
 	}
-      else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
-	       && integer_zerop (op1))
+      else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
 	{
 	  result_type = type0;
 	  if (pedantic || extra_warnings)
 	    pedwarn ("ordered comparison of pointer with integer zero");
 	}
-      else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
-	       && integer_zerop (op0))
+      else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
 	{
 	  result_type = type1;
 	  if (pedantic)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 93e36dc12bca..fb0d84d7141a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2005-12-04  Joseph S. Myers  <joseph@codesourcery.com>
+
+	* gcc.dg/c90-const-expr-5.c, gcc.dg/c99-const-expr-5.c: New tests.
+
 2005-12-04  Joseph S. Myers  <joseph@codesourcery.com>
 
 	* gcc.dg/format/cast-1.c: New test.
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-5.c b/gcc/testsuite/gcc.dg/c90-const-expr-5.c
new file mode 100644
index 000000000000..132932b565a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-5.c
@@ -0,0 +1,39 @@
+/* Test null pointer constants: typedefs for void should be OK but not
+   qualified void.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+typedef void V;
+int *p;
+long *q;
+int j;
+void (*fp)(void);
+
+void
+f (void)
+{
+  /* (V *)0 is a null pointer constant, so the assignment should be
+     diagnosed.  */
+  q = (j ? p : (V *)0); /* { dg-error "error: assignment from incompatible pointer type" } */
+  q = (j ? p : (void *)0); /* { dg-error "error: assignment from incompatible pointer type" } */
+  /* And this conversion should be valid.  */
+  (void (*)(void))(V *)0;
+  (void (*)(void))(void *)0;
+  /* Pointers to qualified void are not valid null pointer
+     constants.  */
+  fp = (const void *)0; /* { dg-error "error: ISO C forbids assignment between function pointer and 'void \\*'" } */
+  fp = (void *)0;
+  fp = (V *)0;
+  fp = 0;
+  fp == 0;
+  0 == fp;
+  fp == (void *)0;
+  (void *)0 == fp;
+  fp == (V *)0;
+  (V *)0 == fp;
+  fp == (V *)1; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
+  (V *)1 == fp; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
+  fp == (const void *)0; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
+  (const void *)0 == fp; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-5.c b/gcc/testsuite/gcc.dg/c99-const-expr-5.c
new file mode 100644
index 000000000000..e7fdf2c644bf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-5.c
@@ -0,0 +1,39 @@
+/* Test null pointer constants: typedefs for void should be OK but not
+   qualified void.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+typedef void V;
+int *p;
+long *q;
+int j;
+void (*fp)(void);
+
+void
+f (void)
+{
+  /* (V *)0 is a null pointer constant, so the assignment should be
+     diagnosed.  */
+  q = (j ? p : (V *)0); /* { dg-error "error: assignment from incompatible pointer type" } */
+  q = (j ? p : (void *)0); /* { dg-error "error: assignment from incompatible pointer type" } */
+  /* And this conversion should be valid.  */
+  (void (*)(void))(V *)0;
+  (void (*)(void))(void *)0;
+  /* Pointers to qualified void are not valid null pointer
+     constants.  */
+  fp = (const void *)0; /* { dg-error "error: ISO C forbids assignment between function pointer and 'void \\*'" } */
+  fp = (void *)0;
+  fp = (V *)0;
+  fp = 0;
+  fp == 0;
+  0 == fp;
+  fp == (void *)0;
+  (void *)0 == fp;
+  fp == (V *)0;
+  (V *)0 == fp;
+  fp == (V *)1; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
+  (V *)1 == fp; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
+  fp == (const void *)0; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
+  (const void *)0 == fp; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
+}
-- 
GitLab