OSDN Git Service

* gcc-interface/gigi.h (gnat_mark_addressable): Rename parameter.
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Apr 2010 10:10:25 +0000 (10:10 +0000)
committerMasaki Muranaka <monaka@monami-software.com>
Sun, 23 May 2010 00:53:33 +0000 (09:53 +0900)
* gcc-interface/decl.c (maybe_variable): Do not set TREE_STATIC on _REF
node.  Use the type of the operand to set TREE_READONLY.
* gcc-interface/trans.c (Identifier_to_gnu): Do not set TREE_STATIC on
_REF node.  Do not overwrite TREE_READONLY.
(call_to_gnu): Rename local variable and fix various nits.  In the
copy-in/copy-out case, build the SAVE_EXPR manually.
(convert_with_check): Call protect_multiple_eval in lieu of save_expr
and fold the computations.
(protect_multiple_eval): Always save entire fat pointers.
(maybe_stabilize_reference): Minor tweaks.
(gnat_stabilize_reference_1): Likewise.  Do not deal with tcc_constant,
tcc_type and tcc_statement.
* gcc-interface/utils.c (convert_to_fat_pointer): Call
protect_multiple_eval in lieu of save_expr.
(convert): Minor tweaks.
(maybe_unconstrained_array): Do not set TREE_STATIC on _REF node.
(builtin_type_for_size): Call gnat_type_for_size directly.
* gcc-interface/utils2.c (contains_save_expr_p): Delete.
(contains_null_expr): Likewise
(gnat_build_constructor): Do not call it.
(compare_arrays): Deal with all side-effects, use protect_multiple_eval
instead of gnat_stabilize_reference to protect the operands.
(nonbinary_modular_operation): Call protect_multiple_eval in lieu of
save_expr.
(maybe_wrap_malloc): Likewise.
(build_allocator): Likewise.
(build_unary_op) <INDIRECT_REF>: Do not set TREE_STATIC on _REF node.
(gnat_mark_addressable): Rename parameter.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158156 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ada/ChangeLog
gcc/ada/gcc-interface/decl.c
gcc/ada/gcc-interface/gigi.h
gcc/ada/gcc-interface/trans.c
gcc/ada/gcc-interface/utils.c
gcc/ada/gcc-interface/utils2.c

index e43a534..8cd43c6 100644 (file)
@@ -1,3 +1,35 @@
+2010-04-09  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc-interface/gigi.h (gnat_mark_addressable): Rename parameter.
+       * gcc-interface/decl.c (maybe_variable): Do not set TREE_STATIC on _REF
+       node.  Use the type of the operand to set TREE_READONLY.
+       * gcc-interface/trans.c (Identifier_to_gnu): Do not set TREE_STATIC on
+       _REF node.  Do not overwrite TREE_READONLY.
+       (call_to_gnu): Rename local variable and fix various nits.  In the
+       copy-in/copy-out case, build the SAVE_EXPR manually.
+       (convert_with_check): Call protect_multiple_eval in lieu of save_expr
+       and fold the computations.
+       (protect_multiple_eval): Always save entire fat pointers.
+       (maybe_stabilize_reference): Minor tweaks.
+       (gnat_stabilize_reference_1): Likewise.  Do not deal with tcc_constant,
+       tcc_type and tcc_statement.
+       * gcc-interface/utils.c (convert_to_fat_pointer): Call
+       protect_multiple_eval in lieu of save_expr.
+       (convert): Minor tweaks.
+       (maybe_unconstrained_array): Do not set TREE_STATIC on _REF node.
+       (builtin_type_for_size): Call gnat_type_for_size directly.
+       * gcc-interface/utils2.c (contains_save_expr_p): Delete.
+       (contains_null_expr): Likewise
+       (gnat_build_constructor): Do not call it.
+       (compare_arrays): Deal with all side-effects, use protect_multiple_eval
+       instead of gnat_stabilize_reference to protect the operands.
+       (nonbinary_modular_operation): Call protect_multiple_eval in lieu of
+       save_expr.
+       (maybe_wrap_malloc): Likewise.
+       (build_allocator): Likewise.
+       (build_unary_op) <INDIRECT_REF>: Do not set TREE_STATIC on _REF node.
+       (gnat_mark_addressable): Rename parameter.
+
 2010-04-08  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc-interface/ada-tree.h (TYPE_RETURNS_UNCONSTRAINED_P): Rename into.
index 25b4c07..03938d1 100644 (file)
@@ -5743,9 +5743,7 @@ maybe_variable (tree gnu_operand)
       tree gnu_result
        = build1 (UNCONSTRAINED_ARRAY_REF, TREE_TYPE (gnu_operand),
                  variable_size (TREE_OPERAND (gnu_operand, 0)));
-
-      TREE_READONLY (gnu_result) = TREE_STATIC (gnu_result)
-       = TYPE_READONLY (TREE_TYPE (TREE_TYPE (gnu_operand)));
+      TREE_READONLY (gnu_result) = TYPE_READONLY (TREE_TYPE (gnu_operand));
       return gnu_result;
     }
 
index ce8fc8a..97c5ca0 100644 (file)
@@ -85,7 +85,7 @@ extern void mark_visited (tree t);
 
 #define MARK_VISITED(EXP)              \
 do {                                   \
-  if((EXP) && !CONSTANT_CLASS_P (EXP)) \
+  if((EXP) && !TREE_CONSTANT (EXP))    \
     mark_visited (EXP);                        \
 } while (0)
 
@@ -112,6 +112,9 @@ extern void mark_out_of_scope (Entity_Id gnat_entity);
 /* Get the unpadded version of a GNAT type.  */
 extern tree get_unpadded_type (Entity_Id gnat_entity);
 
+/* Called when we need to protect a variable object using a save_expr.  */
+extern tree maybe_variable (tree gnu_operand);
+
 /* Create a record type that contains a SIZE bytes long field of TYPE with a
     starting bit position so that it is aligned to ALIGN bits, and leaving at
     least ROOM bytes free before the field.  BASE_ALIGN is the alignment the
@@ -168,18 +171,12 @@ extern tree create_concat_name (Entity_Id gnat_entity, const char *suffix);
    the name followed by "___" and the specified suffix.  */
 extern tree concat_name (tree gnu_name, const char *suffix);
 
-/* Highest number in the front-end node table.  */
-extern int max_gnat_nodes;
-
-/* Current node being treated, in case abort called.  */
-extern Node_Id error_gnat_node;
-
-/* True when gigi is being called on an analyzed but unexpanded
-   tree, and the only purpose of the call is to properly annotate
-   types with representation information.  */
+/* If true, then gigi is being called on an analyzed but unexpanded tree, and
+   the only purpose of the call is to properly annotate types with
+   representation information.  */
 extern bool type_annotate_only;
 
-/* Current file name without path */
+/* Current file name without path */
 extern const char *ref_filename;
 
 /* This structure must be kept synchronized with Call_Back_End.  */
@@ -190,9 +187,11 @@ struct File_Info_Type
 };
 
 /* This is the main program of the back-end.  It sets up all the table
-   structures and then generates code.  */
-extern void gigi (Node_Id gnat_root, int max_gnat_node,
-                  int number_name ATTRIBUTE_UNUSED,
+   structures and then generates code.
+
+   ??? Needs parameter descriptions  */
+
+extern void gigi (Node_Id gnat_root, int max_gnat_node, int number_name,
                   struct Node *nodes_ptr, Node_Id *next_node_ptr,
                   Node_Id *prev_node_ptr, struct Elist_Header *elists_ptr,
                   struct Elmt_Item *elmts_ptr,
@@ -203,7 +202,6 @@ extern void gigi (Node_Id gnat_root, int max_gnat_node,
                   struct File_Info_Type *file_info_ptr,
                   Entity_Id standard_boolean,
                   Entity_Id standard_integer,
-                  Entity_Id standard_character,
                   Entity_Id standard_long_long_float,
                   Entity_Id standard_exception_type,
                   Int gigi_operating_mode);
@@ -233,32 +231,51 @@ extern bool Sloc_to_locus (Source_Ptr Sloc, location_t *locus);
 
 /* Post an error message.  MSG is the error message, properly annotated.
    NODE is the node at which to post the error and the node to use for the
-   '&' substitution.  */
+   "&" substitution.  */
 extern void post_error (const char *msg, Node_Id node);
 
-/* Similar to post_error, but NODE is the node at which to post the error and
-   ENT is the node to use for the '&' substitution.  */
+/* Similar, but NODE is the node at which to post the error and ENT
+   is the node to use for the "&" substitution.  */
 extern void post_error_ne (const char *msg, Node_Id node, Entity_Id ent);
 
-/* Similar to post_error_ne, but NUM is the number to use for the '^'.  */
+/* Similar, but NODE is the node at which to post the error, ENT is the node
+   to use for the "&" substitution, and N is the number to use for the ^.  */
 extern void post_error_ne_num (const char *msg, Node_Id node, Entity_Id ent,
-                               int num);
+                               int n);
 
-/* Similar to post_error_ne, but T is a GCC tree representing the number to
-   write.  If T represents a constant, the text inside curly brackets in
-   MSG will be output (presumably including a '^').  Otherwise it will not
-   be output and the text inside square brackets will be output instead.  */
+/* Similar to post_error_ne_num, but T is a GCC tree representing the number
+   to write.  If the tree represents a constant that fits within a
+   host integer, the text inside curly brackets in MSG will be output
+   (presumably including a '^').  Otherwise that text will not be output
+   and the text inside square brackets will be output instead.  */
 extern void post_error_ne_tree (const char *msg, Node_Id node, Entity_Id ent,
                                 tree t);
 
-/* Similar to post_error_ne_tree, but NUM is a second integer to write.  */
+/* Similar to post_error_ne_tree, except that NUM is a second
+   integer to write in the message.  */
 extern void post_error_ne_tree_2 (const char *msg, Node_Id node, Entity_Id ent,
                                   tree t, int num);
 
+/* Protect EXP from multiple evaluation.  This may make a SAVE_EXPR.  */
+extern tree protect_multiple_eval (tree exp);
+
 /* Return a label to branch to for the exception type in KIND or NULL_TREE
    if none.  */
 extern tree get_exception_label (char kind);
 
+/* Current node being treated, in case gigi_abort or Check_Elaboration_Code
+   called.  */
+extern Node_Id error_gnat_node;
+
+/* This is equivalent to stabilize_reference in tree.c, but we know how to
+   handle our own nodes and we take extra arguments.  FORCE says whether to
+   force evaluation of everything.  We set SUCCESS to true unless we walk
+   through something we don't know how to stabilize.  */
+extern tree maybe_stabilize_reference (tree ref, bool force, bool *success);
+
+/* Highest number in the front-end node table.  */
+extern int max_gnat_nodes;
+
 /* If nonzero, pretend we are allocating at global level.  */
 extern int force_global;
 
@@ -271,6 +288,45 @@ extern int double_float_alignment;
    types whose size is greater or equal to 64 bits, or 0 if this alignment
    is not specifically capped.  */
 extern int double_scalar_alignment;
+
+/* Standard data type sizes.  Most of these are not used.  */
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#ifndef SHORT_TYPE_SIZE
+#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
+#endif
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_LONG_TYPE_SIZE
+#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef FLOAT_TYPE_SIZE
+#define FLOAT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+/* The choice of SIZE_TYPE here is very problematic.  We need a signed
+   type whose bit width is Pmode.  Assume "long" is such a type here.  */
+#undef SIZE_TYPE
+#define SIZE_TYPE "long int"
 \f
 /* Data structures used to represent attributes.  */
 
@@ -318,15 +374,9 @@ enum standard_datatypes
   /* Type declaration node  <==> typedef virtual void *T() */
   ADT_fdesc_type,
 
-  /* Null pointer for above type */
+  /* Null pointer for above type */
   ADT_null_fdesc,
 
-  /* Value 1 in signed bitsizetype.  */
-  ADT_sbitsize_one_node,
-
-  /* Value BITS_PER_UNIT in signed bitsizetype.  */
-  ADT_sbitsize_unit_node,
-
   /* Function declaration nodes for run-time functions for allocating memory.
      Ada allocators cause calls to these functions to be generated.  Malloc32
      is used only on 64bit systems needing to allocate 32bit memory.  */
@@ -336,15 +386,9 @@ enum standard_datatypes
   /* Likewise for freeing memory.  */
   ADT_free_decl,
 
-  /* Function decl node for 64-bit multiplication with overflow checking */
+  /* Function decl node for 64-bit multiplication with overflow checking */
   ADT_mulv64_decl,
 
-  /* Identifier for the name of the _Parent field in tagged record types.  */
-  ADT_parent_name_id,
-
-  /* Identifier for the name of the Exception_Data type.  */
-  ADT_exception_data_name_id,
-
   /* Types and decls used by our temporary exception mechanism.  See
      init_gigi_decls for details.  */
   ADT_jmpbuf_type,
@@ -372,14 +416,10 @@ extern GTY(()) tree gnat_raise_decls[(int) LAST_REASON_CODE + 1];
 #define ptr_void_ftype gnat_std_decls[(int) ADT_ptr_void_ftype]
 #define fdesc_type_node gnat_std_decls[(int) ADT_fdesc_type]
 #define null_fdesc_node gnat_std_decls[(int) ADT_null_fdesc]
-#define sbitsize_one_node gnat_std_decls[(int) ADT_sbitsize_one_node]
-#define sbitsize_unit_node gnat_std_decls[(int) ADT_sbitsize_unit_node]
 #define malloc_decl gnat_std_decls[(int) ADT_malloc_decl]
 #define malloc32_decl gnat_std_decls[(int) ADT_malloc32_decl]
 #define free_decl gnat_std_decls[(int) ADT_free_decl]
 #define mulv64_decl gnat_std_decls[(int) ADT_mulv64_decl]
-#define parent_name_id gnat_std_decls[(int) ADT_parent_name_id]
-#define exception_data_name_id gnat_std_decls[(int) ADT_exception_data_name_id]
 #define jmpbuf_type gnat_std_decls[(int) ADT_jmpbuf_type]
 #define jmpbuf_ptr_type gnat_std_decls[(int) ADT_jmpbuf_ptr_type]
 #define get_jmpbuf_decl gnat_std_decls[(int) ADT_get_jmpbuf_decl]
@@ -418,6 +458,7 @@ extern tree get_block_jmpbuf_decl (void);
    and uses GNAT_NODE for location information.  */
 extern void gnat_pushdecl (tree decl, Node_Id gnat_node);
 
+extern void gnat_init_decl_processing (void);
 extern void gnat_init_gcc_eh (void);
 extern void gnat_install_builtins (void);
 
@@ -592,6 +633,9 @@ create_var_decl_1 (tree var_name, tree asm_name, tree type, tree var_init,
                     const_flag, public_flag, extern_flag,              \
                     static_flag, false, attr_list, gnat_node)
 
+/* Given a DECL and ATTR_LIST, apply the listed attributes.  */
+extern void process_attributes (tree decl, struct attrib *attr_list);
+
 /* Record DECL as a global renaming pointer.  */
 extern void record_global_renaming_pointer (tree decl);
 
@@ -599,15 +643,15 @@ extern void record_global_renaming_pointer (tree decl);
 extern void invalidate_global_renaming_pointers (void);
 
 /* Return a FIELD_DECL node.  FIELD_NAME is the field's name, FIELD_TYPE is
-   its type and RECORD_TYPE is the type of the enclosing record.  If SIZE is
-   nonzero, it is the specified size of the field.  If POS is nonzero, it is
-   the bit position.  PACKED is 1 if the enclosing record is packed, -1 if it
-   has Component_Alignment of Storage_Unit.  If ADDRESSABLE is nonzero, it
+   its type and RECORD_TYPE is the type of the enclosing record.  PACKED is
+   1 if the enclosing record is packed, -1 if it has Component_Alignment of
+   Storage_Unit.  If SIZE is nonzero, it is the specified size of the field.
+   If POS is nonzero, it is the bit position.  If ADDRESSABLE is nonzero, it
    means we are allowed to take the address of the field; if it is negative,
    we should not make a bitfield, which is used by make_aligning_type.  */
 extern tree create_field_decl (tree field_name, tree field_type,
-                              tree record_type, tree size, tree pos,
-                              int packed, int addressable);
+                               tree record_type, int packed, tree size,
+                               tree pos, int addressable);
 
 /* Returns a PARM_DECL node. PARAM_NAME is the name of the parameter,
    PARAM_TYPE is its type.  READONLY is true if the parameter is
@@ -662,20 +706,19 @@ extern tree build_vms_descriptor32 (tree type, Mechanism_Type mech,
    and the GNAT node GNAT_SUBPROG.  */
 extern void build_function_stub (tree gnu_subprog, Entity_Id gnat_subprog);
 
-/* Build a type to be used to represent an aliased object whose nominal type
-   is an unconstrained array.  This consists of a RECORD_TYPE containing a
-   field of TEMPLATE_TYPE and a field of OBJECT_TYPE, which is an ARRAY_TYPE.
-   If ARRAY_TYPE is that of an unconstrained array, this is used to represent
-   an arbitrary unconstrained object.  Use NAME as the name of the record.
-   DEBUG_INFO_P is true if we need to write debug information for the type.  */
+/* Build a type to be used to represent an aliased object whose nominal
+   type is an unconstrained array.  This consists of a RECORD_TYPE containing
+   a field of TEMPLATE_TYPE and a field of OBJECT_TYPE, which is an
+   ARRAY_TYPE.  If ARRAY_TYPE is that of the unconstrained array, this
+   is used to represent an arbitrary unconstrained object.  Use NAME
+   as the name of the record.  */
 extern tree build_unc_object_type (tree template_type, tree object_type,
-                                  tree name, bool debug_info_p);
+                                   tree name);
 
 /* Same as build_unc_object_type, but taking a thin or fat pointer type
    instead of the template type.  */
 extern tree build_unc_object_type_from_ptr (tree thin_fat_ptr_type,
-                                           tree object_type, tree name,
-                                           bool debug_info_p);
+                                           tree object_type, tree name);
 
 /* Shift the component offsets within an unconstrained object TYPE to make it
    suitable for use as a designated type for thin pointers.  */
@@ -832,21 +875,6 @@ extern tree fill_vms_descriptor (tree expr, Entity_Id gnat_formal,
    should not be allocated in a register.  Returns true if successful.  */
 extern bool gnat_mark_addressable (tree t);
 
-/* Save EXP for later use or reuse.  This is equivalent to save_expr in tree.c
-   but we know how to handle our own nodes.  */
-extern tree gnat_save_expr (tree exp);
-
-/* Protect EXP for immediate reuse.  This is a variant of gnat_save_expr that
-   is optimized under the assumption that EXP's value doesn't change before
-   its subsequent reuse(s) except through its potential reevaluation.  */
-extern tree gnat_protect_expr (tree exp);
-
-/* This is equivalent to stabilize_reference in tree.c but we know how to
-   handle our own nodes and we take extra arguments.  FORCE says whether to
-   force evaluation of everything.  We set SUCCESS to true unless we walk
-   through something we don't know how to stabilize.  */
-extern tree gnat_stabilize_reference (tree ref, bool force, bool *success);
-
 /* Implementation of the builtin_function langhook.  */
 extern tree gnat_builtin_function (tree decl);
 
index 049c201..438799c 100644 (file)
@@ -914,7 +914,7 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
          || (TREE_CODE (gnu_result) == PARM_DECL
              && DECL_BY_COMPONENT_PTR_P (gnu_result))))
     {
-      bool ro = DECL_POINTS_TO_READONLY_P (gnu_result);
+      const bool read_only = DECL_POINTS_TO_READONLY_P (gnu_result);
       tree renamed_obj;
 
       if (TREE_CODE (gnu_result) == PARM_DECL
@@ -928,8 +928,8 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
         we can reference the renamed object directly, since the renamed
         expression has been protected against multiple evaluations.  */
       else if (TREE_CODE (gnu_result) == VAR_DECL
-              && (renamed_obj = DECL_RENAMED_OBJECT (gnu_result)) != 0
-              && (! DECL_RENAMING_GLOBAL_P (gnu_result)
+              && (renamed_obj = DECL_RENAMED_OBJECT (gnu_result))
+              && (!DECL_RENAMING_GLOBAL_P (gnu_result)
                   || global_bindings_p ()))
        gnu_result = renamed_obj;
 
@@ -942,7 +942,8 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
       else
        gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result);
 
-      TREE_READONLY (gnu_result) = TREE_STATIC (gnu_result) = ro;
+      if (read_only)
+       TREE_READONLY (gnu_result) = 1;
     }
 
   /* The GNAT tree has the type of a function as the type of its result.  Also
@@ -2404,75 +2405,68 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
 static tree
 call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
 {
-  tree gnu_result;
   /* The GCC node corresponding to the GNAT subprogram name.  This can either
      be a FUNCTION_DECL node if we are dealing with a standard subprogram call,
      or an indirect reference expression (an INDIRECT_REF node) pointing to a
      subprogram.  */
-  tree gnu_subprog_node = gnat_to_gnu (Name (gnat_node));
+  tree gnu_subprog = gnat_to_gnu (Name (gnat_node));
   /* The FUNCTION_TYPE node giving the GCC type of the subprogram.  */
-  tree gnu_subprog_type = TREE_TYPE (gnu_subprog_node);
-  tree gnu_subprog_addr
-    = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_subprog_node);
+  tree gnu_subprog_type = TREE_TYPE (gnu_subprog);
+  tree gnu_subprog_addr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_subprog);
   Entity_Id gnat_formal;
   Node_Id gnat_actual;
   tree gnu_actual_list = NULL_TREE;
   tree gnu_name_list = NULL_TREE;
   tree gnu_before_list = NULL_TREE;
   tree gnu_after_list = NULL_TREE;
-  tree gnu_subprog_call;
+  tree gnu_call;
 
   gcc_assert (TREE_CODE (gnu_subprog_type) == FUNCTION_TYPE);
 
-  /* If we are calling a stubbed function, make this into a raise of
-     Program_Error.  Elaborate all our args first.  */
-  if (TREE_CODE (gnu_subprog_node) == FUNCTION_DECL
-      && DECL_STUBBED_P (gnu_subprog_node))
+  /* If we are calling a stubbed function, raise Program_Error, but Elaborate
+     all our args first.  */
+  if (TREE_CODE (gnu_subprog) == FUNCTION_DECL && DECL_STUBBED_P (gnu_subprog))
     {
+      tree call_expr = build_call_raise (PE_Stubbed_Subprogram_Called,
+                                        gnat_node, N_Raise_Program_Error);
+
       for (gnat_actual = First_Actual (gnat_node);
           Present (gnat_actual);
           gnat_actual = Next_Actual (gnat_actual))
        add_stmt (gnat_to_gnu (gnat_actual));
 
-      {
-       tree call_expr
-         = build_call_raise (PE_Stubbed_Subprogram_Called, gnat_node,
-                             N_Raise_Program_Error);
+      if (Nkind (gnat_node) == N_Function_Call && !gnu_target)
+       {
+         *gnu_result_type_p = TREE_TYPE (gnu_subprog_type);
+         return build1 (NULL_EXPR, TREE_TYPE (gnu_subprog_type), call_expr);
+       }
 
-       if (Nkind (gnat_node) == N_Function_Call && !gnu_target)
-         {
-           *gnu_result_type_p = TREE_TYPE (gnu_subprog_type);
-           return build1 (NULL_EXPR, *gnu_result_type_p, call_expr);
-         }
-       else
-         return call_expr;
-      }
+      return call_expr;
     }
 
   /* The only way we can be making a call via an access type is if Name is an
      explicit dereference.  In that case, get the list of formal args from the
-     type the access type is pointing to.  Otherwise, get the formals from
+     type the access type is pointing to.  Otherwise, get the formals from the
      entity being called.  */
   if (Nkind (Name (gnat_node)) == N_Explicit_Dereference)
     gnat_formal = First_Formal_With_Extras (Etype (Name (gnat_node)));
   else if (Nkind (Name (gnat_node)) == N_Attribute_Reference)
     /* Assume here that this must be 'Elab_Body or 'Elab_Spec.  */
-    gnat_formal = 0;
+    gnat_formal = Empty;
   else
     gnat_formal = First_Formal_With_Extras (Entity (Name (gnat_node)));
 
-  /* Create the list of the actual parameters as GCC expects it, namely a chain
-     of TREE_LIST nodes in which the TREE_VALUE field of each node is a
-     parameter-expression and the TREE_PURPOSE field is null.  Skip Out
-     parameters not passed by reference and don't need to be copied in.  */
+  /* Create the list of the actual parameters as GCC expects it, namely a
+     chain of TREE_LIST nodes in which the TREE_VALUE field of each node
+     is an expression and the TREE_PURPOSE field is null.  But skip Out
+     parameters not passed by reference and that need not be copied in.  */
   for (gnat_actual = First_Actual (gnat_node);
        Present (gnat_actual);
        gnat_formal = Next_Formal_With_Extras (gnat_formal),
        gnat_actual = Next_Actual (gnat_actual))
     {
-      tree gnu_formal
-       = (present_gnu_tree (gnat_formal)
-          ? get_gnu_tree (gnat_formal) : NULL_TREE);
+      tree gnu_formal = present_gnu_tree (gnat_formal)
+                       ? get_gnu_tree (gnat_formal) : NULL_TREE;
       tree gnu_formal_type = gnat_to_gnu_type (Etype (gnat_formal));
       /* We must suppress conversions that can cause the creation of a
         temporary in the Out or In Out case because we need the real
@@ -2487,13 +2481,13 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
            && Ekind (gnat_formal) != E_In_Parameter)
           || (Nkind (gnat_actual) == N_Type_Conversion
               && Is_Composite_Type (Underlying_Type (Etype (gnat_formal)))));
-      Node_Id gnat_name = (suppress_type_conversion
-                          ? Expression (gnat_actual) : gnat_actual);
+      Node_Id gnat_name = suppress_type_conversion
+                         ? Expression (gnat_actual) : gnat_actual;
       tree gnu_name = gnat_to_gnu (gnat_name), gnu_name_type;
       tree gnu_actual;
 
       /* If it's possible we may need to use this expression twice, make sure
-        that any side-effects are handled via SAVE_EXPRs.  Likewise if we need
+        that any side-effects are handled via SAVE_EXPRs; likewise if we need
         to force side-effects before the call.
         ??? This is more conservative than we need since we don't need to do
         this for pass-by-ref with no conversion.  */
@@ -2518,13 +2512,12 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
            post_error
              ("misaligned actual cannot be passed by reference", gnat_actual);
 
-         /* For users of Starlet we issue a warning because the
-            interface apparently assumes that by-ref parameters
-            outlive the procedure invocation.  The code still
-            will not work as intended, but we cannot do much
-            better since other low-level parts of the back-end
-            would allocate temporaries at will because of the
-            misalignment if we did not do so here.  */
+         /* For users of Starlet we issue a warning because the interface
+            apparently assumes that by-ref parameters outlive the procedure
+            invocation.  The code still will not work as intended, but we
+            cannot do much better since low-level parts of the back-end
+            would allocate temporaries at will because of the misalignment
+            if we did not do so here.  */
          else if (Is_Valued_Procedure (Entity (Name (gnat_node))))
            {
              post_error
@@ -2563,13 +2556,13 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
            gnu_name = convert (gnu_name_type, gnu_name);
 
          /* Make a SAVE_EXPR to both properly account for potential side
-            effects and handle the creation of a temporary copy.  Special
-            code in gnat_gimplify_expr ensures that the same temporary is
-            used as the object and copied back after the call if needed.  */
+            effects and handle the creation of a temporary.  Special code
+            in gnat_gimplify_expr ensures that the same temporary is used
+            as the object and copied back after the call if needed.  */
          gnu_name = build1 (SAVE_EXPR, TREE_TYPE (gnu_name), gnu_name);
          TREE_SIDE_EFFECTS (gnu_name) = 1;
 
-         /* Set up to move the copy back to the original.  */
+         /* Set up to move the copy back to the original if needed.  */
          if (Ekind (gnat_formal) != E_In_Parameter)
            {
              tree stmt = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_copy,
@@ -2618,9 +2611,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
          /* We may have suppressed a conversion to the Etype of the actual
             since the parent is a procedure call.  So put it back here.
             ??? We use the reverse order compared to the case above because
-            of an awkward interaction with the check and actually don't put
-            back the conversion at all if a check is emitted.  This is also
-            done for the conversion to the formal's type just below.  */
+            of an awkward interaction with the check.  */
          if (TREE_CODE (gnu_actual) != SAVE_EXPR)
            gnu_actual = convert (gnat_to_gnu_type (Etype (gnat_actual)),
                                  gnu_actual);
@@ -2639,9 +2630,8 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
                            gnu_name);
 
       /* If we have not saved a GCC object for the formal, it means it is an
-        Out parameter not passed by reference and that does not need to be
-        copied in. Otherwise, look at the PARM_DECL to see if it is passed by
-        reference.  */
+        Out parameter not passed by reference and that need not be copied in.
+        Otherwise, first see if the PARM_DECL is passed by reference.  */
       if (gnu_formal
          && TREE_CODE (gnu_formal) == PARM_DECL
          && DECL_BY_REF_P (gnu_formal))
@@ -2707,12 +2697,12 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
               && TREE_CODE (gnu_formal) == PARM_DECL
               && DECL_BY_DESCRIPTOR_P (gnu_formal))
        {
-         /* If arg is 'Null_Parameter, pass zero descriptor.  */
+         /* If this is 'Null_Parameter, pass a zero descriptor.  */
          if ((TREE_CODE (gnu_actual) == INDIRECT_REF
               || TREE_CODE (gnu_actual) == UNCONSTRAINED_ARRAY_REF)
              && TREE_PRIVATE (gnu_actual))
-           gnu_actual = convert (DECL_ARG_TYPE (get_gnu_tree (gnat_formal)),
-                                 integer_zero_node);
+           gnu_actual
+             = convert (DECL_ARG_TYPE (gnu_formal), integer_zero_node);
          else
            gnu_actual = build_unary_op (ADDR_EXPR, NULL_TREE,
                                         fill_vms_descriptor (gnu_actual,
@@ -2721,26 +2711,25 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
        }
       else
        {
-         tree gnu_actual_size = TYPE_SIZE (TREE_TYPE (gnu_actual));
+         tree gnu_size;
 
          if (Ekind (gnat_formal) != E_In_Parameter)
            gnu_name_list = tree_cons (NULL_TREE, gnu_name, gnu_name_list);
 
-         if (!gnu_formal || TREE_CODE (gnu_formal) != PARM_DECL)
+         if (!(gnu_formal && TREE_CODE (gnu_formal) == PARM_DECL))
            continue;
 
          /* If this is 'Null_Parameter, pass a zero even though we are
             dereferencing it.  */
-         else if (TREE_CODE (gnu_actual) == INDIRECT_REF
-                  && TREE_PRIVATE (gnu_actual)
-                  && host_integerp (gnu_actual_size, 1)
-                  && 0 >= compare_tree_int (gnu_actual_size,
-                                                  BITS_PER_WORD))
+         if (TREE_CODE (gnu_actual) == INDIRECT_REF
+             && TREE_PRIVATE (gnu_actual)
+             && (gnu_size = TYPE_SIZE (TREE_TYPE (gnu_actual)))
+             && TREE_CODE (gnu_size) == INTEGER_CST
+             && compare_tree_int (gnu_size, BITS_PER_WORD) <= 0)
            gnu_actual
              = unchecked_convert (DECL_ARG_TYPE (gnu_formal),
                                   convert (gnat_type_for_size
-                                           (tree_low_cst (gnu_actual_size, 1),
-                                            1),
+                                           (TREE_INT_CST_LOW (gnu_size), 1),
                                            integer_zero_node),
                                   false);
          else
@@ -2750,17 +2739,16 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
       gnu_actual_list = tree_cons (NULL_TREE, gnu_actual, gnu_actual_list);
     }
 
-  gnu_subprog_call = build_call_list (TREE_TYPE (gnu_subprog_type),
-                                     gnu_subprog_addr,
-                                     nreverse (gnu_actual_list));
-  set_expr_location_from_node (gnu_subprog_call, gnat_node);
+  gnu_call = build_call_list (TREE_TYPE (gnu_subprog_type), gnu_subprog_addr,
+                             nreverse (gnu_actual_list));
+  set_expr_location_from_node (gnu_call, gnat_node);
 
   /* If it's a function call, the result is the call expression unless a target
      is specified, in which case we copy the result into the target and return
      the assignment statement.  */
   if (Nkind (gnat_node) == N_Function_Call)
     {
-      gnu_result = gnu_subprog_call;
+      tree gnu_result = gnu_call;
       enum tree_code op_code;
 
       /* If the function returns an unconstrained array or by direct reference,
@@ -2802,12 +2790,16 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
        {
          tree gnu_name;
 
-         gnu_subprog_call = save_expr (gnu_subprog_call);
+         /* The call sequence must contain one and only one call, even though
+            the function is const or pure.  So force a SAVE_EXPR.  */
+         gnu_call = build1 (SAVE_EXPR, TREE_TYPE (gnu_call), gnu_call);
+         TREE_SIDE_EFFECTS (gnu_call) = 1;
          gnu_name_list = nreverse (gnu_name_list);
 
          /* If any of the names had side-effects, ensure they are all
             evaluated before the call.  */
-         for (gnu_name = gnu_name_list; gnu_name;
+         for (gnu_name = gnu_name_list;
+              gnu_name;
               gnu_name = TREE_CHAIN (gnu_name))
            if (TREE_SIDE_EFFECTS (TREE_VALUE (gnu_name)))
              append_to_statement_list (TREE_VALUE (gnu_name),
@@ -2838,8 +2830,9 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
               either the result of the function if there is only a single such
               parameter or the appropriate field from the record returned.  */
            tree gnu_result
-             = length == 1 ? gnu_subprog_call
-               : build_component_ref (gnu_subprog_call, NULL_TREE,
+             = length == 1
+               ? gnu_call
+               : build_component_ref (gnu_call, NULL_TREE,
                                       TREE_PURPOSE (scalar_return_list),
                                       false);
 
@@ -2851,9 +2844,9 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
 
            /* If the result is a padded type, remove the padding.  */
            if (TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)))
-             gnu_result = convert (TREE_TYPE (TYPE_FIELDS
-                                              (TREE_TYPE (gnu_result))),
-                                   gnu_result);
+             gnu_result
+               = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))),
+                          gnu_result);
 
            /* If the actual is a type conversion, the real target object is
               denoted by the inner Expression and we need to convert the
@@ -2907,11 +2900,12 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
            scalar_return_list = TREE_CHAIN (scalar_return_list);
            gnu_name_list = TREE_CHAIN (gnu_name_list);
          }
-       }
+    }
   else
-    append_to_statement_list (gnu_subprog_call, &gnu_before_list);
+    append_to_statement_list (gnu_call, &gnu_before_list);
 
   append_to_statement_list (gnu_after_list, &gnu_before_list);
+
   return gnu_before_list;
 }
 \f
@@ -6695,7 +6689,7 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
       && !truncatep)
     {
       REAL_VALUE_TYPE half_minus_pred_half, pred_half;
-      tree gnu_conv, gnu_zero, gnu_comp, gnu_saved_result, calc_type;
+      tree gnu_conv, gnu_zero, gnu_comp, calc_type;
       tree gnu_pred_half, gnu_add_pred_half, gnu_subtract_pred_half;
       const struct real_format *fmt;
 
@@ -6718,14 +6712,14 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
       gnu_pred_half = build_real (calc_type, pred_half);
 
       /* If the input is strictly negative, subtract this value
-        and otherwise add it from the input. For 0.5, the result
+        and otherwise add it from the input.  For 0.5, the result
         is exactly between 1.0 and the machine number preceding 1.0
-        (for calc_type). Since the last bit of 1.0 is even, this 0.5
+        (for calc_type).  Since the last bit of 1.0 is even, this 0.5
         will round to 1.0, while all other number with an absolute
-        value less than 0.5 round to 0.0. For larger numbers exactly
+        value less than 0.5 round to 0.0.  For larger numbers exactly
         halfway between integers, rounding will always be correct as
         the true mathematical result will be closer to the higher
-        integer compared to the lower one. So, this constant works
+        integer compared to the lower one.  So, this constant works
         for all floating-point numbers.
 
         The reason to use the same constant with subtract/add instead
@@ -6734,16 +6728,16 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
         conversion of the input to the calc_type (if necessary).  */
 
       gnu_zero = convert (gnu_in_basetype, integer_zero_node);
-      gnu_saved_result = save_expr (gnu_result);
-      gnu_conv = convert (calc_type, gnu_saved_result);
-      gnu_comp = build2 (GE_EXPR, integer_type_node,
-                        gnu_saved_result, gnu_zero);
+      gnu_result = protect_multiple_eval (gnu_result);
+      gnu_conv = convert (calc_type, gnu_result);
+      gnu_comp
+       = fold_build2 (GE_EXPR, integer_type_node, gnu_result, gnu_zero);
       gnu_add_pred_half
-       = build2 (PLUS_EXPR, calc_type, gnu_conv, gnu_pred_half);
+       = fold_build2 (PLUS_EXPR, calc_type, gnu_conv, gnu_pred_half);
       gnu_subtract_pred_half
-       = build2 (MINUS_EXPR, calc_type, gnu_conv, gnu_pred_half);
-      gnu_result = build3 (COND_EXPR, calc_type, gnu_comp,
-                          gnu_add_pred_half, gnu_subtract_pred_half);
+       = fold_build2 (MINUS_EXPR, calc_type, gnu_conv, gnu_pred_half);
+      gnu_result = fold_build3 (COND_EXPR, calc_type, gnu_comp,
+                               gnu_add_pred_half, gnu_subtract_pred_half);
     }
 
   if (TREE_CODE (gnu_base_type) == INTEGER_TYPE
@@ -6753,10 +6747,8 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
   else
     gnu_result = convert (gnu_base_type, gnu_result);
 
-  /* Finally, do the range check if requested.  Note that if the
-     result type is a modular type, the range check is actually
-     an overflow check.  */
-
+  /* Finally, do the range check if requested.  Note that if the result type
+     is a modular type, the range check is actually an overflow check.  */
   if (rangep
       || (TREE_CODE (gnu_base_type) == INTEGER_TYPE
          && TYPE_MODULAR_P (gnu_base_type) && overflowp))
@@ -7205,6 +7197,7 @@ tree
 protect_multiple_eval (tree exp)
 {
   tree type = TREE_TYPE (exp);
+  enum tree_code code = TREE_CODE (exp);
 
   /* If EXP has no side effects, we theoritically don't need to do anything.
      However, we may be recursively passed more and more complex expressions
@@ -7221,13 +7214,20 @@ protect_multiple_eval (tree exp)
      Similarly, if we're indirectly referencing something, we only
      need to protect the address since the data itself can't change
      in these situations.  */
-  if (TREE_CODE (exp) == NON_LVALUE_EXPR
-      || CONVERT_EXPR_P (exp)
-      || TREE_CODE (exp) == VIEW_CONVERT_EXPR
-      || TREE_CODE (exp) == INDIRECT_REF
-      || TREE_CODE (exp) == UNCONSTRAINED_ARRAY_REF)
-  return build1 (TREE_CODE (exp), type,
-                protect_multiple_eval (TREE_OPERAND (exp, 0)));
+  if (code == NON_LVALUE_EXPR
+      || CONVERT_EXPR_CODE_P (code)
+      || code == VIEW_CONVERT_EXPR
+      || code == INDIRECT_REF
+      || code == UNCONSTRAINED_ARRAY_REF)
+  return build1 (code, type, protect_multiple_eval (TREE_OPERAND (exp, 0)));
+
+  /* If this is a COMPONENT_REF of a fat pointer, save the entire fat pointer.
+     This may be more efficient, but will also allow us to more easily find
+     the match for the PLACEHOLDER_EXPR.  */
+  if (code == COMPONENT_REF
+      && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
+    return build3 (code, type, protect_multiple_eval (TREE_OPERAND (exp, 0)),
+                  TREE_OPERAND (exp, 1), TREE_OPERAND (exp, 2));
 
   /* If this is a fat pointer or something that can be placed in a register,
      just make a SAVE_EXPR.  Likewise for a CALL_EXPR as large objects are
@@ -7235,7 +7235,7 @@ protect_multiple_eval (tree exp)
      directly be filled by the callee.  */
   if (TYPE_IS_FAT_POINTER_P (type)
       || TYPE_MODE (type) != BLKmode
-      || TREE_CODE (exp) == CALL_EXPR)
+      || code == CALL_EXPR)
     return save_expr (exp);
 
   /* Otherwise reference, protect the address and dereference.  */
@@ -7354,26 +7354,23 @@ maybe_stabilize_reference (tree ref, bool force, bool *success)
       return ref;
     }
 
-  TREE_READONLY (result) = TREE_READONLY (ref);
-
-  /* TREE_THIS_VOLATILE and TREE_SIDE_EFFECTS attached to the initial
-     expression may not be sustained across some paths, such as the way via
-     build1 for INDIRECT_REF.  We re-populate those flags here for the general
-     case, which is consistent with the GCC version of this routine.
+  /* TREE_THIS_VOLATILE and TREE_SIDE_EFFECTS set on the initial expression
+     may not be sustained across some paths, such as the way via build1 for
+     INDIRECT_REF.  We reset those flags here in the general case, which is
+     consistent with the GCC version of this routine.
 
      Special care should be taken regarding TREE_SIDE_EFFECTS, because some
-     paths introduce side effects where there was none initially (e.g. calls
-     to save_expr), and we also want to keep track of that.  */
-
-  TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
+     paths introduce side-effects where there was none initially (e.g. if a
+     SAVE_EXPR is built) and we also want to keep track of that.  */
+  TREE_READONLY (result) = TREE_READONLY (ref);
   TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (ref);
+  TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
 
   return result;
 }
 
-/* Wrapper around maybe_stabilize_reference, for common uses without
-   lvalue restrictions and without need to examine the success
-   indication.  */
+/* Wrapper around maybe_stabilize_reference, for common uses without lvalue
+   restrictions and without the need to examine the success indication.  */
 
 static tree
 gnat_stabilize_reference (tree ref, bool force)
@@ -7396,17 +7393,14 @@ gnat_stabilize_reference_1 (tree e, bool force)
      to a const array but whose index contains side-effects.  But we can
      ignore things that are actual constant or that already have been
      handled by this function.  */
-
   if (TREE_CONSTANT (e) || code == SAVE_EXPR)
     return e;
 
   switch (TREE_CODE_CLASS (code))
     {
     case tcc_exceptional:
-    case tcc_type:
     case tcc_declaration:
     case tcc_comparison:
-    case tcc_statement:
     case tcc_expression:
     case tcc_reference:
     case tcc_vl_exp:
@@ -7415,44 +7409,44 @@ gnat_stabilize_reference_1 (tree e, bool force)
         us to more easily find the match for the PLACEHOLDER_EXPR.  */
       if (code == COMPONENT_REF
          && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0))))
-       result = build3 (COMPONENT_REF, type,
-                        gnat_stabilize_reference_1 (TREE_OPERAND (e, 0),
-                                                    force),
-                        TREE_OPERAND (e, 1), TREE_OPERAND (e, 2));
+       result
+         = build3 (code, type,
+                   gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
+                   TREE_OPERAND (e, 1), TREE_OPERAND (e, 2));
+      /* If the expression has side-effects, then encase it in a SAVE_EXPR
+        so that it will only be evaluated once.  */
+      /* The tcc_reference and tcc_comparison classes could be handled as
+        below, but it is generally faster to only evaluate them once.  */
       else if (TREE_SIDE_EFFECTS (e) || force)
        return save_expr (e);
       else
        return e;
       break;
 
-    case tcc_constant:
-      /* Constants need no processing.  In fact, we should never reach
-        here.  */
-      return e;
-
     case tcc_binary:
       /* Recursively stabilize each operand.  */
-      result = build2 (code, type,
-                      gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
-                      gnat_stabilize_reference_1 (TREE_OPERAND (e, 1),
-                                                  force));
+      result
+       = build2 (code, type,
+                 gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
+                 gnat_stabilize_reference_1 (TREE_OPERAND (e, 1), force));
       break;
 
     case tcc_unary:
       /* Recursively stabilize each operand.  */
-      result = build1 (code, type,
-                      gnat_stabilize_reference_1 (TREE_OPERAND (e, 0),
-                                                  force));
+      result
+       = build1 (code, type,
+                 gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force));
       break;
 
     default:
       gcc_unreachable ();
     }
 
+  /* See similar handling in maybe_stabilize_reference.  */
   TREE_READONLY (result) = TREE_READONLY (e);
-
-  TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
   TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e);
+  TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
+
   return result;
 }
 \f
index 27c931a..f35e9c7 100644 (file)
@@ -203,7 +203,6 @@ static tree convert_to_fat_pointer (tree, tree);
 static tree convert_to_thin_pointer (tree, tree);
 static tree make_descriptor_field (const char *,tree, tree, tree);
 static bool potential_alignment_gap (tree, tree, tree);
-static void process_attributes (tree, struct attrib *);
 \f
 /* Initialize the association of GNAT nodes to GCC trees.  */
 
@@ -295,8 +294,8 @@ make_dummy_type (Entity_Id gnat_type)
   TYPE_DUMMY_P (gnu_type) = 1;
   TYPE_STUB_DECL (gnu_type)
     = create_type_stub_decl (TYPE_NAME (gnu_type), gnu_type);
-  if (Is_By_Reference_Type (gnat_type))
-    TREE_ADDRESSABLE (gnu_type) = 1;
+  if (AGGREGATE_TYPE_P (gnu_type))
+    TYPE_BY_REFERENCE_P (gnu_type) = Is_By_Reference_Type (gnat_type);
 
   SET_DUMMY_NODE (gnat_underlying, gnu_type);
 
@@ -311,7 +310,7 @@ global_bindings_p (void)
   return ((force_global || !current_function_decl) ? -1 : 0);
 }
 
-/* Enter a new binding level.  */
+/* Enter a new binding level. */
 
 void
 gnat_pushlevel (void)
@@ -343,11 +342,11 @@ gnat_pushlevel (void)
   if (current_binding_level)
     BLOCK_SUPERCONTEXT (newlevel->block) = current_binding_level->block;
 
-  BLOCK_VARS (newlevel->block) = NULL_TREE;
-  BLOCK_SUBBLOCKS (newlevel->block) = NULL_TREE;
+  BLOCK_VARS (newlevel->block) = BLOCK_SUBBLOCKS (newlevel->block) = NULL_TREE;
   TREE_USED (newlevel->block) = 1;
 
-  /* Add this level to the front of the chain (stack) of active levels.  */
+  /* Add this level to the front of the chain (stack) of levels that are
+     active.  */
   newlevel->chain = current_binding_level;
   newlevel->jmpbuf_decl = NULL_TREE;
   current_binding_level = newlevel;
@@ -361,7 +360,6 @@ set_current_block_context (tree fndecl)
 {
   BLOCK_SUPERCONTEXT (current_binding_level->block) = fndecl;
   DECL_INITIAL (fndecl) = current_binding_level->block;
-  set_block_for_group (current_binding_level->block);
 }
 
 /* Set the jmpbuf_decl for the current binding level to DECL.  */
@@ -380,7 +378,7 @@ get_block_jmpbuf_decl (void)
   return current_binding_level->jmpbuf_decl;
 }
 
-/* Exit a binding level.  Set any BLOCK into the current code group.  */
+/* Exit a binding level. Set any BLOCK into the current code group.  */
 
 void
 gnat_poplevel (void)
@@ -393,7 +391,7 @@ gnat_poplevel (void)
 
   /* If this is a function-level BLOCK don't do anything.  Otherwise, if there
      are no variables free the block and merge its subblocks into those of its
-     parent block.  Otherwise, add it to the list of its parent.  */
+     parent block. Otherwise, add it to the list of its parent.  */
   if (TREE_CODE (BLOCK_SUPERCONTEXT (block)) == FUNCTION_DECL)
     ;
   else if (BLOCK_VARS (block) == NULL_TREE)
@@ -514,6 +512,40 @@ gnat_pushdecl (tree decl, Node_Id gnat_node)
     }
 }
 \f
+/* Do little here.  Set up the standard declarations later after the
+   front end has been run.  */
+
+void
+gnat_init_decl_processing (void)
+{
+  /* Make the binding_level structure for global names.  */
+  current_function_decl = 0;
+  current_binding_level = 0;
+  free_binding_level = 0;
+  gnat_pushlevel ();
+
+  build_common_tree_nodes (true, true);
+
+  /* In Ada, we use a signed type for SIZETYPE.  Use the signed type
+     corresponding to the width of Pmode.  In most cases when ptr_mode
+     and Pmode differ, C will use the width of ptr_mode for SIZETYPE.
+     But we get far better code using the width of Pmode.  */
+  size_type_node = gnat_type_for_mode (Pmode, 0);
+  set_sizetype (size_type_node);
+
+  /* In Ada, we use an unsigned 8-bit type for the default boolean type.  */
+  boolean_type_node = make_unsigned_type (8);
+  TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE);
+  SET_TYPE_RM_MAX_VALUE (boolean_type_node,
+                        build_int_cst (boolean_type_node, 1));
+  SET_TYPE_RM_SIZE (boolean_type_node, bitsize_int (1));
+
+  build_common_tree_nodes_2 (0);
+  boolean_true_node = TYPE_MAX_VALUE (boolean_type_node);
+
+  ptr_void_type_node = build_pointer_type (void_type_node);
+}
+\f
 /* Record TYPE as a builtin type for Ada.  NAME is the name of the type.  */
 
 void
@@ -839,13 +871,11 @@ rest_of_record_type_compilation (tree record_type)
              align = tree_low_cst (TREE_OPERAND (curpos, 1), 1);
 
              /* An offset which is a bitwise AND with a negative power of 2
-                means an alignment corresponding to this power of 2.  Note
-                that, as sizetype is sign-extended but nonetheless unsigned,
-                we don't directly use tree_int_cst_sgn.  */
+                means an alignment corresponding to this power of 2.  */
              offset = remove_conversions (offset, true);
              if (TREE_CODE (offset) == BIT_AND_EXPR
                  && host_integerp (TREE_OPERAND (offset, 1), 0)
-                 && TREE_INT_CST_HIGH (TREE_OPERAND (offset, 1)) < 0)
+                 && tree_int_cst_sgn (TREE_OPERAND (offset, 1)) < 0)
                {
                  unsigned int pow
                    = - tree_low_cst (TREE_OPERAND (offset, 1), 0);
@@ -915,9 +945,9 @@ rest_of_record_type_compilation (tree record_type)
              field_name = concat_name (field_name, suffix);
            }
 
-         new_field
-           = create_field_decl (field_name, field_type, new_record_type,
-                                DECL_SIZE (old_field), pos, 0, 0);
+         new_field = create_field_decl (field_name, field_type,
+                                        new_record_type, 0,
+                                        DECL_SIZE (old_field), pos, 0);
          TREE_CHAIN (new_field) = TYPE_FIELDS (new_record_type);
          TYPE_FIELDS (new_record_type) = new_field;
 
@@ -1258,10 +1288,7 @@ create_type_decl (tree type_name, tree type, struct attrib *attr_list,
                            TYPE_DECL, type_name, type);
 
   DECL_ARTIFICIAL (type_decl) = artificial_p;
-
-  /* Add this decl to the current binding level.  */
   gnat_pushdecl (type_decl, gnat_node);
-
   process_attributes (type_decl, attr_list);
 
   /* If we're naming the type, equate the TYPE_STUB_DECL to the name.
@@ -1391,17 +1418,21 @@ create_var_decl_1 (tree var_name, tree asm_name, tree type, tree var_init,
           != null_pointer_node)
     DECL_IGNORED_P (var_decl) = 1;
 
+  if (TREE_CODE (var_decl) == VAR_DECL)
+    {
+      if (asm_name)
+       SET_DECL_ASSEMBLER_NAME (var_decl, asm_name);
+      process_attributes (var_decl, attr_list);
+    }
+
   /* Add this decl to the current binding level.  */
   gnat_pushdecl (var_decl, gnat_node);
 
   if (TREE_SIDE_EFFECTS (var_decl))
     TREE_ADDRESSABLE (var_decl) = 1;
 
-  if (TREE_CODE (var_decl) == VAR_DECL)
+  if (TREE_CODE (var_decl) != CONST_DECL)
     {
-      if (asm_name)
-       SET_DECL_ASSEMBLER_NAME (var_decl, asm_name);
-      process_attributes (var_decl, attr_list);
       if (global_bindings_p ())
        rest_of_decl_compilation (var_decl, true, 0);
     }
@@ -1439,16 +1470,16 @@ aggregate_type_contains_array_p (tree type)
 }
 
 /* Return a FIELD_DECL node.  FIELD_NAME is the field's name, FIELD_TYPE is
-   its type and RECORD_TYPE is the type of the enclosing record.  If SIZE is
-   nonzero, it is the specified size of the field.  If POS is nonzero, it is
-   the bit position.  PACKED is 1 if the enclosing record is packed, -1 if it
-   has Component_Alignment of Storage_Unit.  If ADDRESSABLE is nonzero, it
+   its type and RECORD_TYPE is the type of the enclosing record.  PACKED is
+   1 if the enclosing record is packed, -1 if it has Component_Alignment of
+   Storage_Unit.  If SIZE is nonzero, it is the specified size of the field.
+   If POS is nonzero, it is the bit position.  If ADDRESSABLE is nonzero, it
    means we are allowed to take the address of the field; if it is negative,
    we should not make a bitfield, which is used by make_aligning_type.  */
 
 tree
 create_field_decl (tree field_name, tree field_type, tree record_type,
-                   tree size, tree pos, int packed, int addressable)
+                   int packed, tree size, tree pos, int addressable)
 {
   tree field_decl = build_decl (input_location,
                                FIELD_DECL, field_name, field_type);
@@ -1621,14 +1652,13 @@ create_param_decl (tree param_name, tree param_type, bool readonly)
 \f
 /* Given a DECL and ATTR_LIST, process the listed attributes.  */
 
-static void
+void
 process_attributes (tree decl, struct attrib *attr_list)
 {
   for (; attr_list; attr_list = attr_list->next)
     switch (attr_list->type)
       {
       case ATTR_MACHINE_ATTRIBUTE:
-       input_location = DECL_SOURCE_LOCATION (decl);
        decl_attributes (&decl, tree_cons (attr_list->name, attr_list->args,
                                           NULL_TREE),
                         ATTR_FLAG_TYPE_IN_PLACE);
@@ -1838,11 +1868,11 @@ create_subprog_decl (tree subprog_name, tree asm_name,
        DECL_NAME (subprog_decl) = main_identifier_node;
     }
 
+  process_attributes (subprog_decl, attr_list);
+
   /* Add this decl to the current binding level.  */
   gnat_pushdecl (subprog_decl, gnat_node);
 
-  process_attributes (subprog_decl, attr_list);
-
   /* Output the assembler code and/or RTL for the declaration.  */
   rest_of_decl_compilation (subprog_decl, global_bindings_p (), 0);
 
@@ -1858,14 +1888,12 @@ begin_subprog_body (tree subprog_decl)
 {
   tree param_decl;
 
-  announce_function (subprog_decl);
-
   current_function_decl = subprog_decl;
+  announce_function (subprog_decl);
 
   /* Enter a new binding level and show that all the parameters belong to
      this function.  */
   gnat_pushlevel ();
-
   for (param_decl = DECL_ARGUMENTS (subprog_decl); param_decl;
        param_decl = TREE_CHAIN (param_decl))
     DECL_CONTEXT (param_decl) = subprog_decl;
@@ -1887,7 +1915,7 @@ end_subprog_body (tree body)
 
   /* Mark the BLOCK for this level as being for this function and pop the
      level.  Since the vars in it are the parameters, clear them.  */
-  BLOCK_VARS (current_binding_level->block) = NULL_TREE;
+  BLOCK_VARS (current_binding_level->block) = 0;
   BLOCK_SUPERCONTEXT (current_binding_level->block) = fndecl;
   DECL_INITIAL (fndecl) = current_binding_level->block;
   gnat_poplevel ();
@@ -1902,6 +1930,7 @@ end_subprog_body (tree body)
   DECL_SAVED_TREE (fndecl) = body;
 
   current_function_decl = DECL_CONTEXT (fndecl);
+  set_cfun (NULL);
 
   /* We cannot track the location of errors past this point.  */
   error_gnat_node = Empty;
@@ -2177,6 +2206,22 @@ max_size (tree exp, bool max_p)
          if (code == COMPOUND_EXPR)
            return max_size (TREE_OPERAND (exp, 1), max_p);
 
+         /* Calculate "(A ? B : C) - D" as "A ? B - D : C - D" which
+            may provide a tighter bound on max_size.  */
+         if (code == MINUS_EXPR
+             && TREE_CODE (TREE_OPERAND (exp, 0)) == COND_EXPR)
+           {
+             tree lhs = fold_build2 (MINUS_EXPR, type,
+                                     TREE_OPERAND (TREE_OPERAND (exp, 0), 1),
+                                     TREE_OPERAND (exp, 1));
+             tree rhs = fold_build2 (MINUS_EXPR, type,
+                                     TREE_OPERAND (TREE_OPERAND (exp, 0), 2),
+                                     TREE_OPERAND (exp, 1));
+             return fold_build2 (max_p ? MAX_EXPR : MIN_EXPR, type,
+                                 max_size (lhs, max_p),
+                                 max_size (rhs, max_p));
+           }
+
          {
            tree lhs = max_size (TREE_OPERAND (exp, 0), max_p);
            tree rhs = max_size (TREE_OPERAND (exp, 1),
@@ -2186,7 +2231,8 @@ max_size (tree exp, bool max_p)
               In that case, if one side overflows, return the other.
               sizetype is signed, but we know sizes are non-negative.
               Likewise, handle a MINUS_EXPR or PLUS_EXPR with the LHS
-              overflowing and the RHS a variable.  */
+              overflowing or the maximum possible value and the RHS
+              a variable.  */
            if (max_p
                && code == MIN_EXPR
                && TREE_CODE (rhs) == INTEGER_CST
@@ -2198,8 +2244,9 @@ max_size (tree exp, bool max_p)
                     && TREE_OVERFLOW (lhs))
              return rhs;
            else if ((code == MINUS_EXPR || code == PLUS_EXPR)
-                    && TREE_CODE (lhs) == INTEGER_CST
-                    && TREE_OVERFLOW (lhs)
+                    && ((TREE_CODE (lhs) == INTEGER_CST
+                         && TREE_OVERFLOW (lhs))
+                        || operand_equal_p (lhs, TYPE_MAX_VALUE (type), 0))
                     && !TREE_CONSTANT (rhs))
              return lhs;
            else
@@ -2286,12 +2333,12 @@ build_template (tree template_type, tree array_type, tree expr)
   return gnat_build_constructor (template_type, nreverse (template_elts));
 }
 \f
-/* Build a 32-bit VMS descriptor from a Mechanism_Type, which must specify a
-   descriptor type, and the GCC type of an object.  Each FIELD_DECL in the
-   type contains in its DECL_INITIAL the expression to use when a constructor
-   is made for the type.  GNAT_ENTITY is an entity used to print out an error
-   message if the mechanism cannot be applied to an object of that type and
-   also for the name.  */
+/* Build a 32bit VMS descriptor from a Mechanism_Type, which must specify
+   a descriptor type, and the GCC type of an object.  Each FIELD_DECL
+   in the type contains in its DECL_INITIAL the expression to use when
+   a constructor is made for the type.  GNAT_ENTITY is an entity used
+   to print out an error message if the mechanism cannot be applied to
+   an object of that type and also for the name.  */
 
 tree
 build_vms_descriptor32 (tree type, Mechanism_Type mech, Entity_Id gnat_entity)
@@ -2430,24 +2477,25 @@ build_vms_descriptor32 (tree type, Mechanism_Type mech, Entity_Id gnat_entity)
       break;
     }
 
-  /* Make the type for a descriptor for VMS.  The first four fields are the
-     same for all types.  */
-  field_list
-    = chainon (field_list,
-              make_descriptor_field ("LENGTH", gnat_type_for_size (16, 1),
-                                     record_type,
-                                     size_in_bytes
-                                     ((mech == By_Descriptor_A
-                                       || mech == By_Short_Descriptor_A)
-                                      ? inner_type : type)));
-  field_list
-    = chainon (field_list,
-              make_descriptor_field ("DTYPE", gnat_type_for_size (8, 1),
-                                     record_type, size_int (dtype)));
+  /* Make the type for a descriptor for VMS.  The first four fields
+     are the same for all types.  */
+
   field_list
     = chainon (field_list,
-              make_descriptor_field ("CLASS", gnat_type_for_size (8, 1),
-                                     record_type, size_int (klass)));
+              make_descriptor_field
+              ("LENGTH", gnat_type_for_size (16, 1), record_type,
+               size_in_bytes ((mech == By_Descriptor_A ||
+                                mech == By_Short_Descriptor_A)
+                               ? inner_type : type)));
+
+  field_list = chainon (field_list,
+                       make_descriptor_field ("DTYPE",
+                                              gnat_type_for_size (8, 1),
+                                              record_type, size_int (dtype)));
+  field_list = chainon (field_list,
+                       make_descriptor_field ("CLASS",
+                                              gnat_type_for_size (8, 1),
+                                              record_type, size_int (klass)));
 
   /* Of course this will crash at run-time if the address space is not
      within the low 32 bits, but there is nothing else we can do.  */
@@ -2455,11 +2503,11 @@ build_vms_descriptor32 (tree type, Mechanism_Type mech, Entity_Id gnat_entity)
 
   field_list
     = chainon (field_list,
-              make_descriptor_field ("POINTER", pointer32_type, record_type,
-                                     build_unary_op (ADDR_EXPR,
-                                                     pointer32_type,
-                                                     build0 (PLACEHOLDER_EXPR,
-                                                             type))));
+              make_descriptor_field
+              ("POINTER", pointer32_type, record_type,
+               build_unary_op (ADDR_EXPR,
+                               pointer32_type,
+                               build0 (PLACEHOLDER_EXPR, type))));
 
   switch (mech)
     {
@@ -2600,12 +2648,12 @@ build_vms_descriptor32 (tree type, Mechanism_Type mech, Entity_Id gnat_entity)
   return record_type;
 }
 
-/* Build a 64-bit VMS descriptor from a Mechanism_Type, which must specify a
-   descriptor type, and the GCC type of an object.  Each FIELD_DECL in the
-   type contains in its DECL_INITIAL the expression to use when a constructor
-   is made for the type.  GNAT_ENTITY is an entity used to print out an error
-   message if the mechanism cannot be applied to an object of that type and
-   also for the name.  */
+/* Build a 64bit VMS descriptor from a Mechanism_Type, which must specify
+   a descriptor type, and the GCC type of an object.  Each FIELD_DECL
+   in the type contains in its DECL_INITIAL the expression to use when
+   a constructor is made for the type.  GNAT_ENTITY is an entity used
+   to print out an error message if the mechanism cannot be applied to
+   an object of that type and also for the name.  */
 
 tree
 build_vms_descriptor (tree type, Mechanism_Type mech, Entity_Id gnat_entity)
@@ -2739,41 +2787,43 @@ build_vms_descriptor (tree type, Mechanism_Type mech, Entity_Id gnat_entity)
       break;
     }
 
-  /* Make the type for a 64-bit descriptor for VMS.  The first six fields
+  /* Make the type for a 64bit descriptor for VMS.  The first six fields
      are the same for all types.  */
+
+  field_list64 = chainon (field_list64,
+                       make_descriptor_field ("MBO",
+                                               gnat_type_for_size (16, 1),
+                                               record64_type, size_int (1)));
+
+  field_list64 = chainon (field_list64,
+                       make_descriptor_field ("DTYPE",
+                                              gnat_type_for_size (8, 1),
+                                              record64_type, size_int (dtype)));
+  field_list64 = chainon (field_list64,
+                       make_descriptor_field ("CLASS",
+                                              gnat_type_for_size (8, 1),
+                                              record64_type, size_int (klass)));
+
+  field_list64 = chainon (field_list64,
+                       make_descriptor_field ("MBMO",
+                                               gnat_type_for_size (32, 1),
+                                               record64_type, ssize_int (-1)));
+
   field_list64
     = chainon (field_list64,
-              make_descriptor_field ("MBO", gnat_type_for_size (16, 1),
-                                     record64_type, size_int (1)));
-  field_list64
-    = chainon (field_list64,
-              make_descriptor_field ("DTYPE", gnat_type_for_size (8, 1),
-                                     record64_type, size_int (dtype)));
-  field_list64
-    = chainon (field_list64,
-              make_descriptor_field ("CLASS", gnat_type_for_size (8, 1),
-                                     record64_type, size_int (klass)));
-  field_list64
-    = chainon (field_list64,
-              make_descriptor_field ("MBMO", gnat_type_for_size (32, 1),
-                                     record64_type, ssize_int (-1)));
-  field_list64
-    = chainon (field_list64,
-              make_descriptor_field ("LENGTH", gnat_type_for_size (64, 1),
-                                     record64_type,
-                                     size_in_bytes (mech == By_Descriptor_A
-                                                    ? inner_type : type)));
+              make_descriptor_field
+              ("LENGTH", gnat_type_for_size (64, 1), record64_type,
+               size_in_bytes (mech == By_Descriptor_A ? inner_type : type)));
 
   pointer64_type = build_pointer_type_for_mode (type, DImode, false);
 
   field_list64
     = chainon (field_list64,
-              make_descriptor_field ("POINTER", pointer64_type,
-                                     record64_type,
-                                     build_unary_op (ADDR_EXPR,
-                                                     pointer64_type,
-                                                     build0 (PLACEHOLDER_EXPR,
-                                                             type))));
+              make_descriptor_field
+              ("POINTER", pointer64_type, record64_type,
+               build_unary_op (ADDR_EXPR,
+                               pointer64_type,
+                               build0 (PLACEHOLDER_EXPR, type))));
 
   switch (mech)
     {
@@ -2919,8 +2969,7 @@ make_descriptor_field (const char *name, tree type,
                       tree rec_type, tree initial)
 {
   tree field
-    = create_field_decl (get_identifier (name), type, rec_type, NULL_TREE,
-                        NULL_TREE, 0, 0);
+    = create_field_decl (get_identifier (name), type, rec_type, 0, 0, 0, 0);
 
   DECL_INITIAL (field) = initial;
   return field;
@@ -2938,11 +2987,11 @@ convert_vms_descriptor64 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
   /* The CLASS field is the 3rd field in the descriptor.  */
   tree klass = TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (desc_type)));
   /* The POINTER field is the 6th field in the descriptor.  */
-  tree pointer = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (klass)));
+  tree pointer64 = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (klass)));
 
   /* Retrieve the value of the POINTER field.  */
   tree gnu_expr64
-    = build3 (COMPONENT_REF, TREE_TYPE (pointer), desc, pointer, NULL_TREE);
+    = build3 (COMPONENT_REF, TREE_TYPE (pointer64), desc, pointer64, NULL_TREE);
 
   if (POINTER_TYPE_P (gnu_type))
     return convert (gnu_type, gnu_expr64);
@@ -2959,7 +3008,7 @@ convert_vms_descriptor64 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
       int iklass = TREE_INT_CST_LOW (DECL_INITIAL (klass));
       tree lfield, ufield;
 
-      /* Convert POINTER to the pointer-to-array type.  */
+      /* Convert POINTER to the type of the P_ARRAY field.  */
       gnu_expr64 = convert (p_array_type, gnu_expr64);
 
       switch (iklass)
@@ -2984,11 +3033,11 @@ convert_vms_descriptor64 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
          /* Test that we really have a SB descriptor, like DEC Ada.  */
          t = build3 (COMPONENT_REF, TREE_TYPE (klass), desc, klass, NULL);
          u = convert (TREE_TYPE (klass), DECL_INITIAL (klass));
-         u = build_binary_op (EQ_EXPR, boolean_type_node, t, u);
+         u = build_binary_op (EQ_EXPR, integer_type_node, t, u);
          /* If so, there is already a template in the descriptor and
             it is located right after the POINTER field.  The fields are
              64bits so they must be repacked. */
-         t = TREE_CHAIN (pointer);
+         t = TREE_CHAIN (pointer64);
           lfield = build3 (COMPONENT_REF, TREE_TYPE (t), desc, t, NULL_TREE);
           lfield = convert (TREE_TYPE (TYPE_FIELDS (template_type)), lfield);
 
@@ -3013,7 +3062,7 @@ convert_vms_descriptor64 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
        case 4:  /* Class A */
          /* The AFLAGS field is the 3rd field after the pointer in the
              descriptor.  */
-         t = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (pointer)));
+         t = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (pointer64)));
          aflags = build3 (COMPONENT_REF, TREE_TYPE (t), desc, t, NULL_TREE);
          /* The DIMCT field is the next field in the descriptor after
              aflags.  */
@@ -3022,12 +3071,12 @@ convert_vms_descriptor64 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
          /* Raise CONSTRAINT_ERROR if either more than 1 dimension
             or FL_COEFF or FL_BOUNDS not set.  */
          u = build_int_cst (TREE_TYPE (aflags), 192);
-         u = build_binary_op (TRUTH_OR_EXPR, boolean_type_node,
-                              build_binary_op (NE_EXPR, boolean_type_node,
+         u = build_binary_op (TRUTH_OR_EXPR, integer_type_node,
+                              build_binary_op (NE_EXPR, integer_type_node,
                                                dimct,
                                                convert (TREE_TYPE (dimct),
                                                         size_one_node)),
-                              build_binary_op (NE_EXPR, boolean_type_node,
+                              build_binary_op (NE_EXPR, integer_type_node,
                                                build2 (BIT_AND_EXPR,
                                                        TREE_TYPE (aflags),
                                                        aflags, u),
@@ -3107,7 +3156,7 @@ convert_vms_descriptor32 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
       /* See the head comment of build_vms_descriptor.  */
       int iklass = TREE_INT_CST_LOW (DECL_INITIAL (klass));
 
-      /* Convert POINTER to the pointer-to-array type.  */
+      /* Convert POINTER to the type of the P_ARRAY field.  */
       gnu_expr32 = convert (p_array_type, gnu_expr32);
 
       switch (iklass)
@@ -3132,7 +3181,7 @@ convert_vms_descriptor32 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
          /* Test that we really have a SB descriptor, like DEC Ada.  */
          t = build3 (COMPONENT_REF, TREE_TYPE (klass), desc, klass, NULL);
          u = convert (TREE_TYPE (klass), DECL_INITIAL (klass));
-         u = build_binary_op (EQ_EXPR, boolean_type_node, t, u);
+         u = build_binary_op (EQ_EXPR, integer_type_node, t, u);
          /* If so, there is already a template in the descriptor and
             it is located right after the POINTER field.  */
          t = TREE_CHAIN (pointer);
@@ -3155,12 +3204,12 @@ convert_vms_descriptor32 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
          /* Raise CONSTRAINT_ERROR if either more than 1 dimension
             or FL_COEFF or FL_BOUNDS not set.  */
          u = build_int_cst (TREE_TYPE (aflags), 192);
-         u = build_binary_op (TRUTH_OR_EXPR, boolean_type_node,
-                              build_binary_op (NE_EXPR, boolean_type_node,
+         u = build_binary_op (TRUTH_OR_EXPR, integer_type_node,
+                              build_binary_op (NE_EXPR, integer_type_node,
                                                dimct,
                                                convert (TREE_TYPE (dimct),
                                                         size_one_node)),
-                              build_binary_op (NE_EXPR, boolean_type_node,
+                              build_binary_op (NE_EXPR, integer_type_node,
                                                build2 (BIT_AND_EXPR,
                                                        TREE_TYPE (aflags),
                                                        aflags, u),
@@ -3222,11 +3271,11 @@ convert_vms_descriptor (tree gnu_type, tree gnu_expr, tree gnu_expr_alt_type,
   mbo = build3 (COMPONENT_REF, TREE_TYPE (mbo), desc, mbo, NULL_TREE);
   mbmo = build3 (COMPONENT_REF, TREE_TYPE (mbmo), desc, mbmo, NULL_TREE);
   is64bit
-    = build_binary_op (TRUTH_ANDIF_EXPR, boolean_type_node,
-                      build_binary_op (EQ_EXPR, boolean_type_node,
+    = build_binary_op (TRUTH_ANDIF_EXPR, integer_type_node,
+                      build_binary_op (EQ_EXPR, integer_type_node,
                                        convert (integer_type_node, mbo),
                                        integer_one_node),
-                      build_binary_op (EQ_EXPR, boolean_type_node,
+                      build_binary_op (EQ_EXPR, integer_type_node,
                                        convert (integer_type_node, mbmo),
                                        integer_minus_one_node));
 
@@ -3245,12 +3294,12 @@ void
 build_function_stub (tree gnu_subprog, Entity_Id gnat_subprog)
 {
   tree gnu_subprog_type, gnu_subprog_addr, gnu_subprog_call;
-  tree gnu_stub_param, gnu_arg_types, gnu_param;
+  tree gnu_stub_param, gnu_param_list, gnu_arg_types, gnu_param;
   tree gnu_stub_decl = DECL_FUNCTION_STUB (gnu_subprog);
   tree gnu_body;
-  VEC(tree,gc) *gnu_param_vec = NULL;
 
   gnu_subprog_type = TREE_TYPE (gnu_subprog);
+  gnu_param_list = NULL_TREE;
 
   begin_subprog_body (gnu_stub_decl);
   gnat_pushlevel ();
@@ -3274,7 +3323,7 @@ build_function_stub (tree gnu_subprog, Entity_Id gnat_subprog)
       else
        gnu_param = gnu_stub_param;
 
-      VEC_safe_push (tree, gc, gnu_param_vec, gnu_param);
+      gnu_param_list = tree_cons (NULL_TREE, gnu_param, gnu_param_list);
     }
 
   gnu_body = end_stmt_group ();
@@ -3282,8 +3331,9 @@ build_function_stub (tree gnu_subprog, Entity_Id gnat_subprog)
   /* Invoke the internal subprogram.  */
   gnu_subprog_addr = build1 (ADDR_EXPR, build_pointer_type (gnu_subprog_type),
                             gnu_subprog);
-  gnu_subprog_call = build_call_vec (TREE_TYPE (gnu_subprog_type),
-                                     gnu_subprog_addr, gnu_param_vec);
+  gnu_subprog_call = build_call_list (TREE_TYPE (gnu_subprog_type),
+                                     gnu_subprog_addr,
+                                     nreverse (gnu_param_list));
 
   /* Propagate the return value, if any.  */
   if (VOID_TYPE_P (TREE_TYPE (gnu_subprog_type)))
@@ -3299,33 +3349,28 @@ build_function_stub (tree gnu_subprog, Entity_Id gnat_subprog)
   end_subprog_body (gnu_body);
 }
 \f
-/* Build a type to be used to represent an aliased object whose nominal type
-   is an unconstrained array.  This consists of a RECORD_TYPE containing a
-   field of TEMPLATE_TYPE and a field of OBJECT_TYPE, which is an ARRAY_TYPE.
-   If ARRAY_TYPE is that of an unconstrained array, this is used to represent
-   an arbitrary unconstrained object.  Use NAME as the name of the record.
-   DEBUG_INFO_P is true if we need to write debug information for the type.  */
+/* Build a type to be used to represent an aliased object whose nominal
+   type is an unconstrained array.  This consists of a RECORD_TYPE containing
+   a field of TEMPLATE_TYPE and a field of OBJECT_TYPE, which is an
+   ARRAY_TYPE.  If ARRAY_TYPE is that of the unconstrained array, this
+   is used to represent an arbitrary unconstrained object.  Use NAME
+   as the name of the record.  */
 
 tree
-build_unc_object_type (tree template_type, tree object_type, tree name,
-                      bool debug_info_p)
+build_unc_object_type (tree template_type, tree object_type, tree name)
 {
   tree type = make_node (RECORD_TYPE);
-  tree template_field
-    = create_field_decl (get_identifier ("BOUNDS"), template_type, type,
-                        NULL_TREE, NULL_TREE, 0, 1);
-  tree array_field
-    = create_field_decl (get_identifier ("ARRAY"), object_type, type,
-                        NULL_TREE, NULL_TREE, 0, 1);
+  tree template_field = create_field_decl (get_identifier ("BOUNDS"),
+                                          template_type, type, 0, 0, 0, 1);
+  tree array_field = create_field_decl (get_identifier ("ARRAY"), object_type,
+                                       type, 0, 0, 0, 1);
 
   TYPE_NAME (type) = name;
   TYPE_CONTAINS_TEMPLATE_P (type) = 1;
-  TREE_CHAIN (template_field) = array_field;
-  finish_record_type (type, template_field, 0, true);
-
-  /* Declare it now since it will never be declared otherwise.  This is
-     necessary to ensure that its subtrees are properly marked.  */
-  create_type_decl (name, type, NULL, true, debug_info_p, Empty);
+  finish_record_type (type,
+                     chainon (chainon (NULL_TREE, template_field),
+                              array_field),
+                     0, true);
 
   return type;
 }
@@ -3334,7 +3379,7 @@ build_unc_object_type (tree template_type, tree object_type, tree name,
 
 tree
 build_unc_object_type_from_ptr (tree thin_fat_ptr_type, tree object_type,
-                               tree name, bool debug_info_p)
+                               tree name)
 {
   tree template_type;
 
@@ -3344,9 +3389,7 @@ build_unc_object_type_from_ptr (tree thin_fat_ptr_type, tree object_type,
     = (TYPE_IS_FAT_POINTER_P (thin_fat_ptr_type)
        ? TREE_TYPE (TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (thin_fat_ptr_type))))
        : TREE_TYPE (TYPE_FIELDS (TREE_TYPE (thin_fat_ptr_type))));
-
-  return
-    build_unc_object_type (template_type, object_type, name, debug_info_p);
+  return build_unc_object_type (template_type, object_type, name);
 }
 
 /* Shift the component offsets within an unconstrained object TYPE to make it
@@ -3379,12 +3422,14 @@ update_pointer_to (tree old_type, tree new_type)
 {
   tree ptr = TYPE_POINTER_TO (old_type);
   tree ref = TYPE_REFERENCE_TO (old_type);
-  tree t;
+  tree ptr1, ref1;
+  tree type;
 
   /* If this is the main variant, process all the other variants first.  */
   if (TYPE_MAIN_VARIANT (old_type) == old_type)
-    for (t = TYPE_NEXT_VARIANT (old_type); t; t = TYPE_NEXT_VARIANT (t))
-      update_pointer_to (t, new_type);
+    for (type = TYPE_NEXT_VARIANT (old_type); type;
+        type = TYPE_NEXT_VARIANT (type))
+      update_pointer_to (type, new_type);
 
   /* If no pointers and no references, we are done.  */
   if (!ptr && !ref)
@@ -3420,79 +3465,47 @@ update_pointer_to (tree old_type, tree new_type)
   /* Otherwise, first handle the simple case.  */
   if (TREE_CODE (new_type) != UNCONSTRAINED_ARRAY_TYPE)
     {
-      tree new_ptr, new_ref;
-
-      /* If pointer or reference already points to new type, nothing to do.
-        This can happen as update_pointer_to can be invoked multiple times
-        on the same couple of types because of the type variants.  */
-      if ((ptr && TREE_TYPE (ptr) == new_type)
-         || (ref && TREE_TYPE (ref) == new_type))
-       return;
-
-      /* Chain PTR and its variants at the end.  */
-      new_ptr = TYPE_POINTER_TO (new_type);
-      if (new_ptr)
-       {
-         while (TYPE_NEXT_PTR_TO (new_ptr))
-           new_ptr = TYPE_NEXT_PTR_TO (new_ptr);
-         TYPE_NEXT_PTR_TO (new_ptr) = ptr;
-       }
-      else
-       TYPE_POINTER_TO (new_type) = ptr;
+      TYPE_POINTER_TO (new_type) = ptr;
+      TYPE_REFERENCE_TO (new_type) = ref;
 
-      /* Now adjust them.  */
       for (; ptr; ptr = TYPE_NEXT_PTR_TO (ptr))
-       for (t = TYPE_MAIN_VARIANT (ptr); t; t = TYPE_NEXT_VARIANT (t))
-         TREE_TYPE (t) = new_type;
-
-      /* Chain REF and its variants at the end.  */
-      new_ref = TYPE_REFERENCE_TO (new_type);
-      if (new_ref)
-       {
-         while (TYPE_NEXT_REF_TO (new_ref))
-           new_ref = TYPE_NEXT_REF_TO (new_ref);
-         TYPE_NEXT_REF_TO (new_ref) = ref;
-       }
-      else
-       TYPE_REFERENCE_TO (new_type) = ref;
+       for (ptr1 = TYPE_MAIN_VARIANT (ptr); ptr1;
+            ptr1 = TYPE_NEXT_VARIANT (ptr1))
+         TREE_TYPE (ptr1) = new_type;
 
-      /* Now adjust them.  */
       for (; ref; ref = TYPE_NEXT_REF_TO (ref))
-       for (t = TYPE_MAIN_VARIANT (ref); t; t = TYPE_NEXT_VARIANT (t))
-         TREE_TYPE (t) = new_type;
+       for (ref1 = TYPE_MAIN_VARIANT (ref); ref1;
+            ref1 = TYPE_NEXT_VARIANT (ref1))
+         TREE_TYPE (ref1) = new_type;
     }
 
-  /* Now deal with the unconstrained array case.  In this case the pointer
-     is actually a record where both fields are pointers to dummy nodes.
+  /* Now deal with the unconstrained array case.  In this case the "pointer"
+     is actually a RECORD_TYPE where both fields are pointers to dummy nodes.
      Turn them into pointers to the correct types using update_pointer_to.  */
+  else if (!TYPE_IS_FAT_POINTER_P (ptr))
+    gcc_unreachable ();
+
   else
     {
-      tree new_ptr = TYPE_MAIN_VARIANT (TYPE_POINTER_TO (new_type));
       tree new_obj_rec = TYPE_OBJECT_RECORD_TYPE (new_type);
-      tree array_field, bounds_field, new_ref, last;
-
-      gcc_assert (TYPE_IS_FAT_POINTER_P (ptr));
-
-      /* If PTR already points to new type, nothing to do.  This can happen
-        since update_pointer_to can be invoked multiple times on the same
-        couple of types because of the type variants.  */
-      if (TYPE_UNCONSTRAINED_ARRAY (ptr) == new_type)
-       return;
-
-      array_field = TYPE_FIELDS (ptr);
-      bounds_field = TREE_CHAIN (array_field);
+      tree array_field = TYPE_FIELDS (ptr);
+      tree bounds_field = TREE_CHAIN (TYPE_FIELDS (ptr));
+      tree new_ptr = TYPE_POINTER_TO (new_type);
+      tree new_ref;
+      tree var;
 
       /* Make pointers to the dummy template point to the real template.  */
       update_pointer_to
        (TREE_TYPE (TREE_TYPE (bounds_field)),
         TREE_TYPE (TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (new_ptr)))));
 
-      /* The references to the template bounds present in the array type use
-        the bounds field of NEW_PTR through a PLACEHOLDER_EXPR.  Since we
-        are going to merge PTR in NEW_PTR, we must rework these references
-        to use the bounds field of PTR instead.  */
+      /* The references to the template bounds present in the array type
+        are made through a PLACEHOLDER_EXPR of type NEW_PTR.  Since we
+        are updating PTR to make it a full replacement for NEW_PTR as
+        pointer to NEW_TYPE, we must rework the PLACEHOLDER_EXPR so as
+        to make it of type PTR.  */
       new_ref = build3 (COMPONENT_REF, TREE_TYPE (bounds_field),
-                       build0 (PLACEHOLDER_EXPR, new_ptr),
+                       build0 (PLACEHOLDER_EXPR, ptr),
                        bounds_field, NULL_TREE);
 
       /* Create the new array for the new PLACEHOLDER_EXPR and make pointers
@@ -3502,35 +3515,30 @@ update_pointer_to (tree old_type, tree new_type)
         substitute_in_type (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (new_ptr))),
                             TREE_CHAIN (TYPE_FIELDS (new_ptr)), new_ref));
 
-      /* Merge PTR in NEW_PTR.  */
-      DECL_FIELD_CONTEXT (array_field) = new_ptr;
-      DECL_FIELD_CONTEXT (bounds_field) = new_ptr;
-      for (t = new_ptr; t; last = t, t = TYPE_NEXT_VARIANT (t))
-       TYPE_FIELDS (t) = TYPE_FIELDS (ptr);
-
-      /* Chain PTR and its variants at the end.  */
-      TYPE_NEXT_VARIANT (last) = TYPE_MAIN_VARIANT (ptr);
-
-      /* Now adjust them.  */
-      for (t = TYPE_MAIN_VARIANT (ptr); t; t = TYPE_NEXT_VARIANT (t))
-       {
-         TYPE_MAIN_VARIANT (t) = new_ptr;
-         SET_TYPE_UNCONSTRAINED_ARRAY (t, new_type);
-       }
+      /* Make PTR the pointer to NEW_TYPE.  */
+      TYPE_POINTER_TO (new_type) = TYPE_REFERENCE_TO (new_type)
+       = TREE_TYPE (new_type) = ptr;
 
       /* And show the original pointer NEW_PTR to the debugger.  This is the
         counterpart of the equivalent processing in gnat_pushdecl when the
-        unconstrained array type is frozen after access types to it.  */
-      if (TYPE_NAME (ptr) && TREE_CODE (TYPE_NAME (ptr)) == TYPE_DECL)
+        unconstrained array type is frozen after access types to it.  Note
+        that update_pointer_to can be invoked multiple times on the same
+        couple of types because of the type variants.  */
+      if (TYPE_NAME (ptr)
+         && TREE_CODE (TYPE_NAME (ptr)) == TYPE_DECL
+         && !DECL_ORIGINAL_TYPE (TYPE_NAME (ptr)))
        {
          DECL_ORIGINAL_TYPE (TYPE_NAME (ptr)) = new_ptr;
          DECL_ARTIFICIAL (TYPE_NAME (ptr)) = 0;
        }
+      for (var = TYPE_MAIN_VARIANT (ptr); var; var = TYPE_NEXT_VARIANT (var))
+       SET_TYPE_UNCONSTRAINED_ARRAY (var, new_type);
 
       /* Now handle updating the allocation record, what the thin pointer
         points to.  Update all pointers from the old record into the new
         one, update the type of the array field, and recompute the size.  */
       update_pointer_to (TYPE_OBJECT_RECORD_TYPE (old_type), new_obj_rec);
+
       TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (new_obj_rec)))
        = TREE_TYPE (TREE_TYPE (array_field));
 
@@ -3538,10 +3546,11 @@ update_pointer_to (tree old_type, tree new_type)
         we let layout_type work it out.  This will reset the field offsets to
         what they would be in a regular record, so we shift them back to what
         we want them to be for a thin pointer designated type afterwards.  */
-      DECL_SIZE (TYPE_FIELDS (new_obj_rec)) = NULL_TREE;
-      DECL_SIZE (TREE_CHAIN (TYPE_FIELDS (new_obj_rec))) = NULL_TREE;
-      TYPE_SIZE (new_obj_rec) = NULL_TREE;
+      DECL_SIZE (TYPE_FIELDS (new_obj_rec)) = 0;
+      DECL_SIZE (TREE_CHAIN (TYPE_FIELDS (new_obj_rec))) = 0;
+      TYPE_SIZE (new_obj_rec) = 0;
       layout_type (new_obj_rec);
+
       shift_unc_components_for_thin_pointers (new_obj_rec);
 
       /* We are done, at last.  */
@@ -3578,7 +3587,7 @@ convert_to_fat_pointer (tree type, tree expr)
     {
       tree fields = TYPE_FIELDS (TREE_TYPE (etype));
 
-      expr = gnat_protect_expr (expr);
+      expr = protect_multiple_eval (expr);
       if (TREE_CODE (expr) == ADDR_EXPR)
        expr = TREE_OPERAND (expr, 0);
       else
@@ -3647,12 +3656,12 @@ convert_to_thin_pointer (tree type, tree expr)
 tree
 convert (tree type, tree expr)
 {
+  enum tree_code code = TREE_CODE (type);
   tree etype = TREE_TYPE (expr);
   enum tree_code ecode = TREE_CODE (etype);
-  enum tree_code code = TREE_CODE (type);
 
-  /* If the expression is already of the right type, we are done.  */
-  if (etype == type)
+  /* If EXPR is already the right type, we are done.  */
+  if (type == etype)
     return expr;
 
   /* If both input and output have padding and are of variable size, do this
@@ -3699,7 +3708,7 @@ convert (tree type, tree expr)
       /* If the inner type is of self-referential size and the expression type
         is a record, do this as an unchecked conversion.  But first pad the
         expression if possible to have the same size on both sides.  */
-      if (ecode == RECORD_TYPE
+      if (TREE_CODE (etype) == RECORD_TYPE
          && CONTAINS_PLACEHOLDER_P (DECL_SIZE (TYPE_FIELDS (type))))
        {
          if (TREE_CONSTANT (TYPE_SIZE (etype)))
@@ -3712,7 +3721,7 @@ convert (tree type, tree expr)
         final conversion as an unchecked conversion, again to avoid the need
         for some variable-sized temporaries.  If valid, this conversion is
         very likely purely technical and without real effects.  */
-      if (ecode == ARRAY_TYPE
+      if (TREE_CODE (etype) == ARRAY_TYPE
          && TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == ARRAY_TYPE
          && !TREE_CONSTANT (TYPE_SIZE (etype))
          && !TREE_CONSTANT (TYPE_SIZE (type)))
@@ -3843,14 +3852,11 @@ convert (tree type, tree expr)
          return expr;
        }
 
-      /* Likewise for a conversion between original and packable version, or
-        conversion between types of the same size and with the same list of
-        fields, but we have to work harder to preserve type consistency.  */
+      /* Likewise for a conversion between original and packable version, but
+        we have to work harder in order to preserve type consistency.  */
       if (code == ecode
          && code == RECORD_TYPE
-         && (TYPE_NAME (type) == TYPE_NAME (etype)
-             || tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (etype))))
-
+         && TYPE_NAME (type) == TYPE_NAME (etype))
        {
          VEC(constructor_elt,gc) *e = CONSTRUCTOR_ELTS (expr);
          unsigned HOST_WIDE_INT len = VEC_length (constructor_elt, e);
@@ -3865,14 +3871,10 @@ convert (tree type, tree expr)
 
          FOR_EACH_CONSTRUCTOR_ELT(e, idx, index, value)
            {
-             constructor_elt *elt;
-             /* We expect only simple constructors.  */
-             if (!SAME_FIELD_P (index, efield))
-               break;
-             /* The field must be the same.  */
-             if (!SAME_FIELD_P (efield, field))
+             constructor_elt *elt = VEC_quick_push (constructor_elt, v, NULL);
+             /* We expect only simple constructors.  Otherwise, punt.  */
+             if (!(index == efield || index == DECL_ORIGINAL_FIELD (efield)))
                break;
-             elt = VEC_quick_push (constructor_elt, v, NULL);
              elt->index = field;
              elt->value = convert (TREE_TYPE (field), value);
 
@@ -3954,12 +3956,10 @@ convert (tree type, tree expr)
     case UNCONSTRAINED_ARRAY_REF:
       /* Convert this to the type of the inner array by getting the address of
         the array from the template.  */
-      expr = TREE_OPERAND (expr, 0);
       expr = build_unary_op (INDIRECT_REF, NULL_TREE,
-                            build_component_ref (expr, NULL_TREE,
-                                                 TYPE_FIELDS
-                                                 (TREE_TYPE (expr)),
-                                                 false));
+                            build_component_ref (TREE_OPERAND (expr, 0),
+                                                 get_identifier ("P_ARRAY"),
+                                                 NULL_TREE, false));
       etype = TREE_TYPE (expr);
       ecode = TREE_CODE (etype);
       break;
@@ -4000,6 +4000,25 @@ convert (tree type, tree expr)
       }
       break;
 
+    case INDIRECT_REF:
+      /* If both types are record types, just convert the pointer and
+        make a new INDIRECT_REF.
+
+        ??? Disable this for now since it causes problems with the
+        code in build_binary_op for MODIFY_EXPR which wants to
+        strip off conversions.  But that code really is a mess and
+        we need to do this a much better way some time.  */
+      if (0
+         && (TREE_CODE (type) == RECORD_TYPE
+             || TREE_CODE (type) == UNION_TYPE)
+         && (TREE_CODE (etype) == RECORD_TYPE
+             || TREE_CODE (etype) == UNION_TYPE)
+         && !TYPE_IS_FAT_POINTER_P (type) && !TYPE_IS_FAT_POINTER_P (etype))
+       return build_unary_op (INDIRECT_REF, NULL_TREE,
+                              convert (build_pointer_type (type),
+                                       TREE_OPERAND (expr, 0)));
+      break;
+
     default:
       break;
     }
@@ -4020,21 +4039,10 @@ convert (tree type, tree expr)
                                           etype)))
     return build1 (VIEW_CONVERT_EXPR, type, expr);
 
-  /* If we are converting between tagged types, try to upcast properly.  */
-  else if (ecode == RECORD_TYPE && code == RECORD_TYPE
-          && TYPE_ALIGN_OK (etype) && TYPE_ALIGN_OK (type))
-    {
-      tree child_etype = etype;
-      do {
-       tree field = TYPE_FIELDS (child_etype);
-       if (DECL_NAME (field) == parent_name_id && TREE_TYPE (field) == type)
-         return build_component_ref (expr, NULL_TREE, field, false);
-       child_etype = TREE_TYPE (field);
-      } while (TREE_CODE (child_etype) == RECORD_TYPE);
-    }
-
   /* In all other cases of related types, make a NOP_EXPR.  */
-  else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (etype))
+  else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (etype)
+          || (code == INTEGER_CST && ecode == INTEGER_CST
+              && (type == TREE_TYPE (etype) || etype == TREE_TYPE (type))))
     return fold_convert (type, expr);
 
   switch (code)
@@ -4093,8 +4101,9 @@ convert (tree type, tree expr)
          tree bit_diff
            = size_diffop (bit_position (TYPE_FIELDS (TREE_TYPE (etype))),
                           bit_position (TYPE_FIELDS (TREE_TYPE (type))));
-         tree byte_diff
-           = size_binop (CEIL_DIV_EXPR, bit_diff, sbitsize_unit_node);
+         tree byte_diff = size_binop (CEIL_DIV_EXPR, bit_diff,
+                                      sbitsize_int (BITS_PER_UNIT));
+
          expr = build1 (NOP_EXPR, type, expr);
          TREE_CONSTANT (expr) = TREE_CONSTANT (TREE_OPERAND (expr, 0));
          if (integer_zerop (byte_diff))
@@ -4112,8 +4121,8 @@ convert (tree type, tree expr)
       /* If converting fat pointer to normal pointer, get the pointer to the
         array and then convert it.  */
       else if (TYPE_IS_FAT_POINTER_P (etype))
-       expr
-         = build_component_ref (expr, NULL_TREE, TYPE_FIELDS (etype), false);
+       expr = build_component_ref (expr, get_identifier ("P_ARRAY"),
+                                   NULL_TREE, false);
 
       return fold (convert_to_pointer (type, expr));
 
@@ -4224,7 +4233,7 @@ remove_conversions (tree exp, bool true_address)
 }
 \f
 /* If EXP's type is an UNCONSTRAINED_ARRAY_TYPE, return an expression that
-   refers to the underlying array.  If it has TYPE_CONTAINS_TEMPLATE_P,
+   refers to the underlying array.  If its type has TYPE_CONTAINS_TEMPLATE_P,
    likewise return an expression pointing to the underlying array.  */
 
 tree
@@ -4238,13 +4247,11 @@ maybe_unconstrained_array (tree exp)
     case UNCONSTRAINED_ARRAY_TYPE:
       if (code == UNCONSTRAINED_ARRAY_REF)
        {
-         new_exp = TREE_OPERAND (exp, 0);
          new_exp
            = build_unary_op (INDIRECT_REF, NULL_TREE,
-                             build_component_ref (new_exp, NULL_TREE,
-                                                  TYPE_FIELDS
-                                                  (TREE_TYPE (new_exp)),
-                                                  false));
+                             build_component_ref (TREE_OPERAND (exp, 0),
+                                                  get_identifier ("P_ARRAY"),
+                                                  NULL_TREE, false));
          TREE_READONLY (new_exp) = TREE_READONLY (exp);
          return new_exp;
        }
@@ -4267,13 +4274,12 @@ maybe_unconstrained_array (tree exp)
              build_component_ref (new_exp, NULL_TREE,
                                   TREE_CHAIN
                                   (TYPE_FIELDS (TREE_TYPE (new_exp))),
-                                  false);
+                                  0);
        }
       else if (TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (exp)))
        return
          build_component_ref (exp, NULL_TREE,
-                              TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp))),
-                              false);
+                              TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp))), 0);
       break;
 
     default:
@@ -4352,26 +4358,29 @@ tree
 unchecked_convert (tree type, tree expr, bool notrunc_p)
 {
   tree etype = TREE_TYPE (expr);
-  enum tree_code ecode = TREE_CODE (etype);
-  enum tree_code code = TREE_CODE (type);
 
-  /* If the expression is already of the right type, we are done.  */
+  /* If the expression is already the right type, we are done.  */
   if (etype == type)
     return expr;
 
   /* If both types types are integral just do a normal conversion.
      Likewise for a conversion to an unconstrained array.  */
   if ((((INTEGRAL_TYPE_P (type)
-        && !(code == INTEGER_TYPE && TYPE_VAX_FLOATING_POINT_P (type)))
+        && !(TREE_CODE (type) == INTEGER_TYPE
+             && TYPE_VAX_FLOATING_POINT_P (type)))
        || (POINTER_TYPE_P (type) && ! TYPE_IS_THIN_POINTER_P (type))
-       || (code == RECORD_TYPE && TYPE_JUSTIFIED_MODULAR_P (type)))
+       || (TREE_CODE (type) == RECORD_TYPE
+           && TYPE_JUSTIFIED_MODULAR_P (type)))
        && ((INTEGRAL_TYPE_P (etype)
-           && !(ecode == INTEGER_TYPE && TYPE_VAX_FLOATING_POINT_P (etype)))
+           && !(TREE_CODE (etype) == INTEGER_TYPE
+                && TYPE_VAX_FLOATING_POINT_P (etype)))
           || (POINTER_TYPE_P (etype) && !TYPE_IS_THIN_POINTER_P (etype))
-          || (ecode == RECORD_TYPE && TYPE_JUSTIFIED_MODULAR_P (etype))))
-      || code == UNCONSTRAINED_ARRAY_TYPE)
+          || (TREE_CODE (etype) == RECORD_TYPE
+              && TYPE_JUSTIFIED_MODULAR_P (etype))))
+      || TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE)
     {
-      if (ecode == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (etype))
+      if (TREE_CODE (etype) == INTEGER_TYPE
+         && TYPE_BIASED_REPRESENTATION_P (etype))
        {
          tree ntype = copy_type (etype);
          TYPE_BIASED_REPRESENTATION_P (ntype) = 0;
@@ -4379,7 +4388,8 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
          expr = build1 (NOP_EXPR, ntype, expr);
        }
 
-      if (code == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (type))
+      if (TREE_CODE (type) == INTEGER_TYPE
+         && TYPE_BIASED_REPRESENTATION_P (type))
        {
          tree rtype = copy_type (type);
          TYPE_BIASED_REPRESENTATION_P (rtype) = 0;
@@ -4399,14 +4409,14 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
                                     GET_MODE_BITSIZE (TYPE_MODE (type))))
     {
       tree rec_type = make_node (RECORD_TYPE);
-      tree field = create_field_decl (get_identifier ("OBJ"), type, rec_type,
-                                     NULL_TREE, NULL_TREE, 1, 0);
+      tree field = create_field_decl (get_identifier ("OBJ"), type,
+                                     rec_type, 1, 0, 0, 0);
 
       TYPE_FIELDS (rec_type) = field;
       layout_type (rec_type);
 
       expr = unchecked_convert (rec_type, expr, notrunc_p);
-      expr = build_component_ref (expr, NULL_TREE, field, false);
+      expr = build_component_ref (expr, NULL_TREE, field, 0);
     }
 
   /* Similarly if we are converting from an integral type whose precision
@@ -4416,8 +4426,9 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
                                GET_MODE_BITSIZE (TYPE_MODE (etype))))
     {
       tree rec_type = make_node (RECORD_TYPE);
-      tree field = create_field_decl (get_identifier ("OBJ"), etype, rec_type,
-                                     NULL_TREE, NULL_TREE, 1, 0);
+      tree field
+       = create_field_decl (get_identifier ("OBJ"), etype, rec_type,
+                            1, 0, 0, 0);
 
       TYPE_FIELDS (rec_type) = field;
       layout_type (rec_type);
@@ -4429,7 +4440,8 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
   /* We have a special case when we are converting between two unconstrained
      array types.  In that case, take the address, convert the fat pointer
      types, and dereference.  */
-  else if (ecode == code && code == UNCONSTRAINED_ARRAY_TYPE)
+  else if (TREE_CODE (etype) == UNCONSTRAINED_ARRAY_TYPE
+          && TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE)
     expr = build_unary_op (INDIRECT_REF, NULL_TREE,
                           build1 (VIEW_CONVERT_EXPR, TREE_TYPE (type),
                                   build_unary_op (ADDR_EXPR, NULL_TREE,
@@ -4437,8 +4449,8 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
 
   /* Another special case is when we are converting to a vector type from its
      representative array type; this a regular conversion.  */
-  else if (code == VECTOR_TYPE
-          && ecode == ARRAY_TYPE
+  else if (TREE_CODE (type) == VECTOR_TYPE
+          && TREE_CODE (etype) == ARRAY_TYPE
           && gnat_types_compatible_p (TYPE_REPRESENTATIVE_ARRAY (type),
                                       etype))
     expr = convert (type, expr);
@@ -4447,7 +4459,6 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
     {
       expr = maybe_unconstrained_array (expr);
       etype = TREE_TYPE (expr);
-      ecode = TREE_CODE (etype);
       if (can_fold_for_view_convert_p (expr))
        expr = fold_build1 (VIEW_CONVERT_EXPR, type, expr);
       else
@@ -4460,7 +4471,8 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
      is a biased type or if both the input and output are unsigned.  */
   if (!notrunc_p
       && INTEGRAL_TYPE_P (type) && TYPE_RM_SIZE (type)
-      && !(code == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (type))
+      && !(TREE_CODE (type) == INTEGER_TYPE
+          && TYPE_BIASED_REPRESENTATION_P (type))
       && 0 != compare_tree_int (TYPE_RM_SIZE (type),
                                GET_MODE_BITSIZE (TYPE_MODE (type)))
       && !(INTEGRAL_TYPE_P (etype)
@@ -4471,8 +4483,8 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
                               0))
       && !(TYPE_UNSIGNED (type) && TYPE_UNSIGNED (etype)))
     {
-      tree base_type
-       = gnat_type_for_mode (TYPE_MODE (type), TYPE_UNSIGNED (type));
+      tree base_type = gnat_type_for_mode (TYPE_MODE (type),
+                                          TYPE_UNSIGNED (type));
       tree shift_expr
        = convert (base_type,
                   size_binop (MINUS_EXPR,
@@ -4733,7 +4745,7 @@ builtin_type_for_size (int size, bool unsignedp)
 static void
 install_builtin_elementary_types (void)
 {
-  signed_size_type_node = gnat_signed_type (size_type_node);
+  signed_size_type_node = size_type_node;
   pid_type_node = integer_type_node;
   void_list_node = build_void_list_node ();
 
@@ -5079,8 +5091,7 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
          if (!argument
              || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE)
            {
-             error ("nonnull argument with out-of-range operand number "
-                    "(argument %lu, operand %lu)",
+             error ("nonnull argument with out-of-range operand number (argument %lu, operand %lu)",
                     (unsigned long) attr_arg_num, (unsigned long) arg_num);
              *no_add_attrs = true;
              return NULL_TREE;
@@ -5088,8 +5099,7 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
 
          if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
            {
-             error ("nonnull argument references non-pointer operand "
-                    "(argument %lu, operand %lu)",
+             error ("nonnull argument references non-pointer operand (argument %lu, operand %lu)",
                   (unsigned long) attr_arg_num, (unsigned long) arg_num);
              *no_add_attrs = true;
              return NULL_TREE;
index 2998605..5db38c5 100644 (file)
@@ -242,11 +242,11 @@ find_common_type (tree t1, tree t2)
 static tree
 compare_arrays (tree result_type, tree a1, tree a2)
 {
-  tree result = convert (result_type, boolean_true_node);
-  tree a1_is_null = convert (result_type, boolean_false_node);
-  tree a2_is_null = convert (result_type, boolean_false_node);
   tree t1 = TREE_TYPE (a1);
   tree t2 = TREE_TYPE (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;
@@ -254,33 +254,34 @@ compare_arrays (tree result_type, tree a1, tree a2)
   /* 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 = gnat_protect_expr (a1);
+    a1 = protect_multiple_eval (a1);
 
   if (a2_side_effects_p)
-    a2 = gnat_protect_expr (a2);
+    a2 = protect_multiple_eval (a2);
 
   /* Process each dimension separately and compare the lengths.  If any
-     dimension has a length known to be zero, set LENGTH_ZERO_P to true
-     in order to suppress the comparison of the data at the end.  */
+     dimension has a size known to be zero, set SIZE_ZERO_P to 1 to
+     suppress the comparison of the data.  */
   while (TREE_CODE (t1) == ARRAY_TYPE && TREE_CODE (t2) == ARRAY_TYPE)
     {
       tree lb1 = TYPE_MIN_VALUE (TYPE_DOMAIN (t1));
       tree ub1 = TYPE_MAX_VALUE (TYPE_DOMAIN (t1));
       tree lb2 = TYPE_MIN_VALUE (TYPE_DOMAIN (t2));
       tree ub2 = TYPE_MAX_VALUE (TYPE_DOMAIN (t2));
-      tree length1 = size_binop (PLUS_EXPR, size_binop (MINUS_EXPR, ub1, lb1),
-                                size_one_node);
-      tree length2 = size_binop (PLUS_EXPR, size_binop (MINUS_EXPR, ub2, lb2),
-                                size_one_node);
+      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 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.  */
-      if (TREE_CODE (length1) == INTEGER_CST && !integer_zerop (length2))
+        unless the length of the second array is the constant zero.
+        Note that we have set the `length' values to the length - 1.  */
+      if (TREE_CODE (length1) == INTEGER_CST
+         && !integer_zerop (fold_build2 (PLUS_EXPR, bt, length2,
+                                         convert (bt, integer_one_node))))
        {
-         tree tem;
-         bool btem;
-
          tem = a1, a1 = a2, a2 = tem;
          tem = t1, t1 = t2, t2 = tem;
          tem = lb1, lb1 = lb2, lb2 = tem;
@@ -291,56 +292,51 @@ compare_arrays (tree result_type, tree a1, tree a2)
          a2_side_effects_p = btem;
        }
 
-      /* If the length of the second array is the constant zero, we can just
-        use the original stored bounds for the first array and see whether
-        last < first holds.  */
-      if (integer_zerop (length2))
+      /* If the length of this dimension in the second array is the constant
+        zero, we can just go inside the original bounds for the first
+        array and see if last < first.  */
+      if (integer_zerop (fold_build2 (PLUS_EXPR, bt, length2,
+                                     convert (bt, integer_one_node))))
        {
-         length_zero_p = true;
-
-         ub1 = TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1)));
-         lb1 = TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1)));
+         tree ub = TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1)));
+         tree lb = TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1)));
 
-         comparison = build_binary_op (LT_EXPR, result_type, ub1, lb1);
+         comparison = build_binary_op (LT_EXPR, result_type, ub, lb);
          comparison = SUBSTITUTE_PLACEHOLDER_IN_EXPR (comparison, a1);
-         if (EXPR_P (comparison))
-           SET_EXPR_LOCATION (comparison, input_location);
+         length1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (length1, a1);
 
+         length_zero_p = true;
          this_a1_is_null = comparison;
-         this_a2_is_null = convert (result_type, boolean_true_node);
+         this_a2_is_null = convert (result_type, integer_one_node);
        }
 
-      /* Otherwise, if the length is some other constant value, we know that
-        this dimension in the second array cannot be superflat, so we can
-        just use its length computed from the actual stored bounds.  */
+      /* If the length is some other constant value, we know that the
+        this dimension in the first array cannot be superflat, so we
+        can just use its length from the actual stored bounds.  */
       else if (TREE_CODE (length2) == INTEGER_CST)
        {
-         tree bt;
-
          ub1 = TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1)));
          lb1 = TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t1)));
-         /* Note that we know that UB2 and LB2 are constant and hence
-            cannot contain a PLACEHOLDER_EXPR.  */
          ub2 = TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t2)));
          lb2 = TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (t2)));
-         bt = get_base_type (TREE_TYPE (ub1));
+         nbt = get_base_type (TREE_TYPE (ub1));
 
          comparison
            = build_binary_op (EQ_EXPR, result_type,
-                              build_binary_op (MINUS_EXPR, bt, ub1, lb1),
-                              build_binary_op (MINUS_EXPR, bt, ub2, lb2));
+                              build_binary_op (MINUS_EXPR, nbt, ub1, lb1),
+                              build_binary_op (MINUS_EXPR, nbt, ub2, lb2));
+
+         /* Note that we know that UB2 and LB2 are constant and hence
+            cannot contain a PLACEHOLDER_EXPR.  */
+
          comparison = SUBSTITUTE_PLACEHOLDER_IN_EXPR (comparison, a1);
-         if (EXPR_P (comparison))
-           SET_EXPR_LOCATION (comparison, input_location);
+         length1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (length1, a1);
 
          this_a1_is_null = build_binary_op (LT_EXPR, result_type, ub1, lb1);
-         if (EXPR_P (this_a1_is_null))
-           SET_EXPR_LOCATION (this_a1_is_null, input_location);
-
-         this_a2_is_null = convert (result_type, boolean_false_node);
+         this_a2_is_null = convert (result_type, integer_zero_node);
        }
 
-      /* Otherwise, compare the computed lengths.  */
+      /* Otherwise compare the computed lengths.  */
       else
        {
          length1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (length1, a1);
@@ -348,39 +344,20 @@ compare_arrays (tree result_type, tree a1, tree a2)
 
          comparison
            = build_binary_op (EQ_EXPR, result_type, length1, length2);
-         if (EXPR_P (comparison))
-           SET_EXPR_LOCATION (comparison, input_location);
-
-         /* If the length expression is of the form (cond ? val : 0), assume
-            that cond is equivalent to (length != 0).  That's guaranteed by
-            construction of the array types in gnat_to_gnu_entity.  */
-         if (TREE_CODE (length1) == COND_EXPR
-             && integer_zerop (TREE_OPERAND (length1, 2)))
-           this_a1_is_null = invert_truthvalue (TREE_OPERAND (length1, 0));
-         else
-           this_a1_is_null = build_binary_op (EQ_EXPR, result_type, length1,
-                                              size_zero_node);
-          if (EXPR_P (this_a1_is_null))
-           SET_EXPR_LOCATION (this_a1_is_null, input_location);
-
-         /* Likewise for the second array.  */
-         if (TREE_CODE (length2) == COND_EXPR
-             && integer_zerop (TREE_OPERAND (length2, 2)))
-           this_a2_is_null = invert_truthvalue (TREE_OPERAND (length2, 0));
-         else
-           this_a2_is_null = build_binary_op (EQ_EXPR, result_type, length2,
-                                              size_zero_node);
-          if (EXPR_P (this_a2_is_null))
-           SET_EXPR_LOCATION (this_a2_is_null, input_location);
+
+         this_a1_is_null
+           = build_binary_op (LT_EXPR, result_type, length1,
+                              convert (bt, integer_zero_node));
+         this_a2_is_null
+           = build_binary_op (LT_EXPR, result_type, length2,
+                              convert (bt, integer_zero_node));
        }
 
-      /* Append expressions for this dimension to the final expressions.  */
       result = build_binary_op (TRUTH_ANDIF_EXPR, result_type,
                                result, comparison);
 
       a1_is_null = build_binary_op (TRUTH_ORIF_EXPR, result_type,
                                    this_a1_is_null, a1_is_null);
-
       a2_is_null = build_binary_op (TRUTH_ORIF_EXPR, result_type,
                                    this_a2_is_null, a2_is_null);
 
@@ -388,12 +365,11 @@ compare_arrays (tree result_type, tree a1, tree a2)
       t2 = TREE_TYPE (t2);
     }
 
-  /* Unless the length of some dimension is known to be zero, compare the
+  /* Unless the size of some bound is known to be zero, compare the
      data in the array.  */
   if (!length_zero_p)
     {
       tree type = find_common_type (TREE_TYPE (a1), TREE_TYPE (a2));
-      tree comparison;
 
       if (type)
        {
@@ -401,12 +377,8 @@ compare_arrays (tree result_type, tree a1, tree a2)
          a2 = convert (type, a2);
        }
 
-      comparison = fold_build2 (EQ_EXPR, result_type, a1, a2);
-      if (EXPR_P (comparison))
-       SET_EXPR_LOCATION (comparison, input_location);
-
-      result
-       = build_binary_op (TRUTH_ANDIF_EXPR, result_type, result, comparison);
+      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.  */
@@ -499,9 +471,9 @@ 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 = gnat_protect_expr (result);
+      result = protect_multiple_eval (result);
       result = fold_build3 (COND_EXPR, op_type,
-                           fold_build2 (LT_EXPR, boolean_type_node, result,
+                           fold_build2 (LT_EXPR, integer_type_node, result,
                                         convert (op_type, integer_zero_node)),
                            fold_build2 (PLUS_EXPR, op_type, result, modulus),
                            result);
@@ -510,9 +482,9 @@ 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 = gnat_protect_expr (result);
+      result = protect_multiple_eval (result);
       result = fold_build3 (COND_EXPR, op_type,
-                           fold_build2 (GE_EXPR, boolean_type_node,
+                           fold_build2 (GE_EXPR, integer_type_node,
                                         result, modulus),
                            fold_build2 (MINUS_EXPR, op_type,
                                         result, modulus),
@@ -726,28 +698,16 @@ build_binary_op (enum tree_code op_code, tree result_type,
       modulus = NULL_TREE;
       break;
 
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-#ifdef ENABLE_CHECKING
-      gcc_assert (TREE_CODE (get_base_type (result_type)) == BOOLEAN_TYPE);
-#endif
-      operation_type = left_base_type;
-      left_operand = convert (operation_type, left_operand);
-      right_operand = convert (operation_type, right_operand);
-      break;
-
     case GE_EXPR:
     case LE_EXPR:
     case GT_EXPR:
     case LT_EXPR:
+      gcc_assert (!POINTER_TYPE_P (left_type));
+
+      /* ... fall through ... */
+
     case EQ_EXPR:
     case NE_EXPR:
-#ifdef ENABLE_CHECKING
-      gcc_assert (TREE_CODE (get_base_type (result_type)) == BOOLEAN_TYPE);
-#endif
       /* If either operand is a NULL_EXPR, just return a new one.  */
       if (TREE_CODE (left_operand) == NULL_EXPR)
        return build2 (op_code, result_type,
@@ -864,6 +824,13 @@ build_binary_op (enum tree_code op_code, tree result_type,
       modulus = NULL_TREE;
       break;
 
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      /* These operations are not used anymore.  */
+      gcc_unreachable ();
+
     case LSHIFT_EXPR:
     case RSHIFT_EXPR:
     case LROTATE_EXPR:
@@ -1016,9 +983,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
       break;
 
     case TRUTH_NOT_EXPR:
-#ifdef ENABLE_CHECKING
-      gcc_assert (TREE_CODE (get_base_type (result_type)) == BOOLEAN_TYPE);
-#endif
+      gcc_assert (result_type == base_type);
       result = invert_truthvalue (operand);
       break;
 
@@ -1060,28 +1025,13 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
          TREE_TYPE (result) = type = build_pointer_type (type);
          break;
 
-       case COMPOUND_EXPR:
-         /* Fold a compound expression if it has unconstrained array type
-            since the middle-end cannot handle it.  But we don't it in the
-            general case because it may introduce aliasing issues if the
-            first operand is an indirect assignment and the second operand
-            the corresponding address, e.g. for an allocator.  */
-         if (TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE)
-           {
-             result = build_unary_op (ADDR_EXPR, result_type,
-                                      TREE_OPERAND (operand, 1));
-             result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
-                              TREE_OPERAND (operand, 0), result);
-             break;
-           }
-         goto common;
-
        case ARRAY_REF:
        case ARRAY_RANGE_REF:
        case COMPONENT_REF:
        case BIT_FIELD_REF:
-           /* If this is for 'Address, find the address of the prefix and add
-              the offset to the field.  Otherwise, do this the normal way.  */
+           /* If this is for 'Address, find the address of the prefix and
+              add the offset to the field.  Otherwise, do this the normal
+              way.  */
          if (op_code == ATTR_ADDR_EXPR)
            {
              HOST_WIDE_INT bitsize;
@@ -1108,6 +1058,11 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
              if (!offset)
                offset = size_zero_node;
 
+             if (bitpos % BITS_PER_UNIT != 0)
+               post_error
+                 ("taking address of object not aligned on storage unit?",
+                  error_gnat_node);
+
              offset = size_binop (PLUS_EXPR, offset,
                                   size_int (bitpos / BITS_PER_UNIT));
 
@@ -1182,17 +1137,21 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
              operand = convert (type, operand);
            }
 
+         if (type != error_mark_node)
+           operation_type = build_pointer_type (type);
+
          gnat_mark_addressable (operand);
-         result = build_fold_addr_expr (operand);
+         result = fold_build1 (ADDR_EXPR, operation_type, operand);
        }
 
       TREE_CONSTANT (result) = staticp (operand) || TREE_CONSTANT (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 we want to refer to an entire unconstrained array,
+        make up an expression to do so.  This will never survive to
+        the backend.  If TYPE is a thin pointer, first convert the
+        operand to a fat pointer.  */
       if (TYPE_IS_THIN_POINTER_P (type)
          && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type)))
        {
@@ -1209,15 +1168,12 @@ build_unary_op (enum tree_code op_code, tree result_type, tree 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);
 
-      /* Otherwise, build and fold the indirect reference.  */
       else
        {
-         result = build_fold_indirect_ref (operand);
+         result = fold_build1 (op_code, TREE_TYPE (type), operand);
          TREE_READONLY (result) = TYPE_READONLY (TREE_TYPE (type));
        }
 
@@ -1270,7 +1226,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
 
                result = fold_build3 (COND_EXPR, operation_type,
                                      fold_build2 (NE_EXPR,
-                                                  boolean_type_node,
+                                                  integer_type_node,
                                                   operand,
                                                   convert
                                                     (operation_type,
@@ -1335,9 +1291,8 @@ build_cond_expr (tree result_type, tree condition_operand,
   true_operand = convert (result_type, true_operand);
   false_operand = convert (result_type, false_operand);
 
-  /* If the result type is unconstrained, take the address of the operands and
-     then dereference the result.  Likewise if the result type is passed by
-     reference, but this is natively handled in the gimplifier.  */
+  /* If the result type is unconstrained, take the address of the operands
+     and then dereference our result.  */
   if (TREE_CODE (result_type) == UNCONSTRAINED_ARRAY_TYPE
       || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (result_type)))
     {
@@ -1505,13 +1460,12 @@ build_call_raise (int msg, Node_Id gnat_node, char kind)
     = (gnat_node != Empty && Sloc (gnat_node) != No_Location)
       ? Get_Logical_Line_Number (Sloc(gnat_node)) : input_line;
 
-  TREE_TYPE (filename) = build_array_type (unsigned_char_type_node,
-                                          build_index_type (size_int (len)));
+  TREE_TYPE (filename)
+    = build_array_type (char_type_node, build_index_type (size_int (len)));
 
   return
     build_call_2_expr (fndecl,
-                      build1 (ADDR_EXPR,
-                              build_pointer_type (unsigned_char_type_node),
+                      build1 (ADDR_EXPR, build_pointer_type (char_type_node),
                               filename),
                       build_int_cst (NULL_TREE, line_number));
 }
@@ -1632,15 +1586,22 @@ 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;
           new_field = TREE_CHAIN (new_field))
-       if (SAME_FIELD_P (field, new_field))
+       if (field == new_field
+           || DECL_ORIGINAL_FIELD (new_field) == field
+           || new_field == DECL_ORIGINAL_FIELD (field)
+           || (DECL_ORIGINAL_FIELD (field)
+               && (DECL_ORIGINAL_FIELD (field)
+                   == DECL_ORIGINAL_FIELD (new_field))))
          break;
 
       /* 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.  */
+
       if (!new_field)
        for (new_field = TYPE_FIELDS (record_type); new_field;
             new_field = TREE_CHAIN (new_field))
@@ -1839,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 = gnat_protect_expr (malloc_ptr);
+      tree storage_ptr = protect_multiple_eval (malloc_ptr);
 
       tree aligning_record_addr
        = convert (build_pointer_type (aligning_type), storage_ptr);
@@ -1849,7 +1810,7 @@ maybe_wrap_malloc (tree data_size, tree data_type, Node_Id gnat_node)
 
       tree aligning_field
        = build_component_ref (aligning_record, NULL_TREE,
-                              TYPE_FIELDS (aligning_type), false);
+                              TYPE_FIELDS (aligning_type), 0);
 
       tree aligning_field_addr
         = build_unary_op (ADDR_EXPR, NULL_TREE, aligning_field);
@@ -1984,7 +1945,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
     {
       tree storage_type
        = build_unc_object_type_from_ptr (result_type, type,
-                                         get_identifier ("ALLOC"), false);
+                                         get_identifier ("ALLOC"));
       tree template_type = TREE_TYPE (TYPE_FIELDS (storage_type));
       tree storage_ptr_type = build_pointer_type (storage_type);
       tree storage;
@@ -2000,7 +1961,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
 
       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 = convert (storage_ptr_type, protect_multiple_eval (storage));
 
       if (TYPE_IS_PADDING_P (type))
        {
@@ -2040,7 +2001,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
            build_component_ref
            (build_unary_op (INDIRECT_REF, NULL_TREE,
                             convert (storage_ptr_type, storage)),
-            NULL_TREE, TYPE_FIELDS (storage_type), false),
+            NULL_TREE, TYPE_FIELDS (storage_type), 0),
            build_template (template_type, type, NULL_TREE)),
           convert (result_type, convert (storage_ptr_type, storage)));
     }
@@ -2078,7 +2039,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
      and return the address with a COMPOUND_EXPR.  */
   if (init)
     {
-      result = gnat_protect_expr (result);
+      result = protect_multiple_eval (result);
       result
        = build2 (COMPOUND_EXPR, TREE_TYPE (result),
                  build_binary_op
@@ -2100,11 +2061,12 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
 tree
 fill_vms_descriptor (tree expr, Entity_Id gnat_formal, Node_Id gnat_actual)
 {
+  tree field;
   tree parm_decl = get_gnu_tree (gnat_formal);
+  tree const_list = NULL_TREE;
   tree record_type = TREE_TYPE (TREE_TYPE (parm_decl));
-  tree const_list = NULL_TREE, field;
-  const bool do_range_check
-    = strcmp ("MBO",
+  int do_range_check =
+      strcmp ("MBO",
              IDENTIFIER_POINTER (DECL_NAME (TYPE_FIELDS (record_type))));
 
   expr = maybe_unconstrained_array (expr);
@@ -2116,24 +2078,23 @@ fill_vms_descriptor (tree expr, Entity_Id gnat_formal, Node_Id gnat_actual)
                              SUBSTITUTE_PLACEHOLDER_IN_EXPR
                              (DECL_INITIAL (field), expr));
 
-      /* Check to ensure that only 32-bit pointers are passed in
-        32-bit descriptors */
-      if (do_range_check
-          && strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), "POINTER") == 0)
+      /* Check to ensure that only 32bit pointers are passed in
+        32bit descriptors */
+      if (do_range_check &&
+          strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), "POINTER") == 0)
         {
-         tree pointer64type
-           = build_pointer_type_for_mode (void_type_node, DImode, false);
+         tree pointer64type =
+            build_pointer_type_for_mode (void_type_node, DImode, false);
          tree addr64expr = build_unary_op (ADDR_EXPR, pointer64type, expr);
-         tree malloc64low
-           = build_int_cstu (long_integer_type_node, 0x80000000);
+         tree malloc64low =
+            build_int_cstu (long_integer_type_node, 0x80000000);
 
          add_stmt (build3 (COND_EXPR, void_type_node,
-                           build_binary_op (GE_EXPR, boolean_type_node,
+                           build_binary_op (GE_EXPR, long_integer_type_node,
                                             convert (long_integer_type_node,
                                                      addr64expr),
                                             malloc64low),
-                           build_call_raise (CE_Range_Check_Failed,
-                                             gnat_actual,
+                           build_call_raise (CE_Range_Check_Failed, gnat_actual,
                                              N_Raise_Constraint_Error),
                            NULL_TREE));
         }
@@ -2164,10 +2125,6 @@ gnat_mark_addressable (tree t)
        t = TREE_OPERAND (t, 0);
        break;
 
-      case COMPOUND_EXPR:
-       t = TREE_OPERAND (t, 1);
-       break;
-
       case CONSTRUCTOR:
        TREE_ADDRESSABLE (t) = 1;
        return true;
@@ -2190,303 +2147,3 @@ gnat_mark_addressable (tree t)
        return true;
     }
 }
-\f
-/* Save EXP for later use or reuse.  This is equivalent to save_expr in tree.c
-   but we know how to handle our own nodes.  */
-
-tree
-gnat_save_expr (tree exp)
-{
-  tree type = TREE_TYPE (exp);
-  enum tree_code code = TREE_CODE (exp);
-
-  if (TREE_CONSTANT (exp) || code == SAVE_EXPR || code == NULL_EXPR)
-    return exp;
-
-  if (code == UNCONSTRAINED_ARRAY_REF)
-    {
-      tree t = build1 (code, type, gnat_save_expr (TREE_OPERAND (exp, 0)));
-      TREE_READONLY (t) = TYPE_READONLY (type);
-      return t;
-    }
-
-  /* If this is a COMPONENT_REF of a fat pointer, save the entire fat pointer.
-     This may be more efficient, but will also allow us to more easily find
-     the match for the PLACEHOLDER_EXPR.  */
-  if (code == COMPONENT_REF
-      && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
-    return build3 (code, type, gnat_save_expr (TREE_OPERAND (exp, 0)),
-                  TREE_OPERAND (exp, 1), TREE_OPERAND (exp, 2));
-
-  return save_expr (exp);
-}
-
-/* Protect EXP for immediate reuse.  This is a variant of gnat_save_expr that
-   is optimized under the assumption that EXP's value doesn't change before
-   its subsequent reuse(s) except through its potential reevaluation.  */
-
-tree
-gnat_protect_expr (tree exp)
-{
-  tree type = TREE_TYPE (exp);
-  enum tree_code code = TREE_CODE (exp);
-
-  if (TREE_CONSTANT (exp) || code == SAVE_EXPR || code == NULL_EXPR)
-    return exp;
-
-  /* If EXP has no side effects, we theoritically don't need to do anything.
-     However, we may be recursively passed more and more complex expressions
-     involving checks which will be reused multiple times and eventually be
-     unshared for gimplification; in order to avoid a complexity explosion
-     at that point, we protect any expressions more complex than a simple
-     arithmetic expression.  */
-  if (!TREE_SIDE_EFFECTS (exp))
-    {
-      tree inner = skip_simple_arithmetic (exp);
-      if (!EXPR_P (inner) || REFERENCE_CLASS_P (inner))
-       return exp;
-    }
-
-  /* If this is a conversion, protect what's inside the conversion.  */
-  if (code == NON_LVALUE_EXPR
-      || CONVERT_EXPR_CODE_P (code)
-      || code == VIEW_CONVERT_EXPR)
-  return build1 (code, type, gnat_protect_expr (TREE_OPERAND (exp, 0)));
-
-  /* If we're indirectly referencing something, we only need to protect the
-     address since the data itself can't change in these situations.  */
-  if (code == INDIRECT_REF || code == UNCONSTRAINED_ARRAY_REF)
-    {
-      tree t = build1 (code, type, gnat_protect_expr (TREE_OPERAND (exp, 0)));
-      TREE_READONLY (t) = TYPE_READONLY (type);
-      return t;
-    }
-
-  /* If this is a COMPONENT_REF of a fat pointer, save the entire fat pointer.
-     This may be more efficient, but will also allow us to more easily find
-     the match for the PLACEHOLDER_EXPR.  */
-  if (code == COMPONENT_REF
-      && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
-    return build3 (code, type, gnat_protect_expr (TREE_OPERAND (exp, 0)),
-                  TREE_OPERAND (exp, 1), TREE_OPERAND (exp, 2));
-
-  /* If this is a fat pointer or something that can be placed in a register,
-     just make a SAVE_EXPR.  Likewise for a CALL_EXPR as large objects are
-     returned via invisible reference in most ABIs so the temporary will
-     directly be filled by the callee.  */
-  if (TYPE_IS_FAT_POINTER_P (type)
-      || TYPE_MODE (type) != BLKmode
-      || code == CALL_EXPR)
-    return save_expr (exp);
-
-  /* Otherwise reference, protect the address and dereference.  */
-  return
-    build_unary_op (INDIRECT_REF, type,
-                   save_expr (build_unary_op (ADDR_EXPR,
-                                              build_reference_type (type),
-                                              exp)));
-}
-
-/* This is equivalent to stabilize_reference_1 in tree.c but we take an extra
-   argument to force evaluation of everything.  */
-
-static tree
-gnat_stabilize_reference_1 (tree e, bool force)
-{
-  enum tree_code code = TREE_CODE (e);
-  tree type = TREE_TYPE (e);
-  tree result;
-
-  /* We cannot ignore const expressions because it might be a reference
-     to a const array but whose index contains side-effects.  But we can
-     ignore things that are actual constant or that already have been
-     handled by this function.  */
-  if (TREE_CONSTANT (e) || code == SAVE_EXPR)
-    return e;
-
-  switch (TREE_CODE_CLASS (code))
-    {
-    case tcc_exceptional:
-    case tcc_declaration:
-    case tcc_comparison:
-    case tcc_expression:
-    case tcc_reference:
-    case tcc_vl_exp:
-      /* If this is a COMPONENT_REF of a fat pointer, save the entire
-        fat pointer.  This may be more efficient, but will also allow
-        us to more easily find the match for the PLACEHOLDER_EXPR.  */
-      if (code == COMPONENT_REF
-         && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0))))
-       result
-         = build3 (code, type,
-                   gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
-                   TREE_OPERAND (e, 1), TREE_OPERAND (e, 2));
-      /* If the expression has side-effects, then encase it in a SAVE_EXPR
-        so that it will only be evaluated once.  */
-      /* The tcc_reference and tcc_comparison classes could be handled as
-        below, but it is generally faster to only evaluate them once.  */
-      else if (TREE_SIDE_EFFECTS (e) || force)
-       return save_expr (e);
-      else
-       return e;
-      break;
-
-    case tcc_binary:
-      /* Recursively stabilize each operand.  */
-      result
-       = build2 (code, type,
-                 gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
-                 gnat_stabilize_reference_1 (TREE_OPERAND (e, 1), force));
-      break;
-
-    case tcc_unary:
-      /* Recursively stabilize each operand.  */
-      result
-       = build1 (code, type,
-                 gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force));
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  /* See similar handling in gnat_stabilize_reference.  */
-  TREE_READONLY (result) = TREE_READONLY (e);
-  TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e);
-  TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
-
-  return result;
-}
-
-/* This is equivalent to stabilize_reference in tree.c but we know how to
-   handle our own nodes and we take extra arguments.  FORCE says whether to
-   force evaluation of everything.  We set SUCCESS to true unless we walk
-   through something we don't know how to stabilize.  */
-
-tree
-gnat_stabilize_reference (tree ref, bool force, bool *success)
-{
-  tree type = TREE_TYPE (ref);
-  enum tree_code code = TREE_CODE (ref);
-  tree result;
-
-  /* Assume we'll success unless proven otherwise.  */
-  if (success)
-    *success = true;
-
-  switch (code)
-    {
-    case CONST_DECL:
-    case VAR_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-      /* No action is needed in this case.  */
-      return ref;
-
-    case ADDR_EXPR:
-    CASE_CONVERT:
-    case FLOAT_EXPR:
-    case FIX_TRUNC_EXPR:
-    case VIEW_CONVERT_EXPR:
-      result
-       = build1 (code, type,
-                 gnat_stabilize_reference (TREE_OPERAND (ref, 0), force,
-                                           success));
-      break;
-
-    case INDIRECT_REF:
-    case UNCONSTRAINED_ARRAY_REF:
-      result = build1 (code, type,
-                      gnat_stabilize_reference_1 (TREE_OPERAND (ref, 0),
-                                                  force));
-      break;
-
-    case COMPONENT_REF:
-     result = build3 (COMPONENT_REF, type,
-                     gnat_stabilize_reference (TREE_OPERAND (ref, 0), force,
-                                               success),
-                     TREE_OPERAND (ref, 1), NULL_TREE);
-      break;
-
-    case BIT_FIELD_REF:
-      result = build3 (BIT_FIELD_REF, type,
-                      gnat_stabilize_reference (TREE_OPERAND (ref, 0), force,
-                                                success),
-                      gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
-                                                  force),
-                      gnat_stabilize_reference_1 (TREE_OPERAND (ref, 2),
-                                                  force));
-      break;
-
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-      result = build4 (code, type,
-                      gnat_stabilize_reference (TREE_OPERAND (ref, 0), force,
-                                                success),
-                      gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
-                                                  force),
-                      NULL_TREE, NULL_TREE);
-      break;
-
-    case CALL_EXPR:
-      result = gnat_stabilize_reference_1 (ref, force);
-      break;
-
-    case COMPOUND_EXPR:
-      result = build2 (COMPOUND_EXPR, type,
-                      gnat_stabilize_reference (TREE_OPERAND (ref, 0), force,
-                                                success),
-                      gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
-                                                  force));
-      break;
-
-    case CONSTRUCTOR:
-      /* Constructors with 1 element are used extensively to formally
-        convert objects to special wrapping types.  */
-      if (TREE_CODE (type) == RECORD_TYPE
-         && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ref)) == 1)
-       {
-         tree index
-           = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (ref), 0)->index;
-         tree value
-           = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (ref), 0)->value;
-         result
-           = build_constructor_single (type, index,
-                                       gnat_stabilize_reference_1 (value,
-                                                                   force));
-       }
-      else
-       {
-         if (success)
-           *success = false;
-         return ref;
-       }
-      break;
-
-    case ERROR_MARK:
-      ref = error_mark_node;
-
-      /* ...  fall through to failure ... */
-
-      /* If arg isn't a kind of lvalue we recognize, make no change.
-        Caller should recognize the error for an invalid lvalue.  */
-    default:
-      if (success)
-       *success = false;
-      return ref;
-    }
-
-  /* TREE_THIS_VOLATILE and TREE_SIDE_EFFECTS set on the initial expression
-     may not be sustained across some paths, such as the way via build1 for
-     INDIRECT_REF.  We reset those flags here in the general case, which is
-     consistent with the GCC version of this routine.
-
-     Special care should be taken regarding TREE_SIDE_EFFECTS, because some
-     paths introduce side-effects where there was none initially (e.g. if a
-     SAVE_EXPR is built) and we also want to keep track of that.  */
-  TREE_READONLY (result) = TREE_READONLY (ref);
-  TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (ref);
-  TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
-
-  return result;
-}