diff mbox

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

Message ID 201105051827.34960.ebotcazou@adacore.com
State New
Headers show

Commit Message

Eric Botcazou May 5, 2011, 4:27 p.m. UTC
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.
diff mbox

Patch

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