This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: Alignment of unions with unnamed fields
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 1 Oct 2002 11:35:56 -0700
- Subject: PATCH: Alignment of unions with unnamed fields
- Reply-to: mark at codesourcery dot com
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;
+ }