OSDN Git Service

2006-10-31 Bob Duff <duff@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / trans.c
index 3a3327a..fe820bf 100644 (file)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *          Copyright (C) 1992-2005, Free Software Foundation, Inc.         *
+ *          Copyright (C) 1992-2006, Free Software Foundation, Inc.         *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
 #include "ada-tree.h"
 #include "gigi.h"
 
+/* Let code below know whether we are targetting VMS without need of
+   intrusive preprocessor directives.  */
+#ifndef TARGET_ABI_OPEN_VMS
+#define TARGET_ABI_OPEN_VMS 0
+#endif
+
 int max_gnat_nodes;
 int number_names;
 struct Node *Nodes_Ptr;
@@ -159,7 +165,7 @@ static tree emit_index_check (tree, tree, tree, tree);
 static tree emit_check (tree, tree, int);
 static tree convert_with_check (Entity_Id, tree, bool, bool, bool);
 static bool addressable_p (tree);
-static tree assoc_to_constructor (Node_Id, tree);
+static tree assoc_to_constructor (Entity_Id, Node_Id, tree);
 static tree extract_values (tree, tree);
 static tree pos_to_constructor (Node_Id, tree, Entity_Id);
 static tree maybe_implicit_deref (tree);
@@ -234,7 +240,7 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name,
 #endif
 
   /* If we are using the GCC exception mechanism, let GCC know.  */
-  if (Exception_Mechanism == GCC_ZCX)
+  if (Exception_Mechanism == Back_End_Exceptions)
     gnat_init_gcc_eh ();
 
   gcc_assert (Nkind (gnat_root) == N_Compilation_Unit);
@@ -285,8 +291,6 @@ gnat_init_stmt_group ()
   /* Enable GNAT stack checking method if needed */
   if (!Stack_Check_Probes_On_Target)
     set_stack_check_libfunc (gen_rtx_SYMBOL_REF (Pmode, "_gnat_stack_check"));
-
-  gcc_assert (Exception_Mechanism != Front_End_ZCX);
 }
 \f
 /* Subroutine of gnat_to_gnu to translate gnat_node, an N_Identifier,
@@ -410,13 +414,7 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
       else if (TREE_CODE (gnu_result) == VAR_DECL
               && (renamed_obj = DECL_RENAMED_OBJECT (gnu_result)) != 0
               && (! DECL_RENAMING_GLOBAL_P (gnu_result)
-                  || global_bindings_p ())
-              /* Make sure it's an lvalue like INDIRECT_REF.  */
-              && (DECL_P (renamed_obj)
-                  || REFERENCE_CLASS_P (renamed_obj)
-                  || (TREE_CODE (renamed_obj) == VIEW_CONVERT_EXPR
-                      && (DECL_P (TREE_OPERAND (renamed_obj, 0))
-                          || REFERENCE_CLASS_P (TREE_OPERAND (renamed_obj,0))))))
+                  || global_bindings_p ()))
        gnu_result = renamed_obj;
       else
        gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE,
@@ -454,7 +452,18 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
                            == Attr_Unchecked_Access)
                       || (Get_Attribute_Id (Attribute_Name (gnat_temp))
                           == Attr_Unrestricted_Access)))))
-       gnu_result = DECL_INITIAL (gnu_result);
+       {
+         gnu_result = DECL_INITIAL (gnu_result);
+         /* ??? The mark/unmark mechanism implemented in Gigi to prevent tree
+            sharing between global level and subprogram level doesn't apply
+            to elaboration routines.  As a result, the DECL_INITIAL tree may
+            be shared between the static initializer of a global object and
+            the elaboration routine, thus wreaking havoc if a local temporary
+            is created in place during gimplification of the latter and the
+            former is emitted afterwards.  Manually unshare for now.  */
+         if (TREE_VISITED (gnu_result))
+           gnu_result = unshare_expr (gnu_result);
+       }
     }
 
   *gnu_result_type_p = gnu_result_type;
@@ -721,6 +730,21 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute)
                  = size_binop (MAX_EXPR, gnu_result,
                                DECL_SIZE (TREE_OPERAND (gnu_expr, 1)));
            }
+         else if (Nkind (Prefix (gnat_node)) == N_Explicit_Dereference)
+           {
+             Node_Id gnat_deref = Prefix (gnat_node);
+             Node_Id gnat_actual_subtype = Actual_Designated_Subtype (gnat_deref);
+             tree gnu_ptr_type = TREE_TYPE (gnat_to_gnu (Prefix (gnat_deref)));
+             if (TYPE_FAT_OR_THIN_POINTER_P (gnu_ptr_type)
+               && Present (gnat_actual_subtype))
+               {
+                 tree gnu_actual_obj_type = gnat_to_gnu_type (gnat_actual_subtype);
+                 gnu_type = build_unc_object_type_from_ptr (gnu_ptr_type,
+                              gnu_actual_obj_type, get_identifier ("SIZE"));
+               }
+
+             gnu_result = TYPE_SIZE (gnu_type);
+           }
          else
            gnu_result = TYPE_SIZE (gnu_type);
        }
@@ -1333,6 +1357,57 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
   return gnu_result;
 }
 \f
+/* Emit statements to establish __gnat_handle_vms_condition as a VMS condition
+   handler for the current function.  */
+
+/* This is implemented by issuing a call to the appropriate VMS specific
+   builtin.  To avoid having VMS specific sections in the global gigi decls
+   array, we maintain the decls of interest here.  We can't declare them
+   inside the function because we must mark them never to be GC'd, which we
+   can only do at the global level.  */
+
+static GTY(()) tree vms_builtin_establish_handler_decl = NULL_TREE;
+static GTY(()) tree gnat_vms_condition_handler_decl = NULL_TREE;
+
+static void
+establish_gnat_vms_condition_handler (void)
+{
+  tree establish_stmt;
+
+  /* Elaborate the required decls on the first call.  Check on the decl for
+     the gnat condition handler to decide, as this is one we create so we are
+     sure that it will be non null on subsequent calls.  The builtin decl is
+     looked up so remains null on targets where it is not implemented yet.  */
+  if (gnat_vms_condition_handler_decl == NULL_TREE)
+    {
+      vms_builtin_establish_handler_decl
+       = builtin_decl_for
+         (get_identifier ("__builtin_establish_vms_condition_handler"));
+
+      gnat_vms_condition_handler_decl
+       = create_subprog_decl (get_identifier ("__gnat_handle_vms_condition"),
+                              NULL_TREE,
+                              build_function_type_list (integer_type_node,
+                                                        ptr_void_type_node,
+                                                        ptr_void_type_node,
+                                                        NULL_TREE),
+                              NULL_TREE, 0, 1, 1, 0, Empty);
+    }
+
+  /* Do nothing if the establish builtin is not available, which might happen
+     on targets where the facility is not implemented.  */
+  if (vms_builtin_establish_handler_decl == NULL_TREE)
+    return;
+
+  establish_stmt
+    = build_call_1_expr (vms_builtin_establish_handler_decl,
+                        build_unary_op
+                        (ADDR_EXPR, NULL_TREE,
+                         gnat_vms_condition_handler_decl));
+
+  add_stmt (establish_stmt);
+}
+\f
 /* Subroutine of gnat_to_gnu to process gnat_node, an N_Subprogram_Body.  We
    don't return anything.  */
 
@@ -1426,6 +1501,22 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
                     gnat_to_gnu_entity (gnat_param, NULL_TREE, 1));
       }
 
+
+  /* On VMS, establish our condition handler to possibly turn a condition into
+     the corresponding exception if the subprogram has a foreign convention or
+     is exported.
+
+     To ensure proper execution of local finalizations on condition instances,
+     we must turn a condition into the corresponding exception even if there
+     is no applicable Ada handler, and need at least one condition handler per
+     possible call chain involving GNAT code.  OTOH, establishing the handler
+     has a cost so we want to minimize the number of subprograms into which this
+     happens.  The foreign or exported condition is expected to satisfy all
+     the constraints.  */
+  if (TARGET_ABI_OPEN_VMS
+      && (Has_Foreign_Convention (gnat_node) || Is_Exported (gnat_node)))
+    establish_gnat_vms_condition_handler ();
+
   process_decls (Declarations (gnat_node), Empty, Empty, true, true);
 
   /* Generate the code of the subprogram itself.  A return statement will be
@@ -1458,9 +1549,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
        gnu_retval = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_retval);
 
       add_stmt_with_node
-       (build1 (RETURN_EXPR, void_type_node,
-                build2 (MODIFY_EXPR, TREE_TYPE (gnu_retval),
-                        DECL_RESULT (current_function_decl), gnu_retval)),
+       (build_return_expr (DECL_RESULT (current_function_decl), gnu_retval),
         gnat_node);
       gnat_poplevel ();
       gnu_result = end_stmt_group ();
@@ -1541,14 +1630,18 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
           gnat_actual = Next_Actual (gnat_actual))
        add_stmt (gnat_to_gnu (gnat_actual));
 
-      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,
-                        build_call_raise (PE_Stubbed_Subprogram_Called));
-       }
-      else
-       return build_call_raise (PE_Stubbed_Subprogram_Called);
+      {
+       tree call_expr
+         = build_call_raise (PE_Stubbed_Subprogram_Called, gnat_node);
+
+       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;
+      }
     }
 
   /* If we are calling by supplying a pointer to a target, set up that
@@ -1568,8 +1661,15 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
                              0, Etype (Name (gnat_node)), "PAD", false,
                              false, false);
 
-         gnu_target = create_tmp_var_raw (gnu_obj_type, "LR");
-         gnat_pushdecl (gnu_target, gnat_node);
+         /* ??? We may be about to create a static temporary if we happen to
+            be at the global binding level.  That's a regression from what
+            the 3.x back-end would generate in the same situation, but we
+            don't have a mechanism in Gigi for creating automatic variables
+            in the elaboration routines.  */
+         gnu_target
+           = create_var_decl (create_tmp_var_name ("LR"), NULL, gnu_obj_type,
+                              NULL, false, false, false, false, NULL,
+                              gnat_node);
        }
 
       gnu_actual_list
@@ -1606,6 +1706,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
       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 treat a conversion between aggregate types as if it is an
         unchecked conversion.  */
       bool unchecked_convert_p
@@ -1617,7 +1718,6 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
       tree gnu_name = gnat_to_gnu (gnat_name);
       tree gnu_name_type = gnat_to_gnu_type (Etype (gnat_name));
       tree gnu_actual;
-      tree gnu_formal_type;
 
       /* If it's possible we may need to use this expression twice, make sure
         than any side-effects are handled via SAVE_EXPRs. Likewise if we need
@@ -1630,6 +1730,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
       if (Ekind (gnat_formal) != E_In_Parameter)
        {
          gnu_name = gnat_stabilize_reference (gnu_name, true);
+
          if (!addressable_p (gnu_name)
              && gnu_formal
              && (DECL_BY_REF_P (gnu_formal)
@@ -1674,23 +1775,20 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
                       && (TYPE_JUSTIFIED_MODULAR_P (gnu_name_type)))
                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 actual and copied back after the call.  */
              gnu_actual = save_expr (gnu_name);
 
-             /* Since we're going to take the address of the SAVE_EXPR, we
-                don't want it to be marked as unchanging. So set
-                TREE_ADDRESSABLE.  */
-             gnu_temp = skip_simple_arithmetic (gnu_actual);
-             if (TREE_CODE (gnu_temp) == SAVE_EXPR)
-               {
-                 TREE_ADDRESSABLE (gnu_temp) = 1;
-                 TREE_READONLY (gnu_temp) = 0;
-               }
-
              /* Set up to move the copy back to the original.  */
-             gnu_temp = build2 (MODIFY_EXPR, TREE_TYPE (gnu_copy),
-                                gnu_copy, gnu_actual);
+             gnu_temp = build_binary_op (MODIFY_EXPR, NULL_TREE,
+                                         gnu_copy, gnu_actual);
              annotate_with_node (gnu_temp, gnat_actual);
              append_to_statement_list (gnu_temp, &gnu_after_list);
+
+             /* Account for next statement just below.  */
+             gnu_name = gnu_actual;
            }
        }
 
@@ -1742,6 +1840,9 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
        gnu_actual = convert (gnat_to_gnu_type (Etype (gnat_actual)),
                              gnu_actual);
 
+      if (TREE_CODE (gnu_actual) != SAVE_EXPR)
+       gnu_actual = convert (gnu_formal_type, gnu_actual);
+
       /* 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
@@ -1990,7 +2091,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
                      && TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (gnu_result)))))
                  gnu_result = convert (TREE_TYPE (gnu_actual), gnu_result);
              }
-               
+
            gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
                                          gnu_actual, gnu_result);
            annotate_with_node (gnu_result, gnat_actual);
@@ -2020,7 +2121,7 @@ Handled_Sequence_Of_Statements_to_gnu (Node_Id gnat_node)
   /* If just annotating, ignore all EH and cleanups.  */
   bool gcc_zcx = (!type_annotate_only
                  && Present (Exception_Handlers (gnat_node))
-                 && Exception_Mechanism == GCC_ZCX);
+                 && Exception_Mechanism == Back_End_Exceptions);
   bool setjmp_longjmp
     = (!type_annotate_only && Present (Exception_Handlers (gnat_node))
        && Exception_Mechanism == Setjmp_Longjmp);
@@ -2066,6 +2167,11 @@ Handled_Sequence_Of_Statements_to_gnu (Node_Id gnat_node)
                                          build_call_0_expr (get_jmpbuf_decl),
                                          false, false, false, false, NULL,
                                          gnat_node);
+      /* The __builtin_setjmp receivers will immediately reinstall it.  Now
+        because of the unstructured form of EH used by setjmp_longjmp, there
+        might be forward edges going to __builtin_setjmp receivers on which
+        it is uninitialized, although they will never be actually taken.  */
+      TREE_NO_WARNING (gnu_jmpsave_decl) = 1;
       gnu_jmpbuf_decl = create_var_decl (get_identifier ("JMP_BUF"),
                                         NULL_TREE, jmpbuf_type,
                                         NULL_TREE, false, false, false, false,
@@ -2496,27 +2602,42 @@ gnat_to_gnu (Node_Id gnat_node)
       && Nkind (gnat_node) != N_Identifier
       && !Compile_Time_Known_Value (gnat_node))
     return build1 (NULL_EXPR, get_unpadded_type (Etype (gnat_node)),
-                  build_call_raise (CE_Range_Check_Failed));
-
-  /* If this is a Statement and we are at top level, it must be part of
-     the elaboration procedure, so mark us as being in that procedure
-     and push our context.  */
-  if (!current_function_decl
-      && ((IN (Nkind (gnat_node), N_Statement_Other_Than_Procedure_Call)
-          && Nkind (gnat_node) != N_Null_Statement)
-         || Nkind (gnat_node) == N_Procedure_Call_Statement
-         || Nkind (gnat_node) == N_Label
-         || Nkind (gnat_node) == N_Implicit_Label_Declaration
-         || Nkind (gnat_node) == N_Handled_Sequence_Of_Statements
-         || ((Nkind (gnat_node) == N_Raise_Constraint_Error
-              || Nkind (gnat_node) == N_Raise_Storage_Error
-              || Nkind (gnat_node) == N_Raise_Program_Error)
-             && (Ekind (Etype (gnat_node)) == E_Void))))
+                  build_call_raise (CE_Range_Check_Failed, gnat_node));
+
+  /* If this is a Statement and we are at top level, it must be part of the
+     elaboration procedure, so mark us as being in that procedure and push our
+     context.
+
+     If we are in the elaboration procedure, check if we are violating a a
+     No_Elaboration_Code restriction by having a statement there.  */
+  if ((IN (Nkind (gnat_node), N_Statement_Other_Than_Procedure_Call)
+       && Nkind (gnat_node) != N_Null_Statement)
+      || Nkind (gnat_node) == N_Procedure_Call_Statement
+      || Nkind (gnat_node) == N_Label
+      || Nkind (gnat_node) == N_Implicit_Label_Declaration
+      || Nkind (gnat_node) == N_Handled_Sequence_Of_Statements
+      || ((Nkind (gnat_node) == N_Raise_Constraint_Error
+          || Nkind (gnat_node) == N_Raise_Storage_Error
+          || Nkind (gnat_node) == N_Raise_Program_Error)
+         && (Ekind (Etype (gnat_node)) == E_Void)))
     {
-      current_function_decl = TREE_VALUE (gnu_elab_proc_stack);
-      start_stmt_group ();
-      gnat_pushlevel ();
-      went_into_elab_proc = true;
+      if (!current_function_decl)
+       {
+         current_function_decl = TREE_VALUE (gnu_elab_proc_stack);
+         start_stmt_group ();
+         gnat_pushlevel ();
+         went_into_elab_proc = true;
+       }
+
+      /* Don't check for a possible No_Elaboration_Code restriction violation
+        on N_Handled_Sequence_Of_Statements, as we want to signal an error on
+        every nested real statement instead.  This also avoids triggering
+        spurious errors on dummy (empty) sequences created by the front-end
+        for package bodies in some cases.  */
+
+      if (current_function_decl == TREE_VALUE (gnu_elab_proc_stack)
+         && Nkind (gnat_node) != N_Handled_Sequence_Of_Statements)
+       Check_Elaboration_Code_Allowed (gnat_node);
     }
 
   switch (Nkind (gnat_node))
@@ -2983,7 +3104,7 @@ gnat_to_gnu (Node_Id gnat_node)
                                   ? Designated_Type (Etype
                                                      (Prefix (gnat_node)))
                                   : Etype (Prefix (gnat_node))))
-             gnu_prefix = gnat_stabilize_reference (gnu_prefix, 0);
+             gnu_prefix = gnat_stabilize_reference (gnu_prefix, false);
 
            gnu_result
              = build_component_ref (gnu_prefix, NULL_TREE, gnu_field,
@@ -3044,25 +3165,11 @@ gnat_to_gnu (Node_Id gnat_node)
        if (Null_Record_Present (gnat_node))
          gnu_result = gnat_build_constructor (gnu_aggr_type, NULL_TREE);
 
-       else if (TREE_CODE (gnu_aggr_type) == UNION_TYPE
-                && TYPE_UNCHECKED_UNION_P (gnu_aggr_type))
-         {
-           /* The first element is the discrimant, which we ignore.  The
-              next is the field we're building.  Convert the expression
-              to the type of the field and then to the union type.  */
-           Node_Id gnat_assoc
-             = Next (First (Component_Associations (gnat_node)));
-           Entity_Id gnat_field = Entity (First (Choices (gnat_assoc)));
-           tree gnu_field_type
-             = TREE_TYPE (gnat_to_gnu_entity (gnat_field, NULL_TREE, 0));
-
-           gnu_result = convert (gnu_field_type,
-                                 gnat_to_gnu (Expression (gnat_assoc)));
-         }
        else if (TREE_CODE (gnu_aggr_type) == RECORD_TYPE
                 || TREE_CODE (gnu_aggr_type) == UNION_TYPE)
          gnu_result
-           = assoc_to_constructor (First (Component_Associations (gnat_node)),
+           = assoc_to_constructor (Etype (gnat_node),
+                                   First (Component_Associations (gnat_node)),
                                    gnu_aggr_type);
        else if (TREE_CODE (gnu_aggr_type) == ARRAY_TYPE)
          gnu_result = pos_to_constructor (First (Expressions (gnat_node)),
@@ -3119,7 +3226,7 @@ gnat_to_gnu (Node_Id gnat_node)
 
          if (align != 0 && align < oalign && !TYPE_ALIGN_OK (gnu_obj_type))
            post_error_ne_tree_2
-             ("?source alignment (^) < alignment of & (^)",
+             ("?source alignment (^) '< alignment of & (^)",
               gnat_node, Designated_Type (Etype (gnat_node)),
               size_int (align / BITS_PER_UNIT), oalign / BITS_PER_UNIT);
        }
@@ -3427,9 +3534,9 @@ gnat_to_gnu (Node_Id gnat_node)
 
       /* If the type has a size that overflows, convert this into raise of
         Storage_Error: execution shouldn't have gotten here anyway.  */
-      if (TREE_CODE (TYPE_SIZE (TREE_TYPE (gnu_lhs))) == INTEGER_CST
-          && TREE_OVERFLOW (TYPE_SIZE (TREE_TYPE (gnu_lhs))))
-       gnu_result = build_call_raise (SE_Object_Too_Large);
+      if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (gnu_lhs))) == INTEGER_CST
+          && TREE_OVERFLOW (TYPE_SIZE_UNIT (TREE_TYPE (gnu_lhs))))
+       gnu_result = build_call_raise (SE_Object_Too_Large, gnat_node);
       else if (Nkind (Expression (gnat_node)) == N_Function_Call
               && !Do_Range_Check (Expression (gnat_node)))
        gnu_result = call_to_gnu (Expression (gnat_node),
@@ -3521,8 +3628,6 @@ gnat_to_gnu (Node_Id gnat_node)
        tree gnu_ret_val = NULL_TREE;
        /* The place to put the return value.  */
        tree gnu_lhs;
-       /* Avoid passing error_mark_node to RETURN_EXPR.  */
-       gnu_result = NULL_TREE;
 
        /* If we are dealing with a "return;" from an Ada procedure with
           parameters passed by copy in copy out, we need to return a record
@@ -3628,18 +3733,20 @@ gnat_to_gnu (Node_Id gnat_node)
                  }
              }
          }
-
-       if (gnu_ret_val)
-         gnu_result = build2 (MODIFY_EXPR, TREE_TYPE (gnu_ret_val),
-                              gnu_lhs, gnu_ret_val);
+       else
+         /* If the Ada subprogram is a regular procedure, just return.  */
+         gnu_lhs = NULL_TREE;
 
        if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type))
          {
+           if (gnu_ret_val)
+             gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
+                                           gnu_lhs, gnu_ret_val);
            add_stmt_with_node (gnu_result, gnat_node);
-           gnu_result = NULL_TREE;
+           gnu_lhs = NULL_TREE;
          }
 
-       gnu_result = build1 (RETURN_EXPR, void_type_node, gnu_result);
+       gnu_result = build_return_expr (gnu_lhs, gnu_ret_val);
       }
       break;
 
@@ -3800,7 +3907,7 @@ gnat_to_gnu (Node_Id gnat_node)
     case N_Exception_Handler:
       if (Exception_Mechanism == Setjmp_Longjmp)
        gnu_result = Exception_Handler_to_gnu_sjlj (gnat_node);
-      else if (Exception_Mechanism == GCC_ZCX)
+      else if (Exception_Mechanism == Back_End_Exceptions)
        gnu_result = Exception_Handler_to_gnu_zcx (gnat_node);
       else
        gcc_unreachable ();
@@ -3928,7 +4035,9 @@ gnat_to_gnu (Node_Id gnat_node)
       if (!type_annotate_only)
        {
          tree gnu_ptr = gnat_to_gnu (Expression (gnat_node));
+         tree gnu_ptr_type = TREE_TYPE (gnu_ptr);
          tree gnu_obj_type;
+         tree gnu_actual_obj_type = 0;
          tree gnu_obj_size;
          int align;
 
@@ -3953,7 +4062,22 @@ gnat_to_gnu (Node_Id gnat_node)
                         gnu_ptr);
 
          gnu_obj_type = TREE_TYPE (TREE_TYPE (gnu_ptr));
-         gnu_obj_size = TYPE_SIZE_UNIT (gnu_obj_type);
+
+         if (Present (Actual_Designated_Subtype (gnat_node)))
+           {
+             gnu_actual_obj_type
+               = gnat_to_gnu_type (Actual_Designated_Subtype (gnat_node));
+
+             if (TYPE_FAT_OR_THIN_POINTER_P (gnu_ptr_type))
+               gnu_actual_obj_type
+                 = build_unc_object_type_from_ptr (gnu_ptr_type,
+                     gnu_actual_obj_type,
+                     get_identifier ("DEALLOC"));
+           }
+         else
+           gnu_actual_obj_type = gnu_obj_type;
+
+         gnu_obj_size = TYPE_SIZE_UNIT (gnu_actual_obj_type);
          align = TYPE_ALIGN (gnu_obj_type);
 
          if (TREE_CODE (gnu_obj_type) == RECORD_TYPE
@@ -3987,7 +4111,8 @@ gnat_to_gnu (Node_Id gnat_node)
        }
 
       gnu_result_type = get_unpadded_type (Etype (gnat_node));
-      gnu_result = build_call_raise (UI_To_Int (Reason (gnat_node)));
+      gnu_result
+       = build_call_raise (UI_To_Int (Reason (gnat_node)), gnat_node);
 
       /* If the type is VOID, this is a statement, so we need to
         generate the code for the call.  Handle a Condition, if there
@@ -4098,7 +4223,7 @@ gnat_to_gnu (Node_Id gnat_node)
 
       gnu_result
        = build1 (NULL_EXPR, gnu_result_type,
-                 build_call_raise (CE_Overflow_Check_Failed));
+                 build_call_raise (CE_Overflow_Check_Failed, gnat_node));
     }
 
   /* If our result has side-effects and is of an unconstrained type,
@@ -4107,7 +4232,7 @@ gnat_to_gnu (Node_Id gnat_node)
   if (TREE_SIDE_EFFECTS (gnu_result)
       && (TREE_CODE (gnu_result_type) == UNCONSTRAINED_ARRAY_TYPE
          || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_result_type))))
-    gnu_result = gnat_stabilize_reference (gnu_result, 0);
+    gnu_result = gnat_stabilize_reference (gnu_result, false);
 
   /* Now convert the result to the proper type.  If the type is void or if
      we have no result, return error_mark_node to show we have no result.
@@ -4520,6 +4645,7 @@ int
 gnat_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
 {
   tree expr = *expr_p;
+  tree op;
 
   if (IS_ADA_STMT (expr))
     return gnat_gimplify_stmt (expr_p);
@@ -4550,25 +4676,63 @@ gnat_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
       return GS_OK;
 
     case ADDR_EXPR:
+      op = TREE_OPERAND (expr, 0);
+
       /* If we're taking the address of a constant CONSTRUCTOR, force it to
         be put into static memory.  We know it's going to be readonly given
         the semantics we have and it's required to be static memory in
-        the case when the reference is in an elaboration procedure.  */
-      if (TREE_CODE (TREE_OPERAND (expr, 0)) == CONSTRUCTOR
-         && TREE_CONSTANT (TREE_OPERAND (expr, 0)))
+        the case when the reference is in an elaboration procedure.   */
+      if (TREE_CODE (op) == CONSTRUCTOR && TREE_CONSTANT (op))
        {
-         tree new_var
-           = create_tmp_var (TREE_TYPE (TREE_OPERAND (expr, 0)), "C");
+         tree new_var = create_tmp_var (TREE_TYPE (op), "C");
 
          TREE_READONLY (new_var) = 1;
          TREE_STATIC (new_var) = 1;
          TREE_ADDRESSABLE (new_var) = 1;
-         DECL_INITIAL (new_var) = TREE_OPERAND (expr, 0);
+         DECL_INITIAL (new_var) = op;
+
+         TREE_OPERAND (expr, 0) = new_var;
+         recompute_tree_invariant_for_addr_expr (expr);
+         return GS_ALL_DONE;
+       }
+
+      /* If we are taking the address of a SAVE_EXPR, we are typically
+        processing a misaligned argument to be passed by reference in a
+        procedure call.  We just mark the operand as addressable + not
+        readonly here and let the common gimplifier code perform the
+        temporary creation, initialization, and "instantiation" in place of
+        the SAVE_EXPR in further operands, in particular in the copy back
+        code inserted after the call.  */
+      else if (TREE_CODE (op) == SAVE_EXPR)
+       {
+         TREE_ADDRESSABLE (op) = 1;
+         TREE_READONLY (op) = 0;
+       }
+
+      /* Otherwise, if we are taking the address of something that is neither
+        reference, declaration, or constant, make a variable for the operand
+        here and then take its address.  If we don't do it this way, we may
+        confuse the gimplifier because it needs to know the variable is
+        addressable at this point.  This duplicates code in
+        internal_get_tmp_var, which is unfortunate.  */
+      else if (TREE_CODE_CLASS (TREE_CODE (op)) != tcc_reference
+              && TREE_CODE_CLASS (TREE_CODE (op)) != tcc_declaration
+              && TREE_CODE_CLASS (TREE_CODE (op)) != tcc_constant)
+       {
+         tree new_var = create_tmp_var (TREE_TYPE (op), "A");
+         tree mod = build2 (MODIFY_EXPR, TREE_TYPE (op), new_var, op);
+
+         TREE_ADDRESSABLE (new_var) = 1;
+
+         if (EXPR_HAS_LOCATION (op))
+           SET_EXPR_LOCUS (mod, EXPR_LOCUS (op));
 
+         gimplify_and_add (mod, pre_p);
          TREE_OPERAND (expr, 0) = new_var;
-         recompute_tree_invarant_for_addr_expr (expr);
+         recompute_tree_invariant_for_addr_expr (expr);
          return GS_ALL_DONE;
        }
+
       return GS_UNHANDLED;
 
     case COMPONENT_REF:
@@ -4677,7 +4841,7 @@ gnat_gimplify_stmt (tree *stmt_p)
 /* The reason for this routine's existence is two-fold.
    First, with some debugging formats, notably MDEBUG on SGI
    IRIX, the linker will remove duplicate debugging information if two
-   clients have identical debugguing information.  With the normal scheme
+   clients have identical debugging information.  With the normal scheme
    of elaboration, this does not usually occur, since entities in with'ed
    packages are elaborated on demand, and if clients have different usage
    patterns, the normal case, then the order and selection of entities
@@ -5131,7 +5295,7 @@ emit_check (tree gnu_cond, tree gnu_expr, int reason)
   tree gnu_call;
   tree gnu_result;
 
-  gnu_call = build_call_raise (reason);
+  gnu_call = build_call_raise (reason, Empty);
 
   /* Use an outer COMPOUND_EXPR to make sure that GNU_EXPR will get evaluated
      in front of the comparison in case it ends up being a SAVE_EXPR.  Put the
@@ -5171,7 +5335,6 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
   tree gnu_in_type = TREE_TYPE (gnu_expr);
   tree gnu_in_basetype = get_base_type (gnu_in_type);
   tree gnu_base_type = get_base_type (gnu_type);
-  tree gnu_ada_base_type = get_ada_base_type (gnu_type);
   tree gnu_result = gnu_expr;
 
   /* If we are not doing any checks, the output is an integral type, and
@@ -5263,7 +5426,7 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
 
   /* Now convert to the result base type.  If this is a non-truncating
      float-to-integer conversion, round.  */
-  if (INTEGRAL_TYPE_P (gnu_ada_base_type) && FLOAT_TYPE_P (gnu_in_basetype)
+  if (INTEGRAL_TYPE_P (gnu_base_type) && FLOAT_TYPE_P (gnu_in_basetype)
       && !truncatep)
     {
       REAL_VALUE_TYPE half_minus_pred_half, pred_half;
@@ -5322,12 +5485,12 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
                           gnu_add_pred_half, gnu_subtract_pred_half);
     }
 
-  if (TREE_CODE (gnu_ada_base_type) == INTEGER_TYPE
-      && TYPE_HAS_ACTUAL_BOUNDS_P (gnu_ada_base_type)
+  if (TREE_CODE (gnu_base_type) == INTEGER_TYPE
+      && TYPE_HAS_ACTUAL_BOUNDS_P (gnu_base_type)
       && TREE_CODE (gnu_result) == UNCONSTRAINED_ARRAY_REF)
-    gnu_result = unchecked_convert (gnu_ada_base_type, gnu_result, false);
+    gnu_result = unchecked_convert (gnu_base_type, gnu_result, false);
   else
-    gnu_result = convert (gnu_ada_base_type, gnu_result);
+    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
@@ -5342,9 +5505,8 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
 }
 \f
 /* Return 1 if GNU_EXPR can be directly addressed.  This is the case unless
-   it is an expression involving computation or if it involves a bitfield
-   reference.  This returns the same as gnat_mark_addressable in most
-   cases.  */
+   it is an expression involving computation or if it involves a reference
+   to a bitfield or to a field not sufficiently aligned for its type.  */
 
 static bool
 addressable_p (tree gnu_expr)
@@ -5368,8 +5530,15 @@ addressable_p (tree gnu_expr)
 
     case COMPONENT_REF:
       return (!DECL_BIT_FIELD (TREE_OPERAND (gnu_expr, 1))
-             && !(STRICT_ALIGNMENT
-                  && DECL_NONADDRESSABLE_P (TREE_OPERAND (gnu_expr, 1)))
+             && (!STRICT_ALIGNMENT
+                 /* If the field was marked as "semantically" addressable
+                    in create_field_decl, we are guaranteed that it can
+                    be directly addressed.  */
+                 || !DECL_NONADDRESSABLE_P (TREE_OPERAND (gnu_expr, 1))
+                 /* Otherwise it can nevertheless be directly addressed
+                    if it has been sufficiently aligned in the record.  */
+                 || DECL_ALIGN (TREE_OPERAND (gnu_expr, 1))
+                      >= TYPE_ALIGN (TREE_TYPE (gnu_expr)))
              && addressable_p (TREE_OPERAND (gnu_expr, 0)));
 
     case ARRAY_REF:  case ARRAY_RANGE_REF:
@@ -5495,13 +5664,14 @@ process_type (Entity_Id gnat_entity)
     }
 }
 \f
-/* GNAT_ASSOC is the front of the Component_Associations of an N_Aggregate.
-   GNU_TYPE is the GCC type of the corresponding record.
+/* GNAT_ENTITY is the type of the resulting constructors,
+   GNAT_ASSOC is the front of the Component_Associations of an N_Aggregate,
+   and GNU_TYPE is the GCC type of the corresponding record.
 
    Return a CONSTRUCTOR to build the record.  */
 
 static tree
-assoc_to_constructor (Node_Id gnat_assoc, tree gnu_type)
+assoc_to_constructor (Entity_Id gnat_entity, Node_Id gnat_assoc, tree gnu_type)
 {
   tree gnu_list, gnu_result;
 
@@ -5527,6 +5697,11 @@ assoc_to_constructor (Node_Id gnat_assoc, tree gnu_type)
          && Is_Tagged_Type (Scope (Entity (gnat_field))))
        continue;
 
+      /* Also ignore discriminants of Unchecked_Unions.  */
+      else if (Is_Unchecked_Union (gnat_entity)
+              && Ekind (Entity (gnat_field)) == E_Discriminant)
+       continue;
+
       /* Before assigning a value in an aggregate make sure range checks
         are done if required.  Then convert to the type of the field.  */
       if (Do_Range_Check (Expression (gnat_assoc)))
@@ -5625,7 +5800,8 @@ extract_values (tree values, tree record_type)
       else if (DECL_INTERNAL_P (field))
        {
          value = extract_values (values, TREE_TYPE (field));
-         if (TREE_CODE (value) == CONSTRUCTOR && !CONSTRUCTOR_ELTS (value))
+         if (TREE_CODE (value) == CONSTRUCTOR
+             && VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (value)))
            value = 0;
        }
       else
@@ -5703,17 +5879,26 @@ protect_multiple_eval (tree exp)
                                                 exp)));
 }
 \f
-/* This is equivalent to stabilize_reference in GCC's tree.c, but we know
-   how to handle our new nodes and we take an extra argument that says
-   whether to force evaluation of everything.  */
+/* This is equivalent to stabilize_reference in GCC's tree.c, but we know how
+   to handle our new nodes and we take extra arguments:
+
+   FORCE says whether to force evaluation of everything,
+
+   SUCCESS we set to true unless we walk through something we don't know how
+   to stabilize, or through something which is not an lvalue and LVALUES_ONLY
+   is true, in which cases we set to false.  */
 
 tree
-gnat_stabilize_reference (tree ref, bool force)
+maybe_stabilize_reference (tree ref, bool force, bool lvalues_only,
+                          bool *success)
 {
   tree type = TREE_TYPE (ref);
   enum tree_code code = TREE_CODE (ref);
   tree result;
 
+  /* Assume we'll success unless proven otherwise.  */
+  *success = true;
+
   switch (code)
     {
     case VAR_DECL:
@@ -5722,6 +5907,15 @@ gnat_stabilize_reference (tree ref, bool force)
       /* No action is needed in this case.  */
       return ref;
 
+    case ADDR_EXPR:
+      /*  A standalone ADDR_EXPR is never an lvalue, and this one can't
+         be nested inside an outer INDIRECT_REF, since INDIREC_REF goes
+         straight to stabilize_1.  */
+      if (lvalues_only)
+       goto failure;
+
+      /* ... Fallthru ... */
+
     case NOP_EXPR:
     case CONVERT_EXPR:
     case FLOAT_EXPR:
@@ -5730,10 +5924,10 @@ gnat_stabilize_reference (tree ref, bool force)
     case FIX_ROUND_EXPR:
     case FIX_CEIL_EXPR:
     case VIEW_CONVERT_EXPR:
-    case ADDR_EXPR:
       result
        = build1 (code, type,
-                 gnat_stabilize_reference (TREE_OPERAND (ref, 0), force));
+                 maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
+                                            lvalues_only, success));
       break;
 
     case INDIRECT_REF:
@@ -5744,15 +5938,16 @@ gnat_stabilize_reference (tree ref, bool force)
       break;
 
     case COMPONENT_REF:
-      result = build3 (COMPONENT_REF, type,
-                      gnat_stabilize_reference (TREE_OPERAND (ref, 0),
-                                                force),
-                      TREE_OPERAND (ref, 1), NULL_TREE);
+     result = build3 (COMPONENT_REF, type,
+                     maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
+                                                lvalues_only, 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),
+                      maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
+                                                 lvalues_only, success),
                       gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
                                                   force),
                       gnat_stabilize_reference_1 (TREE_OPERAND (ref, 2),
@@ -5762,7 +5957,8 @@ gnat_stabilize_reference (tree ref, bool force)
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
       result = build4 (code, type,
-                      gnat_stabilize_reference (TREE_OPERAND (ref, 0), force),
+                      maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
+                                                 lvalues_only, success),
                       gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
                                                   force),
                       NULL_TREE, NULL_TREE);
@@ -5772,17 +5968,21 @@ gnat_stabilize_reference (tree ref, bool force)
       result = build2 (COMPOUND_EXPR, type,
                       gnat_stabilize_reference_1 (TREE_OPERAND (ref, 0),
                                                   force),
-                      gnat_stabilize_reference (TREE_OPERAND (ref, 1),
-                                                force));
+                      maybe_stabilize_reference (TREE_OPERAND (ref, 1), force,
+                                                 lvalues_only, success));
       break;
 
+    case ERROR_MARK:
+      ref = error_mark_node;
+
+      /* ...  Fallthru 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:
+    failure:
+      *success = false;
       return ref;
-
-    case ERROR_MARK:
-      return error_mark_node;
     }
 
   TREE_READONLY (result) = TREE_READONLY (ref);
@@ -5802,6 +6002,17 @@ gnat_stabilize_reference (tree ref, bool force)
   return result;
 }
 
+/* Wrapper around maybe_stabilize_reference, for common uses without
+   lvalue restrictions and without need to examine the success
+   indication.  */
+
+tree
+gnat_stabilize_reference (tree ref, bool force)
+{
+  bool stabilized;
+  return maybe_stabilize_reference (ref, force, false, &stabilized);
+}
+
 /* Similar to stabilize_reference_1 in tree.c, but supports an extra
    arg to force a SAVE_EXPR for everything.  */