C++ PATCH: Check pod-class

Nathan Sidwell nathan@acm.org
Thu Apr 8 07:21:00 GMT 1999


Jason Merrill wrote:
> In the standard, it's spelled POD, not PoD.
Check. For some reason I've had PoD erroneously etched onto my brain.

> Please avoid re-indenting code when reasonable, to make cvs annotate more
> useful.  Often this means that if you need a new variable
> (i.e. field_type), you add it at the top of the function.
Check. Actually, this showed up several places in finish_struct_1 where we
repeatedly used the member's type, or looked into its array core. I hold the
member's type in an existing variable, TYPE, which I moved up from an inner
scope.

> The sense of the flag should be reversed so it indicates non-POD, so that
> internally generated classes are considered POD by default.
Check. I was trying to avoid double negatives...

> The warnings you've added to build_component_ref need to be more verbose;
> tell them what they can't do, not just why.
Check, they now say "using member function `foo' with NULL ptr to `class X'" or
equivalent.

> Never use IDENTIFIER_POINTER in printing an diagnostic in the C++ frontend.
> Use cp_error et al instead.
Check. My fault for copying some errant code -- I've tidied an additional
instance in typeck.c too.

> We need to get you an account on egcs so you can check things in
> yourself...
I'll hold off submitting an exception specification patch for a bit then.

As ever, no new regressions. Hope it's ok this time :-)

Enjoy

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
      You can up the bandwidth, but you can't up the speed of light      
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
egcs/gcc/cp/ChangeLog:
Thu Apr  8 13:28:36 BST 1999  Nathan Sidwell  <nathan@acm.org>

	* call.c (convert_arg_to_ellipsis): Use pod_type_p.
	* cp-tree.h (struct lang_type): Added non_pod_class flag.
	(CLASSTYPE_NON_POD_P): New macro to access it.
	(build_component_addr): Remove prototype.
	* class.c (finish_struct_1): Determine non-PODness.
	Check for arrays of pointers (-Weffc++).
	Remove array inspection duplicated code.
	* tree.c (pod_type_p): Use CLASSTYPE_NON_POD_P.
	* typeck.c (build_component_addr): Make static. Remove MSG
	argument.
	(build_component_ref): Check for `offsetof' idiom, and warn on
	undefined uses.
	(build_component_addr): Likewise. Remove MSG parameter, clean up
	comment.
	(build_x_function_call): Use cp_error.
	(build_unary_op): Change call of build_component_addr.
	
Index: egcs/gcc/cp/call.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/call.c,v
retrieving revision 1.140
diff -c -3 -p -r1.140 call.c
*** call.c	1999/04/02 15:36:02	1.140
--- call.c	1999/04/08 13:03:17
*************** convert_like (convs, expr)
*** 3142,3162 ****
  }
  
  /* ARG is being passed to a varargs function.  Perform any conversions
!    required.  Return the converted value.  */
  
  tree
  convert_arg_to_ellipsis (arg)
       tree arg;
  {
    if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE
        && (TYPE_PRECISION (TREE_TYPE (arg))
  	  < TYPE_PRECISION (double_type_node)))
      /* Convert `float' to `double'.  */
      arg = cp_convert (double_type_node, arg);
-   else if (IS_AGGR_TYPE (TREE_TYPE (arg))
- 	   && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (arg)))
-     cp_warning ("cannot pass objects of type `%T' through `...'",
- 		TREE_TYPE (arg));
    else
      /* Convert `short' and `char' to full-size `int'.  */
      arg = default_conversion (arg);
--- 3142,3163 ----
  }
  
  /* ARG is being passed to a varargs function.  Perform any conversions
!    required.  Array/function to pointer decay must have already happened.
!    Return the converted value.  */
  
  tree
  convert_arg_to_ellipsis (arg)
       tree arg;
  {
+   if (! pod_type_p (TREE_TYPE (arg)))
+     cp_warning ("cannot pass objects of non-POD type `%#T' through `...'",
+ 		TREE_TYPE (arg));
+ 
    if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE
        && (TYPE_PRECISION (TREE_TYPE (arg))
  	  < TYPE_PRECISION (double_type_node)))
      /* Convert `float' to `double'.  */
      arg = cp_convert (double_type_node, arg);
    else
      /* Convert `short' and `char' to full-size `int'.  */
      arg = default_conversion (arg);
Index: egcs/gcc/cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.141
diff -c -3 -p -r1.141 class.c
*** class.c	1999/04/03 01:23:24	1.141
--- class.c	1999/04/08 13:03:21
*************** finish_struct_1 (t, warn_anon)
*** 3097,3102 ****
--- 3097,3103 ----
    int cant_have_const_ctor;
    int no_const_asn_ref;
    int has_mutable = 0;
+   int non_pod_class = 0;
  
    /* The index of the first base class which has virtual
       functions.  Only applied to non-virtual baseclasses.  */
*************** finish_struct_1 (t, warn_anon)
*** 3243,3248 ****
--- 3244,3250 ----
    last_x = NULL_TREE;
    for (x = fields; x; x = TREE_CHAIN (x))
      {
+       tree type = TREE_TYPE (x);
        GNU_xref_member (current_class_name, x);
  
        if (TREE_CODE (x) == FIELD_DECL)
*************** finish_struct_1 (t, warn_anon)
*** 3284,3304 ****
  
        /* Perform error checking that did not get done in
  	 grokdeclarator.  */
!       if (TREE_CODE (TREE_TYPE (x)) == FUNCTION_TYPE)
  	{
  	  cp_error_at ("field `%D' invalidly declared function type",
  		       x);
! 	  TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
  	}
!       else if (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE)
  	{
  	  cp_error_at ("field `%D' invalidly declared method type", x);
! 	  TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
  	}
!       else if (TREE_CODE (TREE_TYPE (x)) == OFFSET_TYPE)
  	{
  	  cp_error_at ("field `%D' invalidly declared offset type", x);
! 	  TREE_TYPE (x) = build_pointer_type (TREE_TYPE (x));
  	}
  
  #if 0
--- 3286,3309 ----
  
        /* Perform error checking that did not get done in
  	 grokdeclarator.  */
!       if (TREE_CODE (type) == FUNCTION_TYPE)
  	{
  	  cp_error_at ("field `%D' invalidly declared function type",
  		       x);
! 	  type = build_pointer_type (type);
! 	  TREE_TYPE (x) = type;
  	}
!       else if (TREE_CODE (type) == METHOD_TYPE)
  	{
  	  cp_error_at ("field `%D' invalidly declared method type", x);
! 	  type = build_pointer_type (type);
! 	  TREE_TYPE (x) = type;
  	}
!       else if (TREE_CODE (type) == OFFSET_TYPE)
  	{
  	  cp_error_at ("field `%D' invalidly declared offset type", x);
! 	  type = build_pointer_type (type);
! 	  TREE_TYPE (x) = type;
  	}
  
  #if 0
*************** finish_struct_1 (t, warn_anon)
*** 3336,3341 ****
--- 3341,3348 ----
  	 Also do a little ANSI jig if necessary.  */
        if (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE)
   	{
+           non_pod_class = 1;
+           
  	  if (DECL_INITIAL (x) == NULL_TREE)
  	    ref_sans_init = 1;
  
*************** finish_struct_1 (t, warn_anon)
*** 3355,3366 ****
  	    }
  	}
  
!       if (TREE_CODE (TREE_TYPE (x)) == POINTER_TYPE)
  	has_pointers = 1;
  
!       if (DECL_MUTABLE_P (x) || TYPE_HAS_MUTABLE_P (TREE_TYPE (x)))
          has_mutable = 1;
  
        /* If any field is const, the structure type is pseudo-const.  */
        if (TREE_READONLY (x))
  	{
--- 3362,3380 ----
  	    }
  	}
  
!       while (TREE_CODE (type) == ARRAY_TYPE)
!         type = TREE_TYPE (type);
!       
!       if (TREE_CODE (type) == POINTER_TYPE)
  	has_pointers = 1;
  
!       if (DECL_MUTABLE_P (x) || TYPE_HAS_MUTABLE_P (type))
          has_mutable = 1;
  
+       if (! pod_type_p (type) || TYPE_PTRMEM_P (type)
+           || TYPE_PTRMEMFUNC_P (type))
+         non_pod_class = 1;
+ 
        /* If any field is const, the structure type is pseudo-const.  */
        if (TREE_READONLY (x))
  	{
*************** finish_struct_1 (t, warn_anon)
*** 3388,3401 ****
  	{
  	  /* A field that is pseudo-const makes the structure
  	     likewise.  */
! 	  tree t1 = TREE_TYPE (x);
! 	  while (TREE_CODE (t1) == ARRAY_TYPE)
! 	    t1 = TREE_TYPE (t1);
! 	  if (IS_AGGR_TYPE (t1))
  	    {
! 	      if (C_TYPE_FIELDS_READONLY (t1))
  		C_TYPE_FIELDS_READONLY (t) = 1;
! 	      if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (t1))
  		const_sans_init = 1;
  	    }
  	}
--- 3402,3412 ----
  	{
  	  /* A field that is pseudo-const makes the structure
  	     likewise.  */
! 	  if (IS_AGGR_TYPE (type))
  	    {
! 	      if (C_TYPE_FIELDS_READONLY (type))
  		C_TYPE_FIELDS_READONLY (t) = 1;
! 	      if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (type))
  		const_sans_init = 1;
  	    }
  	}
*************** finish_struct_1 (t, warn_anon)
*** 3407,3413 ****
  	  /* Invalid bit-field size done by grokfield.  */
  	  /* Detect invalid bit-field type.  */
  	  if (DECL_INITIAL (x)
! 	      && ! INTEGRAL_TYPE_P (TREE_TYPE (x)))
  	    {
  	      cp_error_at ("bit-field `%#D' with non-integral type", x);
  	      DECL_INITIAL (x) = NULL;
--- 3418,3424 ----
  	  /* Invalid bit-field size done by grokfield.  */
  	  /* Detect invalid bit-field type.  */
  	  if (DECL_INITIAL (x)
! 	      && ! (type == TREE_TYPE (x) && INTEGRAL_TYPE_P (type)))
  	    {
  	      cp_error_at ("bit-field `%#D' with non-integral type", x);
  	      DECL_INITIAL (x) = NULL;
*************** finish_struct_1 (t, warn_anon)
*** 3455,3474 ****
  			 TYPE_PRECISION (long_long_unsigned_type_node));
  		  cp_error_at ("  in declaration of `%D'", x);
  		}
! 	      else if (width > TYPE_PRECISION (TREE_TYPE (x))
! 		       && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE
! 		       && TREE_CODE (TREE_TYPE (x)) != BOOLEAN_TYPE)
  		{
  		  cp_warning_at ("width of `%D' exceeds its type", x);
  		}
! 	      else if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
! 		       && ((min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
! 					   TREE_UNSIGNED (TREE_TYPE (x))) > width)
! 			   || (min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
! 					      TREE_UNSIGNED (TREE_TYPE (x))) > width)))
  		{
  		  cp_warning_at ("`%D' is too small to hold all values of `%#T'",
! 				 x, TREE_TYPE (x));
  		}
  
  	      if (DECL_INITIAL (x))
--- 3466,3485 ----
  			 TYPE_PRECISION (long_long_unsigned_type_node));
  		  cp_error_at ("  in declaration of `%D'", x);
  		}
! 	      else if (width > TYPE_PRECISION (type)
! 		       && TREE_CODE (type) != ENUMERAL_TYPE
! 		       && TREE_CODE (type) != BOOLEAN_TYPE)
  		{
  		  cp_warning_at ("width of `%D' exceeds its type", x);
  		}
! 	      else if (TREE_CODE (type) == ENUMERAL_TYPE
! 		       && ((min_precision (TYPE_MIN_VALUE (type),
! 					   TREE_UNSIGNED (type)) > width)
! 			   || (min_precision (TYPE_MAX_VALUE (type),
! 					      TREE_UNSIGNED (type)) > width)))
  		{
  		  cp_warning_at ("`%D' is too small to hold all values of `%#T'",
! 				 x, type);
  		}
  
  	      if (DECL_INITIAL (x))
*************** finish_struct_1 (t, warn_anon)
*** 3486,3507 ****
  #ifdef PCC_BITFIELD_TYPE_MATTERS
  		      if (PCC_BITFIELD_TYPE_MATTERS)
  			DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
! 					      TYPE_ALIGN (TREE_TYPE (x)));
  #endif
  		    }
  		}
  	    }
  	  else
  	    /* Non-bit-fields are aligned for their type.  */
! 	    DECL_ALIGN (x) = MAX (DECL_ALIGN (x), TYPE_ALIGN (TREE_TYPE (x)));
  	}
        else
  	{
- 	  tree type = TREE_TYPE (x);
- 
- 	  while (TREE_CODE (type) == ARRAY_TYPE)
- 	    type = TREE_TYPE (type);
- 
  	  if (TYPE_LANG_SPECIFIC (type) && ! ANON_UNION_P (x)
  	      && ! TYPE_PTRMEMFUNC_P (type))
  	    {
--- 3497,3513 ----
  #ifdef PCC_BITFIELD_TYPE_MATTERS
  		      if (PCC_BITFIELD_TYPE_MATTERS)
  			DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
! 					      TYPE_ALIGN (type));
  #endif
  		    }
  		}
  	    }
  	  else
  	    /* Non-bit-fields are aligned for their type.  */
! 	    DECL_ALIGN (x) = MAX (DECL_ALIGN (x), TYPE_ALIGN (type));
  	}
        else
  	{
  	  if (TYPE_LANG_SPECIFIC (type) && ! ANON_UNION_P (x)
  	      && ! TYPE_PTRMEMFUNC_P (type))
  	    {
*************** finish_struct_1 (t, warn_anon)
*** 3606,3611 ****
--- 3612,3620 ----
    if (! IS_SIGNATURE (t))
      CLASSTYPE_NON_AGGREGATE (t)
        = ! aggregate || has_virtual || TYPE_HAS_CONSTRUCTOR (t);
+   CLASSTYPE_NON_POD_P (t)
+       = non_pod_class || CLASSTYPE_NON_AGGREGATE (t)
+         || TYPE_HAS_DESTRUCTOR (t) || TYPE_HAS_ASSIGN_REF (t);
    TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);
    TYPE_HAS_COMPLEX_ASSIGN_REF (t)
      |= TYPE_HAS_ASSIGN_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t);
Index: egcs/gcc/cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.213
diff -c -3 -p -r1.213 cp-tree.h
*** cp-tree.h	1999/04/02 15:36:01	1.213
--- cp-tree.h	1999/04/08 13:03:24
*************** struct lang_type
*** 727,737 ****
        unsigned non_aggregate : 1;
        unsigned is_partial_instantiation : 1;
        unsigned has_mutable : 1;
  
        /* The MIPS compiler gets it wrong if this struct also
  	 does not fill out to a multiple of 4 bytes.  Add a
  	 member `dummy' with new bits if you go over the edge.  */
!       unsigned dummy : 11;
      } type_flags;
  
    int vsize;
--- 727,738 ----
        unsigned non_aggregate : 1;
        unsigned is_partial_instantiation : 1;
        unsigned has_mutable : 1;
+       unsigned non_pod_class : 1;
  
        /* The MIPS compiler gets it wrong if this struct also
  	 does not fill out to a multiple of 4 bytes.  Add a
  	 member `dummy' with new bits if you go over the edge.  */
!       unsigned dummy : 10;
      } type_flags;
  
    int vsize;
*************** struct lang_type
*** 1001,1006 ****
--- 1002,1011 ----
  #define CLASSTYPE_HAS_MUTABLE(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_mutable)
  #define TYPE_HAS_MUTABLE_P(NODE) (cp_has_mutable_p (NODE))
  
+ /* Determine class PODness.
+    Nonzero means that this class type is a pod class.  */
+ #define CLASSTYPE_NON_POD_P(NODE) (TYPE_LANG_SPECIFIC (NODE)->type_flags.non_pod_class)
+ 
  /* A list of class types of which this type is a friend.  The
     TREE_VALUE is normally a TYPE, but will be a TEMPLATE_DECL in the
     case of a template friend.  */
*************** extern tree convert_arguments			PROTO((t
*** 3410,3416 ****
  extern tree build_x_binary_op			PROTO((enum tree_code, tree, tree));
  extern tree build_binary_op			PROTO((enum tree_code, tree, tree, int));
  extern tree build_binary_op_nodefault		PROTO((enum tree_code, tree, tree, enum tree_code));
- extern tree build_component_addr		PROTO((tree, tree, const char *));
  extern tree build_x_unary_op			PROTO((enum tree_code, tree));
  extern tree build_unary_op			PROTO((enum tree_code, tree, int));
  extern tree unary_complex_lvalue		PROTO((enum tree_code, tree));
--- 3415,3420 ----
Index: egcs/gcc/cp/tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/tree.c,v
retrieving revision 1.103
diff -c -3 -p -r1.103 tree.c
*** tree.c	1999/03/31 18:59:19	1.103
--- tree.c	1999/04/08 13:03:48
*************** int
*** 2673,2701 ****
  pod_type_p (t)
       tree t;
  {
-   tree f;
- 
    while (TREE_CODE (t) == ARRAY_TYPE)
      t = TREE_TYPE (t);
  
!   if (! IS_AGGR_TYPE (t))
      return 1;
! 
!   if (CLASSTYPE_NON_AGGREGATE (t)
!       || TYPE_HAS_COMPLEX_ASSIGN_REF (t)
!       || TYPE_HAS_DESTRUCTOR (t))
      return 0;
- 
-   for (f = TYPE_FIELDS (t); f; f = TREE_CHAIN (f))
-     {
-       if (TREE_CODE (f) != FIELD_DECL)
- 	continue;
- 
-       if (TREE_CODE (TREE_TYPE (f)) == REFERENCE_TYPE
- 	  || TYPE_PTRMEMFUNC_P (TREE_TYPE (f))
- 	  || TYPE_PTRMEM_P (TREE_TYPE (f)))
- 	return 0;
-     }
- 
    return 1;
  }
--- 2673,2684 ----
  pod_type_p (t)
       tree t;
  {
    while (TREE_CODE (t) == ARRAY_TYPE)
      t = TREE_TYPE (t);
  
!   if (! CLASS_TYPE_P (t))
      return 1;
!   if (CLASSTYPE_NON_POD_P (t))
      return 0;
    return 1;
  }
Index: egcs/gcc/cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.150
diff -c -3 -p -r1.150 typeck.c
*** typeck.c	1999/04/02 15:36:57	1.150
--- typeck.c	1999/04/08 13:03:52
*************** static tree convert_sequence PROTO((tree
*** 55,60 ****
--- 55,61 ----
  #endif
  static tree lookup_anon_field PROTO((tree, tree));
  static tree pointer_diff PROTO((tree, tree, tree));
+ static tree build_component_addr PROTO((tree, tree));
  static tree qualify_type PROTO((tree, tree));
  static tree get_delta_difference PROTO((tree, tree, int));
  static int comp_cv_target_types PROTO((tree, tree, int));
*************** build_component_ref (datum, component, b
*** 2035,2040 ****
--- 2036,2042 ----
    register tree ref;
    tree field_type;
    int type_quals;
+   int off_null_ptr = 0;
  
    if (processing_template_decl)
      return build_min_nt (COMPONENT_REF, datum, component);
*************** build_component_ref (datum, component, b
*** 2128,2133 ****
--- 2130,2145 ----
        return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1);
      }
  
+   {
+     /* Determine if this is an offsetof idiom.  */
+     tree probe = datum;
+     
+     while (TREE_CODE (probe) == COMPONENT_REF)
+       probe = TREE_OPERAND (probe, 0);
+     off_null_ptr = (TREE_CODE (probe) == INDIRECT_REF
+                     && integer_zerop (TREE_OPERAND (probe, 0)));
+   }
+ 
    /* Look up component name in the structure type definition.  */
    if (CLASSTYPE_VFIELD (basetype)
        && DECL_NAME (CLASSTYPE_VFIELD (basetype)) == component)
*************** build_component_ref (datum, component, b
*** 2168,2174 ****
  		 now.  Otherwise, we have to wait and see what context it is
  		 used in; a component_ref involving a non-static member
  		 function can only be used in a call (expr.ref).  */
! 
  	      if (TREE_CHAIN (fndecls) == NULL_TREE
  		  && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL)
  		{
--- 2180,2190 ----
  		 now.  Otherwise, we have to wait and see what context it is
  		 used in; a component_ref involving a non-static member
  		 function can only be used in a call (expr.ref).  */
! 	      
! 	      if (off_null_ptr)
!                 cp_warning ("using member function `%D' with NULL ptr to `%#T'",
!                             name, TREE_TYPE (datum));
!               
  	      if (TREE_CHAIN (fndecls) == NULL_TREE
  		  && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL)
  		{
*************** build_component_ref (datum, component, b
*** 2209,2214 ****
--- 2225,2235 ----
  	    mark_used (field);
  	  else
  	    TREE_USED (field) = 1;
+ 
+ 	  if (off_null_ptr && TREE_CODE (field) == VAR_DECL)
+             cp_warning ("using static member `%D' with NULL ptr to `%#T'",
+                         name, TREE_TYPE (datum));
+ 
  	  return field;
  	}
      }
*************** build_component_ref (datum, component, b
*** 2225,2230 ****
--- 2246,2255 ----
  	  base = TYPE_CONTEXT (base);
  	}
  
+       if (base != basetype && off_null_ptr && ! pod_type_p (basetype))
+         cp_warning ("using non-POD type `%#T' with NULL ptr",
+                     basetype);
+ 
        /* Handle base classes here...  */
        if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))
  	{
*************** build_x_function_call (function, params,
*** 2685,2692 ****
  	{
  	  if (current_class_type == NULL_TREE)
  	    {
! 	      error ("object missing in call to method `%s'",
! 		     IDENTIFIER_POINTER (function));
  	      return error_mark_node;
  	    }
  	  /* Yow: call from a static member function.  */
--- 2710,2716 ----
  	{
  	  if (current_class_type == NULL_TREE)
  	    {
! 	      cp_error ("object missing in call to method `%D'", function);
  	      return error_mark_node;
  	    }
  	  /* Yow: call from a static member function.  */
*************** pointer_diff (op0, op1, ptrtype)
*** 4248,4264 ****
  }
  
  /* Handle the case of taking the address of a COMPONENT_REF.
!    Called by `build_unary_op' and `build_up_reference'.
  
     ARG is the COMPONENT_REF whose address we want.
!    ARGTYPE is the pointer type that this address should have.
!    MSG is an error message to print if this COMPONENT_REF is not
!    addressable (such as a bitfield).  */
  
! tree
! build_component_addr (arg, argtype, msg)
       tree arg, argtype;
-      const char *msg;
  {
    tree field = TREE_OPERAND (arg, 1);
    tree basetype = decl_type_context (field);
--- 4272,4285 ----
  }
  
  /* Handle the case of taking the address of a COMPONENT_REF.
!    Called by `build_unary_op'.
  
     ARG is the COMPONENT_REF whose address we want.
!    ARGTYPE is the pointer type that this address should have. */
  
! static tree
! build_component_addr (arg, argtype)
       tree arg, argtype;
  {
    tree field = TREE_OPERAND (arg, 1);
    tree basetype = decl_type_context (field);
*************** build_component_addr (arg, argtype, msg)
*** 4266,4274 ****
  
    my_friendly_assert (TREE_CODE (field) == FIELD_DECL, 981018);
  
    if (DECL_C_BIT_FIELD (field))
      {
!       error (msg, IDENTIFIER_POINTER (DECL_NAME (field)));
        return error_mark_node;
      }
  
--- 4287,4308 ----
  
    my_friendly_assert (TREE_CODE (field) == FIELD_DECL, 981018);
  
+   if (! pod_type_p (basetype))
+     {
+       /* Determine if this is an offsetof idiom.  */
+       tree probe = arg;
+       
+       while (TREE_CODE (probe) == COMPONENT_REF)
+         probe = TREE_OPERAND (probe, 0);
+       if (TREE_CODE (probe) == INDIRECT_REF
+           && integer_zerop (TREE_OPERAND (probe, 0)))
+         cp_warning ("using non-POD type `%#T' with NULL ptr", basetype);
+     }
+ 
    if (DECL_C_BIT_FIELD (field))
      {
!       cp_error ("attempt to take address of bit-field structure member `%D'",
!                 field);
        return error_mark_node;
      }
  
*************** build_unary_op (code, xarg, noconvert)
*** 4731,4739 ****
  	tree addr;
  
  	if (TREE_CODE (arg) == COMPONENT_REF)
! 	  addr = build_component_addr
! 	    (arg, argtype,
! 	     "attempt to take address of bit-field structure member `%s'");
  	else
  	  addr = build1 (ADDR_EXPR, argtype, arg);
  
--- 4765,4771 ----
  	tree addr;
  
  	if (TREE_CODE (arg) == COMPONENT_REF)
! 	  addr = build_component_addr (arg, argtype);
  	else
  	  addr = build1 (ADDR_EXPR, argtype, arg);
  


More information about the Gcc-patches mailing list