OSDN Git Service

* gcc-interface/gigi.h (gnat_mark_addressable): Rename parameter.
[pf3gnuchains/gcc-fork.git] / gcc / ada / gcc-interface / utils2.c
index fcd9ecd..5db38c5 100644 (file)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *          Copyright (C) 1992-2009, Free Software Foundation, Inc.         *
+ *          Copyright (C) 1992-2010, Free Software Foundation, Inc.         *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
@@ -49,8 +49,6 @@
 #include "gigi.h"
 
 static tree find_common_type (tree, tree);
-static bool contains_save_expr_p (tree);
-static tree contains_null_expr (tree);
 static tree compare_arrays (tree, tree, tree);
 static tree nonbinary_modular_operation (enum tree_code, tree, tree, tree);
 static tree build_simple_component_ref (tree, tree, tree, bool);
@@ -233,100 +231,13 @@ find_common_type (tree t1, tree t2)
   return NULL_TREE;
 }
 \f
-/* See if EXP contains a SAVE_EXPR in a position where we would
-   normally put it.
+/* Return an expression tree representing an equality comparison of A1 and A2,
+   two objects of type ARRAY_TYPE.  The result should be of type RESULT_TYPE.
 
-   ??? This is a real kludge, but is probably the best approach short
-   of some very general solution.  */
-
-static bool
-contains_save_expr_p (tree exp)
-{
-  switch (TREE_CODE (exp))
-    {
-    case SAVE_EXPR:
-      return true;
-
-    case ADDR_EXPR:  case INDIRECT_REF:
-    case COMPONENT_REF:
-    CASE_CONVERT: case VIEW_CONVERT_EXPR:
-      return contains_save_expr_p (TREE_OPERAND (exp, 0));
-
-    case CONSTRUCTOR:
-      {
-       tree value;
-       unsigned HOST_WIDE_INT ix;
-
-       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), ix, value)
-         if (contains_save_expr_p (value))
-           return true;
-       return false;
-      }
-
-    default:
-      return false;
-    }
-}
-\f
-/* See if EXP contains a NULL_EXPR in an expression we use for sizes. Return
-   it if so.  This is used to detect types whose sizes involve computations
-   that are known to raise Constraint_Error.  */
-
-static tree
-contains_null_expr (tree exp)
-{
-  tree tem;
-
-  if (TREE_CODE (exp) == NULL_EXPR)
-    return exp;
-
-  switch (TREE_CODE_CLASS (TREE_CODE (exp)))
-    {
-    case tcc_unary:
-      return contains_null_expr (TREE_OPERAND (exp, 0));
-
-    case tcc_comparison:
-    case tcc_binary:
-      tem = contains_null_expr (TREE_OPERAND (exp, 0));
-      if (tem)
-       return tem;
-
-      return contains_null_expr (TREE_OPERAND (exp, 1));
-
-    case tcc_expression:
-      switch (TREE_CODE (exp))
-       {
-       case SAVE_EXPR:
-         return contains_null_expr (TREE_OPERAND (exp, 0));
-
-       case COND_EXPR:
-         tem = contains_null_expr (TREE_OPERAND (exp, 0));
-         if (tem)
-           return tem;
-
-         tem = contains_null_expr (TREE_OPERAND (exp, 1));
-         if (tem)
-           return tem;
-
-         return contains_null_expr (TREE_OPERAND (exp, 2));
-
-       default:
-         return 0;
-       }
-
-    default:
-      return 0;
-    }
-}
-\f
-/* Return an expression tree representing an equality comparison of
-   A1 and A2, two objects of ARRAY_TYPE.  The returned expression should
-   be of type RESULT_TYPE
-
-   Two arrays are equal in one of two ways: (1) if both have zero length
-   in some dimension (not necessarily the same dimension) or (2) if the
-   lengths in each dimension are equal and the data is equal.  We perform the
-   length tests in as efficient a manner as possible.  */
+   Two arrays are equal in one of two ways: (1) if both have zero length in
+   some dimension (not necessarily the same dimension) or (2) if the lengths
+   in each dimension are equal and the data is equal.  We perform the length
+   tests in as efficient a manner as possible.  */
 
 static tree
 compare_arrays (tree result_type, tree a1, tree a2)
@@ -336,8 +247,18 @@ compare_arrays (tree result_type, tree a1, tree a2)
   tree result = convert (result_type, integer_one_node);
   tree a1_is_null = convert (result_type, integer_zero_node);
   tree a2_is_null = convert (result_type, integer_zero_node);
+  bool a1_side_effects_p = TREE_SIDE_EFFECTS (a1);
+  bool a2_side_effects_p = TREE_SIDE_EFFECTS (a2);
   bool length_zero_p = false;
 
+  /* 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.  */
+  if (a1_side_effects_p)
+    a1 = protect_multiple_eval (a1);
+
+  if (a2_side_effects_p)
+    a2 = protect_multiple_eval (a2);
+
   /* Process each dimension separately and compare the lengths.  If any
      dimension has a size known to be zero, set SIZE_ZERO_P to 1 to
      suppress the comparison of the data.  */
@@ -350,9 +271,9 @@ compare_arrays (tree result_type, tree a1, tree a2)
       tree bt = get_base_type (TREE_TYPE (lb1));
       tree length1 = fold_build2 (MINUS_EXPR, bt, ub1, lb1);
       tree length2 = fold_build2 (MINUS_EXPR, bt, ub2, lb2);
-      tree nbt;
-      tree tem;
       tree comparison, this_a1_is_null, this_a2_is_null;
+      tree nbt, tem;
+      bool btem;
 
       /* If the length of the first array is a constant, swap our operands
         unless the length of the second array is the constant zero.
@@ -367,6 +288,8 @@ compare_arrays (tree result_type, tree a1, tree a2)
          tem = ub1, ub1 = ub2, ub2 = tem;
          tem = length1, length1 = length2, length2 = tem;
          tem = a1_is_null, a1_is_null = a2_is_null, a2_is_null = tem;
+         btem = a1_side_effects_p, a1_side_effects_p = a2_side_effects_p,
+         a2_side_effects_p = btem;
        }
 
       /* If the length of this dimension in the second array is the constant
@@ -449,11 +372,13 @@ compare_arrays (tree result_type, tree a1, tree a2)
       tree type = find_common_type (TREE_TYPE (a1), TREE_TYPE (a2));
 
       if (type)
-       a1 = convert (type, a1), a2 = convert (type, a2);
+       {
+         a1 = convert (type, a1),
+         a2 = convert (type, a2);
+       }
 
       result = build_binary_op (TRUTH_ANDIF_EXPR, result_type, result,
                                fold_build2 (EQ_EXPR, result_type, a1, a2));
-
     }
 
   /* The result is also true if both sizes are zero.  */
@@ -462,14 +387,13 @@ compare_arrays (tree result_type, tree a1, tree a2)
                                             a1_is_null, a2_is_null),
                            result);
 
-  /* If either operand contains SAVE_EXPRs, they have to be evaluated before
-     starting the comparison above since the place it would be otherwise
-     evaluated would be wrong.  */
-
-  if (contains_save_expr_p (a1))
+  /* If either operand has side-effects, they have to be evaluated before
+     starting the comparison above since the place they would be otherwise
+     evaluated could be wrong.  */
+  if (a1_side_effects_p)
     result = build2 (COMPOUND_EXPR, result_type, a1, result);
 
-  if (contains_save_expr_p (a2))
+  if (a2_side_effects_p)
     result = build2 (COMPOUND_EXPR, result_type, a2, result);
 
   return result;
@@ -547,7 +471,7 @@ nonbinary_modular_operation (enum tree_code op_code, tree type, tree lhs,
   /* For subtraction, add the modulus back if we are negative.  */
   else if (op_code == MINUS_EXPR)
     {
-      result = save_expr (result);
+      result = protect_multiple_eval (result);
       result = fold_build3 (COND_EXPR, op_type,
                            fold_build2 (LT_EXPR, integer_type_node, result,
                                         convert (op_type, integer_zero_node)),
@@ -558,7 +482,7 @@ nonbinary_modular_operation (enum tree_code op_code, tree type, tree lhs,
   /* For the other operations, subtract the modulus if we are >= it.  */
   else
     {
-      result = save_expr (result);
+      result = protect_multiple_eval (result);
       result = fold_build3 (COND_EXPR, op_type,
                            fold_build2 (GE_EXPR, integer_type_node,
                                         result, modulus),
@@ -609,6 +533,7 @@ build_binary_op (enum tree_code op_code, tree result_type,
 
   switch (op_code)
     {
+    case INIT_EXPR:
     case MODIFY_EXPR:
       /* If there were integral or pointer conversions on the LHS, remove
         them; we'll be putting them back below if needed.  Likewise for
@@ -755,6 +680,12 @@ build_binary_op (enum tree_code op_code, tree result_type,
          left_type = TREE_TYPE (left_operand);
        }
 
+      /* For a range, make sure the element type is consistent.  */
+      if (op_code == ARRAY_RANGE_REF
+         && TREE_TYPE (operation_type) != TREE_TYPE (left_type))
+       operation_type = build_array_type (TREE_TYPE (left_type),
+                                          TYPE_DOMAIN (operation_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);
@@ -828,26 +759,28 @@ build_binary_op (enum tree_code op_code, tree result_type,
          return result;
        }
 
-      /* Otherwise, the base types must be the same unless the objects are
-        fat pointers or records.  If we have records, use the best type and
-        convert both operands to that type.  */
+      /* Otherwise, the base types must be the same, unless they are both fat
+        pointer types or record types.  In the latter case, use the best type
+        and convert both operands to that type.  */
       if (left_base_type != right_base_type)
        {
          if (TYPE_IS_FAT_POINTER_P (left_base_type)
-             && TYPE_IS_FAT_POINTER_P (right_base_type)
-             && TYPE_MAIN_VARIANT (left_base_type)
-                == TYPE_MAIN_VARIANT (right_base_type))
-           best_type = left_base_type;
+             && TYPE_IS_FAT_POINTER_P (right_base_type))
+           {
+             gcc_assert (TYPE_MAIN_VARIANT (left_base_type)
+                         == TYPE_MAIN_VARIANT (right_base_type));
+             best_type = left_base_type;
+           }
+
          else if (TREE_CODE (left_base_type) == RECORD_TYPE
                   && TREE_CODE (right_base_type) == RECORD_TYPE)
            {
-             /* The only way these are permitted to be the same is if both
-                types have the same name.  In that case, one of them must
-                not be self-referential.  Use that one as the best type.
-                Even better is if one is of fixed size.  */
+             /* The only way this is permitted is if both types have the same
+                name.  In that case, one of them must not be self-referential.
+                Use it as the best type.  Even better with a fixed size.  */
              gcc_assert (TYPE_NAME (left_base_type)
-                         && (TYPE_NAME (left_base_type)
-                             == TYPE_NAME (right_base_type)));
+                         && TYPE_NAME (left_base_type)
+                            == TYPE_NAME (right_base_type));
 
              if (TREE_CONSTANT (TYPE_SIZE (left_base_type)))
                best_type = left_base_type;
@@ -860,34 +793,34 @@ build_binary_op (enum tree_code op_code, tree result_type,
              else
                gcc_unreachable ();
            }
+
          else
            gcc_unreachable ();
 
          left_operand = convert (best_type, left_operand);
          right_operand = convert (best_type, right_operand);
        }
-
-      /* If we are comparing a fat pointer against zero, we need to
-        just compare the data pointer.  */
-      else 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))
-       {
-         right_operand = build_component_ref (left_operand, NULL_TREE,
-                                              TYPE_FIELDS (left_base_type),
-                                              false);
-         left_operand = convert (TREE_TYPE (right_operand),
-                                 integer_zero_node);
-       }
       else
        {
          left_operand = convert (left_base_type, left_operand);
          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))
+       {
+         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);
+       }
+
       modulus = NULL_TREE;
       break;
 
@@ -1232,7 +1165,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
        {
          result = build1 (UNCONSTRAINED_ARRAY_REF,
                           TYPE_UNCONSTRAINED_ARRAY (type), operand);
-         TREE_READONLY (result) = TREE_STATIC (result)
+         TREE_READONLY (result)
            = TYPE_READONLY (TYPE_UNCONSTRAINED_ARRAY (type));
        }
       else if (TREE_CODE (operand) == ADDR_EXPR)
@@ -1389,45 +1322,40 @@ build_cond_expr (tree result_type, tree condition_operand,
   return result;
 }
 
-/* Similar, but for RETURN_EXPR.  If RESULT_DECL is non-zero, build
-   a RETURN_EXPR around the assignment of RET_VAL to RESULT_DECL.
-   If RESULT_DECL is zero, build a bare RETURN_EXPR.  */
+/* Similar, but for RETURN_EXPR.  If RET_VAL is non-null, build a RETURN_EXPR
+   around the assignment of RET_VAL to RET_OBJ.  Otherwise just build a bare
+   RETURN_EXPR around RESULT_OBJ, which may be null in this case.  */
 
 tree
-build_return_expr (tree result_decl, tree ret_val)
+build_return_expr (tree ret_obj, tree ret_val)
 {
   tree result_expr;
 
-  if (result_decl)
+  if (ret_val)
     {
       /* The gimplifier explicitly enforces the following invariant:
 
-           RETURN_EXPR
-               |
-           MODIFY_EXPR
-           /        \
-          /          \
-      RESULT_DECL    ...
-
-      As a consequence, type-homogeneity dictates that we use the type
-      of the RESULT_DECL as the operation type.  */
-
-      tree operation_type = TREE_TYPE (result_decl);
+             RETURN_EXPR
+                 |
+             MODIFY_EXPR
+             /        \
+            /          \
+        RET_OBJ        ...
 
-      /* Convert the right operand to the operation type.  Note that
-         it's the same transformation as in the MODIFY_EXPR case of
-         build_binary_op with the additional guarantee that the type
-         cannot involve a placeholder, since otherwise the function
-         would use the "target pointer" return mechanism.  */
+        As a consequence, type consistency dictates that we use the type
+        of the RET_OBJ as the operation type.  */
+      tree operation_type = TREE_TYPE (ret_obj);
 
+      /* Convert the right operand to the operation type.  Note that it's the
+        same transformation as in the MODIFY_EXPR case of build_binary_op,
+        with the assumption that the type cannot involve a placeholder.  */
       if (operation_type != TREE_TYPE (ret_val))
        ret_val = convert (operation_type, ret_val);
 
-      result_expr
-       = build2 (MODIFY_EXPR, operation_type, result_decl, ret_val);
+      result_expr = build2 (MODIFY_EXPR, operation_type, ret_obj, ret_val);
     }
   else
-    result_expr = NULL_TREE;
+    result_expr = ret_obj;
 
   return build1 (RETURN_EXPR, void_type_node, result_expr);
 }
@@ -1586,13 +1514,6 @@ gnat_build_constructor (tree type, tree list)
 
       if (TREE_SIDE_EFFECTS (val))
        side_effects = true;
-
-      /* Propagate an NULL_EXPR from the size of the type.  We won't ever
-        be executing the code we generate here in that case, but handle it
-        specially to avoid the compiler blowing up.  */
-      if (TREE_CODE (type) == RECORD_TYPE
-         && (result = contains_null_expr (DECL_SIZE (obj))) != NULL_TREE)
-       return build1 (NULL_EXPR, type, TREE_OPERAND (result, 0));
     }
 
   /* For record types with constant components only, sort field list
@@ -1879,7 +1800,7 @@ maybe_wrap_malloc (tree data_size, tree data_type, Node_Id gnat_node)
     {
       /* Latch malloc's return value and get a pointer to the aligning field
         first.  */
-      tree storage_ptr = save_expr (malloc_ptr);
+      tree storage_ptr = protect_multiple_eval (malloc_ptr);
 
       tree aligning_record_addr
        = convert (build_pointer_type (aligning_type), storage_ptr);
@@ -2114,12 +2035,11 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
                                              gnat_proc, gnat_pool,
                                              gnat_node));
 
-  /* If we have an initial value, put the new address into a SAVE_EXPR, assign
-     the value, and return the address.  Do this with a COMPOUND_EXPR.  */
-
+  /* If we have an initial value, protect the new address, assign the value
+     and return the address with a COMPOUND_EXPR.  */
   if (init)
     {
-      result = save_expr (result);
+      result = protect_multiple_eval (result);
       result
        = build2 (COMPOUND_EXPR, TREE_TYPE (result),
                  build_binary_op
@@ -2184,14 +2104,14 @@ fill_vms_descriptor (tree expr, Entity_Id gnat_formal, Node_Id gnat_actual)
   return gnat_build_constructor (record_type, nreverse (const_list));
 }
 
-/* Indicate that we need to make the address of EXPR_NODE and it therefore
+/* Indicate that we need to take the address of T and that it therefore
    should not be allocated in a register.  Returns true if successful.  */
 
 bool
-gnat_mark_addressable (tree expr_node)
+gnat_mark_addressable (tree t)
 {
-  while (1)
-    switch (TREE_CODE (expr_node))
+  while (true)
+    switch (TREE_CODE (t))
       {
       case ADDR_EXPR:
       case COMPONENT_REF:
@@ -2202,27 +2122,27 @@ gnat_mark_addressable (tree expr_node)
       case VIEW_CONVERT_EXPR:
       case NON_LVALUE_EXPR:
       CASE_CONVERT:
-       expr_node = TREE_OPERAND (expr_node, 0);
+       t = TREE_OPERAND (t, 0);
        break;
 
       case CONSTRUCTOR:
-       TREE_ADDRESSABLE (expr_node) = 1;
+       TREE_ADDRESSABLE (t) = 1;
        return true;
 
       case VAR_DECL:
       case PARM_DECL:
       case RESULT_DECL:
-       TREE_ADDRESSABLE (expr_node) = 1;
+       TREE_ADDRESSABLE (t) = 1;
        return true;
 
       case FUNCTION_DECL:
-       TREE_ADDRESSABLE (expr_node) = 1;
+       TREE_ADDRESSABLE (t) = 1;
        return true;
 
       case CONST_DECL:
-       return (DECL_CONST_CORRESPONDING_VAR (expr_node)
-               && (gnat_mark_addressable
-                   (DECL_CONST_CORRESPONDING_VAR (expr_node))));
+       return DECL_CONST_CORRESPONDING_VAR (t)
+              && gnat_mark_addressable (DECL_CONST_CORRESPONDING_VAR (t));
+
       default:
        return true;
     }