public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [Ada] Fix crash on extension with variable size and representation clause
@ 2019-05-28  8:10 Eric Botcazou
  0 siblings, 0 replies; only message in thread
From: Eric Botcazou @ 2019-05-28  8:10 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 663 bytes --]

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

[-- Attachment #2: discr5.ads --]
[-- Type: text/x-adasrc, Size: 1112 bytes --]

-- { dg-do compile }

with System;

package Discr5 is

   X, Y : Boolean;

   type R (D : Boolean := False) is tagged limited record
      F : Integer;
      case D is
         when True =>
            F1, F2 : Integer;
         when False =>
            null;
      end case;
   end record;
   for R use record
      F1 at 100 range 0..31;
   end record;
   
   subtype Rt is R(True);
   subtype Rf is R(False);

   type R1 (D1 : Boolean) is new R (X) with record
      FF : Float;
      case D1 is
         when True =>
            F3, F4 : Float;
         when False =>
            null;
      end case;
   end record;
   for R1 use record
      F4 at 200 range 0..31;
   end record;

   subtype R1t is R1 (True);
   subtype R1f is R1 (False);

   type R2 (D2 : Boolean) is new R1 (Y) with record
      FFF: System.Address;
      case D2 is
         when True =>
            F5, F6: System.Address;
         when False =>
            null;
      end case;
   end record;
   for R2 use record
      F6 at 300 range 0..63;
   end record;

   subtype R2t is R2 (True);
   subtype R2f is R2 (False);

end Discr5;

[-- Attachment #3: p.diff --]
[-- Type: text/x-patch, Size: 4868 bytes --]

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2019-05-28  7:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-28  8:10 [Ada] Fix crash on extension with variable size and representation clause Eric Botcazou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).