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]

PATCH for NULL handling



This patch brings g++'s handling of NULL into full
standard-conformance, while still issuing warnings in situations where
NULL is used as integer, rather than a pointer.  In particular, this
patch fixes subtle bugs in overload resolution and template
instantiation on corner cases involving NULL, and removes the
difference in semantics between the use of NULL in ansi and non-ansi
modes.

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

1998-08-23  Mark Mitchell  <mark@markmitchell.com>

	* cp-tree.h (ansi_null_node): Remove.
	* call.c (build_over_call): Warn about converting NULL to an
	arithmetic type.
	* cvt.c (build_expr_type_conversion): Likewise.  Use
	null_ptr_cst_p instead of expanding it inline.
	* decl.c (ansi_null_node): Remove. 
	(init_decl_processing): Make null_node always have integral type.
	* except.c (build_throw): Warn about converting NULL to an
	arithmetic type.
	* lex.c (init_parse): Remove handling of ansi_null_node.
	* pt.c (type_unification_real): Don't convert NULL to void* type.
	* typeck.c (build_binary_op_nodefault): Fix NULL warnings.
	(convert_for_assignment): Warn about converting NULL to an
	arithmetic type.
	(convert_for_initialization): Likewise.
	
Index: gcc/testsuite/g++.old-deja/g++.other/null1.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.other/null1.C,v
retrieving revision 1.2
diff -c -p -r1.2 null1.C
*** null1.C	1998/08/19 18:48:54	1.2
--- null1.C	1998/08/23 18:10:34
***************
*** 1,12 ****
! // Build don't link:
  
  #include <cstddef>
  
! void f()
  {
!   int i;
!   float f;
  
    i != NULL; // WARNING - NULL used in arithmetic
!   f != NULL; // WARNING - NULL used in arithmetic
  }
--- 1,40 ----
! // Build don't run:
  
  #include <cstddef>
  
! void g(int) {}
! extern void g(void*);
! 
! template <int I>
! void h() {}
! 
! void k(int) {}
! 
! template <class T>
! void l(T);
! 
! template <>
! void l(int) {}
! 
! int main()
  {
!   int i = NULL; // WARNING - converting NULL to non-pointer type
!   float z = NULL; // WARNING - converting NULL to non-pointer type
!   int a[2];
  
    i != NULL; // WARNING - NULL used in arithmetic
!   NULL != z; // WARNING - NULL used in arithmetic
!   k != NULL; // No warning: decay conversion
!   NULL != a; // Likewise.
!   -NULL;     // WARNING - converting NULL to non-pointer type
!   +NULL;     // WARNING - converting NULL to non-pointer type
!   ~NULL;     // WARNING - converting NULL to non-pointer type
!   a[NULL] = 3; // WARNING - converting NULL to non-pointer-type
!   i = NULL;  // WARNING - converting NULL to non-pointer type
!   z = NULL;  // WARNING - converting NULL to non-pointer type
!   k(NULL);   // WARNING - converting NULL to int
!   g(NULL);   // WARNING - converting NULL to int
!   h<NULL>(); // WARNING - NULL bound to integer template parameter
!   l(NULL);   // WARNING - converting NULL to int
!   NULL && NULL; // No warning: converting NULL to bool is OK
  }
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.112
diff -c -p -r1.112 cp-tree.h
*** cp-tree.h	1998/08/20 17:41:38	1.112
--- cp-tree.h	1998/08/23 18:08:13
*************** extern tree long_long_integer_type_node,
*** 1918,1924 ****
  extern tree integer_two_node, integer_three_node;
  extern tree boolean_type_node, boolean_true_node, boolean_false_node;
  
- extern tree ansi_null_node;
  extern tree null_node;
  
  /* in pt.c  */
--- 1918,1923 ----
Index: gcc/cp/call.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/call.c,v
retrieving revision 1.99
diff -c -p -r1.99 call.c
*** call.c	1998/08/17 17:13:35	1.99
--- call.c	1998/08/23 18:08:01
*************** build_over_call (cand, args, flags)
*** 3331,3337 ****
  	     "argument passing", fn, i - is_method);
  	}
        else
! 	val = convert_like (conv, TREE_VALUE (arg));
  
  #ifdef PROMOTE_PROTOTYPES
        if ((TREE_CODE (type) == INTEGER_TYPE
--- 3331,3344 ----
  	     "argument passing", fn, i - is_method);
  	}
        else
! 	{
! 	  /* Issue warnings about peculiar, but legal, uses of NULL.  */
! 	  if (ARITHMETIC_TYPE_P (TREE_VALUE (parm))
! 	      && TREE_VALUE (arg) == null_node)
! 	    cp_warning ("converting NULL to non-pointer type");
! 	    
! 	  val = convert_like (conv, TREE_VALUE (arg));
! 	}
  
  #ifdef PROMOTE_PROTOTYPES
        if ((TREE_CODE (type) == INTEGER_TYPE
Index: gcc/cp/cvt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cvt.c,v
retrieving revision 1.25
diff -c -p -r1.25 cvt.c
*** cvt.c	1998/08/17 17:13:36	1.25
--- cvt.c	1998/08/23 18:08:16
*************** build_expr_type_conversion (desires, exp
*** 946,951 ****
--- 946,956 ----
    tree conv;
    tree winner = NULL_TREE;
  
+   if (expr == null_node 
+       && (desires & WANT_INT) 
+       && !(desires & WANT_NULL))
+     cp_warning ("converting NULL to non-pointer type");
+     
    if (TREE_CODE (basetype) == OFFSET_TYPE)
      expr = resolve_offset_ref (expr);
    expr = convert_from_reference (expr);
*************** build_expr_type_conversion (desires, exp
*** 955,962 ****
      switch (TREE_CODE (basetype))
        {
        case INTEGER_TYPE:
! 	if ((desires & WANT_NULL) && TREE_CODE (expr) == INTEGER_CST
! 	    && integer_zerop (expr))
  	  return expr;
  	/* else fall through...  */
  
--- 960,966 ----
      switch (TREE_CODE (basetype))
        {
        case INTEGER_TYPE:
! 	if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
  	  return expr;
  	/* else fall through...  */
Index: gcc/cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.184
diff -c -p -r1.184 decl.c
*** decl.c	1998/08/20 17:41:39	1.184
--- decl.c	1998/08/23 18:08:57
*************** tree static_aggregates;
*** 429,441 ****
  tree integer_zero_node;
  tree null_pointer_node;
  
! /* The value for __null (NULL), when -ansi is specified.  As per the
!    standard, this is an implementation-defined null pointer constant.  */
! tree ansi_null_node;
! 
! /* The value for __null (NULL).  With -ansi, this is just
!    ansi_null_node.  Without -ansi, this is a zero-valued pointer
!    constant of type `{unknown type}*'.  */
  tree null_node;
  
  /* A node for the integer constants 1, 2, and 3.  */
--- 429,436 ----
  tree integer_zero_node;
  tree null_pointer_node;
  
! /* The value for __null (NULL), namely, a zero of an integer type with
!    the same number of bits as a pointer.  */
  tree null_node;
  
  /* A node for the integer constants 1, 2, and 3.  */
*************** init_decl_processing ()
*** 6035,6043 ****
    /* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node.  */
    TREE_TYPE (unknown_type_node) = unknown_type_node;
  
!   TREE_TYPE (ansi_null_node) = type_for_size (POINTER_SIZE, 0);
!   if (!flag_ansi)
!     TREE_TYPE (null_node) = build_pointer_type (unknown_type_node);
  
    /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same
       result.  */
--- 6030,6036 ----
    /* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node.  */
    TREE_TYPE (unknown_type_node) = unknown_type_node;
  
!   TREE_TYPE (null_node) = type_for_size (POINTER_SIZE, 0);
  
    /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same
       result.  */
Index: gcc/cp/except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/except.c,v
retrieving revision 1.47
diff -c -p -r1.47 except.c
*** except.c	1998/08/19 18:48:57	1.47
--- except.c	1998/08/23 18:09:16
*************** build_throw (e)
*** 1278,1287 ****
      return build_min (THROW_EXPR, void_type_node, e);
  
    if (e == null_node)
!     {
!       cp_warning ("throwing NULL, which has integral, not pointer type");
!       e = ansi_null_node;
!     }
  
    e = build1 (THROW_EXPR, void_type_node, e);
    TREE_SIDE_EFFECTS (e) = 1;
--- 1278,1284 ----
      return build_min (THROW_EXPR, void_type_node, e);
  
    if (e == null_node)
!     cp_warning ("throwing NULL, which has integral, not pointer type");
  
    e = build1 (THROW_EXPR, void_type_node, e);
    TREE_SIDE_EFFECTS (e) = 1;
Index: gcc/cp/lex.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/lex.c,v
retrieving revision 1.63
diff -c -p -r1.63 lex.c
*** lex.c	1998/08/19 15:14:56	1.63
--- lex.c	1998/08/23 18:09:29
*************** init_parse (filename)
*** 781,791 ****
       type_for_size here because integer_type_node and so forth are not
       set up.  Therefore, we don't set the type of these nodes until
       init_decl_processing.  */
!   ansi_null_node = build_int_2 (0, 0);
!   if (flag_ansi)
!     null_node = ansi_null_node;
!   else
!     null_node = build_int_2 (0, 0);
    ridpointers[RID_NULL] = null_node;
  
    opname_tab[(int) COMPONENT_REF] = "->";
--- 781,787 ----
       type_for_size here because integer_type_node and so forth are not
       set up.  Therefore, we don't set the type of these nodes until
       init_decl_processing.  */
!   null_node = build_int_2 (0, 0);
    ridpointers[RID_NULL] = null_node;
  
    opname_tab[(int) COMPONENT_REF] = "->";
Index: gcc/cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.181
diff -c -p -r1.181 pt.c
*** pt.c	1998/08/20 17:41:42	1.181
--- pt.c	1998/08/23 18:36:38
*************** type_unification_real (tparms, targs, pa
*** 6595,6606 ****
  	  arg = TREE_TYPE (arg);
  	}
  #endif
-       if (! flag_ansi && arg == TREE_TYPE (null_node))
- 	{
- 	  warning ("using type void* for NULL");
- 	  arg = ptr_type_node;
- 	}
- 
        if (!subr)
  	maybe_adjust_types_for_deduction (strict, &parm, &arg);
  
--- 6590,6595 ----
Index: gcc/cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.96
diff -c -p -r1.96 typeck.c
*** typeck.c	1998/08/19 18:48:55	1.96
--- typeck.c	1998/08/23 18:10:14
*************** build_binary_op_nodefault (code, orig_op
*** 3244,3268 ****
    /* Nonzero means set RESULT_TYPE to the common type of the args.  */
    int common = 0;
  
-   /* Unless -ansi is specified, __null has pointer type.  But, then,
-      things like `7 != NULL' result in errors about comparisons
-      between pointers and integers.  So, here, we replace __null with
-      an appropriate null pointer constant.  */
-   op0 = (orig_op0 == null_node) ? ansi_null_node : orig_op0;
-   op1 = (orig_op1 == null_node) ? ansi_null_node : orig_op1;
- 
    /* Apply default conversions.  */
    if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
        || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
        || code == TRUTH_XOR_EXPR)
      {
!       op0 = decay_conversion (op0);
!       op1 = decay_conversion (op1);
      }
    else
      {
!       op0 = default_conversion (op0);
!       op1 = default_conversion (op1);
      }
  
    type0 = TREE_TYPE (op0);
--- 3244,3261 ----
    /* Nonzero means set RESULT_TYPE to the common type of the args.  */
    int common = 0;
  
    /* Apply default conversions.  */
    if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
        || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
        || code == TRUTH_XOR_EXPR)
      {
!       op0 = decay_conversion (orig_op0);
!       op1 = decay_conversion (orig_op1);
      }
    else
      {
!       op0 = default_conversion (orig_op0);
!       op1 = default_conversion (orig_op1);
      }
  
    type0 = TREE_TYPE (op0);
*************** build_binary_op_nodefault (code, orig_op
*** 3961,3975 ****
        return error_mark_node;
      }
  
!   if (/* If OP0 is NULL and OP1 is not a pointer, or vice versa.  */
!       (orig_op0 == null_node
!        && TREE_CODE (TREE_TYPE (orig_op1)) != POINTER_TYPE)
!       /* Or vice versa.  */
!       || (orig_op1 == null_node
! 	  && TREE_CODE (TREE_TYPE (orig_op0)) != POINTER_TYPE)
!       /* Or, both are NULL and the operation was not a comparison.  */
!       || (orig_op0 == null_node && orig_op1 == null_node 
! 	  && code != EQ_EXPR && code != NE_EXPR))
      /* Some sort of arithmetic operation involving NULL was
         performed.  Note that pointer-difference and pointer-addition
         have already been handled above, and so we don't end up here in
--- 3954,3972 ----
        return error_mark_node;
      }
  
!   /* Issue warnings about peculiar, but legal, uses of NULL.  */
!   if (/* It's reasonable to use pointer values as operands of &&
! 	 and ||, so NULL is no exception.  */
!       !(code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
!       && (/* If OP0 is NULL and OP1 is not a pointer, or vice versa.  */
! 	  (orig_op0 == null_node
! 	   && TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE)
! 	  /* Or vice versa.  */
! 	  || (orig_op1 == null_node
! 	      && TREE_CODE (TREE_TYPE (op0)) != POINTER_TYPE)
! 	  /* Or, both are NULL and the operation was not a comparison.  */
! 	  || (orig_op0 == null_node && orig_op1 == null_node 
! 	      && code != EQ_EXPR && code != NE_EXPR)))
      /* Some sort of arithmetic operation involving NULL was
         performed.  Note that pointer-difference and pointer-addition
         have already been handled above, and so we don't end up here in
*************** convert_for_assignment (type, rhs, errty
*** 6593,6598 ****
--- 6590,6599 ----
    register tree rhstype;
    register enum tree_code coder = TREE_CODE (TREE_TYPE (rhs));
  
+   /* Issue warnings about peculiar, but legal, uses of NULL.  */
+   if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
+     cp_warning ("converting NULL to non-pointer type");
+ 
    if (coder == UNKNOWN_TYPE)
      rhs = instantiate_type (type, rhs, 1);
  
*************** convert_for_initialization (exp, type, r
*** 7045,7050 ****
--- 7046,7055 ----
    register enum tree_code codel = TREE_CODE (type);
    register tree rhstype;
    register enum tree_code coder;
+ 
+   /* Issue warnings about peculiar, but legal, uses of NULL.  */
+   if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
+     cp_warning ("converting NULL to non-pointer type");
  
    /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
       Strip such NOP_EXPRs, since RHS is used in non-lvalue context.  */


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