OSDN Git Service

* gcc-interface/trans.c (Attribute_to_gnu): Use remove_conversions.
[pf3gnuchains/gcc-fork.git] / gcc / ada / gcc-interface / utils2.c
index 977f881..10d12ef 100644 (file)
@@ -420,6 +420,80 @@ compare_arrays (location_t loc, tree result_type, tree a1, tree a2)
 
   return result;
 }
+
+/* Return an expression tree representing an equality comparison of P1 and P2,
+   two objects of fat pointer type.  The result should be of type RESULT_TYPE.
+
+   Two fat pointers are equal in one of two ways: (1) if both have a null
+   pointer to the array or (2) if they contain the same couple of pointers.
+   We perform the comparison in as efficient a manner as possible.  */
+
+static tree
+compare_fat_pointers (location_t loc, tree result_type, tree p1, tree p2)
+{
+  tree p1_array, p2_array, p1_bounds, p2_bounds, same_array, same_bounds;
+  tree p1_array_is_null, p2_array_is_null;
+
+  /* If either operand has side-effects, they have to be evaluated only once
+     in spite of the multiple references to the operand in the comparison.  */
+  p1 = gnat_protect_expr (p1);
+  p2 = gnat_protect_expr (p2);
+
+  /* The constant folder doesn't fold fat pointer types so we do it here.  */
+  if (TREE_CODE (p1) == CONSTRUCTOR)
+    p1_array = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (p1), 0)->value;
+  else
+    p1_array = build_component_ref (p1, NULL_TREE,
+                                   TYPE_FIELDS (TREE_TYPE (p1)), true);
+
+  p1_array_is_null
+    = fold_build2_loc (loc, EQ_EXPR, result_type, p1_array,
+                      fold_convert_loc (loc, TREE_TYPE (p1_array),
+                                        null_pointer_node));
+
+  if (TREE_CODE (p2) == CONSTRUCTOR)
+    p2_array = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (p2), 0)->value;
+  else
+    p2_array = build_component_ref (p2, NULL_TREE,
+                                   TYPE_FIELDS (TREE_TYPE (p2)), true);
+
+  p2_array_is_null
+    = fold_build2_loc (loc, EQ_EXPR, result_type, p2_array,
+                      fold_convert_loc (loc, TREE_TYPE (p2_array),
+                                        null_pointer_node));
+
+  /* If one of the pointers to the array is null, just compare the other.  */
+  if (integer_zerop (p1_array))
+    return p2_array_is_null;
+  else if (integer_zerop (p2_array))
+    return p1_array_is_null;
+
+  /* Otherwise, do the fully-fledged comparison.  */
+  same_array
+    = fold_build2_loc (loc, EQ_EXPR, result_type, p1_array, p2_array);
+
+  if (TREE_CODE (p1) == CONSTRUCTOR)
+    p1_bounds = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (p1), 1)->value;
+  else
+    p1_bounds
+      = build_component_ref (p1, NULL_TREE,
+                            DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p1))), true);
+
+  if (TREE_CODE (p2) == CONSTRUCTOR)
+    p2_bounds = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (p2), 1)->value;
+  else
+    p2_bounds
+      = build_component_ref (p2, NULL_TREE,
+                            DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p2))), true);
+
+  same_bounds
+    = fold_build2_loc (loc, EQ_EXPR, result_type, p1_bounds, p2_bounds);
+
+  /* P1_ARRAY == P2_ARRAY && (P1_ARRAY == NULL || P1_BOUNDS == P2_BOUNDS).  */
+  return build_binary_op (TRUTH_ANDIF_EXPR, result_type, same_array,
+                         build_binary_op (TRUTH_ORIF_EXPR, result_type,
+                                          p1_array_is_null, same_bounds));
+}
 \f
 /* Compute the result of applying OP_CODE to LHS and RHS, where both are of
    type TYPE.  We know that TYPE is a modular type with a nonbinary
@@ -724,7 +798,7 @@ build_binary_op (enum tree_code op_code, tree result_type,
       /* Then convert the right operand to its base type.  This will prevent
         unneeded sign conversions when sizetype is wider than integer.  */
       right_operand = convert (right_base_type, right_operand);
-      right_operand = convert (sizetype, right_operand);
+      right_operand = convert_to_index_type (right_operand);
       modulus = NULL_TREE;
       break;
 
@@ -848,19 +922,18 @@ build_binary_op (enum tree_code op_code, tree result_type,
          right_operand = convert (right_base_type, right_operand);
        }
 
-      /* If we are comparing a fat pointer against zero, we just need to
-        compare the data pointer.  */
-      if (TYPE_IS_FAT_POINTER_P (left_base_type)
-         && TREE_CODE (right_operand) == CONSTRUCTOR
-         && integer_zerop (VEC_index (constructor_elt,
-                                      CONSTRUCTOR_ELTS (right_operand),
-                                      0)->value))
+      /* If both objects are fat pointers, compare them specially.  */
+      if (TYPE_IS_FAT_POINTER_P (left_base_type))
        {
-         left_operand
-           = build_component_ref (left_operand, NULL_TREE,
-                                  TYPE_FIELDS (left_base_type), false);
-         right_operand
-           = convert (TREE_TYPE (left_operand), integer_zero_node);
+         result
+           = compare_fat_pointers (input_location,
+                                   result_type, left_operand, right_operand);
+         if (op_code == NE_EXPR)
+           result = invert_truthvalue_loc (EXPR_LOCATION (result), result);
+         else
+           gcc_assert (op_code == EQ_EXPR);
+
+         return result;
        }
 
       modulus = NULL_TREE;
@@ -1000,7 +1073,6 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
   tree base_type = get_base_type (type);
   tree operation_type = result_type;
   tree result;
-  bool side_effects = false;
 
   if (operation_type
       && TREE_CODE (operation_type) == RECORD_TYPE
@@ -1204,40 +1276,55 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
       break;
 
     case INDIRECT_REF:
-      /* If we want to refer to an unconstrained array, use the appropriate
-        expression to do so.  This will never survive down to the back-end.
-        But if TYPE is a thin pointer, first convert to a fat pointer.  */
-      if (TYPE_IS_THIN_POINTER_P (type)
-         && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type)))
-       {
-         operand
-           = convert (TREE_TYPE (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))),
+      {
+       tree t = remove_conversions (operand, false);
+       bool can_never_be_null = DECL_P (t) && DECL_CAN_NEVER_BE_NULL_P (t);
+
+       /* If TYPE is a thin pointer, first convert to the fat pointer.  */
+       if (TYPE_IS_THIN_POINTER_P (type)
+           && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type)))
+         {
+           operand = convert
+                     (TREE_TYPE (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))),
                       operand);
-         type = TREE_TYPE (operand);
-       }
+           type = TREE_TYPE (operand);
+         }
 
-      if (TYPE_IS_FAT_POINTER_P (type))
-       {
-         result = build1 (UNCONSTRAINED_ARRAY_REF,
-                          TYPE_UNCONSTRAINED_ARRAY (type), operand);
-         TREE_READONLY (result)
-           = TYPE_READONLY (TYPE_UNCONSTRAINED_ARRAY (type));
-       }
+       /* If we want to refer to an unconstrained array, use the appropriate
+          expression.  But this will never survive down to the back-end.  */
+       if (TYPE_IS_FAT_POINTER_P (type))
+         {
+           result = build1 (UNCONSTRAINED_ARRAY_REF,
+                            TYPE_UNCONSTRAINED_ARRAY (type), operand);
+           TREE_READONLY (result)
+             = TYPE_READONLY (TYPE_UNCONSTRAINED_ARRAY (type));
+         }
 
-      /* If we are dereferencing an ADDR_EXPR, return its operand.  */
-      else if (TREE_CODE (operand) == ADDR_EXPR)
-       result = TREE_OPERAND (operand, 0);
+       /* If we are dereferencing an ADDR_EXPR, return its operand.  */
+       else if (TREE_CODE (operand) == ADDR_EXPR)
+         result = TREE_OPERAND (operand, 0);
 
-      /* Otherwise, build and fold the indirect reference.  */
-      else
-       {
-         result = build_fold_indirect_ref (operand);
-         TREE_READONLY (result) = TYPE_READONLY (TREE_TYPE (type));
-       }
+       /* Otherwise, build and fold the indirect reference.  */
+       else
+         {
+           result = build_fold_indirect_ref (operand);
+           TREE_READONLY (result) = TYPE_READONLY (TREE_TYPE (type));
+         }
 
-      side_effects
-       = (!TYPE_IS_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type)));
-      break;
+       if (!TYPE_IS_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type)))
+         {
+           TREE_SIDE_EFFECTS (result) = 1;
+           if (TREE_CODE (result) == INDIRECT_REF)
+             TREE_THIS_VOLATILE (result) = TYPE_VOLATILE (TREE_TYPE (result));
+         }
+
+       if ((TREE_CODE (result) == INDIRECT_REF
+            || TREE_CODE (result) == UNCONSTRAINED_ARRAY_REF)
+           && can_never_be_null)
+         TREE_THIS_NOTRAP (result) = 1;
+
+       break;
+      }
 
     case NEGATE_EXPR:
     case BIT_NOT_EXPR:
@@ -1322,13 +1409,6 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
                            convert (operation_type, operand));
     }
 
-  if (side_effects)
-    {
-      TREE_SIDE_EFFECTS (result) = 1;
-      if (TREE_CODE (result) == INDIRECT_REF)
-       TREE_THIS_VOLATILE (result) = TYPE_VOLATILE (TREE_TYPE (result));
-    }
-
   if (result_type && TREE_TYPE (result) != result_type)
     result = convert (result_type, result);
 
@@ -1409,43 +1489,22 @@ build_compound_expr (tree result_type, tree stmt_operand, tree expr_operand)
   return result;
 }
 \f
-/* Build a CALL_EXPR to call FUNDECL with one argument, ARG.  Return
-   the CALL_EXPR.  */
-
-tree
-build_call_1_expr (tree fundecl, tree arg)
-{
-  tree call = build_call_nary (TREE_TYPE (TREE_TYPE (fundecl)),
-                              build_unary_op (ADDR_EXPR, NULL_TREE, fundecl),
-                              1, arg);
-  TREE_SIDE_EFFECTS (call) = 1;
-  return call;
-}
-
-/* Build a CALL_EXPR to call FUNDECL with two arguments, ARG1 & ARG2.  Return
-   the CALL_EXPR.  */
-
-tree
-build_call_2_expr (tree fundecl, tree arg1, tree arg2)
-{
-  tree call = build_call_nary (TREE_TYPE (TREE_TYPE (fundecl)),
-                              build_unary_op (ADDR_EXPR, NULL_TREE, fundecl),
-                              2, arg1, arg2);
-  TREE_SIDE_EFFECTS (call) = 1;
-  return call;
-}
-
-/* Likewise to call FUNDECL with no arguments.  */
+/* Conveniently construct a function call expression.  FNDECL names the
+   function to be called, N is the number of arguments, and the "..."
+   parameters are the argument expressions.  Unlike build_call_expr
+   this doesn't fold the call, hence it will always return a CALL_EXPR.  */
 
 tree
-build_call_0_expr (tree fundecl)
+build_call_n_expr (tree fndecl, int n, ...)
 {
-  /* We rely on build_call_nary to compute TREE_SIDE_EFFECTS.  This makes
-     it possible to propagate DECL_IS_PURE on parameterless functions.  */
-  tree call = build_call_nary (TREE_TYPE (TREE_TYPE (fundecl)),
-                              build_unary_op (ADDR_EXPR, NULL_TREE, fundecl),
-                              0);
-  return call;
+  va_list ap;
+  tree fntype = TREE_TYPE (fndecl);
+  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+  va_start (ap, n);
+  fn = build_call_valist (TREE_TYPE (fntype), fn, n, ap);
+  va_end (ap);
+  return fn;
 }
 \f
 /* Call a function that raises an exception and pass the line number and file
@@ -1483,7 +1542,7 @@ build_call_raise (int msg, Node_Id gnat_node, char kind)
          tree gnu_exception_entity
            = gnat_to_gnu_entity (Get_RT_Exception_Entity (msg), NULL_TREE, 0);
          tree gnu_call
-           = build_call_1_expr (gnu_local_raise,
+           = build_call_n_expr (gnu_local_raise, 1,
                                 build_unary_op (ADDR_EXPR, NULL_TREE,
                                                 gnu_exception_entity));
 
@@ -1513,7 +1572,7 @@ build_call_raise (int msg, Node_Id gnat_node, char kind)
                                           build_index_type (size_int (len)));
 
   return
-    build_call_2_expr (fndecl,
+    build_call_n_expr (fndecl, 2,
                       build1 (ADDR_EXPR,
                               build_pointer_type (unsigned_char_type_node),
                               filename),
@@ -1528,7 +1587,6 @@ tree
 build_call_raise_range (int msg, Node_Id gnat_node,
                        tree index, tree first, tree last)
 {
-  tree call;
   tree fndecl = gnat_raise_decls_ext[msg];
   tree filename;
   int line_number, column_number;
@@ -1561,19 +1619,16 @@ build_call_raise_range (int msg, Node_Id gnat_node,
   TREE_TYPE (filename) = build_array_type (unsigned_char_type_node,
                                           build_index_type (size_int (len)));
 
-  call = build_call_nary (TREE_TYPE (TREE_TYPE (fndecl)),
-                         build_unary_op (ADDR_EXPR, NULL_TREE, fndecl),
-                         6,
-                         build1 (ADDR_EXPR,
-                                 build_pointer_type (unsigned_char_type_node),
-                                 filename),
-                         build_int_cst (NULL_TREE, line_number),
-                         build_int_cst (NULL_TREE, column_number),
-                         convert (integer_type_node, index),
-                         convert (integer_type_node, first),
-                         convert (integer_type_node, last));
-  TREE_SIDE_EFFECTS (call) = 1;
-  return call;
+  return
+    build_call_n_expr (fndecl, 6,
+                      build1 (ADDR_EXPR,
+                              build_pointer_type (unsigned_char_type_node),
+                              filename),
+                      build_int_cst (NULL_TREE, line_number),
+                      build_int_cst (NULL_TREE, column_number),
+                      convert (integer_type_node, index),
+                      convert (integer_type_node, first),
+                      convert (integer_type_node, last));
 }
 
 /* Similar to build_call_raise, with extra information about the column
@@ -1583,7 +1638,6 @@ tree
 build_call_raise_column (int msg, Node_Id gnat_node)
 {
   tree fndecl = gnat_raise_decls_ext[msg];
-  tree call;
   tree filename;
   int line_number, column_number;
   const char *str;
@@ -1615,16 +1669,13 @@ build_call_raise_column (int msg, Node_Id gnat_node)
   TREE_TYPE (filename) = build_array_type (unsigned_char_type_node,
                                           build_index_type (size_int (len)));
 
-  call = build_call_nary (TREE_TYPE (TREE_TYPE (fndecl)),
-                         build_unary_op (ADDR_EXPR, NULL_TREE, fndecl),
-                         3,
-                         build1 (ADDR_EXPR,
-                                 build_pointer_type (unsigned_char_type_node),
-                                 filename),
-                         build_int_cst (NULL_TREE, line_number),
-                         build_int_cst (NULL_TREE, column_number));
-  TREE_SIDE_EFFECTS (call) = 1;
-  return call;
+  return
+    build_call_n_expr (fndecl, 3,
+                      build1 (ADDR_EXPR,
+                              build_pointer_type (unsigned_char_type_node),
+                              filename),
+                      build_int_cst (NULL_TREE, line_number),
+                      build_int_cst (NULL_TREE, column_number));
 }
 \f
 /* qsort comparer for the bit positions of two constructor elements
@@ -1700,14 +1751,15 @@ build_simple_component_ref (tree record_variable, tree component,
   gcc_assert ((TREE_CODE (record_type) == RECORD_TYPE
               || TREE_CODE (record_type) == UNION_TYPE
               || TREE_CODE (record_type) == QUAL_UNION_TYPE)
-             && TYPE_SIZE (record_type)
-             && (component != 0) != (field != 0));
+             && COMPLETE_TYPE_P (record_type)
+             && (component == NULL_TREE) != (field == NULL_TREE));
 
-  /* If no field was specified, look for a field with the specified name
-     in the current record only.  */
+  /* If no field was specified, look for a field with the specified name in
+     the current record only.  */
   if (!field)
-    for (field = TYPE_FIELDS (record_type); field;
-        field = TREE_CHAIN (field))
+    for (field = TYPE_FIELDS (record_type);
+        field;
+        field = DECL_CHAIN (field))
       if (DECL_NAME (field) == component)
        break;
 
@@ -1721,7 +1773,8 @@ build_simple_component_ref (tree record_variable, tree component,
       tree new_field;
 
       /* First loop thru normal components.  */
-      for (new_field = TYPE_FIELDS (record_type); new_field;
+      for (new_field = TYPE_FIELDS (record_type);
+          new_field;
           new_field = DECL_CHAIN (new_field))
        if (SAME_FIELD_P (field, new_field))
          break;
@@ -1741,12 +1794,12 @@ build_simple_component_ref (tree record_variable, tree component,
            return ref;
        }
 
-      /* Next, loop thru DECL_INTERNAL_P components if we haven't found
-         the component in the first search. Doing this search in 2 steps
-         is required to avoiding hidden homonymous fields in the
-         _Parent field.  */
+      /* Next, loop thru DECL_INTERNAL_P components if we haven't found the
+        component in the first search.  Doing this search in two steps is
+        required to avoid hidden homonymous fields in the _Parent field.  */
       if (!new_field)
-       for (new_field = TYPE_FIELDS (record_type); new_field;
+       for (new_field = TYPE_FIELDS (record_type);
+            new_field;
             new_field = DECL_CHAIN (new_field))
          if (DECL_INTERNAL_P (new_field))
            {
@@ -1755,7 +1808,6 @@ build_simple_component_ref (tree record_variable, tree component,
                                              NULL_TREE, new_field, no_fold_p);
              ref = build_simple_component_ref (field_ref, NULL_TREE, field,
                                                no_fold_p);
-
              if (ref)
                return ref;
            }
@@ -1766,16 +1818,15 @@ build_simple_component_ref (tree record_variable, tree component,
   if (!field)
     return NULL_TREE;
 
-  /* If the field's offset has overflowed, do not attempt to access it
-     as doing so may trigger sanity checks deeper in the back-end.
-     Note that we don't need to warn since this will be done on trying
-     to declare the object.  */
+  /* If the field's offset has overflowed, do not try to access it, as doing
+     so may trigger sanity checks deeper in the back-end.  Note that we don't
+     need to warn since this will be done on trying to declare the object.  */
   if (TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST
       && TREE_OVERFLOW (DECL_FIELD_OFFSET (field)))
     return NULL_TREE;
 
-  /* Look through conversion between type variants.  Note that this
-     is transparent as far as the field is concerned.  */
+  /* Look through conversion between type variants.  This is transparent as
+     far as the field is concerned.  */
   if (TREE_CODE (record_variable) == VIEW_CONVERT_EXPR
       && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (record_variable, 0)))
         == record_type)
@@ -1786,9 +1837,13 @@ build_simple_component_ref (tree record_variable, tree component,
   ref = build3 (COMPONENT_REF, TREE_TYPE (field), inner_variable, field,
                NULL_TREE);
 
-  if (TREE_READONLY (record_variable) || TREE_READONLY (field))
+  if (TREE_READONLY (record_variable)
+      || TREE_READONLY (field)
+      || TYPE_READONLY (record_type))
     TREE_READONLY (ref) = 1;
-  if (TREE_THIS_VOLATILE (record_variable) || TREE_THIS_VOLATILE (field)
+
+  if (TREE_THIS_VOLATILE (record_variable)
+      || TREE_THIS_VOLATILE (field)
       || TYPE_VOLATILE (record_type))
     TREE_THIS_VOLATILE (ref) = 1;
 
@@ -1797,8 +1852,8 @@ build_simple_component_ref (tree record_variable, tree component,
 
   /* The generic folder may punt in this case because the inner array type
      can be self-referential, but folding is in fact not problematic.  */
-  else if (TREE_CODE (record_variable) == CONSTRUCTOR
-          && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (record_variable)))
+  if (TREE_CODE (record_variable) == CONSTRUCTOR
+      && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (record_variable)))
     {
       VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (record_variable);
       unsigned HOST_WIDE_INT idx;
@@ -1809,8 +1864,7 @@ build_simple_component_ref (tree record_variable, tree component,
       return ref;
     }
 
-  else
-    return fold (ref);
+  return fold (ref);
 }
 \f
 /* Like build_simple_component_ref, except that we give an error if the
@@ -1842,7 +1896,6 @@ build_call_alloc_dealloc_proc (tree gnu_obj, tree gnu_size, tree gnu_type,
                               Entity_Id gnat_proc, Entity_Id gnat_pool)
 {
   tree gnu_proc = gnat_to_gnu (gnat_proc);
-  tree gnu_proc_addr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_proc);
   tree gnu_call;
 
   /* The storage pools are obviously always tagged types, but the
@@ -1866,13 +1919,11 @@ build_call_alloc_dealloc_proc (tree gnu_obj, tree gnu_size, tree gnu_type,
         comes the address of the object, for a deallocator, then the
         size and alignment.  */
       if (gnu_obj)
-       gnu_call = build_call_nary (TREE_TYPE (TREE_TYPE (gnu_proc)),
-                                   gnu_proc_addr, 4, gnu_pool_addr,
-                                   gnu_obj, gnu_size, gnu_align);
+       gnu_call = build_call_n_expr (gnu_proc, 4, gnu_pool_addr, gnu_obj,
+                                     gnu_size, gnu_align);
       else
-       gnu_call = build_call_nary (TREE_TYPE (TREE_TYPE (gnu_proc)),
-                                   gnu_proc_addr, 3, gnu_pool_addr,
-                                   gnu_size, gnu_align);
+       gnu_call = build_call_n_expr (gnu_proc, 3, gnu_pool_addr,
+                                     gnu_size, gnu_align);
     }
 
   /* Secondary stack case.  */
@@ -1888,14 +1939,11 @@ build_call_alloc_dealloc_proc (tree gnu_obj, tree gnu_size, tree gnu_type,
       /* The first arg is the address of the object, for a deallocator,
         then the size.  */
       if (gnu_obj)
-       gnu_call = build_call_nary (TREE_TYPE (TREE_TYPE (gnu_proc)),
-                                   gnu_proc_addr, 2, gnu_obj, gnu_size);
+       gnu_call = build_call_n_expr (gnu_proc, 2, gnu_obj, gnu_size);
       else
-       gnu_call = build_call_nary (TREE_TYPE (TREE_TYPE (gnu_proc)),
-                                   gnu_proc_addr, 1, gnu_size);
+       gnu_call = build_call_n_expr (gnu_proc, 1, gnu_size);
     }
 
-  TREE_SIDE_EFFECTS (gnu_call) = 1;
   return gnu_call;
 }
 
@@ -1935,9 +1983,9 @@ maybe_wrap_malloc (tree data_size, tree data_type, Node_Id gnat_node)
       && Nkind (gnat_node) == N_Allocator
       && (UI_To_Int (Esize (Etype (gnat_node))) == 32
           || Convention (Etype (gnat_node)) == Convention_C))
-    malloc_ptr = build_call_1_expr (malloc32_decl, size_to_malloc);
+    malloc_ptr = build_call_n_expr (malloc32_decl, 1, size_to_malloc);
   else
-    malloc_ptr = build_call_1_expr (malloc_decl, size_to_malloc);
+    malloc_ptr = build_call_n_expr (malloc_decl, 1, size_to_malloc);
 
   if (aligning_type)
     {
@@ -2016,7 +2064,7 @@ maybe_wrap_free (tree data_ptr, tree data_type)
   else
     free_ptr = data_ptr;
 
-  return build_call_1_expr (free_decl, free_ptr);
+  return build_call_n_expr (free_decl, 1, free_ptr);
 }
 
 /* Build a GCC tree to call an allocation or deallocation function.
@@ -2059,9 +2107,9 @@ build_call_alloc_dealloc (tree gnu_obj, tree gnu_size, tree gnu_type,
     }
 }
 \f
-/* Build a GCC tree to correspond to allocating an object of TYPE whose
+/* Build a GCC tree that corresponds to allocating an object of TYPE whose
    initial value is INIT, if INIT is nonzero.  Convert the expression to
-   RESULT_TYPE, which must be some type of pointer.  Return the tree.
+   RESULT_TYPE, which must be some pointer type, and return the result.
 
    GNAT_PROC and GNAT_POOL optionally give the procedure to call and
    the storage pool to use.  GNAT_NODE is used to provide an error
@@ -2074,13 +2122,22 @@ tree
 build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
                  Entity_Id gnat_pool, Node_Id gnat_node, bool ignore_init_type)
 {
-  tree size = TYPE_SIZE_UNIT (type);
-  tree result;
+  tree size, storage, storage_deref, storage_init;
 
   /* If the initializer, if present, is a NULL_EXPR, just return a new one.  */
   if (init && TREE_CODE (init) == NULL_EXPR)
     return build1 (NULL_EXPR, result_type, TREE_OPERAND (init, 0));
 
+  /* If the initializer, if present, is a COND_EXPR, deal with each branch.  */
+  else if (init && TREE_CODE (init) == COND_EXPR)
+    return build3 (COND_EXPR, result_type, TREE_OPERAND (init, 0),
+                  build_allocator (type, TREE_OPERAND (init, 1), result_type,
+                                   gnat_proc, gnat_pool, gnat_node,
+                                   ignore_init_type),
+                  build_allocator (type, TREE_OPERAND (init, 2), result_type,
+                                   gnat_proc, gnat_pool, gnat_node,
+                                   ignore_init_type));
+
   /* If RESULT_TYPE is a fat or thin pointer, set SIZE to be the sum of the
      sizes of the object and its template.  Allocate the whole thing and
      fill in the parts that are known.  */
@@ -2091,19 +2148,19 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
                                          get_identifier ("ALLOC"), false);
       tree template_type = TREE_TYPE (TYPE_FIELDS (storage_type));
       tree storage_ptr_type = build_pointer_type (storage_type);
-      tree storage;
 
       size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (storage_type),
                                             init);
 
-      /* If the size overflows, pass -1 so the allocator will raise
-        storage error.  */
+      /* If the size overflows, pass -1 so Storage_Error will be raised.  */
       if (TREE_CODE (size) == INTEGER_CST && TREE_OVERFLOW (size))
        size = ssize_int (-1);
 
       storage = build_call_alloc_dealloc (NULL_TREE, size, storage_type,
                                          gnat_proc, gnat_pool, gnat_node);
       storage = convert (storage_ptr_type, gnat_protect_expr (storage));
+      storage_deref = build_unary_op (INDIRECT_REF, NULL_TREE, storage);
+      TREE_THIS_NOTRAP (storage_deref) = 1;
 
       /* If there is an initializing expression, then make a constructor for
         the entire object including the bounds and copy it into the object.
@@ -2116,29 +2173,24 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
                                  build_template (template_type, type, init));
          CONSTRUCTOR_APPEND_ELT (v, DECL_CHAIN (TYPE_FIELDS (storage_type)),
                                  init);
-         return convert
-           (result_type,
-            build2 (COMPOUND_EXPR, storage_ptr_type,
-                    build_binary_op
-                    (MODIFY_EXPR, NULL_TREE,
-                     build_unary_op (INDIRECT_REF, NULL_TREE,
-                                     convert (storage_ptr_type, storage)),
-                     gnat_build_constructor (storage_type, v)),
-                    convert (storage_ptr_type, storage)));
+         storage_init
+           = build_binary_op (MODIFY_EXPR, NULL_TREE, storage_deref,
+                              gnat_build_constructor (storage_type, v));
        }
       else
-       return build2
-         (COMPOUND_EXPR, result_type,
-          build_binary_op
-          (MODIFY_EXPR, NULL_TREE,
-           build_component_ref
-           (build_unary_op (INDIRECT_REF, NULL_TREE,
-                            convert (storage_ptr_type, storage)),
-            NULL_TREE, TYPE_FIELDS (storage_type), false),
-           build_template (template_type, type, NULL_TREE)),
-          convert (result_type, convert (storage_ptr_type, storage)));
+       storage_init
+         = build_binary_op (MODIFY_EXPR, NULL_TREE,
+                            build_component_ref (storage_deref, NULL_TREE,
+                                                 TYPE_FIELDS (storage_type),
+                                                 false),
+                            build_template (template_type, type, NULL_TREE));
+
+      return build2 (COMPOUND_EXPR, result_type,
+                    storage_init, convert (result_type, storage));
     }
 
+  size = TYPE_SIZE_UNIT (type);
+
   /* If we have an initializing expression, see if its size is simpler
      than the size from the type.  */
   if (!ignore_init_type && init && TYPE_SIZE_UNIT (TREE_TYPE (init))
@@ -2158,32 +2210,28 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
        size = max_size (size, true);
     }
 
-  /* If the size overflows, pass -1 so the allocator will raise
-     storage error.  */
+  /* If the size overflows, pass -1 so Storage_Error will be raised.  */
   if (TREE_CODE (size) == INTEGER_CST && TREE_OVERFLOW (size))
     size = ssize_int (-1);
 
-  result = convert (result_type,
-                   build_call_alloc_dealloc (NULL_TREE, size, type,
-                                             gnat_proc, gnat_pool,
-                                             gnat_node));
+  storage = convert (result_type,
+                    build_call_alloc_dealloc (NULL_TREE, size, type,
+                                              gnat_proc, gnat_pool,
+                                              gnat_node));
 
   /* If we have an initial value, protect the new address, assign the value
      and return the address with a COMPOUND_EXPR.  */
   if (init)
     {
-      result = gnat_protect_expr (result);
-      result
-       = build2 (COMPOUND_EXPR, TREE_TYPE (result),
-                 build_binary_op
-                 (MODIFY_EXPR, NULL_TREE,
-                  build_unary_op (INDIRECT_REF,
-                                  TREE_TYPE (TREE_TYPE (result)), result),
-                  init),
-                 result);
+      storage = gnat_protect_expr (storage);
+      storage_deref = build_unary_op (INDIRECT_REF, NULL_TREE, storage);
+      TREE_THIS_NOTRAP (storage_deref) = 1;
+      storage_init
+       = build_binary_op (MODIFY_EXPR, NULL_TREE, storage_deref, init);
+      return build2 (COMPOUND_EXPR, result_type, storage_init, storage);
     }
 
-  return convert (result_type, result);
+  return storage;
 }
 \f
 /* Indicate that we need to take the address of T and that it therefore
@@ -2398,7 +2446,10 @@ gnat_stabilize_reference_1 (tree e, bool force)
   TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
 
-  if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
+  if (code == INDIRECT_REF
+      || code == UNCONSTRAINED_ARRAY_REF
+      || code == ARRAY_REF
+      || code == ARRAY_RANGE_REF)
     TREE_THIS_NOTRAP (result) = TREE_THIS_NOTRAP (e);
 
   return result;
@@ -2534,8 +2585,93 @@ gnat_stabilize_reference (tree ref, bool force, bool *success)
   TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (ref);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
 
-  if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
+  if (code == INDIRECT_REF
+      || code == UNCONSTRAINED_ARRAY_REF
+      || code == ARRAY_REF
+      || code == ARRAY_RANGE_REF)
     TREE_THIS_NOTRAP (result) = TREE_THIS_NOTRAP (ref);
 
   return result;
 }
+
+/* If EXPR is an expression that is invariant in the current function, in the
+   sense that it can be evaluated anywhere in the function and any number of
+   times, return EXPR or an equivalent expression.  Otherwise return NULL.  */
+
+tree
+gnat_invariant_expr (tree expr)
+{
+  tree type = TREE_TYPE (expr), t;
+
+  expr = remove_conversions (expr, false);
+
+  while ((TREE_CODE (expr) == CONST_DECL
+         || (TREE_CODE (expr) == VAR_DECL && TREE_READONLY (expr)))
+        && decl_function_context (expr) == current_function_decl
+        && DECL_INITIAL (expr))
+    expr = remove_conversions (DECL_INITIAL (expr), false);
+
+  if (TREE_CONSTANT (expr))
+    return fold_convert (type, expr);
+
+  t = expr;
+
+  while (true)
+    {
+      switch (TREE_CODE (t))
+       {
+       case COMPONENT_REF:
+         if (TREE_OPERAND (t, 2) != NULL_TREE)
+           return NULL_TREE;
+         break;
+
+       case ARRAY_REF:
+       case ARRAY_RANGE_REF:
+         if (!TREE_CONSTANT (TREE_OPERAND (t, 1))
+             || TREE_OPERAND (t, 2) != NULL_TREE
+             || TREE_OPERAND (t, 3) != NULL_TREE)
+           return NULL_TREE;
+         break;
+
+       case BIT_FIELD_REF:
+       case VIEW_CONVERT_EXPR:
+       case REALPART_EXPR:
+       case IMAGPART_EXPR:
+         break;
+
+       case INDIRECT_REF:
+         if (!TREE_READONLY (t)
+             || TREE_SIDE_EFFECTS (t)
+             || !TREE_THIS_NOTRAP (t))
+           return NULL_TREE;
+         break;
+
+       default:
+         goto object;
+       }
+
+      t = TREE_OPERAND (t, 0);
+    }
+
+object:
+  if (TREE_SIDE_EFFECTS (t))
+    return NULL_TREE;
+
+  if (TREE_CODE (t) == CONST_DECL
+      && (DECL_EXTERNAL (t)
+         || decl_function_context (t) != current_function_decl))
+    return fold_convert (type, expr);
+
+  if (!TREE_READONLY (t))
+    return NULL_TREE;
+
+  if (TREE_CODE (t) == PARM_DECL)
+    return fold_convert (type, expr);
+
+  if (TREE_CODE (t) == VAR_DECL
+      && (DECL_EXTERNAL (t)
+         || decl_function_context (t) != current_function_decl))
+    return fold_convert (type, expr);
+
+  return NULL_TREE;
+}