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]

[Ada] Fix ICE on assignment of aggregate with discriminated record type


This is PR ada/48844, a regression present on the mainline and 4.6 branch.
The compiler aborts on an assignment of an aggregate to another object, if the 
nominal subtype of the former is a discriminated record type with a variant 
part for which the variants all have the same size and one of the variant 
contains a component whose type is tagged or controlled.  It is trying to 
create a temporary for a VIEW_CONVERT_EXPR and the type doesn't allow it.
Fixed by not generating the VIEW_CONVERT_EXPR in the first place.

Tested on i586-suse-linux, applied on the mainline and 4.6 branch.


2011-05-05  Eric Botcazou  <ebotcazou@adacore.com>

	PR ada/48844
	* gcc-interface/gigi.h (get_variant_part): Declare.
	* gcc-interface/decl.c (get_variant_part): Make global.
	* gcc-interface/utils2.c (find_common_type): Do not return T1 if the
	types have the same constant size, are record types and T1 has a
	variant part while T2 doesn't.


2011-05-05  Eric Botcazou  <ebotcazou@adacore.com>

	* gnat.dg/discr29.ad[sb]: New test.
	* gnat.dg/discr30.adb: Likewise.


-- 
Eric Botcazou
Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 173422)
+++ gcc-interface/decl.c	(working copy)
@@ -177,7 +177,6 @@ static void check_ok_for_atomic (tree, E
 static tree create_field_decl_from (tree, tree, tree, tree, tree,
 				    VEC(subst_pair,heap) *);
 static tree get_rep_part (tree);
-static tree get_variant_part (tree);
 static tree create_variant_part_from (tree, VEC(variant_desc,heap) *, tree,
 				      tree, VEC(subst_pair,heap) *);
 static void copy_and_substitute_in_size (tree, tree, VEC(subst_pair,heap) *);
@@ -8509,7 +8508,7 @@ get_rep_part (tree record_type)
 
 /* Return the variant part of RECORD_TYPE, if any.  Otherwise return NULL.  */
 
-static tree
+tree
 get_variant_part (tree record_type)
 {
   tree field;
Index: gcc-interface/utils2.c
===================================================================
--- gcc-interface/utils2.c	(revision 173422)
+++ gcc-interface/utils2.c	(working copy)
@@ -193,15 +193,21 @@ find_common_type (tree t1, tree t2)
      calling into build_binary_op), some others are really expected and we
      have to be careful.  */
 
-  /* We must prevent writing more than what the target may hold if this is for
+  /* We must avoid writing more than what the target can hold if this is for
      an assignment and the case of tagged types is handled in build_binary_op
-     so use the lhs type if it is known to be smaller, or of constant size and
-     the rhs type is not, whatever the modes.  We also force t1 in case of
+     so we use the lhs type if it is known to be smaller or of constant size
+     and the rhs type is not, whatever the modes.  We also force t1 in case of
      constant size equality to minimize occurrences of view conversions on the
-     lhs of assignments.  */
+     lhs of an assignment, except for the case of record types with a variant
+     part on the lhs but not on the rhs to make the conversion simpler.  */
   if (TREE_CONSTANT (TYPE_SIZE (t1))
       && (!TREE_CONSTANT (TYPE_SIZE (t2))
-          || !tree_int_cst_lt (TYPE_SIZE (t2), TYPE_SIZE (t1))))
+	  || tree_int_cst_lt (TYPE_SIZE (t1), TYPE_SIZE (t2))
+	  || (TYPE_SIZE (t1) == TYPE_SIZE (t2)
+	      && !(TREE_CODE (t1) == RECORD_TYPE
+		   && TREE_CODE (t2) == RECORD_TYPE
+		   && get_variant_part (t1) != NULL_TREE
+		   && get_variant_part (t2) == NULL_TREE))))
     return t1;
 
   /* Otherwise, if the lhs type is non-BLKmode, use it.  Note that we know
Index: gcc-interface/gigi.h
===================================================================
--- gcc-interface/gigi.h	(revision 173422)
+++ gcc-interface/gigi.h	(working copy)
@@ -150,6 +150,9 @@ extern tree choices_to_gnu (tree operand
 extern void annotate_object (Entity_Id gnat_entity, tree gnu_type, tree size,
 			     bool by_ref, bool by_double_ref);
 
+/* Return the variant part of RECORD_TYPE, if any.  Otherwise return NULL.  */
+extern tree get_variant_part (tree record_type);
+
 /* Given a type T, a FIELD_DECL F, and a replacement value R, return a new
    type with all size expressions that contain F updated by replacing F
    with R.  If F is NULL_TREE, always make a new RECORD_TYPE, even if
package body Discr29 is

   procedure Proc (R : out Rec3) is
   begin
      R := (False, Tmp);
   end;

end Discr29;
-- { dg-do compile }

package Discr29 is

   type Rec1 is record
      I1 : Integer;
      I2 : Integer;
      I3 : Integer;
   end record;

   type Rec2 is tagged record
      I1 : Integer;
      I2 : Integer;
   end record;

   type Rec3 (D : Boolean) is record
      case D is
         when True =>  A : Rec1;
         when False => B : Rec2;
      end case;
   end record;

   procedure Proc (R : out Rec3);

   Tmp : Rec2;

end Discr29;
-- PR ada/48844
-- Reported by Georg Bauhaus <bauhaus@futureapps.de> */

-- { dg-do compile }

procedure Discr30 is

   generic
     type Source is private;
     type Target is private;
   function Conversion (S : Source) return Target;

   function Conversion (S : Source) return Target is
      type Source_Wrapper is tagged record
         S : Source;
      end record;
      type Target_Wrapper is tagged record
         T : Target;
      end record;

      type Selector is (Source_Field, Target_Field);
      type Magic (Sel : Selector := Target_Field) is record
         case Sel is
            when Source_Field => S : Source_Wrapper;
            when Target_Field => T : Target_Wrapper;
         end case;
      end record;

      M : Magic;

      function Convert (T : Target_Wrapper) return Target is
      begin
         M := (Sel => Source_Field, S => (S => S));
         return T.T;
      end Convert;

   begin
      return Convert (M.T);
   end Conversion;

   type Integer_Access is access all Integer;

   I : aliased Integer;
   I_Access : Integer_Access := I'Access;

   function Convert is new Conversion (Integer_Access, Integer);

begin
   I := Convert (I_Access);
end;

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