OSDN Git Service

* gigi.h (standard_datatypes): Add ADT_fdesc_type and ADT_null_fdesc.
[pf3gnuchains/gcc-fork.git] / gcc / ada / trans.c
index d1b454c..4dc5202 100644 (file)
@@ -202,7 +202,8 @@ static tree emit_range_check (tree, Node_Id);
 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 bool larger_record_type_p (tree, tree);
+static bool addressable_p (tree, 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);
@@ -244,7 +245,6 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name,
 
   type_annotate_only = (gigi_operating_mode == 1);
 
-#ifdef USE_MAPPED_LOCATION
   for (i = 0; i < number_files; i++)
     {
       /* Use the identifier table to make a permanent copy of the filename as
@@ -268,7 +268,6 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name,
       linemap_position_for_column (line_table, 252 - 1);
       linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
     }
-#endif
 
   /* Initialize ourselves.  */
   init_code_table ();
@@ -688,10 +687,11 @@ Pragma_to_gnu (Node_Id gnat_node)
 
   /* Check for (and ignore) unrecognized pragma and do nothing if we are just
      annotating types.  */
-  if (type_annotate_only || !Is_Pragma_Name (Chars (gnat_node)))
+  if (type_annotate_only
+      || !Is_Pragma_Name (Chars (Pragma_Identifier (gnat_node))))
     return gnu_result;
 
-  switch (Get_Pragma_Id (Chars (gnat_node)))
+  switch (Get_Pragma_Id (Chars (Pragma_Identifier (gnat_node))))
     {
     case Pragma_Inspection_Point:
       /* Do nothing at top level: all such variables are already viewable.  */
@@ -852,6 +852,53 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute)
       if (attribute == Attr_Address)
        gnu_prefix = maybe_unconstrained_array (gnu_prefix);
 
+      /* If we are building a static dispatch table, we have to honor
+        TARGET_VTABLE_USES_DESCRIPTORS if we want to be compatible
+        with the C++ ABI.  We do it in the non-static case as well,
+        see gnat_to_gnu_entity, case E_Access_Subprogram_Type.  */
+      else if (TARGET_VTABLE_USES_DESCRIPTORS
+              && Is_Dispatch_Table_Entity (Etype (gnat_node)))
+       {
+         tree gnu_field, gnu_list = NULL_TREE, t;
+         /* Descriptors can only be built here for top-level functions.  */
+         bool build_descriptor = (global_bindings_p () != 0);
+         int i;
+
+         gnu_result_type = get_unpadded_type (Etype (gnat_node));
+
+         /* If we're not going to build the descriptor, we have to retrieve
+            the one which will be built by the linker (or by the compiler
+            later if a static chain is requested).  */
+         if (!build_descriptor)
+           {
+             gnu_result = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_prefix);
+             gnu_result = fold_convert (build_pointer_type (gnu_result_type),
+                                        gnu_result);
+             gnu_result = build1 (INDIRECT_REF, gnu_result_type, gnu_result);
+           }
+
+         for (gnu_field = TYPE_FIELDS (gnu_result_type), i = 0;
+              i < TARGET_VTABLE_USES_DESCRIPTORS;
+              gnu_field = TREE_CHAIN (gnu_field), i++)
+           {
+             if (build_descriptor)
+               {
+                 t = build2 (FDESC_EXPR, TREE_TYPE (gnu_field), gnu_prefix,
+                             build_int_cst (NULL_TREE, i));
+                 TREE_CONSTANT (t) = 1;
+                 TREE_INVARIANT (t) = 1;
+               }
+             else
+               t = build3 (COMPONENT_REF, ptr_void_ftype, gnu_result,
+                           gnu_field, NULL_TREE);
+
+             gnu_list = tree_cons (gnu_field, t, gnu_list);
+           }
+
+         gnu_result = gnat_build_constructor (gnu_result_type, gnu_list);
+         break;
+       }
+
       /* ... fall through ... */
 
     case Attr_Access:
@@ -1182,33 +1229,42 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute)
 
        else /* attribute == Attr_Range_Length || attribute == Attr_Length  */
          {
-           tree gnu_compute_type;
-
            if (pa && pa->length)
              {
                gnu_result = pa->length;
                break;
              }
+           else
+             {
+               tree gnu_compute_type
+                 = signed_or_unsigned_type_for
+                     (0, get_base_type (gnu_result_type));
+
+               tree index_type
+                 = TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type));
+               tree lb
+                 = convert (gnu_compute_type, TYPE_MIN_VALUE (index_type));
+               tree hb
+                 = convert (gnu_compute_type, TYPE_MAX_VALUE (index_type));
+               
+               /* We used to compute the length as max (hb - lb + 1, 0),
+                  which could overflow for some cases of empty arrays, e.g.
+                  when lb == index_type'first.
+
+                  We now compute it as (hb < lb) ? 0 : hb - lb + 1, which
+                  could overflow as well, but only for extremely large arrays
+                  which we expect never to encounter in practice.  */
 
-           gnu_compute_type
-             = signed_or_unsigned_type_for (0,
-                                            get_base_type (gnu_result_type));
-
-           gnu_result
-             = build_binary_op
-               (MAX_EXPR, gnu_compute_type,
-                build_binary_op
-                (PLUS_EXPR, gnu_compute_type,
-                 build_binary_op
-                 (MINUS_EXPR, gnu_compute_type,
-                  convert (gnu_compute_type,
-                           TYPE_MAX_VALUE
-                           (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)))),
-                  convert (gnu_compute_type,
-                           TYPE_MIN_VALUE
-                           (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type))))),
-                 convert (gnu_compute_type, integer_one_node)),
-                convert (gnu_compute_type, integer_zero_node));
+               gnu_result
+                 = build3
+                   (COND_EXPR, gnu_compute_type,
+                    build_binary_op (LT_EXPR, gnu_compute_type, hb, lb),
+                    convert (gnu_compute_type, integer_zero_node),
+                    build_binary_op
+                    (PLUS_EXPR, gnu_compute_type,
+                     build_binary_op (MINUS_EXPR, gnu_compute_type, hb, lb),
+                     convert (gnu_compute_type, integer_one_node)));
+             }
          }
 
        /* If this has a PLACEHOLDER_EXPR, qualify it by the object we are
@@ -1528,33 +1584,31 @@ Case_Statement_to_gnu (Node_Id gnat_node)
              gcc_unreachable ();
            }
 
-         /* If the case value is a subtype that raises Constraint_Error at
-             run-time because of a wrong bound, then gnu_low or gnu_high
-             is not translated into an INTEGER_CST.  In such a case, we need
-             to ensure that the when statement is not added in the tree,
-             otherwise it will crash the gimplifier.  */
-         if ((!gnu_low || TREE_CODE (gnu_low) == INTEGER_CST)
-              && (!gnu_high || TREE_CODE (gnu_high) == INTEGER_CST))
-          {
-
-             add_stmt_with_node (build3 (CASE_LABEL_EXPR, void_type_node,
-                                         gnu_low, gnu_high,
-                                         create_artificial_label ()),
-                                 gnat_choice);
-             choices_added++;
-          }
+         /* If the case value is a subtype that raises Constraint_Error at
+            run-time because of a wrong bound, then gnu_low or gnu_high is
+            not transtaleted into an INTEGER_CST.  In such a case, we need
+            to ensure that the when statement is not added in the tree,
+            otherwise it will crash the gimplifier.  */
+         if ((!gnu_low || TREE_CODE (gnu_low) == INTEGER_CST)
+             && (!gnu_high || TREE_CODE (gnu_high) == INTEGER_CST))
+           {
+             add_stmt_with_node (build3 (CASE_LABEL_EXPR, void_type_node,
+                                         gnu_low, gnu_high,
+                                         create_artificial_label ()),
+                                 gnat_choice);
+             choices_added++;
+           }
        }
 
-      /* Push a binding level here in case variables are declared since we want
-         them to be local to this set of statements instead of the block
-         containing the Case statement.  */
-
-       if (choices_added > 0)
-       {
-         add_stmt (build_stmt_group (Statements (gnat_when), true));
-         add_stmt (build1 (GOTO_EXPR, void_type_node,
-                           TREE_VALUE (gnu_switch_label_stack)));
-       }
+      /* Push a binding level here in case variables are declared as we want
+        them to be local to this set of statements instead of to the block
+        containing the Case statement.  */
+      if (choices_added > 0)
+       {
+         add_stmt (build_stmt_group (Statements (gnat_when), true));
+         add_stmt (build1 (GOTO_EXPR, void_type_node,
+                           TREE_VALUE (gnu_switch_label_stack)));
+       }
     }
 
   /* Now emit a definition of the label all the cases branched to. */
@@ -1585,6 +1639,8 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
   TREE_SIDE_EFFECTS (gnu_loop_stmt) = 1;
   LOOP_STMT_LABEL (gnu_loop_stmt) = create_artificial_label ();
   set_expr_location_from_node (gnu_loop_stmt, gnat_node);
+  Sloc_to_locus (Sloc (End_Label (gnat_node)),
+                &DECL_SOURCE_LOCATION (LOOP_STMT_LABEL (gnu_loop_stmt)));
 
   /* Save the end label of this LOOP_STMT in a stack so that the corresponding
      N_Exit_Statement can find it.  */
@@ -2091,8 +2147,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
               && Is_Composite_Type (Underlying_Type (Etype (gnat_formal)))));
       Node_Id gnat_name = (suppress_type_conversion
                           ? Expression (gnat_actual) : gnat_actual);
-      tree gnu_name = gnat_to_gnu (gnat_name);
-      tree gnu_name_type = gnat_to_gnu_type (Etype (gnat_name));
+      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
@@ -2111,14 +2166,15 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
              || (TREE_CODE (gnu_formal) == PARM_DECL
                  && (DECL_BY_COMPONENT_PTR_P (gnu_formal)
                      || (DECL_BY_DESCRIPTOR_P (gnu_formal)))))
-         && !addressable_p (gnu_name))
+         && (gnu_name_type = gnat_to_gnu_type (Etype (gnat_name)))
+         && !addressable_p (gnu_name, gnu_name_type))
        {
          tree gnu_copy = gnu_name, gnu_temp;
 
          /* If the type is by_reference, a copy is not allowed.  */
          if (Is_By_Reference_Type (Etype (gnat_formal)))
            post_error
-             ("misaligned & cannot be passed by reference", gnat_actual);
+             ("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
@@ -2138,8 +2194,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
                             gnat_formal);
            }
 
-         /* Remove any unpadding and make a copy.  But if it's a justified
-            modular type, just convert to it.  */
+         /* Remove any unpadding from the object and reset the copy.  */
          if (TREE_CODE (gnu_name) == COMPONENT_REF
              && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_name, 0)))
                   == RECORD_TYPE)
@@ -2147,14 +2202,23 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
                      (TREE_TYPE (TREE_OPERAND (gnu_name, 0))))))
            gnu_name = gnu_copy = TREE_OPERAND (gnu_name, 0);
 
+         /* Otherwise convert to the nominal type of the object if it's
+            a record type.  There are several cases in which we need to
+            make the temporary using this type instead of the actual type
+            of the object if they are distinct, because the expectations
+            of the callee would otherwise not be met:
+              - if it's a justified modular type,
+              - if the actual type is a packed version of it.  */
          else if (TREE_CODE (gnu_name_type) == RECORD_TYPE
-                  && (TYPE_JUSTIFIED_MODULAR_P (gnu_name_type)))
+                  && (TYPE_JUSTIFIED_MODULAR_P (gnu_name_type)
+                      || larger_record_type_p (gnu_name_type,
+                                               TREE_TYPE (gnu_name))))
            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 if needed.  */
+            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;
          TREE_INVARIANT (gnu_name) = 1;
@@ -3632,7 +3696,12 @@ gnat_to_gnu (Node_Id gnat_node)
       break;
 
     case N_Null:
-      gnu_result = null_pointer_node;
+      if (TARGET_VTABLE_USES_DESCRIPTORS
+         && Ekind (Etype (gnat_node)) == E_Access_Subprogram_Type
+         && Is_Dispatch_Table_Entity (Etype (gnat_node)))
+       gnu_result = null_fdesc_node;
+      else
+       gnu_result = null_pointer_node;
       gnu_result_type = get_unpadded_type (Etype (gnat_node));
       break;
 
@@ -3656,7 +3725,6 @@ gnat_to_gnu (Node_Id gnat_node)
 
       /* If the result is a pointer type, see if we are improperly
         converting to a stricter alignment.  */
-
       if (STRICT_ALIGNMENT && POINTER_TYPE_P (gnu_result_type)
          && IN (Ekind (Etype (gnat_node)), Access_Kind))
        {
@@ -3671,6 +3739,13 @@ gnat_to_gnu (Node_Id gnat_node)
               size_int (align / BITS_PER_UNIT), oalign / BITS_PER_UNIT);
        }
 
+      /* If we are converting a descriptor to a function pointer, first
+        build the pointer.  */
+      if (TARGET_VTABLE_USES_DESCRIPTORS
+         && TREE_TYPE (gnu_result) == fdesc_type_node
+         && POINTER_TYPE_P (gnu_result_type))
+       gnu_result = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_result);
+
       gnu_result = unchecked_convert (gnu_result_type, gnu_result,
                                      No_Truncation (gnat_node));
       break;
@@ -4165,26 +4240,13 @@ gnat_to_gnu (Node_Id gnat_node)
                else if (TYPE_RETURNS_UNCONSTRAINED_P (gnu_subprog_type))
                  {
                    gnu_ret_val = maybe_unconstrained_array (gnu_ret_val);
-
-                   /* We have two cases: either the function returns with
-                      depressed stack or not.  If not, we allocate on the
-                      secondary stack.  If so, we allocate in the stack frame.
-                      if no copy is needed, the front end will set By_Ref,
-                      which we handle in the case above.  */
-                   if (TYPE_RETURNS_STACK_DEPRESSED (gnu_subprog_type))
-                     gnu_ret_val
-                       = build_allocator (TREE_TYPE (gnu_ret_val),
-                                          gnu_ret_val,
-                                          TREE_TYPE (gnu_subprog_type),
-                                          0, -1, gnat_node, false);
-                   else
-                     gnu_ret_val
-                       = build_allocator (TREE_TYPE (gnu_ret_val),
-                                          gnu_ret_val,
-                                          TREE_TYPE (gnu_subprog_type),
-                                          Procedure_To_Call (gnat_node),
-                                          Storage_Pool (gnat_node),
-                                          gnat_node, false);
+                   gnu_ret_val
+                     = build_allocator (TREE_TYPE (gnu_ret_val),
+                                        gnu_ret_val,
+                                        TREE_TYPE (gnu_subprog_type),
+                                        Procedure_To_Call (gnat_node),
+                                        Storage_Pool (gnat_node),
+                                        gnat_node, false);
                  }
              }
          }
@@ -4235,7 +4297,7 @@ gnat_to_gnu (Node_Id gnat_node)
 
       for (gnat_temp
           = First_Formal_With_Extras
-              (Defining_Entity (Specification (gnat_node)));
+             (Defining_Entity (Specification (gnat_node)));
           Present (gnat_temp);
           gnat_temp = Next_Formal_With_Extras (gnat_temp))
        if (Is_Itype (Etype (gnat_temp))
@@ -4828,36 +4890,41 @@ gnat_to_gnu (Node_Id gnat_node)
          || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_result_type))))
     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.
-     If the type of the result is correct or if we have a label (which doesn't
-     have any well-defined type), return our result.  Also don't do the
-     conversion if the "desired" type involves a PLACEHOLDER_EXPR in its size
-     since those are the cases where the front end may have the type wrong due
-     to "instantiating" the unconstrained record with discriminant values
-     or if this is a FIELD_DECL.  If this is the Name of an assignment
-     statement or a parameter of a procedure call, return what we have since
-     the RHS has to be converted to our type there in that case, unless
-     GNU_RESULT_TYPE has a simpler size.  Similarly, if the two types are
-     record types with the same name, the expression type has integral mode,
-     and GNU_RESULT_TYPE BLKmode, don't convert.  This will be the case when
-     we are converting from a packable type to its actual type and we need
-     those conversions to be NOPs in order for assignments into these types to
-     work properly if the inner object is a bitfield and hence can't have
-     its address taken.  Finally, don't convert integral types that are the
-     operand of an unchecked conversion since we need to ignore those
-     conversions (for 'Valid).  Otherwise, convert the result to the proper
-     type.  */
+  /* Now convert the result to the result type, unless we are in one of the
+     following cases:
+
+       1. If this is the Name of an assignment statement or a parameter of
+         a procedure call, return the result almost unmodified since the
+         RHS will have to be converted to our type in that case, unless
+         the result type has a simpler size.   Similarly, don't convert
+         integral types that are the operands of an unchecked conversion
+         since we need to ignore those conversions (for 'Valid).
+
+       2. If we have a label (which doesn't have any well-defined type), a
+         field or an error, return the result almost unmodified.  Also don't
+         do the conversion if the result type involves a PLACEHOLDER_EXPR in
+         its size since those are the cases where the front end may have the
+         type wrong due to "instantiating" the unconstrained record with
+         discriminant values.  Similarly, if the two types are record types
+         with the same name don't convert.  This will be the case when we are
+         converting from a packed version of a type to its original type and
+         we need those conversions to be NOPs in order for assignments into
+         these types to work properly.
+
+       3. If the type is void or if we have no result, return error_mark_node
+         to show we have no result.
+
+       4. Finally, if the type of the result is already correct.  */
 
   if (Present (Parent (gnat_node))
       && ((Nkind (Parent (gnat_node)) == N_Assignment_Statement
           && Name (Parent (gnat_node)) == gnat_node)
          || (Nkind (Parent (gnat_node)) == N_Procedure_Call_Statement
              && Name (Parent (gnat_node)) != gnat_node)
+         || Nkind (Parent (gnat_node)) == N_Parameter_Association
          || (Nkind (Parent (gnat_node)) == N_Unchecked_Type_Conversion
              && !AGGREGATE_TYPE_P (gnu_result_type)
-             && !AGGREGATE_TYPE_P (TREE_TYPE (gnu_result)))
-         || Nkind (Parent (gnat_node)) == N_Parameter_Association)
+             && !AGGREGATE_TYPE_P (TREE_TYPE (gnu_result))))
       && !(TYPE_SIZE (gnu_result_type)
           && TYPE_SIZE (TREE_TYPE (gnu_result))
           && (AGGREGATE_TYPE_P (gnu_result_type)
@@ -4872,16 +4939,14 @@ gnat_to_gnu (Node_Id gnat_node)
           && !(TREE_CODE (gnu_result_type) == RECORD_TYPE
                && TYPE_JUSTIFIED_MODULAR_P (gnu_result_type))))
     {
-      /* In this case remove padding only if the inner object type is the
-        same as gnu_result_type or is of self-referential size (in that later
-        case it must be an object of unconstrained type with a default
-        discriminant).  We want to avoid copying too much data.  */
+      /* Remove padding only if the inner object is of self-referential
+        size: in that case it must be an object of unconstrained type
+        with a default discriminant and we want to avoid copying too
+        much data.  */
       if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE
          && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result))
-         && (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result)))
-                         == gnu_result_type
-             || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS
-                                            (TREE_TYPE (gnu_result)))))))
+         && CONTAINS_PLACEHOLDER_P (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS
+                                    (TREE_TYPE (gnu_result))))))
        gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))),
                              gnu_result);
     }
@@ -4896,25 +4961,22 @@ gnat_to_gnu (Node_Id gnat_node)
           || ((TYPE_NAME (gnu_result_type)
                == TYPE_NAME (TREE_TYPE (gnu_result)))
               && TREE_CODE (gnu_result_type) == RECORD_TYPE
-              && TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE
-              && TYPE_MODE (gnu_result_type) == BLKmode
-              && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (gnu_result)))
-                  == MODE_INT)))
+              && TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE))
     {
-      /* Remove any padding record, but do nothing more in this case.  */
+      /* Remove any padding.  */
       if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE
          && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)))
        gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))),
                              gnu_result);
     }
 
-  else if (gnu_result == error_mark_node
-          || gnu_result_type == void_type_node)
-    gnu_result =  error_mark_node;
+  else if (gnu_result == error_mark_node || gnu_result_type == void_type_node)
+    gnu_result = error_mark_node;
+
   else if (gnu_result_type != TREE_TYPE (gnu_result))
     gnu_result = convert (gnu_result_type, gnu_result);
 
-  /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on GNU_RESULT.  */
+  /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on the result.  */
   while ((TREE_CODE (gnu_result) == NOP_EXPR
          || TREE_CODE (gnu_result) == NON_LVALUE_EXPR)
         && TREE_TYPE (TREE_OPERAND (gnu_result, 0)) == TREE_TYPE (gnu_result))
@@ -5283,6 +5345,13 @@ gnat_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
          TREE_READONLY (op) = 0;
        }
 
+      /* We let the gimplifier process &COND_EXPR and expect it to yield the
+        address of the selected operand when it is addressable.  Besides, we
+        also expect addressable_p to only let COND_EXPRs where both arms are
+        addressable reach here.  */
+      else if (TREE_CODE (op) == COND_EXPR)
+       ;
+
       /* 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
@@ -5331,6 +5400,7 @@ gnat_gimplify_stmt (tree *stmt_p)
       {
        tree gnu_start_label = create_artificial_label ();
        tree gnu_end_label = LOOP_STMT_LABEL (stmt);
+       tree t;
 
        /* Set to emit the statements of the loop.  */
        *stmt_p = NULL_TREE;
@@ -5367,9 +5437,10 @@ gnat_gimplify_stmt (tree *stmt_p)
        if (LOOP_STMT_UPDATE (stmt))
          append_to_statement_list (LOOP_STMT_UPDATE (stmt), stmt_p);
 
-       append_to_statement_list (build1 (GOTO_EXPR, void_type_node,
-                                         gnu_start_label),
-                                 stmt_p);
+       t = build1 (GOTO_EXPR, void_type_node, gnu_start_label);
+       set_expr_location (t, DECL_SOURCE_LOCATION (gnu_end_label));
+       append_to_statement_list (t, stmt_p);
+
        append_to_statement_list (build1 (LABEL_EXPR, void_type_node,
                                          gnu_end_label),
                                  stmt_p);
@@ -5752,6 +5823,11 @@ emit_range_check (tree gnu_expr, Entity_Id gnat_range_type)
   tree gnu_high = TYPE_MAX_VALUE (gnu_range_type);
   tree gnu_compare_type = get_base_type (TREE_TYPE (gnu_expr));
 
+  /* If GNU_EXPR has GNAT_RANGE_TYPE as its base type, no check is needed.
+     This can for example happen when translating 'Val or 'Value.  */
+  if (gnu_compare_type == gnu_range_type)
+    return gnu_expr;
+
   /* If GNU_EXPR has an integral type that is narrower than GNU_RANGE_TYPE,
      we can't do anything since we might be truncating the bounds.  No
      check is needed in this case.  */
@@ -6049,13 +6125,97 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
   return convert (gnu_type, gnu_result);
 }
 \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 reference
-   to a bitfield or to a field not sufficiently aligned for its type.  */
+/* Return true if RECORD_TYPE, a record type, is larger than TYPE.  */
+
+static bool
+larger_record_type_p (tree record_type, tree type)
+{
+  tree rsize, size;
+
+  /* Padding types are not considered larger on their own.  */
+  if (TYPE_IS_PADDING_P (record_type))
+    return false;
+
+  rsize = TYPE_SIZE (record_type);
+  size = TYPE_SIZE (type);
+
+  if (!(TREE_CODE (rsize) == INTEGER_CST && TREE_CODE (size) == INTEGER_CST))
+    return false;
+
+  return tree_int_cst_lt (size, rsize) != 0;
+}
+
+/* Return true if GNU_EXPR can be directly addressed.  This is the case
+   unless it is an expression involving computation or if it involves a
+   reference to a bitfield or to an object not sufficiently aligned for
+   its type.  If GNU_TYPE is non-null, return true only if GNU_EXPR can
+   be directly addressed as an object of this type.
+
+   *** Notes on addressability issues in the Ada compiler ***
+
+   This predicate is necessary in order to bridge the gap between Gigi
+   and the middle-end about addressability of GENERIC trees.  A tree
+   is said to be addressable if it can be directly addressed, i.e. if
+   its address can be taken, is a multiple of the type's alignment on
+   strict-alignment architectures and returns the first storage unit
+   assigned to the object represented by the tree.
+
+   In the C family of languages, everything is in practice addressable
+   at the language level, except for bit-fields.  This means that these
+   compilers will take the address of any tree that doesn't represent
+   a bit-field reference and expect the result to be the first storage
+   unit assigned to the object.  Even in cases where this will result
+   in unaligned accesses at run time, nothing is supposed to be done
+   and the program is considered as erroneous instead (see PR c/18287).
+
+   The implicit assumptions made in the middle-end are in keeping with
+   the C viewpoint described above:
+     - the address of a bit-field reference is supposed to be never
+       taken; the compiler (generally) will stop on such a construct,
+     - any other tree is addressable if it is formally addressable,
+       i.e. if it is formally allowed to be the operand of ADDR_EXPR.
+
+   In Ada, the viewpoint is the opposite one: nothing is addressable
+   at the language level unless explicitly declared so.  This means
+   that the compiler will both make sure that the trees representing
+   references to addressable ("aliased" in Ada parlance) objects are
+   addressable and make no real attempts at ensuring that the trees
+   representing references to non-addressable objects are addressable.
+
+   In the first case, Ada is effectively equivalent to C and handing
+   down the direct result of applying ADDR_EXPR to these trees to the
+   middle-end works flawlessly.  In the second case, Ada cannot afford
+   to consider the program as erroneous if the address of trees that
+   are not addressable is requested for technical reasons, unlike C;
+   as a consequence, the Ada compiler must arrange for either making
+   sure that this address is not requested in the middle-end or for
+   compensating by inserting temporaries if it is requested in Gigi.
+
+   The first goal can be achieved because the middle-end should not
+   request the address of non-addressable trees on its own; the only
+   exception is for the invocation of low-level block operations like
+   memcpy, for which the addressability requirements are lower since
+   the type's alignment can be disregarded.  In practice, this means
+   that Gigi must make sure that such operations cannot be applied to
+   non-BLKmode bit-fields.
+
+   The second goal is achieved by means of the addressable_p predicate
+   and by inserting SAVE_EXPRs around trees deemed non-addressable.
+   They will be turned during gimplification into proper temporaries
+   whose address will be used in lieu of that of the original tree.  */
 
 static bool
-addressable_p (tree gnu_expr)
+addressable_p (tree gnu_expr, tree gnu_type)
 {
+  /* The size of the real type of the object must not be smaller than
+     that of the expected type, otherwise an indirect access in the
+     latter type would be larger than the object.  Only records need
+     to be considered in practice.  */
+  if (gnu_type
+      && TREE_CODE (gnu_type) == RECORD_TYPE
+      && larger_record_type_p (gnu_type, TREE_TYPE (gnu_expr)))
+    return false;
+
   switch (TREE_CODE (gnu_expr))
     {
     case VAR_DECL:
@@ -6076,6 +6236,12 @@ addressable_p (tree gnu_expr)
     case CALL_EXPR:
       return true;
 
+    case COND_EXPR:
+      /* We accept &COND_EXPR as soon as both operands are addressable and
+        expect the outcome to be the address of the selected operand.  */
+      return (addressable_p (TREE_OPERAND (gnu_expr, 1), NULL_TREE)
+             && addressable_p (TREE_OPERAND (gnu_expr, 2), NULL_TREE));
+
     case COMPONENT_REF:
       return (!DECL_BIT_FIELD (TREE_OPERAND (gnu_expr, 1))
              && (!STRICT_ALIGNMENT
@@ -6087,23 +6253,22 @@ addressable_p (tree gnu_expr)
                     aligned field that is not a bit-field.  */
                  || DECL_ALIGN (TREE_OPERAND (gnu_expr, 1))
                       >= TYPE_ALIGN (TREE_TYPE (gnu_expr)))
-             && addressable_p (TREE_OPERAND (gnu_expr, 0)));
+             && addressable_p (TREE_OPERAND (gnu_expr, 0), NULL_TREE));
 
     case ARRAY_REF:  case ARRAY_RANGE_REF:
     case REALPART_EXPR:  case IMAGPART_EXPR:
     case NOP_EXPR:
-      return addressable_p (TREE_OPERAND (gnu_expr, 0));
+      return addressable_p (TREE_OPERAND (gnu_expr, 0), NULL_TREE);
 
     case CONVERT_EXPR:
       return (AGGREGATE_TYPE_P (TREE_TYPE (gnu_expr))
-             && addressable_p (TREE_OPERAND (gnu_expr, 0)));
+             && addressable_p (TREE_OPERAND (gnu_expr, 0), NULL_TREE));
 
     case VIEW_CONVERT_EXPR:
       {
        /* This is addressable if we can avoid a copy.  */
        tree type = TREE_TYPE (gnu_expr);
        tree inner_type = TREE_TYPE (TREE_OPERAND (gnu_expr, 0));
-
        return (((TYPE_MODE (type) == TYPE_MODE (inner_type)
                  && (!STRICT_ALIGNMENT
                      || TYPE_ALIGN (type) <= TYPE_ALIGN (inner_type)
@@ -6115,7 +6280,7 @@ addressable_p (tree gnu_expr)
                         || TYPE_ALIGN (inner_type) >= BIGGEST_ALIGNMENT
                         || TYPE_ALIGN_OK (type)
                         || TYPE_ALIGN_OK (inner_type))))
-               && addressable_p (TREE_OPERAND (gnu_expr, 0)));
+               && addressable_p (TREE_OPERAND (gnu_expr, 0), NULL_TREE));
       }
 
     default:
@@ -6262,7 +6427,7 @@ assoc_to_constructor (Entity_Id gnat_entity, Node_Id gnat_assoc, tree gnu_type)
   {
     tree gnu_field;
 
-    /* Verify every enty in GNU_LIST was used.  */
+    /* Verify every entry in GNU_LIST was used.  */
     for (gnu_field = gnu_list; gnu_field; gnu_field = TREE_CHAIN (gnu_field))
       gcc_assert (TREE_ADDRESSABLE (gnu_field));
   }
@@ -6650,7 +6815,6 @@ Sloc_to_locus (Source_Ptr Sloc, location_t *locus)
     return false;
 
   if (Sloc <= Standard_Location)
-#ifdef USE_MAPPED_LOCATION
     {
       *locus = BUILTINS_LOCATION;
       return false;
@@ -6667,22 +6831,6 @@ Sloc_to_locus (Source_Ptr Sloc, location_t *locus)
                + ((line - map->to_line) << map->column_bits)
                + (column & ((1 << map->column_bits) - 1));
     }
-#else
-  return false;
-
-  /* Use the identifier table to make a hashed, permanent copy of the filename,
-     since the name table gets reallocated after Gigi returns but before all
-     the debugging information is output. The __gnat_to_canonical_file_spec
-     call translates filenames from pragmas Source_Reference that contain host
-     style syntax not understood by gdb. */
-  locus->file
-    = IDENTIFIER_POINTER
-      (get_identifier
-       (__gnat_to_canonical_file_spec
-       (Get_Name_String (Full_Debug_Name (Get_Source_File_Index (Sloc))))));
-
-  locus->line = Get_Logical_Line_Number (Sloc);
-#endif
 
   ref_filename
     = IDENTIFIER_POINTER