This fixes an internal error on an overlay of 2 aliased unconstrained array 
objects.  These objects have a special layout (they contain the bounds ahead 
of the array itself) so overlaying them is a bit delicate.

Tested on x86_64-suse-linux, applied on the mainline.


2015-06-01  Eric Botcazou  <ebotca...@adacore.com>

        * gcc-interface/gigi.h (build_simple_component_ref): Declare.
        * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Variable>: Deal with
        address clause on aliased object with unconstrained nominal subtype.
        Mark the aligning variable as artificial, do not convert the address
        expression immediately but mark it as constant instead.
        * gcc-interface/utils.c (convert): If the target type contains a
        template, be prepared for an empty array.
        (maybe_unconstrained_array): Likewise.
        * gcc-interface/utils2.c (known_alignment) <POINTER_PLUS_EXPR>: Deal
        with the pattern built for aligning types.
        <INTEGER_CST>: Do not cap the value at BIGGEST_ALIGNMENT.
        (build_simple_component_ref): Make public.
        If the base object is a constructor that contains a template, fold the
        result field by field.


2015-06-01  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/addr9_1.adb: New test.
        * gnat.dg/addr9_2.adb: Likewise.
        * gnat.dg/addr9_3.adb: Likewise.
        * gnat.dg/addr9_4.adb: Likewise.


-- 
Eric Botcazou
Index: gcc-interface/utils.c
===================================================================
--- gcc-interface/utils.c	(revision 223897)
+++ gcc-interface/utils.c	(working copy)
@@ -4092,8 +4092,9 @@ convert (tree type, tree expr)
       CONSTRUCTOR_APPEND_ELT (v, TYPE_FIELDS (type),
 			      build_template (TREE_TYPE (TYPE_FIELDS (type)),
 					      obj_type, NULL_TREE));
-      CONSTRUCTOR_APPEND_ELT (v, DECL_CHAIN (TYPE_FIELDS (type)),
-			      convert (obj_type, expr));
+      if (expr)
+	CONSTRUCTOR_APPEND_ELT (v, DECL_CHAIN (TYPE_FIELDS (type)),
+				convert (obj_type, expr));
       return gnat_build_constructor (type, v);
     }
 
@@ -4699,14 +4700,13 @@ maybe_unconstrained_array (tree exp)
 
       if (TYPE_CONTAINS_TEMPLATE_P (type))
 	{
-	  exp = build_component_ref (exp, NULL_TREE,
-				     DECL_CHAIN (TYPE_FIELDS (type)),
-				     false);
-	  type = TREE_TYPE (exp);
+	  exp = build_simple_component_ref (exp, NULL_TREE,
+					    DECL_CHAIN (TYPE_FIELDS (type)),
+					    false);
 
 	  /* If the array type is padded, convert to the unpadded type.  */
-	  if (TYPE_IS_PADDING_P (type))
-	    exp = convert (TREE_TYPE (TYPE_FIELDS (type)), exp);
+	  if (exp && TYPE_IS_PADDING_P (TREE_TYPE (exp)))
+	    exp = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (exp))), exp);
 	}
       break;
 
Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 223897)
+++ gcc-interface/decl.c	(working copy)
@@ -882,8 +882,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	    check_ok_for_atomic_type (gnu_inner, gnat_entity, true);
 	  }
 
-	/* If this is an aliased object with an unconstrained nominal subtype,
-	   make a type that includes the template.  */
+	/* If this is an aliased object with an unconstrained array nominal
+	   subtype, make a type that includes the template.  We will either
+	   allocate or create a variable of that type, see below.  */
 	if (Is_Constr_Subt_For_UN_Aliased (Etype (gnat_entity))
 	    && Is_Array_Type (Underlying_Type (Etype (gnat_entity)))
 	    && !type_annotate_only)
@@ -1149,7 +1150,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	   effects in this case.  */
 	if (definition && Present (Address_Clause (gnat_entity)))
 	  {
-	    Node_Id gnat_expr = Expression (Address_Clause (gnat_entity));
+	    const Node_Id gnat_clause = Address_Clause (gnat_entity);
+	    Node_Id gnat_expr = Expression (gnat_clause);
 	    tree gnu_address
 	      = present_gnu_tree (gnat_entity)
 		? get_gnu_tree (gnat_entity) : gnat_to_gnu (gnat_expr);
@@ -1167,6 +1169,40 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 		|| compile_time_known_address_p (gnat_expr);
 	    gnu_size = NULL_TREE;
 
+	    /* If this is an aliased object with an unconstrained array nominal
+	       subtype, then it can overlay only another aliased object with an
+	       unconstrained array nominal subtype and compatible template.  */
+	    if (Is_Constr_Subt_For_UN_Aliased (Etype (gnat_entity))
+		&& Is_Array_Type (Underlying_Type (Etype (gnat_entity)))
+		&& !type_annotate_only)
+	      {
+		tree rec_type = TREE_TYPE (gnu_type);
+		tree off = byte_position (DECL_CHAIN (TYPE_FIELDS (rec_type)));
+
+		/* This is the pattern built for a regular object.  */
+		if (TREE_CODE (gnu_address) == POINTER_PLUS_EXPR
+		    && TREE_OPERAND (gnu_address, 1) == off)
+		  gnu_address = TREE_OPERAND (gnu_address, 0);
+		/* This is the pattern built for an overaligned object.  */
+		else if (TREE_CODE (gnu_address) == POINTER_PLUS_EXPR
+			 && TREE_CODE (TREE_OPERAND (gnu_address, 1))
+			    == PLUS_EXPR
+			 && TREE_OPERAND (TREE_OPERAND (gnu_address, 1), 1)
+			    == off)
+		  gnu_address
+		    = build2 (POINTER_PLUS_EXPR, gnu_type,
+			      TREE_OPERAND (gnu_address, 0),
+			      TREE_OPERAND (TREE_OPERAND (gnu_address, 1), 0));
+		else
+		  {
+		    post_error_ne ("aliased object& with unconstrained array "
+				   "nominal subtype", gnat_clause,
+				   gnat_entity);
+		    post_error ("\\can overlay only aliased object with "
+				"compatible subtype", gnat_clause);
+		  }
+	      }
+
 	    /* If this is a deferred constant, the initializer is attached to
 	       the full view.  */
 	    if (kind == E_Constant && Present (Full_View (gnat_entity)))
@@ -1183,11 +1219,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	    else
 	      gnu_expr
 		= build2 (COMPOUND_EXPR, gnu_type,
-			  build_binary_op
-			  (MODIFY_EXPR, NULL_TREE,
-			   build_unary_op (INDIRECT_REF, NULL_TREE,
-					   gnu_address),
-			   gnu_expr),
+			  build_binary_op (INIT_EXPR, NULL_TREE,
+					   build_unary_op (INDIRECT_REF,
+							   NULL_TREE,
+							   gnu_address),
+					   gnu_expr),
 			  gnu_address);
 	  }
 
@@ -1302,8 +1338,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	/* If this object would go into the stack and has an alignment larger
 	   than the largest stack alignment the back-end can honor, resort to
 	   a variable of "aligning type".  */
-	if (!global_bindings_p () && !static_p && definition
-	    && !imported_p && TYPE_ALIGN (gnu_type) > BIGGEST_ALIGNMENT)
+	if (definition
+	    && !global_bindings_p ()
+	    && !static_p
+	    && !imported_p
+	    && TYPE_ALIGN (gnu_type) > BIGGEST_ALIGNMENT)
 	  {
 	    /* Create the new variable.  No need for extra room before the
 	       aligned field as this is in automatic storage.  */
@@ -1315,11 +1354,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	      = create_var_decl (create_concat_name (gnat_entity, "ALIGN"),
 				 NULL_TREE, gnu_new_type, NULL_TREE, false,
 				 false, false, false, NULL, gnat_entity);
+	    DECL_ARTIFICIAL (gnu_new_var) = 1;
 
 	    /* Initialize the aligned field if we have an initializer.  */
 	    if (gnu_expr)
 	      add_stmt_with_node
-		(build_binary_op (MODIFY_EXPR, NULL_TREE,
+		(build_binary_op (INIT_EXPR, NULL_TREE,
 				  build_component_ref
 				  (gnu_new_var, NULL_TREE,
 				   TYPE_FIELDS (gnu_new_type), false),
@@ -1330,28 +1370,26 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	    gnu_type = build_reference_type (gnu_type);
 	    gnu_expr
 	      = build_unary_op
-		(ADDR_EXPR, gnu_type,
+		(ADDR_EXPR, NULL_TREE,
 		 build_component_ref (gnu_new_var, NULL_TREE,
 				      TYPE_FIELDS (gnu_new_type), false));
+	    TREE_CONSTANT (gnu_expr) = 1;
 
 	    used_by_ref = true;
 	    const_flag = true;
 	    gnu_size = NULL_TREE;
 	  }
 
-	/* If this is an aliased object with an unconstrained nominal subtype,
-	   we make its type a thin reference, i.e. the reference counterpart
-	   of a thin pointer, so that it points to the array part.  This is
-	   aimed at making it easier for the debugger to decode the object.
-	   Note that we have to do that this late because of the couple of
-	   allocation adjustments that might be made just above.  */
+	/* If this is an aliased object with an unconstrained array nominal
+	   subtype, we make its type a thin reference, i.e. the reference
+	   counterpart of a thin pointer, so it points to the array part.
+	   This is aimed to make it easier for the debugger to decode the
+	   object.  Note that we have to do it this late because of the
+	   couple of allocation adjustments that might be made above.  */
 	if (Is_Constr_Subt_For_UN_Aliased (Etype (gnat_entity))
 	    && Is_Array_Type (Underlying_Type (Etype (gnat_entity)))
 	    && !type_annotate_only)
 	  {
-	    tree gnu_array
-	      = gnat_to_gnu_type (Base_Type (Etype (gnat_entity)));
-
 	    /* In case the object with the template has already been allocated
 	       just above, we have nothing to do here.  */
 	    if (!TYPE_IS_THIN_POINTER_P (gnu_type))
@@ -1362,8 +1400,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 				      const_flag, Is_Public (gnat_entity),
 				      imported_p || !definition, static_p,
 				      NULL, gnat_entity);
-		gnu_expr
-		  = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_unc_var);
+		gnu_expr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_unc_var);
 		TREE_CONSTANT (gnu_expr) = 1;
 
 		used_by_ref = true;
@@ -1372,6 +1409,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 		gnu_size = NULL_TREE;
 	      }
 
+	    tree gnu_array
+	      = gnat_to_gnu_type (Base_Type (Etype (gnat_entity)));
 	    gnu_type
 	      = build_reference_type (TYPE_OBJECT_RECORD_TYPE (gnu_array));
 	  }
Index: gcc-interface/utils2.c
===================================================================
--- gcc-interface/utils2.c	(revision 223897)
+++ gcc-interface/utils2.c	(working copy)
@@ -78,9 +78,9 @@ get_base_type (tree type)
   return type;
 }
 
-/* EXP is a GCC tree representing an address.  See if we can find how
-   strictly the object at that address is aligned.   Return that alignment
-   in bits.  If we don't know anything about the alignment, return 0.  */
+/* EXP is a GCC tree representing an address.  See if we can find how strictly
+   the object at this address is aligned and, if so, return the alignment of
+   the object in bits.  Otherwise return 0.  */
 
 unsigned int
 known_alignment (tree exp)
@@ -99,13 +99,13 @@ known_alignment (tree exp)
       break;
 
     case COMPOUND_EXPR:
-      /* The value of a COMPOUND_EXPR is that of it's second operand.  */
+      /* The value of a COMPOUND_EXPR is that of its second operand.  */
       this_alignment = known_alignment (TREE_OPERAND (exp, 1));
       break;
 
     case PLUS_EXPR:
     case MINUS_EXPR:
-      /* If two address are added, the alignment of the result is the
+      /* If two addresses are added, the alignment of the result is the
 	 minimum of the two alignments.  */
       lhs = known_alignment (TREE_OPERAND (exp, 0));
       rhs = known_alignment (TREE_OPERAND (exp, 1));
@@ -113,10 +113,20 @@ known_alignment (tree exp)
       break;
 
     case POINTER_PLUS_EXPR:
-      lhs = known_alignment (TREE_OPERAND (exp, 0));
-      rhs = known_alignment (TREE_OPERAND (exp, 1));
+      /* If this is the pattern built for aligning types, decode it.  */
+      if (TREE_CODE (TREE_OPERAND (exp, 1)) == BIT_AND_EXPR
+	  && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)) == NEGATE_EXPR)
+	{
+	  tree op = TREE_OPERAND (TREE_OPERAND (exp, 1), 1);
+	  return
+	    known_alignment (fold_build1 (BIT_NOT_EXPR, TREE_TYPE (op), op));
+	}
+
       /* If we don't know the alignment of the offset, we assume that
 	 of the base.  */
+      lhs = known_alignment (TREE_OPERAND (exp, 0));
+      rhs = known_alignment (TREE_OPERAND (exp, 1));
+
       if (rhs == 0)
 	this_alignment = lhs;
       else
@@ -124,7 +134,7 @@ known_alignment (tree exp)
       break;
 
     case COND_EXPR:
-      /* If there is a choice between two values, use the smallest one.  */
+      /* If there is a choice between two values, use the smaller one.  */
       lhs = known_alignment (TREE_OPERAND (exp, 1));
       rhs = known_alignment (TREE_OPERAND (exp, 2));
       this_alignment = MIN (lhs, rhs);
@@ -135,7 +145,7 @@ known_alignment (tree exp)
 	unsigned HOST_WIDE_INT c = TREE_INT_CST_LOW (exp);
 	/* The first part of this represents the lowest bit in the constant,
 	   but it is originally in bytes, not bits.  */
-	this_alignment = MIN (BITS_PER_UNIT * (c & -c), BIGGEST_ALIGNMENT);
+	this_alignment = (c & -c) * BITS_PER_UNIT;
       }
       break;
 
@@ -172,7 +182,7 @@ known_alignment (tree exp)
 	  return known_alignment (t);
       }
 
-      /* Fall through... */
+      /* ... fall through ... */
 
     default:
       /* For other pointer expressions, we assume that the pointed-to object
@@ -1990,7 +2000,7 @@ gnat_build_constructor (tree type, vec<c
    We also handle the fact that we might have been passed a pointer to the
    actual record and know how to look for fields in variant parts.  */
 
-static tree
+tree
 build_simple_component_ref (tree record_variable, tree component, tree field,
 			    bool no_fold_p)
 {
@@ -2128,18 +2138,26 @@ build_simple_component_ref (tree record_
   if (TREE_CODE (base) == CONSTRUCTOR
       && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (base)))
     {
-      vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (base);
-      unsigned HOST_WIDE_INT idx;
-      tree index, value;
-      FOR_EACH_CONSTRUCTOR_ELT (elts, idx, index, value)
-	if (index == field)
-	  return value;
+      unsigned int len = CONSTRUCTOR_NELTS (base);
+      gcc_assert (len > 0);
+
+      if (field == CONSTRUCTOR_ELT (base, 0)->index)
+	return CONSTRUCTOR_ELT (base, 0)->value;
+
+      if (len > 1)
+	{
+	  if (field == CONSTRUCTOR_ELT (base, 1)->index)
+	    return CONSTRUCTOR_ELT (base, 1)->value;
+	}
+      else
+	return NULL_TREE;
+
       return ref;
     }
 
   return fold (ref);
 }
-
+
 /* Likewise, but generate a Constraint_Error if the reference could not be
    found.  */
 
Index: gcc-interface/gigi.h
===================================================================
--- gcc-interface/gigi.h	(revision 223897)
+++ gcc-interface/gigi.h	(working copy)
@@ -914,6 +914,11 @@ extern tree gnat_build_constructor (tree
 /* Return a COMPONENT_REF to access a field that is given by COMPONENT,
    an IDENTIFIER_NODE giving the name of the field, FIELD, a FIELD_DECL,
    for the field, or both.  Don't fold the result if NO_FOLD_P.  */
+extern tree build_simple_component_ref (tree record_variable, tree component,
+					tree field, bool no_fold_p);
+
+/* Likewise, but generate a Constraint_Error if the reference could not be
+   found.  */
 extern tree build_component_ref (tree record_variable, tree component,
                                  tree field, bool no_fold_p);
 
-- { dg-do compile }

with Ada.Streams; use Ada.Streams;

procedure Addr9_1 is

   type Signal_Type is mod 2 ** 16;

   type A_Item is record
      I : Signal_Type;
      Q : Signal_Type;
   end record
   with Size => 32;

   for A_Item use record
      I at 0 range 0 .. 15;
      Q at 2 range 0 .. 15;
   end record;

   type A_Array_Type is
     array (Positive range <>)
     of A_Item
   with Alignment => 16;

   pragma Pack (A_Array_Type);

   type B_Array_Type is new Ada.Streams.Stream_Element_Array
   with Alignment => 16;

   Ct_Count : constant := 7_000;

   package Set is
      A : aliased A_Array_Type := (1 .. Ct_Count => <>);
      B : aliased B_Array_Type := (1 .. Ct_Count * A_Item'Size / 8 => <>);
      for B'Address use A'Address;
   end Set;

begin
   null;
end;
-- { dg-do compile }

with Ada.Streams; use Ada.Streams;

procedure Addr9_2 is

   type Signal_Type is mod 2 ** 16;

   type A_Item is record
      I : Signal_Type;
      Q : Signal_Type;
   end record
   with Size => 32;

   for A_Item use record
      I at 0 range 0 .. 15;
      Q at 2 range 0 .. 15;
   end record;

   type A_Array_Type is
     array (Positive range <>)
     of A_Item
   with Alignment => 16;

   pragma Pack (A_Array_Type);

   type B_Array_Type is new Ada.Streams.Stream_Element_Array
   with Alignment => 16;

   Ct_Count : constant := 7_000;

   package Set is
      A : A_Array_Type := (1 .. Ct_Count => <>);
      B : aliased B_Array_Type := (1 .. Ct_Count * A_Item'Size / 8 => <>);
      for B'Address use A'Address; -- { dg-warning "aliased object" }
   end Set;

begin
   null;
end;
-- { dg-do compile }

with Ada.Streams; use Ada.Streams;

procedure Addr9_3 is

   type Signal_Type is mod 2 ** 16;

   type A_Item is record
      I : Signal_Type;
      Q : Signal_Type;
   end record
   with Size => 32;

   for A_Item use record
      I at 0 range 0 .. 15;
      Q at 2 range 0 .. 15;
   end record;

   type A_Array_Type is
     array (Positive range <>)
     of A_Item
   with Alignment => 16;

   pragma Pack (A_Array_Type);

   type B_Array_Type is new Ada.Streams.Stream_Element_Array
   with Alignment => 16;

   Ct_Count : constant := 7_000;

   package Set is
      A : aliased A_Array_Type := (1 .. Ct_Count => <>);
      B : B_Array_Type := (1 .. Ct_Count * A_Item'Size / 8 => <>);
      for B'Address use A'Address;
   end Set;

begin
   null;
end;
-- { dg-do compile }

with Ada.Streams; use Ada.Streams;

procedure Addr9_4 is

   type Signal_Type is mod 2 ** 16;

   type A_Item is record
      I : Signal_Type;
      Q : Signal_Type;
   end record
   with Size => 32;

   for A_Item use record
      I at 0 range 0 .. 15;
      Q at 2 range 0 .. 15;
   end record;

   type A_Array_Type is
     array (Positive range <>)
     of A_Item
   with Alignment => 16;

   pragma Pack (A_Array_Type);

   type B_Array_Type is new Ada.Streams.Stream_Element_Array
   with Alignment => 16;

   Ct_Count : constant := 7_000;

   package Set is
      A : A_Array_Type := (1 .. Ct_Count => <>);
      B : B_Array_Type := (1 .. Ct_Count * A_Item'Size / 8 => <>);
      for B'Address use A'Address;
   end Set;

begin
   null;
end;

Reply via email to