[Ada] Fix crash on extension with variable size and representation clause

Message ID 2748056.V8E78CCTFA@polaris
State New
Headers show
Series
  • [Ada] Fix crash on extension with variable size and representation clause
Related show

Commit Message

Eric Botcazou May 28, 2019, 7:44 a.m.
The compiler segfaults on the extension of a tagged record type with variable 
size subject to a partial representation clause, which is quite pathological.

Tested on x86_64-suse-linux, applied on the mainline and 9 branch.


2019-05-28  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc-interface/decl.c (components_to_record): Set a name on the
	created for the REP part, if any.
	* gcc-interface/utils.c (finish_record_type): Only take the maximum
	when merging sizes for a variant part at offset 0.
	(merge_sizes): Rename has_rep parameter into max.


2019-05-28  Eric Botcazou  <ebotcazou@adacore.com>

	* gnat.dg/specs/discr5.ads: New test.

-- 
Eric Botcazou

Patch

Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 271679)
+++ gcc-interface/decl.c	(working copy)
@@ -8162,6 +8162,8 @@  components_to_record (Node_Id gnat_compo
 	gnu_field_list = gnu_rep_list;
       else
 	{
+	  TYPE_NAME (gnu_rep_type)
+	    = create_concat_name (gnat_record_type, "REP");
 	  TYPE_REVERSE_STORAGE_ORDER (gnu_rep_type)
 	    = TYPE_REVERSE_STORAGE_ORDER (gnu_record_type);
 	  finish_record_type (gnu_rep_type, gnu_rep_list, 1, debug_info);
Index: gcc-interface/utils.c
===================================================================
--- gcc-interface/utils.c	(revision 271680)
+++ gcc-interface/utils.c	(working copy)
@@ -1863,6 +1863,9 @@  finish_record_type (tree record_type, tr
       else
 	this_ada_size = this_size;
 
+      const bool variant_part = (TREE_CODE (type) == QUAL_UNION_TYPE);
+      const bool variant_part_at_zero = variant_part && integer_zerop (pos);
+
       /* Clear DECL_BIT_FIELD for the cases layout_decl does not handle.  */
       if (DECL_BIT_FIELD (field)
 	  && operand_equal_p (this_size, TYPE_SIZE (type), 0))
@@ -1904,9 +1907,7 @@  finish_record_type (tree record_type, tr
       /* 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))
+      if (variant_part_at_zero)
 	DECL_BIT_FIELD_TYPE (field) = NULL_TREE;
 
       /* If we still have DECL_BIT_FIELD set at this point, we know that the
@@ -1941,18 +1942,18 @@  finish_record_type (tree record_type, tr
 	case RECORD_TYPE:
 	  /* Since we know here that all fields are sorted in order of
 	     increasing bit position, the size of the record is one
-	     higher than the ending bit of the last field processed
-	     unless we have a rep clause, since in that case we might
-	     have a field outside a QUAL_UNION_TYPE that has a higher ending
-	     position.  So use a MAX in that case.  Also, if this field is a
-	     QUAL_UNION_TYPE, we need to take into account the previous size in
-	     the case of empty variants.  */
+	     higher than the ending bit of the last field processed,
+	     unless we have a variant part at offset 0, since in this
+	     case we might have a field outside the variant part that
+	     has a higher ending position; so use a MAX in this case.
+	     Also, if this field is a QUAL_UNION_TYPE, we need to take
+	     into account the previous size in the case of empty variants.  */
 	  ada_size
-	    = merge_sizes (ada_size, pos, this_ada_size,
-			   TREE_CODE (type) == QUAL_UNION_TYPE, rep_level > 0);
+	    = merge_sizes (ada_size, pos, this_ada_size, variant_part,
+			   variant_part_at_zero);
 	  size
-	    = merge_sizes (size, pos, this_size,
-			   TREE_CODE (type) == QUAL_UNION_TYPE, rep_level > 0);
+	    = merge_sizes (size, pos, this_size, variant_part,
+			   variant_part_at_zero);
 	  break;
 
 	default:
@@ -2233,13 +2234,12 @@  rest_of_record_type_compilation (tree re
 /* Utility function of above to merge LAST_SIZE, the previous size of a record
    with FIRST_BIT and SIZE that describe a field.  SPECIAL is true if this
    represents a QUAL_UNION_TYPE in which case we must look for COND_EXPRs and
-   replace a value of zero with the old size.  If HAS_REP is true, we take the
+   replace a value of zero with the old size.  If MAX is true, we take the
    MAX of the end position of this field with LAST_SIZE.  In all other cases,
    we use FIRST_BIT plus SIZE.  Return an expression for the size.  */
 
 static tree
-merge_sizes (tree last_size, tree first_bit, tree size, bool special,
-	     bool has_rep)
+merge_sizes (tree last_size, tree first_bit, tree size, bool special, bool max)
 {
   tree type = TREE_TYPE (last_size);
   tree new_size;
@@ -2247,7 +2247,7 @@  merge_sizes (tree last_size, tree first_
   if (!special || TREE_CODE (size) != COND_EXPR)
     {
       new_size = size_binop (PLUS_EXPR, first_bit, size);
-      if (has_rep)
+      if (max)
 	new_size = size_binop (MAX_EXPR, last_size, new_size);
     }
 
@@ -2256,11 +2256,11 @@  merge_sizes (tree last_size, tree first_
 			    integer_zerop (TREE_OPERAND (size, 1))
 			    ? last_size : merge_sizes (last_size, first_bit,
 						       TREE_OPERAND (size, 1),
-						       1, has_rep),
+						       1, max),
 			    integer_zerop (TREE_OPERAND (size, 2))
 			    ? last_size : merge_sizes (last_size, first_bit,
 						       TREE_OPERAND (size, 2),
-						       1, has_rep));
+						       1, max));
 
   /* We don't need any NON_VALUE_EXPRs and they can confuse us (especially
      when fed through SUBSTITUTE_IN_EXPR) into thinking that a constant