[Ada] Disable DECL_BIT_FIELD_REPRESENTATIVE machinery in some cases

Message ID 8567951.N08qWEOn1i@polaris
State New
Headers show
Series
  • [Ada] Disable DECL_BIT_FIELD_REPRESENTATIVE machinery in some cases
Related show

Commit Message

Eric Botcazou Nov. 8, 2018, 3:19 p.m.
We can have quite convoluted layouts in Ada when a representation clause is 
given for a record type with variant part and this doesn't always play nice 
with the DECL_BIT_FIELD_REPRESENTATIVE machinery.  This patch arranges for 
DECL_BIT_FIELD_TYPE to be cleared on the variant part in these cases.

Tested on x86_64-suse-linux, applied on the mainline.


2018-11-08  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc-interface/decl.c (components_to_record): Remove obsolete kludge.
	* gcc-interface/utils.c (make_packable_type): Set TYPE_PACKED on the
	new type but do not take into account the setting on the old type for
	the new fields.  Rename a local variable.
	(finish_record_type): Clear DECL_BIT_FIELD_TYPE on a variant part at
	offset 0, if any.
	(create_field_decl): Tweak comment.

Patch

Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 265866)
+++ gcc-interface/decl.c	(working copy)
@@ -8146,23 +8146,7 @@  components_to_record (Node_Id gnat_compo
 
   /* Chain the variant part at the end of the field list.  */
   if (gnu_variant_part)
-    {
-      /* We make an exception if the variant part is at offset 0, has a fixed
-	 size, and there is a single rep'ed field placed after it because, in
-	 this case, there is an obvious order of increasing position.  */
-      if (variants_have_rep
-	  && TREE_CODE (DECL_SIZE_UNIT (gnu_variant_part)) == INTEGER_CST
-	  && gnu_rep_list
-	  && gnu_field_list == gnu_rep_list
-	  && !tree_int_cst_lt (DECL_FIELD_OFFSET (gnu_rep_list),
-			       DECL_SIZE_UNIT (gnu_variant_part)))
-	{
-	  DECL_CHAIN (gnu_variant_part) = gnu_field_list;
-	  gnu_field_list = gnu_variant_part;
-	}
-      else
-	gnu_field_list = chainon (gnu_field_list, gnu_variant_part);
-    }
+    gnu_field_list = chainon (gnu_field_list, gnu_variant_part);
 
   if (cancel_alignment)
     SET_TYPE_ALIGN (gnu_record_type, 0);
Index: gcc-interface/utils.c
===================================================================
--- gcc-interface/utils.c	(revision 265866)
+++ gcc-interface/utils.c	(working copy)
@@ -973,6 +973,7 @@  make_packable_type (tree type, bool in_r
      Note that we rely on the pointer equality created here for
      TYPE_NAME to look through conversions in various places.  */
   TYPE_NAME (new_type) = TYPE_NAME (type);
+  TYPE_PACKED (new_type) = 1;
   TYPE_JUSTIFIED_MODULAR_P (new_type) = TYPE_JUSTIFIED_MODULAR_P (type);
   TYPE_CONTAINS_TEMPLATE_P (new_type) = TYPE_CONTAINS_TEMPLATE_P (type);
   TYPE_REVERSE_STORAGE_ORDER (new_type) = TYPE_REVERSE_STORAGE_ORDER (type);
@@ -1018,7 +1019,7 @@  make_packable_type (tree type, bool in_r
   for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     {
       tree new_field_type = TREE_TYPE (field);
-      tree new_field, new_size;
+      tree new_field, new_field_size;
 
       if (RECORD_OR_UNION_TYPE_P (new_field_type)
 	  && !TYPE_FAT_POINTER_P (new_field_type)
@@ -1034,14 +1035,15 @@  make_packable_type (tree type, bool in_r
 	  && !TYPE_FAT_POINTER_P (new_field_type)
 	  && !TYPE_CONTAINS_TEMPLATE_P (new_field_type)
 	  && TYPE_ADA_SIZE (new_field_type))
-	new_size = TYPE_ADA_SIZE (new_field_type);
+	new_field_size = TYPE_ADA_SIZE (new_field_type);
       else
-	new_size = DECL_SIZE (field);
+	new_field_size = DECL_SIZE (field);
 
+      /* This is a layout with full representation, alignment and size clauses
+	 so we simply pass 0 as PACKED like gnat_to_gnu_field in this case.  */
       new_field
 	= create_field_decl (DECL_NAME (field), new_field_type, new_type,
-			     new_size, bit_position (field),
-			     TYPE_PACKED (type),
+			     new_field_size, bit_position (field), 0,
 			     !DECL_NONADDRESSABLE_P (field));
 
       DECL_INTERNAL_P (new_field) = DECL_INTERNAL_P (field);
@@ -1896,6 +1898,14 @@  finish_record_type (tree record_type, tr
 	    DECL_BIT_FIELD (field) = 0;
 	}
 
+      /* Clear DECL_BIT_FIELD_TYPE for a variant part at offset 0, it's simply
+	 not supported by the DECL_BIT_FIELD_REPRESENTATIVE machinery because
+	 the variant part is always the last field in the list.  */
+      if (DECL_INTERNAL_P (field)
+	  && TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
+	  && integer_zerop (pos))
+	DECL_BIT_FIELD_TYPE (field) = NULL_TREE;
+
       /* If we still have DECL_BIT_FIELD set at this point, we know that the
 	 field is technically not addressable.  Except that it can actually
 	 be addressed if it is BLKmode and happens to be properly aligned.  */
@@ -2725,9 +2735,9 @@  create_field_decl (tree name, tree type,
 	size = round_up (size, BITS_PER_UNIT);
     }
 
-  /* If we may, according to ADDRESSABLE, make a bitfield if a size is
+  /* If we may, according to ADDRESSABLE, make a bitfield when the size is
      specified for two reasons: first if the size differs from the natural
-     size.  Second, if the alignment is insufficient.  There are a number of
+     size; second, if the alignment is insufficient.  There are a number of
      ways the latter can be true.
 
      We never make a bitfield if the type of the field has a nonconstant size,
@@ -2735,7 +2745,7 @@  create_field_decl (tree name, tree type,
 
      We do *preventively* make a bitfield when there might be the need for it
      but we don't have all the necessary information to decide, as is the case
-     of a field with no specified position in a packed record.
+     of a field in a packed record.
 
      We also don't look at STRICT_ALIGNMENT here, and rely on later processing
      in layout_decl or finish_record_type to clear the bit_field indication if