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]

C++ PATCH: New ABI pointers-to-members



This patch contains a test-case for some of the trick empty-base class
layout aspects of the new ABI.  If any of the folks out there that are
interested in the new ABI would like to write more test-cases like
this to test the class layout code (which should be pretty much done
at this point), plesae go for it.  That would be really useful.

I've also fixed the way pointers-to-members are defined in the new
ABI.  I'd misinterpreted the ABI draft the last time ago, and we've
now nailed down how to represent a NULL pointer-to-data member.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

Index: testsuite/g++.old-deja/g++.abi/empty.C
===================================================================
RCS file: empty.C
diff -N empty.C
*** /dev/null	Tue May  5 13:32:27 1998
--- empty.C	Sat Mar 18 20:30:59 2000
***************
*** 0 ****
--- 1,68 ----
+ // Special g++ Options: -w
+ // Origin: Mark Mitchell <mark@codesourcery.com>
+ 
+ #if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
+ 
+ struct S0
+ {
+ };
+ 
+ struct S1 : public S0
+ {
+ };
+ 
+ struct S2 : public S1
+ {
+   char c;
+ };
+ 
+ // In S3, the S1 instance is allocated first at offset zero.  The S2
+ // instance has to be allocated at a subsequent offset; it's first
+ // part is also an S1.
+ 
+ struct S3 : public S1, public S2
+ {
+ };
+ 
+ struct S4 
+ {
+   int i;
+ };
+ 
+ // In S4, in contrast to S3, S2 is allocated first, and S1 can be
+ // allocated on top of S4.
+ 
+ struct S5 : public S2, public S1, public S4
+ {
+ };
+ 
+ // The T classes are by-hand layouts that should be equivalent to the
+ // S classes.
+ 
+ struct T3
+ {
+   S1 s1;
+   S2 s2;
+ };
+ 
+ struct T5
+ {
+   S2 s2;
+   S4 s4;
+ };
+ 
+ int main ()
+ {
+   if (sizeof (S3) != sizeof (T3))
+     return 1;
+   else if (sizeof (S5) != sizeof (T5))
+     return 2;
+ }
+ 
+ #else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
+ 
+ int main () 
+ {
+ }
+ 
+ #endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
Index: testsuite/g++.old-deja/g++.abi/ptrmem.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C,v
retrieving revision 1.2
diff -c -p -r1.2 ptrmem.C
*** ptrmem.C	2000/02/22 22:47:56	1.2
--- ptrmem.C	2000/03/19 04:30:59
*************** main ()
*** 82,97 ****
    if (xp->adj != delta)
      return 8;
  
!   // For a virtual function, we should see twice the vtable index,
!   // plus one.  `T::h' is in the third slot: there's the RTTI entry,
!   // then the two virtual functions.
    y = &T::h;
!   if ((ptrdiff_t) yp->ptr != 7)
      return 9;
    if (yp->adj != 0)
      return 10;
    x = (sp) y;
!   if ((ptrdiff_t) xp->ptr != 7)
      return 11;
    if (xp->adj != delta)
      return 12;
--- 82,97 ----
    if (xp->adj != delta)
      return 8;
  
!   // For a virtual function, we should see the vtable offset, plus
!   // one.  `T::h' is in the second slot: the vtable pointer points to
!   // the first virtual function.
    y = &T::h;
!   if ((ptrdiff_t) yp->ptr != sizeof (void *) + 1)
      return 9;
    if (yp->adj != 0)
      return 10;
    x = (sp) y;
!   if ((ptrdiff_t) xp->ptr != sizeof (void *) + 1)
      return 11;
    if (xp->adj != delta)
      return 12;
*************** main ()
*** 103,111 ****
    if (__alignof__ (sdp) != __alignof__ (ptrdiff_t))
      return 14;
  
    sdp z = &S::j;
!   if ((char *) &s.j - (char *) &s != *((ptrdiff_t *) &z) - 1)
      return 15;
  }
  
  #else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
--- 103,116 ----
    if (__alignof__ (sdp) != __alignof__ (ptrdiff_t))
      return 14;
  
+   // The value of a pointer-to-data member should be the offset from
+   // the start of the structure.
    sdp z = &S::j;
!   if ((char *) &s.j - (char *) &s != *((ptrdiff_t *) &z))
      return 15;
+   z = 0;
+   if (*((ptrdiff_t *) &z) != -1)
+     return 16;
  }
  
  #else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.272
diff -c -p -r1.272 class.c
*** class.c	2000/03/19 00:59:51	1.272
--- class.c	2000/03/19 04:30:43
*************** check_bitfield_decl (field)
*** 3616,3637 ****
       tree field;
  {
    tree type = TREE_TYPE (field);
  
!   /* 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 (field) is integral, then TYPE must be the same.  */
    if (DECL_INITIAL (field)
        && ! INTEGRAL_TYPE_P (TREE_TYPE (field)))
      {
        cp_error_at ("bit-field `%#D' with non-integral type", field);
!       DECL_INITIAL (field) = NULL;
      }
  
    /* Detect and ignore out of range field width.  */
    if (DECL_INITIAL (field))
      {
!       tree w = DECL_INITIAL (field);
  
        /* Avoid the non_lvalue wrapper added by fold for PLUS_EXPRs.  */
        STRIP_NOPS (w);
--- 3616,3635 ----
       tree field;
  {
    tree type = TREE_TYPE (field);
+   tree w = NULL_TREE;
  
!   /* Detect invalid bit-field type.  */
    if (DECL_INITIAL (field)
        && ! INTEGRAL_TYPE_P (TREE_TYPE (field)))
      {
        cp_error_at ("bit-field `%#D' with non-integral type", field);
!       w = error_mark_node;
      }
  
    /* Detect and ignore out of range field width.  */
    if (DECL_INITIAL (field))
      {
!       w = DECL_INITIAL (field);
  
        /* Avoid the non_lvalue wrapper added by fold for PLUS_EXPRs.  */
        STRIP_NOPS (w);
*************** check_bitfield_decl (field)
*** 3646,3662 ****
  	{
  	  cp_error_at ("bit-field `%D' width not an integer constant",
  		       field);
! 	  DECL_INITIAL (field) = NULL_TREE;
  	}
        else if (tree_int_cst_sgn (w) < 0)
  	{
- 	  DECL_INITIAL (field) = NULL;
  	  cp_error_at ("negative width in bit-field `%D'", field);
  	}
        else if (integer_zerop (w) && DECL_NAME (field) != 0)
  	{
- 	  DECL_INITIAL (field) = NULL;
  	  cp_error_at ("zero width for bit-field `%D'", field);
  	}
        else if (compare_tree_int (w, TYPE_PRECISION (type)) > 0
  	       && TREE_CODE (type) != ENUMERAL_TYPE
--- 3644,3660 ----
  	{
  	  cp_error_at ("bit-field `%D' width not an integer constant",
  		       field);
! 	  w = error_mark_node;
  	}
        else if (tree_int_cst_sgn (w) < 0)
  	{
  	  cp_error_at ("negative width in bit-field `%D'", field);
+ 	  w = error_mark_node;
  	}
        else if (integer_zerop (w) && DECL_NAME (field) != 0)
  	{
  	  cp_error_at ("zero width for bit-field `%D'", field);
+ 	  w = error_mark_node;
  	}
        else if (compare_tree_int (w, TYPE_PRECISION (type)) > 0
  	       && TREE_CODE (type) != ENUMERAL_TYPE
*************** check_bitfield_decl (field)
*** 3672,3701 ****
  					      TREE_UNSIGNED (type)))))
  	cp_warning_at ("`%D' is too small to hold all values of `%#T'",
  		       field, type);
  
!       if (DECL_INITIAL (field))
! 	{
! 	  DECL_INITIAL (field) = NULL_TREE;
! 	  DECL_SIZE (field) = convert (bitsizetype, w);
! 	  DECL_BIT_FIELD (field) = 1;
  
! 	  if (integer_zerop (w))
! 	    {
  #ifdef EMPTY_FIELD_BOUNDARY
! 	      DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
! 					EMPTY_FIELD_BOUNDARY);
  #endif
  #ifdef PCC_BITFIELD_TYPE_MATTERS
! 	      if (PCC_BITFIELD_TYPE_MATTERS)
! 		DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
! 					  TYPE_ALIGN (type));
  #endif
- 	    }
  	}
      }
    else
!     /* Non-bit-fields are aligned for their type.  */
!     DECL_ALIGN (field) = MAX (DECL_ALIGN (field), TYPE_ALIGN (type));
  }
  
  /* FIELD is a non bit-field.  We are finishing the processing for its
--- 3670,3706 ----
  					      TREE_UNSIGNED (type)))))
  	cp_warning_at ("`%D' is too small to hold all values of `%#T'",
  		       field, type);
+     }
+   
+   /* Remove the bit-field width indicator so that the rest of the
+      compiler does not treat that value as an initializer.  */
+   DECL_INITIAL (field) = NULL_TREE;
  
!   if (w != error_mark_node)
!     {
!       DECL_SIZE (field) = convert (bitsizetype, w);
!       DECL_BIT_FIELD (field) = 1;
  
!       if (integer_zerop (w))
! 	{
  #ifdef EMPTY_FIELD_BOUNDARY
! 	  DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
! 				    EMPTY_FIELD_BOUNDARY);
  #endif
  #ifdef PCC_BITFIELD_TYPE_MATTERS
! 	  if (PCC_BITFIELD_TYPE_MATTERS)
! 	    DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
! 				      TYPE_ALIGN (type));
  #endif
  	}
      }
    else
!     {
!       /* Non-bit-fields are aligned for their type.  */
!       DECL_BIT_FIELD (field) = 0;
!       CLEAR_DECL_C_BIT_FIELD (field);
!       DECL_ALIGN (field) = MAX (DECL_ALIGN (field), TYPE_ALIGN (type));
!     }
  }
  
  /* FIELD is a non bit-field.  We are finishing the processing for its
*************** dfs_propagate_binfo_offsets (binfo, data
*** 4678,4684 ****
    tree offset = (tree) data;
  
    /* Update the BINFO_OFFSET for this base.  */
!   BINFO_OFFSET (binfo) = size_binop (PLUS_EXPR, BINFO_OFFSET (binfo), offset);
  
    SET_BINFO_MARKED (binfo);
  
--- 4683,4692 ----
    tree offset = (tree) data;
  
    /* Update the BINFO_OFFSET for this base.  */
!   BINFO_OFFSET (binfo) = fold (build (PLUS_EXPR,
! 				      sizetype,
! 				      BINFO_OFFSET (binfo), 
! 				      offset));
  
    SET_BINFO_MARKED (binfo);
  
*************** dfs_set_offset_for_unshared_vbases (binf
*** 4744,4751 ****
        tree offset;
        
        vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), t);
!       offset = size_binop (MINUS_EXPR, 
! 			   BINFO_OFFSET (vbase), BINFO_OFFSET (binfo));
        propagate_binfo_offsets (binfo, offset);
      }
  
--- 4752,4758 ----
        tree offset;
        
        vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), t);
!       offset = size_diffop (BINFO_OFFSET (vbase), BINFO_OFFSET (binfo));
        propagate_binfo_offsets (binfo, offset);
      }
  
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.420
diff -c -p -r1.420 cp-tree.h
*** cp-tree.h	2000/03/17 17:31:56	1.420
--- cp-tree.h	2000/03/19 04:30:47
*************** extern int flag_new_for_scope;
*** 2347,2352 ****
--- 2347,2354 ----
     && DECL_LANG_SPECIFIC (NODE)->decl_flags.bitfield)
  #define SET_DECL_C_BIT_FIELD(NODE) \
    (DECL_LANG_SPECIFIC (FIELD_DECL_CHECK (NODE))->decl_flags.bitfield = 1)
+ #define CLEAR_DECL_C_BIT_FIELD(NODE) \
+   (DECL_LANG_SPECIFIC (FIELD_DECL_CHECK (NODE))->decl_flags.bitfield = 0)
  
  /* In a FUNCTION_DECL, nonzero if the function cannot be inlined.  */
  #define DECL_UNINLINABLE(NODE) \
Index: cp/cvt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cvt.c,v
retrieving revision 1.77
diff -c -p -r1.77 cvt.c
*** cvt.c	2000/02/27 21:39:37	1.77
--- cvt.c	2000/03/19 04:30:48
*************** cp_convert_to_pointer (type, expr)
*** 240,246 ****
      {
        if (TYPE_PTRMEMFUNC_P (type))
  	return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
!       expr = build_int_2 (0, 0);
        TREE_TYPE (expr) = type;
        return expr;
      }
--- 240,252 ----
      {
        if (TYPE_PTRMEMFUNC_P (type))
  	return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
! 
!       if (flag_new_abi && TYPE_PTRMEM_P (type))
! 	/* Under the new ABI, a NULL pointer-to-member is represented
! 	   by -1, not by zero.  */
! 	expr = build_int_2 (-1, -1);
!       else
! 	expr = build_int_2 (0, 0);
        TREE_TYPE (expr) = type;
        return expr;
      }
Index: cp/expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/expr.c,v
retrieving revision 1.46
diff -c -p -r1.46 expr.c
*** expr.c	2000/03/17 17:31:56	1.46
--- expr.c	2000/03/19 04:30:48
*************** cplus_expand_constant (cst)
*** 65,75 ****
  					  bit_position (member),
  					  bitsize_int (BITS_PER_UNIT)));
  
! 	    /* We offset all pointer to data members by 1 so that we
! 	       can distinguish between a null pointer to data member
! 	       and the first data member of a structure.  */
! 	    offset = size_binop (PLUS_EXPR, offset, size_one_node);
! 	    cst = cp_convert (type, offset);
  	  }
  	else
  	  {
--- 65,82 ----
  					  bit_position (member),
  					  bitsize_int (BITS_PER_UNIT)));
  
! 	    if (flag_new_abi)
! 	      /* Under the new ABI, we use -1 to represent the NULL
! 		 pointer; non-NULL values simply contain the offset of
! 		 the data member.  */
! 	      ;
! 	    else
! 	      /* We offset all pointer to data members by 1 so that we
! 		 can distinguish between a null pointer to data member
! 		 and the first data member of a structure.  */
! 	      offset = size_binop (PLUS_EXPR, offset, size_one_node);
! 
! 	    cst = fold (build1 (NOP_EXPR, type, offset));
  	  }
  	else
  	  {
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.175
diff -c -p -r1.175 init.c
*** init.c	2000/03/17 17:31:56	1.175
--- init.c	2000/03/19 04:30:50
*************** resolve_offset_ref (exp)
*** 1821,1831 ****
        addr = convert_pointer_to (basetype, addr);
        member = cp_convert (ptrdiff_type_node, member);
  
!       /* Pointer to data members are offset by one, so that a null
! 	 pointer with a real value of 0 is distinguishable from an
! 	 offset of the first member of a structure.  */
!       member = build_binary_op (MINUS_EXPR, member,
! 				cp_convert (ptrdiff_type_node, integer_one_node));
  
        return build1 (INDIRECT_REF, type,
  		     build (PLUS_EXPR, build_pointer_type (type),
--- 1821,1833 ----
        addr = convert_pointer_to (basetype, addr);
        member = cp_convert (ptrdiff_type_node, member);
  
!       if (!flag_new_abi)
! 	/* Pointer to data members are offset by one, so that a null
! 	   pointer with a real value of 0 is distinguishable from an
! 	   offset of the first member of a structure.  */
! 	member = build_binary_op (MINUS_EXPR, member,
! 				  cp_convert (ptrdiff_type_node, 
! 					      integer_one_node));
  
        return build1 (INDIRECT_REF, type,
  		     build (PLUS_EXPR, build_pointer_type (type),
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.266
diff -c -p -r1.266 typeck.c
*** typeck.c	2000/03/17 17:31:56	1.266
--- typeck.c	2000/03/19 04:30:59
*************** get_member_function_from_ptrfunc (instan
*** 2858,2864 ****
  	{
  	  idx = build_binary_op (TRUNC_DIV_EXPR, 
  				 build1 (NOP_EXPR, vtable_index_type, e3),
! 				 integer_two_node);
  	  e1 = build_binary_op (BIT_AND_EXPR,
  				build1 (NOP_EXPR, vtable_index_type, e3),
  				integer_one_node);
--- 2858,2864 ----
  	{
  	  idx = build_binary_op (TRUNC_DIV_EXPR, 
  				 build1 (NOP_EXPR, vtable_index_type, e3),
! 				 TYPE_SIZE_UNIT (vtable_entry_type));
  	  e1 = build_binary_op (BIT_AND_EXPR,
  				build1 (NOP_EXPR, vtable_index_type, e3),
  				integer_one_node);
*************** expand_ptrmemfunc_cst (cst, delta, idx, 
*** 6332,6342 ****
  	}
        else
  	{
! 	  /* Under the new ABI, we set PFN to twice the index, plus
! 	     one.  */
  	  *idx = NULL_TREE;
  	  *pfn = fold (build (MULT_EXPR, integer_type_node,
! 			      DECL_VINDEX (fn), integer_two_node));
  	  *pfn = fold (build (PLUS_EXPR, integer_type_node, *pfn,
  			      integer_one_node));
  	  *pfn = fold (build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
--- 6332,6343 ----
  	}
        else
  	{
! 	  /* Under the new ABI, we set PFN to the vtable offset, plus
! 	     one, at which the function can be found.  */
  	  *idx = NULL_TREE;
  	  *pfn = fold (build (MULT_EXPR, integer_type_node,
! 			      DECL_VINDEX (fn), 
! 			      TYPE_SIZE_UNIT (vtable_entry_type)));
  	  *pfn = fold (build (PLUS_EXPR, integer_type_node, *pfn,
  			      integer_one_node));
  	  *pfn = fold (build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),

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