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: Alignment of unions with unnamed fields


Everyone seemed to agree that it was a bug that:

  union { int : 0; };

got aligned differently from the correspoding struct.  

Here is the fix.

Bootstrapped and tested on i686-pc-linux-gnu, applied on the mainline.

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

2002-10-01  Mark Mitchell  <mark@codesourcery.com>

	* stor-layout.c (update_alignment_for_field): New function.
	(place_union_field): Use it.
	(place_field): Likewise.

2002-10-01  Mark Mitchell  <mark@codesourcery.com>

	* gcc.dg/empty1.C: New test.

Index: stor-layout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stor-layout.c,v
retrieving revision 1.132
diff -c -p -r1.132 stor-layout.c
*** stor-layout.c	30 Sep 2002 16:52:08 -0000	1.132
--- stor-layout.c	1 Oct 2002 18:34:45 -0000
*************** static int reference_types_internal = 0;
*** 60,65 ****
--- 60,68 ----
  static void finalize_record_size	PARAMS ((record_layout_info));
  static void finalize_type_size		PARAMS ((tree));
  static void place_union_field		PARAMS ((record_layout_info, tree));
+ static unsigned int update_alignment_for_field
+                                         PARAMS ((record_layout_info, tree, 
+ 						 unsigned int));
  extern void debug_rli			PARAMS ((record_layout_info));
  
  /* SAVE_EXPRs for sizes of types and decls, waiting to be expanded.  */
*************** rli_size_so_far (rli)
*** 644,773 ****
    return bit_from_pos (rli->offset, rli->bitpos);
  }
  
! /* Called from place_field to handle unions.  */
  
! static void
! place_union_field (rli, field)
!      record_layout_info rli;
!      tree field;
! {
!   unsigned int desired_align;
! 
!   layout_decl (field, 0);
! 
!   DECL_FIELD_OFFSET (field) = size_zero_node;
!   DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
!   SET_DECL_OFFSET_ALIGN (field, BIGGEST_ALIGNMENT);
! 
!   desired_align = DECL_ALIGN (field);
! 
! #ifdef BIGGEST_FIELD_ALIGNMENT
!   /* Some targets (i.e. i386) limit union field alignment
!      to a lower boundary than alignment of variables unless
!      it was overridden by attribute aligned.  */
!   if (! DECL_USER_ALIGN (field))
!     desired_align =
!       MIN (desired_align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
! #endif
! 
! #ifdef ADJUST_FIELD_ALIGN
!   if (! DECL_USER_ALIGN (field))
!     desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
! #endif
! 
!   TYPE_USER_ALIGN (rli->t) |= DECL_USER_ALIGN (field);
! 
!   /* Union must be at least as aligned as any field requires.  */
!   rli->record_align = MAX (rli->record_align, desired_align);
!   rli->unpadded_align = MAX (rli->unpadded_align, desired_align);
! 
! #ifdef PCC_BITFIELD_TYPE_MATTERS
!   /* On the m88000, a bit field of declare type `int' forces the
!      entire union to have `int' alignment.  */
!   if (PCC_BITFIELD_TYPE_MATTERS && DECL_BIT_FIELD_TYPE (field))
!     {
!       unsigned int type_align = TYPE_ALIGN (TREE_TYPE (field));
! 
! #ifdef ADJUST_FIELD_ALIGN
!       if (! TYPE_USER_ALIGN (TREE_TYPE (field)))
! 	type_align = ADJUST_FIELD_ALIGN (field, type_align);
! #endif
!       rli->record_align = MAX (rli->record_align, type_align);
!       rli->unpadded_align = MAX (rli->unpadded_align, type_align);
!       TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (TREE_TYPE (field));
!     }
! #endif
! 
!   /* We assume the union's size will be a multiple of a byte so we don't
!      bother with BITPOS.  */
!   if (TREE_CODE (rli->t) == UNION_TYPE)
!     rli->offset = size_binop (MAX_EXPR, rli->offset, DECL_SIZE_UNIT (field));
!   else if (TREE_CODE (rli->t) == QUAL_UNION_TYPE)
!     rli->offset = fold (build (COND_EXPR, sizetype,
! 			       DECL_QUALIFIER (field),
! 			       DECL_SIZE_UNIT (field), rli->offset));
! }
! 
! /* RLI contains information about the layout of a RECORD_TYPE.  FIELD
!    is a FIELD_DECL to be added after those fields already present in
!    T.  (FIELD is not actually added to the TYPE_FIELDS list here;
!    callers that desire that behavior must manually perform that step.)  */
! 
! void
! place_field (rli, field)
       record_layout_info rli;
       tree field;
  {
    /* The alignment required for FIELD.  */
    unsigned int desired_align;
-   /* The alignment FIELD would have if we just dropped it into the
-      record as it presently stands.  */
-   unsigned int known_align;
-   unsigned int actual_align;
-   unsigned int user_align;
    /* The type of this field.  */
    tree type = TREE_TYPE (field);
! 
!   if (TREE_CODE (field) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
!       return;
! 
!   /* If FIELD is static, then treat it like a separate variable, not
!      really like a structure field.  If it is a FUNCTION_DECL, it's a
!      method.  In both cases, all we do is lay out the decl, and we do
!      it *after* the record is laid out.  */
!   if (TREE_CODE (field) == VAR_DECL)
!     {
!       rli->pending_statics = tree_cons (NULL_TREE, field,
! 					rli->pending_statics);
!       return;
!     }
! 
!   /* Enumerators and enum types which are local to this class need not
!      be laid out.  Likewise for initialized constant fields.  */
!   else if (TREE_CODE (field) != FIELD_DECL)
!     return;
! 
!   /* Unions are laid out very differently than records, so split
!      that code off to another function.  */
!   else if (TREE_CODE (rli->t) != RECORD_TYPE)
!     {
!       place_union_field (rli, field);
!       return;
!     }
! 
!   /* Work out the known alignment so far.  Note that A & (-A) is the
!      value of the least-significant bit in A that is one.  */
!   if (! integer_zerop (rli->bitpos))
!     known_align = (tree_low_cst (rli->bitpos, 1)
! 		   & - tree_low_cst (rli->bitpos, 1));
!   else if (integer_zerop (rli->offset))
!     known_align = BIGGEST_ALIGNMENT;
!   else if (host_integerp (rli->offset, 1))
!     known_align = (BITS_PER_UNIT
! 		   * (tree_low_cst (rli->offset, 1)
! 		      & - tree_low_cst (rli->offset, 1)));
!   else
!     known_align = rli->offset_align;
  
    /* Lay out the field so we know what alignment it needs.  For a
       packed field, use the alignment as specified, disregarding what
--- 647,669 ----
    return bit_from_pos (rli->offset, rli->bitpos);
  }
  
! /* FIELD is about to be added to RLI->T.  The alignment (in bits) of
!    the next available location is given by KNOWN_ALIGN.  Update the
!    variable alignment fields in RLI, and return the alignment to give
!    the FIELD.  */
  
! static unsigned int
! update_alignment_for_field (rli, field, known_align)
       record_layout_info rli;
       tree field;
+      unsigned int known_align;
  {
    /* The alignment required for FIELD.  */
    unsigned int desired_align;
    /* The type of this field.  */
    tree type = TREE_TYPE (field);
!   /* True if the field was explicitly aligned by the user.  */
!   bool user_align;
  
    /* Lay out the field so we know what alignment it needs.  For a
       packed field, use the alignment as specified, disregarding what
*************** place_field (rli, field)
*** 785,797 ****
       to a lower boundary than alignment of variables unless
       it was overridden by attribute aligned.  */
  #ifdef BIGGEST_FIELD_ALIGNMENT
!   if (! user_align)
      desired_align
        = MIN (desired_align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
  #endif
  
  #ifdef ADJUST_FIELD_ALIGN
!   if (! user_align)
      desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
  #endif
  
--- 681,693 ----
       to a lower boundary than alignment of variables unless
       it was overridden by attribute aligned.  */
  #ifdef BIGGEST_FIELD_ALIGNMENT
!   if (!user_align)
      desired_align
        = MIN (desired_align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
  #endif
  
  #ifdef ADJUST_FIELD_ALIGN
!   if (!user_align)
      desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
  #endif
  
*************** place_field (rli, field)
*** 873,878 ****
--- 769,864 ----
        rli->unpadded_align = MAX (rli->unpadded_align, DECL_ALIGN (field));
      }
  
+   TYPE_USER_ALIGN (rli->t) |= user_align;
+ 
+   return desired_align;
+ }
+ 
+ /* Called from place_field to handle unions.  */
+ 
+ static void
+ place_union_field (rli, field)
+      record_layout_info rli;
+      tree field;
+ {
+   update_alignment_for_field (rli, field, /*known_align=*/0);
+ 
+   DECL_FIELD_OFFSET (field) = size_zero_node;
+   DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
+   SET_DECL_OFFSET_ALIGN (field, BIGGEST_ALIGNMENT);
+ 
+   /* We assume the union's size will be a multiple of a byte so we don't
+      bother with BITPOS.  */
+   if (TREE_CODE (rli->t) == UNION_TYPE)
+     rli->offset = size_binop (MAX_EXPR, rli->offset, DECL_SIZE_UNIT (field));
+   else if (TREE_CODE (rli->t) == QUAL_UNION_TYPE)
+     rli->offset = fold (build (COND_EXPR, sizetype,
+ 			       DECL_QUALIFIER (field),
+ 			       DECL_SIZE_UNIT (field), rli->offset));
+ }
+ 
+ /* RLI contains information about the layout of a RECORD_TYPE.  FIELD
+    is a FIELD_DECL to be added after those fields already present in
+    T.  (FIELD is not actually added to the TYPE_FIELDS list here;
+    callers that desire that behavior must manually perform that step.)  */
+ 
+ void
+ place_field (rli, field)
+      record_layout_info rli;
+      tree field;
+ {
+   /* The alignment required for FIELD.  */
+   unsigned int desired_align;
+   /* The alignment FIELD would have if we just dropped it into the
+      record as it presently stands.  */
+   unsigned int known_align;
+   unsigned int actual_align;
+   /* The type of this field.  */
+   tree type = TREE_TYPE (field);
+ 
+   if (TREE_CODE (field) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
+       return;
+ 
+   /* If FIELD is static, then treat it like a separate variable, not
+      really like a structure field.  If it is a FUNCTION_DECL, it's a
+      method.  In both cases, all we do is lay out the decl, and we do
+      it *after* the record is laid out.  */
+   if (TREE_CODE (field) == VAR_DECL)
+     {
+       rli->pending_statics = tree_cons (NULL_TREE, field,
+ 					rli->pending_statics);
+       return;
+     }
+ 
+   /* Enumerators and enum types which are local to this class need not
+      be laid out.  Likewise for initialized constant fields.  */
+   else if (TREE_CODE (field) != FIELD_DECL)
+     return;
+ 
+   /* Unions are laid out very differently than records, so split
+      that code off to another function.  */
+   else if (TREE_CODE (rli->t) != RECORD_TYPE)
+     {
+       place_union_field (rli, field);
+       return;
+     }
+ 
+   /* Work out the known alignment so far.  Note that A & (-A) is the
+      value of the least-significant bit in A that is one.  */
+   if (! integer_zerop (rli->bitpos))
+     known_align = (tree_low_cst (rli->bitpos, 1)
+ 		   & - tree_low_cst (rli->bitpos, 1));
+   else if (integer_zerop (rli->offset))
+     known_align = BIGGEST_ALIGNMENT;
+   else if (host_integerp (rli->offset, 1))
+     known_align = (BITS_PER_UNIT
+ 		   * (tree_low_cst (rli->offset, 1)
+ 		      & - tree_low_cst (rli->offset, 1)));
+   else
+     known_align = rli->offset_align;
+   
+   desired_align = update_alignment_for_field (rli, field, known_align);
+ 
    if (warn_packed && DECL_PACKED (field))
      {
        if (known_align > TYPE_ALIGN (type))
*************** place_field (rli, field)
*** 956,962 ****
  	  > tree_low_cst (TYPE_SIZE (type), 1) / type_align)
  	rli->bitpos = round_up (rli->bitpos, type_align);
  
!       user_align |= TYPE_USER_ALIGN (type);
      }
  #endif
  
--- 942,948 ----
  	  > tree_low_cst (TYPE_SIZE (type), 1) / type_align)
  	rli->bitpos = round_up (rli->bitpos, type_align);
  
!       TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (type);
      }
  #endif
  
*************** place_field (rli, field)
*** 999,1005 ****
  	      / type_align))
  	rli->bitpos = round_up (rli->bitpos, type_align);
  
!       user_align |= TYPE_USER_ALIGN (type);
      }
  #endif
  
--- 985,991 ----
  	      / type_align))
  	rli->bitpos = round_up (rli->bitpos, type_align);
  
!       TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (type);
      }
  #endif
  
*************** place_field (rli, field)
*** 1152,1159 ****
    DECL_FIELD_OFFSET (field) = rli->offset;
    DECL_FIELD_BIT_OFFSET (field) = rli->bitpos;
    SET_DECL_OFFSET_ALIGN (field, rli->offset_align);
- 
-   TYPE_USER_ALIGN (rli->t) |= user_align;
  
    /* If this field ended up more aligned than we thought it would be (we
       approximate this by seeing if its position changed), lay out the field
--- 1138,1143 ----
Index: testsuite/gcc.dg/empty1.c
===================================================================
RCS file: testsuite/gcc.dg/empty1.c
diff -N testsuite/gcc.dg/empty1.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/empty1.c	1 Oct 2002 18:38:39 -0000
***************
*** 0 ****
--- 1,10 ----
+ /* { dg-do run } */
+ /* { dg-options "" } */
+ 
+ struct S { int : 0; };
+ union U { int : 0; };
+ 
+ int main () {
+   if (__alignof__ (struct S) != __alignof__ (union U))
+     return 1;
+ }


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