The compiler aborts on the initialization of an object with an aggregate, if its nominal subtype is a discriminated record type with a variant part for which the variants all have the same size and one of the variants contains a component whose type is tagged or controlled.
Tested on x86_64-suse-linux, applied on the mainline. 2011-08-30 Eric Botcazou <ebotca...@adacore.com> * gcc-interface/decl.c (gnat_to_gnu_entity) <object>: Do not convert the expression to the nominal type if the latter is a record type with a variant part and the type of the former is a record type without one. 2011-08-30 Eric Botcazou <ebotca...@adacore.com> * gnat.dg/specs/aggr3.ads: New test. * gnat.dg/specs/aggr3_pkg.ads: New helper. -- Eric Botcazou
Index: gcc-interface/decl.c =================================================================== --- gcc-interface/decl.c (revision 178287) +++ gcc-interface/decl.c (working copy) @@ -1124,13 +1124,19 @@ gnat_to_gnu_entity (Entity_Id gnat_entit is a padded record whose field is of self-referential size. In the former case, converting will generate unnecessary evaluations of the CONSTRUCTOR to compute the size and in the latter case, we - want to only copy the actual data. */ + want to only copy the actual data. Also don't convert to a record + type with a variant part from a record type without one, to keep + the object simpler. */ if (gnu_expr && TREE_CODE (gnu_type) != UNCONSTRAINED_ARRAY_TYPE && !CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_type)) && !(TYPE_IS_PADDING_P (gnu_type) && CONTAINS_PLACEHOLDER_P - (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type)))))) + (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type))))) + && !(TREE_CODE (gnu_type) == RECORD_TYPE + && TREE_CODE (TREE_TYPE (gnu_expr)) == RECORD_TYPE + && get_variant_part (gnu_type) != NULL_TREE + && get_variant_part (TREE_TYPE (gnu_expr)) == NULL_TREE)) gnu_expr = convert (gnu_type, gnu_expr); /* If this is a pointer that doesn't have an initializing expression, @@ -1350,13 +1356,19 @@ gnat_to_gnu_entity (Entity_Id gnat_entit is a padded record whose field is of self-referential size. In the former case, converting will generate unnecessary evaluations of the CONSTRUCTOR to compute the size and in the latter case, we - want to only copy the actual data. */ + want to only copy the actual data. Also don't convert to a record + type with a variant part from a record type without one, to keep + the object simpler. */ if (gnu_expr && TREE_CODE (gnu_type) != UNCONSTRAINED_ARRAY_TYPE && !CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_type)) && !(TYPE_IS_PADDING_P (gnu_type) && CONTAINS_PLACEHOLDER_P - (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type)))))) + (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type))))) + && !(TREE_CODE (gnu_type) == RECORD_TYPE + && TREE_CODE (TREE_TYPE (gnu_expr)) == RECORD_TYPE + && get_variant_part (gnu_type) != NULL_TREE + && get_variant_part (TREE_TYPE (gnu_expr)) == NULL_TREE)) gnu_expr = convert (gnu_type, gnu_expr); /* If this name is external or there was a name specified, use it,
-- { dg-do compile } with Aggr3_Pkg; use Aggr3_Pkg; package Aggr3 is type Enum is (One); type R (D : Enum := One) is record case D is when One => The_T : T; end case; end record; My_R : R := (D => One, The_T => My_T); end Aggr3;
package Aggr3_Pkg is type Root is abstract tagged null record; type T is new Root with null record; My_T : T; end Aggr3_Pkg;