case N_Object_Declaration:
/* We cannot use a constructor if this is an atomic object because
the actual assignment might end up being done component-wise. */
- return ((Is_Composite_Type (Underlying_Type (Etype (gnat_node)))
- && Is_Atomic (Defining_Entity (gnat_parent)))
+ return (!constant
+ ||(Is_Composite_Type (Underlying_Type (Etype (gnat_node)))
+ && Is_Atomic (Defining_Entity (gnat_parent)))
/* We don't use a constructor if this is a class-wide object
because the effective type of the object is the equivalent
type of the class-wide subtype and it smashes most of the
/* ... fall through ... */
case N_Unchecked_Type_Conversion:
- return lvalue_required_p (gnat_parent,
- get_unpadded_type (Etype (gnat_parent)),
- constant, address_of_constant, aliased);
+ return (!constant
+ || lvalue_required_p (gnat_parent,
+ get_unpadded_type (Etype (gnat_parent)),
+ constant, address_of_constant, aliased));
case N_Allocator:
/* We should only reach here through the N_Qualified_Expression case
= lvalue_required_p (gnat_node, gnu_result_type, true,
address_of_constant, Is_Aliased (gnat_temp));
+ /* ??? We need to unshare the initializer if the object is external
+ as such objects are not marked for unsharing if we are not at the
+ global level. This should be fixed in add_decl_expr. */
if ((constant_only && !address_of_constant) || !require_lvalue)
gnu_result = unshare_expr (DECL_INITIAL (gnu_result));
}
tree gnu_char_ptr_type
= build_pointer_type (unsigned_char_type_node);
tree gnu_pos = byte_position (TYPE_FIELDS (gnu_obj_type));
+ tree gnu_byte_offset
+ = convert (sizetype,
+ size_diffop (size_zero_node, gnu_pos));
+ gnu_byte_offset
+ = fold_build1 (NEGATE_EXPR, sizetype, gnu_byte_offset);
+
gnu_ptr = convert (gnu_char_ptr_type, gnu_ptr);
gnu_ptr = build_binary_op (POINTER_PLUS_EXPR, gnu_char_ptr_type,
gnu_ptr, gnu_pos);
/* Set either the top or bottom exit condition. */
LOOP_STMT_COND (gnu_loop_stmt)
- = build_binary_op (test_code, boolean_type_node, gnu_loop_var,
+ = build_binary_op (test_code, integer_type_node, gnu_loop_var,
gnu_last);
/* Set either the top or bottom update statement and give it the source
tree gnu_before_list = NULL_TREE;
tree gnu_after_list = NULL_TREE;
tree gnu_call;
+ bool went_into_elab_proc = false;
gcc_assert (TREE_CODE (gnu_subprog_type) == FUNCTION_TYPE);
else
gnat_formal = First_Formal_With_Extras (Entity (Name (gnat_node)));
+ /* If we are translating a statement, open a new nesting level that will
+ surround it to declare the temporaries created for the call. */
+ if (Nkind (gnat_node) == N_Procedure_Call_Statement || gnu_target)
+ {
+ start_stmt_group ();
+ gnat_pushlevel ();
+ }
+
+ /* The lifetime of the temporaries created for the call ends with the call
+ so we can give them the scope of the elaboration routine at top level. */
+ else if (!current_function_decl)
+ {
+ current_function_decl = TREE_VALUE (gnu_elab_proc_stack);
+ went_into_elab_proc = true;
+ }
+
/* 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
&& (gnu_name_type = gnat_to_gnu_type (Etype (gnat_name)))
&& !addressable_p (gnu_name, gnu_name_type))
{
- tree gnu_copy = gnu_name;
+ tree gnu_orig = gnu_name, gnu_temp, gnu_stmt;
+
+ /* Do not issue warnings for CONSTRUCTORs since this is not a copy
+ but sort of an instantiation for them. */
+ if (TREE_CODE (gnu_name) == CONSTRUCTOR)
+ ;
+
+ /* If the type is passed by reference, a copy is not allowed. */
+ else if (TREE_ADDRESSABLE (gnu_formal_type))
+ 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 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
+ ("?possible violation of implicit assumption", gnat_actual);
+ post_error_ne
+ ("?made by pragma Import_Valued_Procedure on &", gnat_actual,
+ Entity (Name (gnat_node)));
+ post_error_ne ("?because of misalignment of &", gnat_actual,
+ gnat_formal);
+ }
/* If the actual type of the object is already the nominal type,
we have nothing to do, except if the size is self-referential
TREE_TYPE (gnu_name))))
gnu_name = convert (gnu_name_type, gnu_name);
- /* Make a SAVE_EXPR to force 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;
+ /* Create an explicit temporary holding the copy. This ensures that
+ its lifetime is as narrow as possible around a statement. */
+ gnu_temp = create_var_decl (create_tmp_var_name ("A"), NULL_TREE,
+ TREE_TYPE (gnu_name), NULL_TREE, false,
+ false, false, false, NULL, Empty);
+ DECL_ARTIFICIAL (gnu_temp) = 1;
+ DECL_IGNORED_P (gnu_temp) = 1;
- /* If the type is passed by reference, a copy is not allowed. */
- if (TREE_ADDRESSABLE (gnu_formal_type))
- {
- post_error ("misaligned actual cannot be passed by reference",
- gnat_actual);
+ /* But initialize it on the fly like for an implicit temporary as
+ we aren't necessarily dealing with a statement. */
+ gnu_stmt
+ = build_binary_op (INIT_EXPR, NULL_TREE, gnu_temp, gnu_name);
+ set_expr_location_from_node (gnu_stmt, gnat_actual);
- /* Avoid the back-end assertion on temporary creation. */
- gnu_name = TREE_OPERAND (gnu_name, 0);
- }
-
- /* 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
- ("?possible violation of implicit assumption", gnat_actual);
- post_error_ne
- ("?made by pragma Import_Valued_Procedure on &", gnat_actual,
- Entity (Name (gnat_node)));
- post_error_ne ("?because of misalignment of &", gnat_actual,
- gnat_formal);
- }
+ /* From now on, the real object is the temporary. */
+ gnu_name = build2 (COMPOUND_EXPR, TREE_TYPE (gnu_name), gnu_stmt,
+ gnu_temp);
/* Set up to move the copy back to the original if needed. */
if (Ekind (gnat_formal) != E_In_Parameter)
gnu_actual
= emit_range_check (gnu_actual, Etype (gnat_formal), gnat_actual);
- /* And convert it to this type. */
- if (TREE_CODE (gnu_actual) != SAVE_EXPR)
- gnu_actual = convert (gnu_formal_type, gnu_actual);
-
/* Unless this is an In parameter, we must remove any justified modular
building from GNU_NAME to get an lvalue. */
if (Ekind (gnat_formal) != E_In_Parameter
/* If we have not saved a GCC object for the formal, it means it is an
Out parameter not passed by reference and that need not be copied in.
- Otherwise, first see if the PARM_DECL is passed by reference. */
+ Otherwise, first see if the parameter is passed by reference. */
if (gnu_formal
&& TREE_CODE (gnu_formal) == PARM_DECL
&& DECL_BY_REF_P (gnu_formal))
&& TREE_CODE (gnu_formal) == PARM_DECL
&& DECL_BY_DESCRIPTOR_P (gnu_formal))
{
+ gnu_actual = convert (gnu_formal_type, gnu_actual);
+
/* If this is 'Null_Parameter, pass a zero descriptor. */
if ((TREE_CODE (gnu_actual) == INDIRECT_REF
|| TREE_CODE (gnu_actual) == UNCONSTRAINED_ARRAY_REF)
continue;
}
+ gnu_actual = convert (gnu_formal_type, gnu_actual);
+
/* If this is 'Null_Parameter, pass a zero even though we are
dereferencing it. */
if (TREE_CODE (gnu_actual) == INDIRECT_REF
if (Nkind (gnat_node) == N_Function_Call)
{
tree gnu_result = gnu_call;
- enum tree_code op_code;
/* If the function returns an unconstrained array or by direct reference,
we have to dereference the pointer. */
if (gnu_target)
{
+ Node_Id gnat_parent = Parent (gnat_node);
+ enum tree_code op_code;
+
+ /* If range check is needed, emit code to generate it. */
+ if (Do_Range_Check (gnat_node))
+ gnu_result
+ = emit_range_check (gnu_result, Etype (Name (gnat_parent)),
+ gnat_parent);
+
/* ??? If the return type has non-constant size, then force the
return slot optimization as we would not be able to generate
a temporary. That's what has been done historically. */
gnu_result
= build_binary_op (op_code, NULL_TREE, gnu_target, gnu_result);
+ add_stmt_with_node (gnu_result, gnat_parent);
+ gnat_poplevel ();
+ gnu_result = end_stmt_group ();
}
else
{
passing mechanism must be used. */
if (TYPE_CI_CO_LIST (gnu_subprog_type))
{
- /* List of FIELD_DECLs associated with the PARM_DECLs of the copy
- in copy out parameters. */
+ /* List of FIELD_DECLs associated with the PARM_DECLs of the copy-in/
+ copy-out parameters. */
tree gnu_cico_list = TYPE_CI_CO_LIST (gnu_subprog_type);
const int length = list_length (gnu_cico_list);
if (length > 1)
{
+ tree gnu_temp, gnu_stmt;
+
/* 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;
+ the function is pure. Save the result into a temporary. */
+ gnu_temp = create_var_decl (create_tmp_var_name ("R"), NULL_TREE,
+ TREE_TYPE (gnu_call), NULL_TREE, false,
+ false, false, false, NULL, Empty);
+ DECL_ARTIFICIAL (gnu_temp) = 1;
+ DECL_IGNORED_P (gnu_temp) = 1;
+
+ gnu_stmt
+ = build_binary_op (INIT_EXPR, NULL_TREE, gnu_temp, gnu_call);
+ set_expr_location_from_node (gnu_stmt, gnat_node);
+
+ /* Add the call statement to the list and start from its result. */
+ append_to_statement_list (gnu_stmt, &gnu_before_list);
+ gnu_call = gnu_temp;
+
gnu_name_list = nreverse (gnu_name_list);
}
append_to_statement_list (gnu_after_list, &gnu_before_list);
- return gnu_before_list;
+ add_stmt (gnu_before_list);
+ gnat_poplevel ();
+ return end_stmt_group ();
}
\f
/* Subroutine of gnat_to_gnu to translate gnat_node, an
/* Initialize the information structure for the function. */
allocate_struct_function (gnu_elab_proc_decl, false);
- Sloc_to_locus (Sloc (gnat_unit_entity), &cfun->function_end_locus);
- current_function_decl = NULL_TREE;
set_cfun (NULL);
+
+ current_function_decl = NULL_TREE;
+
start_stmt_group ();
gnat_pushlevel ();
gnu_actual_obj_type
= build_unc_object_type_from_ptr (gnu_ptr_type,
gnu_actual_obj_type,
- get_identifier ("DEALLOC"),
- false);
+ get_identifier
+ ("DEALLOC"));
}
else
gnu_actual_obj_type = gnu_obj_type;
tree gnu_char_ptr_type
= build_pointer_type (unsigned_char_type_node);
tree gnu_pos = byte_position (TYPE_FIELDS (gnu_obj_type));
+ tree gnu_byte_offset
+ = convert (sizetype,
+ size_diffop (size_zero_node, gnu_pos));
+ gnu_byte_offset
+ = fold_build1 (NEGATE_EXPR, sizetype, gnu_byte_offset);
+
gnu_ptr = convert (gnu_char_ptr_type, gnu_ptr);
gnu_ptr = build_binary_op (POINTER_PLUS_EXPR, gnu_char_ptr_type,
gnu_ptr, gnu_pos);
if (went_into_elab_proc)
current_function_decl = NULL_TREE;
+ /* When not optimizing, turn boolean rvalues B into B != false tests
+ so that the code just below can put the location information of the
+ reference to B on the inequality operator for better debug info. */
+ if (!optimize
+ && (kind == N_Identifier
+ || kind == N_Expanded_Name
+ || kind == N_Explicit_Dereference
+ || kind == N_Function_Call
+ || kind == N_Indexed_Component
+ || kind == N_Selected_Component)
+ && TREE_CODE (get_base_type (gnu_result_type)) == BOOLEAN_TYPE
+ && !lvalue_required_p (gnat_node, gnu_result_type, false, false, false))
+ gnu_result = build_binary_op (NE_EXPR, gnu_result_type,
+ convert (gnu_result_type, gnu_result),
+ convert (gnu_result_type,
+ boolean_false_node));
+
/* Set the location information on the result if it is a real expression.
References can be reused for multiple GNAT nodes and they would get
the location information of their last use. Note that we may have
return GS_ALL_DONE;
}
- /* Otherwise explicitly create the local temporary. That's required
- if the type is passed by reference. */
- else
- {
- tree mod, new_var = create_tmp_var_raw (TREE_TYPE (op), "C");
- TREE_ADDRESSABLE (new_var) = 1;
- gimple_add_tmp_var (new_var);
-
- mod = build2 (INIT_EXPR, TREE_TYPE (new_var), new_var, op);
- gimplify_and_add (mod, pre_p);
-
- TREE_OPERAND (expr, 0) = new_var;
- recompute_tree_invariant_for_addr_expr (expr);
- }
-
- return GS_ALL_DONE;
- }
-
return GS_UNHANDLED;
case DECL_EXPR: