This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch for null pointer constant issues


This patch fixes some issues with null pointer constants found in the
course of removing NOP_EXPR/CONVERT_EXPR distinctions from the C front
end.  Some code was too restrictive and failed to allow casts to
pointers to typedefs for void, other code was too permissive and
allowed casts to pointers to qualified void.

I put the TREE_CONSTANT_OVERFLOW check in null_pointer_constant_p,
even though it's also in integer_zerop, in the hope that a similar
change can be made to the C++ front end and then integer_zerop can
stop checking TREE_CONSTANT_OVERFLOW.

Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  Applied
to mainline.

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.

testsuite:
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.

diff -rupN GCC.orig/gcc/c-typeck.c GCC/gcc/c-typeck.c
--- GCC.orig/gcc/c-typeck.c	2005-12-03 18:56:59.000000000 +0000
+++ GCC/gcc/c-typeck.c	2005-12-04 20:59:54.000000000 +0000
@@ -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 lv
 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 {
@@ -3184,9 +3202,9 @@ build_conditional_expr (tree ifexp, tree
     {
       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)))
 	{
@@ -3212,7 +3230,7 @@ build_conditional_expr (tree ifexp, tree
     }
   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
 	{
@@ -3222,7 +3240,7 @@ build_conditional_expr (tree ifexp, tree
     }
   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
 	{
@@ -3460,7 +3478,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;
@@ -3813,7 +3831,7 @@ convert_for_assignment (tree type, tree 
 	    }
 
 	  /* Can convert integer zero to any pointer type.  */
-	  if (integer_zerop (rhs))
+	  if (null_pointer_constant_p (rhs))
 	    {
 	      rhs = null_pointer_node;
 	      break;
@@ -3951,7 +3969,7 @@ convert_for_assignment (tree type, tree 
 	      && ((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 "
@@ -4041,7 +4059,7 @@ convert_for_assignment (tree type, tree 
       /* 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 "
@@ -7879,14 +7897,14 @@ build_binary_op (enum tree_code code, tr
 	    {
 	      /* 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");
@@ -7899,11 +7917,9 @@ build_binary_op (enum tree_code code, tr
 	  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)
 	{
@@ -7943,15 +7959,13 @@ build_binary_op (enum tree_code code, tr
 	      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 -rupN GCC.orig/gcc/testsuite/gcc.dg/c90-const-expr-5.c GCC/gcc/testsuite/gcc.dg/c90-const-expr-5.c
--- GCC.orig/gcc/testsuite/gcc.dg/c90-const-expr-5.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/c90-const-expr-5.c	2005-12-04 20:39:26.000000000 +0000
@@ -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 -rupN GCC.orig/gcc/testsuite/gcc.dg/c99-const-expr-5.c GCC/gcc/testsuite/gcc.dg/c99-const-expr-5.c
--- GCC.orig/gcc/testsuite/gcc.dg/c99-const-expr-5.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/c99-const-expr-5.c	2005-12-04 20:41:06.000000000 +0000
@@ -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" } */
+}

-- 
Joseph S. Myers               http://www.srcf.ucam.org/~jsm28/gcc/
    jsm@polyomino.org.uk (personal mail)
    joseph@codesourcery.com (CodeSourcery mail)
    jsm28@gcc.gnu.org (Bugzilla assignments and CCs)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]