C++ PATCH: Check pod-class

Nathan Sidwell nathan@acm.org
Tue Aug 3 08:10:00 GMT 1999


Hi,
I've applied the attached patch originally submitted as
http://egcs.cygnus.com/ml/gcc-patches/1999-04/msg00388.html . This adds a
non_pod_class flag into the lang_type struct, and reimplements pod_type_p to
use that.

This version is slightly different from the original, because Mark Mitchell
pointed out that not all non-class types are POD (references and functions
aren't POD).

In doing this, I noticed something strange. Pointers to member types are a
scalar type and therefore POD [3.9/10]. Yet a class containing such a type is
non-POD [9/4]. I consider this a defect, so submitted a defect report.

Some tests in g++.brendan needed patching to expect a POD warning (also
attached).

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
        I have seen the death of PhotoShop -- it is called GIMP
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
Index: egcs/gcc/cp/ChangeLog
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/ChangeLog,v
retrieving revision 1.1161
diff -c -3 -p -r1.1161 ChangeLog
*** ChangeLog	1999/08/03 14:45:15	1.1161
--- ChangeLog	1999/08/03 14:58:24
***************
*** 1,5 ****
--- 1,16 ----
  1999-08-03  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.
+ 	* class.c (finish_struct_1): Determine non-PODness.
+ 	Check for arrays of pointers (-Weffc++).
+ 	Remove array inspection duplicated code.
+ 	* tree.c (pod_type_p): Detect non-pod non-aggregate types.
+ 	Use CLASSTYPE_NON_POD_P.
+ 
+ 1999-08-03  Nathan Sidwell  <nathan@acm.org>
+ 
  	* class.c (duplicate_tag_error): Preserve template information.
  
  1999-08-03  Nathan Sidwell  <nathan@acm.org>
Index: egcs/gcc/cp/call.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/call.c,v
retrieving revision 1.159
diff -c -3 -p -r1.159 call.c
*** call.c	1999/08/03 10:18:11	1.159
--- call.c	1999/08/03 14:58:28
*************** convert_like (convs, expr)
*** 3752,3772 ****
  }
  
  /* 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);
--- 3752,3776 ----
  }
  
  /* 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)))
+     {
+       /* Undefined behaviour [expr.call] 5.2.2/7.  */
+       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/cp-tree.h
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.253
diff -c -3 -p -r1.253 cp-tree.h
*** cp-tree.h	1999/08/03 01:37:45	1.253
--- cp-tree.h	1999/08/03 14:58:33
*************** struct lang_type
*** 802,807 ****
--- 802,808 ----
        unsigned is_partial_instantiation : 1;
        unsigned has_mutable : 1;
        unsigned com_interface : 1;
+       unsigned non_pod_class : 1;
        /* When adding a flag here, consider whether or not it ought to
  	 apply to a template instance if it applies to the template.
  	 If so, make sure to copy it in instantiate_class_template!  */
*************** struct lang_type
*** 809,815 ****
        /* 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;
--- 810,816 ----
        /* 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 : 9;
      } type_flags;
  
    int vsize;
*************** struct lang_type
*** 1075,1080 ****
--- 1076,1084 ----
  /* Nonzero means that this type contains a mutable member */
  #define CLASSTYPE_HAS_MUTABLE(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_mutable)
  #define TYPE_HAS_MUTABLE_P(NODE) (cp_has_mutable_p (NODE))
+ 
+ /*  Nonzero means that this class type is a non-POD class.  */
+ #define CLASSTYPE_NON_POD_P(NODE) (TYPE_LANG_SPECIFIC (NODE)->type_flags.non_pod_class)
  
  /* Nonzero means that this type is meant for communication via COM.  */
  #define CLASSTYPE_COM_INTERFACE(NODE) \
Index: egcs/gcc/cp/class.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/class.c,v
retrieving revision 1.171
diff -c -3 -p -r1.171 class.c
*** class.c	1999/08/03 14:45:20	1.171
--- class.c	1999/08/03 14:58:38
*************** finish_struct_1 (t)
*** 3297,3302 ****
--- 3297,3303 ----
    int no_const_asn_ref;
    int has_mutable = 0;
    int n_fields = 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)
*** 3431,3436 ****
--- 3432,3438 ----
    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)
*** 3472,3492 ****
  
        /* 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
--- 3474,3497 ----
  
        /* 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)
*** 3494,3500 ****
  	cant_have_default_ctor = 1;
  #endif
  
!       if (TREE_TYPE (x) == error_mark_node)
  	continue;
  	  
        DECL_SAVED_INSNS (x) = NULL_RTX;
--- 3499,3505 ----
  	cant_have_default_ctor = 1;
  #endif
  
!       if (type == error_mark_node)
  	continue;
  	  
        DECL_SAVED_INSNS (x) = NULL_RTX;
*************** finish_struct_1 (t)
*** 3522,3529 ****
  
        /* If this is of reference type, check if it needs an init.
  	 Also do a little ANSI jig if necessary.  */
!       if (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE)
   	{
  	  if (DECL_INITIAL (x) == NULL_TREE)
  	    ref_sans_init = 1;
  
--- 3527,3536 ----
  
        /* If this is of reference type, check if it needs an init.
  	 Also do a little ANSI jig if necessary.  */
!       if (TREE_CODE (type) == REFERENCE_TYPE)
   	{
+           non_pod_class = 1;
+           
  	  if (DECL_INITIAL (x) == NULL_TREE)
  	    ref_sans_init = 1;
  
*************** finish_struct_1 (t)
*** 3543,3556 ****
  	    }
  	}
  
!       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 (CP_TYPE_CONST_P (TREE_TYPE (x)))
  	{
  	  C_TYPE_FIELDS_READONLY (t) = 1;
  	  if (DECL_INITIAL (x) == NULL_TREE)
--- 3550,3570 ----
  	    }
  	}
  
!       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 (CP_TYPE_CONST_P (type))
  	{
  	  C_TYPE_FIELDS_READONLY (t) = 1;
  	  if (DECL_INITIAL (x) == NULL_TREE)
*************** finish_struct_1 (t)
*** 3576,3589 ****
  	{
  	  /* 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;
  	    }
  	}
--- 3590,3600 ----
  	{
  	  /* 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)
*** 3593,3599 ****
        if (DECL_C_BIT_FIELD (x))
  	{
  	  /* Invalid bit-field size done by grokfield.  */
! 	  /* Detect invalid bit-field type.  */
  	  if (DECL_INITIAL (x)
  	      && ! INTEGRAL_TYPE_P (TREE_TYPE (x)))
  	    {
--- 3604,3613 ----
        if (DECL_C_BIT_FIELD (x))
  	{
  	  /* Invalid bit-field size done by grokfield.  */
! 	  /* Detect invalid bit-field type. Simply checking if TYPE is
!              integral is insufficient, as that is the array core of the
!              field type. If TREE_TYPE (x) is integral, then TYPE must be
!              the same.  */
  	  if (DECL_INITIAL (x)
  	      && ! INTEGRAL_TYPE_P (TREE_TYPE (x)))
  	    {
*************** finish_struct_1 (t)
*** 3643,3662 ****
  			 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))
--- 3657,3676 ----
  			 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)
*** 3674,3695 ****
  #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 (CLASS_TYPE_P (type) && ! ANON_AGGR_TYPE_P (type))
  	    {
  	      /* Never let anything with uninheritable virtuals
--- 3688,3704 ----
  #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 (CLASS_TYPE_P (type) && ! ANON_AGGR_TYPE_P (type))
  	    {
  	      /* Never let anything with uninheritable virtuals
*************** finish_struct_1 (t)
*** 3792,3797 ****
--- 3801,3809 ----
    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/tree.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/tree.c,v
retrieving revision 1.120
diff -c -3 -p -r1.120 tree.c
*** tree.c	1999/07/27 18:15:21	1.120
--- tree.c	1999/08/03 14:58:39
*************** int
*** 2749,2778 ****
  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;
  }
  
--- 2749,2772 ----
  pod_type_p (t)
       tree t;
  {
    while (TREE_CODE (t) == ARRAY_TYPE)
      t = TREE_TYPE (t);
  
!   if (INTEGRAL_TYPE_P (t))
!     return 1;  /* integral, character or enumeral type */
!   if (FLOAT_TYPE_P (t))
      return 1;
!   if (TYPE_PTR_P (t))
!     return 1; /* pointer to non-member */
!   if (TYPE_PTRMEM_P (t))
!     return 1; /* pointer to member object */
!   if (TYPE_PTRMEMFUNC_P (t))
!     return 1; /* pointer to member function */
!   
!   if (! CLASS_TYPE_P (t))
!     return 0; /* other non-class type (reference or function) */
!   if (CLASSTYPE_NON_POD_P (t))
      return 0;
    return 1;
  }
  


More information about the Gcc-patches mailing list