OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / ada / gcc-interface / utils.c
index dcf0558..8c5dc58 100644 (file)
@@ -577,6 +577,7 @@ init_gigi_decls (tree long_long_float_type, tree exception_type)
   /* Build the special descriptor type and its null node if needed.  */
   if (TARGET_VTABLE_USES_DESCRIPTORS)
     {
+      tree null_node = fold_convert (ptr_void_ftype, null_pointer_node);
       tree field_list = NULL_TREE, null_list = NULL_TREE;
       int j;
 
@@ -588,7 +589,7 @@ init_gigi_decls (tree long_long_float_type, tree exception_type)
                                          fdesc_type_node, 0, 0, 0, 1);
          TREE_CHAIN (field) = field_list;
          field_list = field;
-         null_list = tree_cons (field, null_pointer_node, null_list);
+         null_list = tree_cons (field, null_node, null_list);
        }
 
       finish_record_type (fdesc_type_node, nreverse (field_list), 0, false);
@@ -838,7 +839,7 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level,
   if (rep_level > 0)
     {
       TYPE_ALIGN (record_type) = MAX (BITS_PER_UNIT, TYPE_ALIGN (record_type));
-      TYPE_MODE (record_type) = BLKmode;
+      SET_TYPE_MODE (record_type, BLKmode);
 
       if (!had_size_unit)
        TYPE_SIZE_UNIT (record_type) = size_zero_node;
@@ -1706,7 +1707,7 @@ create_field_decl (tree field_name, tree field_type, tree record_type,
      we get the alignment from the type, indicate if this is from an explicit
      user request, which prevents stor-layout from lowering it later on.  */
   {
-    int bit_align
+    unsigned int bit_align
       = (DECL_BIT_FIELD (field_decl) ? 1
         : packed && TYPE_MODE (field_type) != BLKmode ? BITS_PER_UNIT : 0);
 
@@ -1973,12 +1974,16 @@ create_subprog_decl (tree subprog_name, tree asm_name,
   tree return_type  = TREE_TYPE (subprog_type);
   tree subprog_decl = build_decl (FUNCTION_DECL, subprog_name, subprog_type);
 
-  /* If this is a function nested inside an inlined external function, it
-     means we aren't going to compile the outer function unless it is
-     actually inlined, so do the same for us.  */
-  if (current_function_decl && DECL_INLINE (current_function_decl)
+  /* If this is a non-inline function nested inside an inlined external
+     function, we cannot honor both requests without cloning the nested
+     function in the current unit since it is private to the other unit.
+     We could inline the nested function as well but it's probably better
+     to err on the side of too little inlining.  */
+  if (!inline_flag
+      && current_function_decl
+      && DECL_DECLARED_INLINE_P (current_function_decl)
       && DECL_EXTERNAL (current_function_decl))
-    extern_flag = true;
+    DECL_DECLARED_INLINE_P (current_function_decl) = 0;
 
   DECL_EXTERNAL (subprog_decl)  = extern_flag;
   TREE_PUBLIC (subprog_decl)    = public_flag;
@@ -1986,6 +1991,7 @@ create_subprog_decl (tree subprog_name, tree asm_name,
   TREE_READONLY (subprog_decl)  = TYPE_READONLY (subprog_type);
   TREE_THIS_VOLATILE (subprog_decl) = TYPE_VOLATILE (subprog_type);
   TREE_SIDE_EFFECTS (subprog_decl) = TYPE_VOLATILE (subprog_type);
+  DECL_DECLARED_INLINE_P (subprog_decl) = inline_flag;
   DECL_ARGUMENTS (subprog_decl) = param_decl_list;
   DECL_RESULT (subprog_decl)    = build_decl (RESULT_DECL, 0, return_type);
   DECL_ARTIFICIAL (DECL_RESULT (subprog_decl)) = 1;
@@ -2004,9 +2010,6 @@ create_subprog_decl (tree subprog_name, tree asm_name,
       DECL_BY_REFERENCE (result_decl) = 1;
     }
 
-  if (inline_flag)
-    DECL_DECLARED_INLINE_P (subprog_decl) = 1;
-
   if (asm_name)
     {
       SET_DECL_ASSEMBLER_NAME (subprog_decl, asm_name);
@@ -2232,10 +2235,6 @@ end_subprog_body (tree body, bool elab_p)
   DECL_INITIAL (fndecl) = current_binding_level->block;
   gnat_poplevel ();
 
-  /* Deal with inline.  If declared inline or we should default to inline,
-     set the flag in the decl.  */
-  DECL_INLINE (fndecl) = 1;
-
   /* We handle pending sizes via the elaboration of types, so we don't
      need to save them.  */
   get_pending_sizes ();
@@ -2446,10 +2445,13 @@ gnat_types_compatible_p (tree t1, tree t2)
      the same component type and the same domain.  */
   if (code == ARRAY_TYPE
       && TREE_TYPE (t1) == TREE_TYPE (t2)
-      && tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (t1)),
-                            TYPE_MIN_VALUE (TYPE_DOMAIN (t2)))
-      && tree_int_cst_equal (TYPE_MAX_VALUE (TYPE_DOMAIN (t1)),
-                            TYPE_MAX_VALUE (TYPE_DOMAIN (t2))))
+      && (TYPE_DOMAIN (t1) == TYPE_DOMAIN (t2)
+         || (TYPE_DOMAIN (t1)
+             && TYPE_DOMAIN (t2)      
+             && tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (t1)),
+                                    TYPE_MIN_VALUE (TYPE_DOMAIN (t2)))
+             && tree_int_cst_equal (TYPE_MAX_VALUE (TYPE_DOMAIN (t1)),
+                                    TYPE_MAX_VALUE (TYPE_DOMAIN (t2))))))
     return 1;
 
   /* Padding record types are also compatible if they pad the same
@@ -4491,8 +4493,72 @@ maybe_unconstrained_array (tree exp)
   return exp;
 }
 \f
+/* Return true if EXPR is an expression that can be folded as an operand
+   of a VIEW_CONVERT_EXPR.  See the head comment of unchecked_convert for
+   the rationale.  */
+
+static bool
+can_fold_for_view_convert_p (tree expr)
+{
+  tree t1, t2;
+
+  /* The folder will fold NOP_EXPRs between integral types with the same
+     precision (in the middle-end's sense).  We cannot allow it if the
+     types don't have the same precision in the Ada sense as well.  */
+  if (TREE_CODE (expr) != NOP_EXPR)
+    return true;
+
+  t1 = TREE_TYPE (expr);
+  t2 = TREE_TYPE (TREE_OPERAND (expr, 0));
+
+  /* Defer to the folder for non-integral conversions.  */
+  if (!(INTEGRAL_TYPE_P (t1) && INTEGRAL_TYPE_P (t2)))
+    return true;
+
+  /* Only fold conversions that preserve both precisions.  */
+  if (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
+      && operand_equal_p (rm_size (t1), rm_size (t2), 0))
+    return true;
+
+  return false;
+}
+
 /* Return an expression that does an unchecked conversion of EXPR to TYPE.
-   If NOTRUNC_P is true, truncation operations should be suppressed.  */
+   If NOTRUNC_P is true, truncation operations should be suppressed.
+
+   Special care is required with (source or target) integral types whose
+   precision is not equal to their size, to make sure we fetch or assign
+   the value bits whose location might depend on the endianness, e.g.
+
+     Rmsize : constant := 8;
+     subtype Int is Integer range 0 .. 2 ** Rmsize - 1;
+
+     type Bit_Array is array (1 .. Rmsize) of Boolean;
+     pragma Pack (Bit_Array);
+
+     function To_Bit_Array is new Unchecked_Conversion (Int, Bit_Array);
+
+     Value : Int := 2#1000_0001#;
+     Vbits : Bit_Array := To_Bit_Array (Value);
+
+   we expect the 8 bits at Vbits'Address to always contain Value, while
+   their original location depends on the endianness, at Value'Address
+   on a little-endian architecture but not on a big-endian one.
+
+   ??? There is a problematic discrepancy between what is called precision
+   here (and more generally throughout gigi) for integral types and what is
+   called precision in the middle-end.  In the former case it's the RM size
+   as given by TYPE_RM_SIZE (or rm_size) whereas it's TYPE_PRECISION in the
+   latter case, the hitch being that they are not equal when they matter,
+   that is when the number of value bits is not equal to the type's size:
+   TYPE_RM_SIZE does give the number of value bits but TYPE_PRECISION is set
+   to the size.  The sole exception are BOOLEAN_TYPEs for which both are 1.
+
+   The consequence is that gigi must duplicate code bridging the gap between
+   the type's size and its precision that exists for TYPE_PRECISION in the
+   middle-end, because the latter knows nothing about TYPE_RM_SIZE, and be
+   wary of transformations applied in the middle-end based on TYPE_PRECISION
+   because this value doesn't reflect the actual precision for Ada.  */
 
 tree
 unchecked_convert (tree type, tree expr, bool notrunc_p)
@@ -4519,14 +4585,10 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
               && TYPE_JUSTIFIED_MODULAR_P (etype))))
       || TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE)
     {
-      tree rtype = type;
-      bool final_unchecked = false;
-
       if (TREE_CODE (etype) == INTEGER_TYPE
          && TYPE_BIASED_REPRESENTATION_P (etype))
        {
          tree ntype = copy_type (etype);
-
          TYPE_BIASED_REPRESENTATION_P (ntype) = 0;
          TYPE_MAIN_VARIANT (ntype) = ntype;
          expr = build1 (NOP_EXPR, ntype, expr);
@@ -4535,15 +4597,18 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
       if (TREE_CODE (type) == INTEGER_TYPE
          && TYPE_BIASED_REPRESENTATION_P (type))
        {
-         rtype = copy_type (type);
+         tree rtype = copy_type (type);
          TYPE_BIASED_REPRESENTATION_P (rtype) = 0;
          TYPE_MAIN_VARIANT (rtype) = rtype;
+         expr = convert (rtype, expr);
+         expr = build1 (NOP_EXPR, type, expr);
        }
 
-      /* We have another special case: if we are unchecked converting subtype
-        into a base type, we need to ensure that VRP doesn't propagate range
-        information since this conversion may be done precisely to validate
-        that the object is within the range it is supposed to have.  */
+      /* We have another special case: if we are unchecked converting either
+        a subtype or a type with limited range into a base type, we need to
+        ensure that VRP doesn't propagate range information because this
+        conversion may be done precisely to validate that the object is
+        within the range it is supposed to have.  */
       else if (TREE_CODE (expr) != INTEGER_CST
               && TREE_CODE (type) == INTEGER_TYPE && !TREE_TYPE (type)
               && ((TREE_CODE (etype) == INTEGER_TYPE && TREE_TYPE (etype))
@@ -4554,26 +4619,34 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
             in order not to be deemed an useless type conversion, it must
             be from subtype to base type.
 
+            Therefore we first do the bulk of the conversion to a subtype of
+            the final type.  And this conversion must itself not be deemed
+            useless if the source type is not a subtype because, otherwise,
+            the final VIEW_CONVERT_EXPR will be deemed so as well.  That's
+            why we toggle the unsigned flag in this conversion, which is
+            harmless since the final conversion is only a reinterpretation
+            of the bit pattern.
+
             ??? This may raise addressability and/or aliasing issues because
             VIEW_CONVERT_EXPR gets gimplified as an lvalue, thus causing the
             address of its operand to be taken if it is deemed addressable
             and not already in GIMPLE form.  */
-         rtype = gnat_type_for_mode (TYPE_MODE (type), TYPE_UNSIGNED (type));
+         tree rtype
+           = gnat_type_for_mode (TYPE_MODE (type), !TYPE_UNSIGNED (etype));
          rtype = copy_type (rtype);
          TYPE_MAIN_VARIANT (rtype) = rtype;
          TREE_TYPE (rtype) = type;
-         final_unchecked = true;
+         expr = convert (rtype, expr);
+         expr = build1 (VIEW_CONVERT_EXPR, type, expr);
        }
 
-      expr = convert (rtype, expr);
-      if (type != rtype)
-       expr = fold_build1 (final_unchecked ? VIEW_CONVERT_EXPR : NOP_EXPR,
-                           type, expr);
+      else
+       expr = convert (type, expr);
     }
 
-  /* If we are converting TO an integral type whose precision is not the
-     same as its size, first unchecked convert to a record that contains
-     an object of the output type.  Then extract the field. */
+  /* If we are converting to an integral type whose precision is not equal
+     to its size, first unchecked convert to a record that contains an
+     object of the output type.  Then extract the field. */
   else if (INTEGRAL_TYPE_P (type) && TYPE_RM_SIZE (type)
           && 0 != compare_tree_int (TYPE_RM_SIZE (type),
                                     GET_MODE_BITSIZE (TYPE_MODE (type))))
@@ -4589,8 +4662,8 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
       expr = build_component_ref (expr, NULL_TREE, field, 0);
     }
 
-  /* Similarly for integral input type whose precision is not equal to its
-     size.  */
+  /* Similarly if we are converting from an integral type whose precision
+     is not equal to its size.  */
   else if (INTEGRAL_TYPE_P (etype) && TYPE_RM_SIZE (etype)
       && 0 != compare_tree_int (TYPE_RM_SIZE (etype),
                                GET_MODE_BITSIZE (TYPE_MODE (etype))))
@@ -4620,13 +4693,15 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
     {
       expr = maybe_unconstrained_array (expr);
       etype = TREE_TYPE (expr);
-      expr = fold_build1 (VIEW_CONVERT_EXPR, type, expr);
+      if (can_fold_for_view_convert_p (expr))
+       expr = fold_build1 (VIEW_CONVERT_EXPR, type, expr);
+      else
+       expr = build1 (VIEW_CONVERT_EXPR, type, expr);
     }
 
-  /* If the result is an integral type whose size is not equal to
-     the size of the underlying machine type, sign- or zero-extend
-     the result.  We need not do this in the case where the input is
-     an integral type of the same precision and signedness or if the output
+  /* If the result is an integral type whose precision is not equal to its
+     size, sign- or zero-extend the result.  We need not do this if the input
+     is an integral type of the same precision and signedness or if the output
      is a biased type or if both the input and output are unsigned.  */
   if (!notrunc_p
       && INTEGRAL_TYPE_P (type) && TYPE_RM_SIZE (type)