static void set_gnu_expr_location_from_node (tree, Node_Id);
static int lvalue_required_p (Node_Id, tree, bool, bool, bool);
static tree build_raise_check (int, enum exception_info_kind);
+static tree create_init_temporary (const char *, tree, tree *, Node_Id);
/* Hooks for debug info back-ends, only supported and used in a restricted set
of configurations. */
&& DECL_BY_COMPONENT_PTR_P (gnu_result))))
{
const bool read_only = DECL_POINTS_TO_READONLY_P (gnu_result);
- tree renamed_obj;
+ /* First do the first dereference if needed. */
if (TREE_CODE (gnu_result) == PARM_DECL
&& DECL_BY_DOUBLE_REF_P (gnu_result))
{
TREE_THIS_NOTRAP (gnu_result) = 1;
}
+ /* If it's a PARM_DECL to foreign convention subprogram, convert it. */
if (TREE_CODE (gnu_result) == PARM_DECL
&& DECL_BY_COMPONENT_PTR_P (gnu_result))
- {
- gnu_result
- = build_unary_op (INDIRECT_REF, NULL_TREE,
- convert (build_pointer_type (gnu_result_type),
- gnu_result));
- if (TREE_CODE (gnu_result) == INDIRECT_REF)
- TREE_THIS_NOTRAP (gnu_result) = 1;
- }
+ gnu_result
+ = convert (build_pointer_type (gnu_result_type), gnu_result);
+
+ /* If it's a CONST_DECL, return the underlying constant like below. */
+ else if (TREE_CODE (gnu_result) == CONST_DECL)
+ gnu_result = DECL_INITIAL (gnu_result);
/* If it's a renaming pointer and we are at the right binding level,
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))
- && (!DECL_RENAMING_GLOBAL_P (gnu_result)
- || global_bindings_p ()))
- gnu_result = renamed_obj;
-
- /* Return the underlying CST for a CONST_DECL like a few lines below,
- after dereferencing in this case. */
- else if (TREE_CODE (gnu_result) == CONST_DECL)
- gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE,
- DECL_INITIAL (gnu_result));
+ if (TREE_CODE (gnu_result) == VAR_DECL
+ && DECL_RENAMED_OBJECT (gnu_result)
+ && (!DECL_RENAMING_GLOBAL_P (gnu_result) || global_bindings_p ()))
+ gnu_result = DECL_RENAMED_OBJECT (gnu_result);
+ /* Otherwise, do the final dereference. */
else
{
gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result);
- if (TREE_CODE (gnu_result) == INDIRECT_REF
+
+ if ((TREE_CODE (gnu_result) == INDIRECT_REF
+ || TREE_CODE (gnu_result) == UNCONSTRAINED_ARRAY_REF)
&& No (Address_Clause (gnat_temp)))
TREE_THIS_NOTRAP (gnu_result) = 1;
- }
- if (read_only)
- TREE_READONLY (gnu_result) = 1;
+ if (read_only)
+ TREE_READONLY (gnu_result) = 1;
+ }
}
/* The GNAT tree has the type of a function as the type of its result. Also
&& DECL_P (gnu_result)
&& DECL_INITIAL (gnu_result)
&& !(AGGREGATE_TYPE_P (TREE_TYPE (gnu_result))
+ && !TYPE_IS_FAT_POINTER_P (TREE_TYPE (gnu_result))
&& type_contains_placeholder_p (TREE_TYPE (gnu_result))))
{
bool constant_only = (TREE_CODE (gnu_result) == CONST_DECL
/* Make sure any implicit dereference gets done. */
gnu_prefix = maybe_implicit_deref (gnu_prefix);
gnu_prefix = maybe_unconstrained_array (gnu_prefix);
+
/* We treat unconstrained array In parameters specially. */
- if (Nkind (Prefix (gnat_node)) == N_Identifier
- && !Is_Constrained (Etype (Prefix (gnat_node)))
- && Ekind (Entity (Prefix (gnat_node))) == E_In_Parameter)
- gnat_param = Entity (Prefix (gnat_node));
+ if (!Is_Constrained (Etype (Prefix (gnat_node))))
+ {
+ Node_Id gnat_prefix = Prefix (gnat_node);
+
+ /* This is the direct case. */
+ if (Nkind (gnat_prefix) == N_Identifier
+ && Ekind (Entity (gnat_prefix)) == E_In_Parameter)
+ gnat_param = Entity (gnat_prefix);
+
+ /* This is the indirect case. Note that we need to be sure that
+ the access value cannot be null as we'll hoist the load. */
+ if (Nkind (gnat_prefix) == N_Explicit_Dereference
+ && Nkind (Prefix (gnat_prefix)) == N_Identifier
+ && Ekind (Entity (Prefix (gnat_prefix))) == E_In_Parameter
+ && Can_Never_Be_Null (Entity (Prefix (gnat_prefix))))
+ gnat_param = Entity (Prefix (gnat_prefix));
+ }
+
gnu_type = TREE_TYPE (gnu_prefix);
prefix_unused = true;
gnu_result_type = get_unpadded_type (Etype (gnat_node));
tree gnu_loop_stmt = build4 (LOOP_STMT, void_type_node, NULL_TREE,
NULL_TREE, NULL_TREE, NULL_TREE);
tree gnu_loop_label = create_artificial_label (input_location);
- tree gnu_loop_var = NULL_TREE, gnu_cond_expr = NULL_TREE;
- tree gnu_result;
+ tree gnu_cond_expr = NULL_TREE, gnu_result;
/* Set location information for statement and end label. */
set_expr_location_from_node (gnu_loop_stmt, gnat_node);
tree gnu_high = TYPE_MAX_VALUE (gnu_type);
tree gnu_base_type = get_base_type (gnu_type);
tree gnu_one_node = convert (gnu_base_type, integer_one_node);
- tree gnu_first, gnu_last;
+ tree gnu_loop_var, gnu_loop_iv, gnu_first, gnu_last, gnu_stmt;
enum tree_code update_code, test_code, shift_code;
- bool reverse = Reverse_Present (gnat_loop_spec), fallback = false;
+ bool reverse = Reverse_Present (gnat_loop_spec), use_iv = false;
/* We must disable modulo reduction for the iteration variable, if any,
in order for the loop comparison to be effective. */
/* We use two different strategies to translate the loop, depending on
whether optimization is enabled.
- If it is, we try to generate the canonical form of loop expected by
- the loop optimizer, which is the do-while form:
+ If it is, we generate the canonical loop form expected by the loop
+ optimizer and the loop vectorizer, which is the do-while form:
ENTRY_COND
loop:
BOTTOM_COND
GOTO loop
- This makes it possible to bypass loop header copying and to turn the
- BOTTOM_COND into an inequality test. This should catch (almost) all
- loops with constant starting point. If we cannot, we try to generate
- the default form, which is:
+ This avoids an implicit dependency on loop header copying and makes
+ it possible to turn BOTTOM_COND into an inequality test.
+
+ If optimization is disabled, loop header copying doesn't come into
+ play and we try to generate the loop form with the fewer conditional
+ branches. First, the default form, which is:
loop:
TOP_COND
BOTTOM_UPDATE
GOTO loop
- It will be rotated during loop header copying and an entry test added
- to yield the do-while form. This should catch (almost) all loops with
- constant ending point. If we cannot, we generate the fallback form:
+ It should catch most loops with constant ending point. Then, if we
+ cannot, we try to generate the shifted form:
- ENTRY_COND
loop:
+ TOP_COND
+ TOP_UPDATE
BODY
- BOTTOM_COND
- BOTTOM_UPDATE
GOTO loop
- which works in all cases but for which loop header copying will copy
- the BOTTOM_COND, thus adding a third conditional branch.
-
- If optimization is disabled, loop header copying doesn't come into
- play and we try to generate the loop forms with the less conditional
- branches directly. First, the default form, it should catch (almost)
- all loops with constant ending point. Then, if we cannot, we try to
- generate the shifted form:
+ which should catch loops with constant starting point. Otherwise, if
+ we cannot, we generate the fallback form:
+ ENTRY_COND
loop:
- TOP_COND
- TOP_UPDATE
BODY
+ BOTTOM_COND
+ BOTTOM_UPDATE
GOTO loop
- which should catch loops with constant starting point. Otherwise, if
- we cannot, we generate the fallback form. */
+ which works in all cases. */
if (optimize)
{
- /* We can use the do-while form if GNU_FIRST-1 doesn't overflow. */
+ /* We can use the do-while form directly if GNU_FIRST-1 doesn't
+ overflow. */
if (!can_equal_min_val_p (gnu_first, gnu_base_type, reverse))
- {
- gnu_first = build_binary_op (shift_code, gnu_base_type,
- gnu_first, gnu_one_node);
- LOOP_STMT_TOP_UPDATE_P (gnu_loop_stmt) = 1;
- LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt) = 1;
- }
-
- /* Otherwise, we can use the default form if GNU_LAST+1 doesn't. */
- else if (!can_equal_max_val_p (gnu_last, gnu_base_type, reverse))
;
- /* Otherwise, use the fallback form. */
+ /* Otherwise, use the do-while form with the help of a special
+ induction variable in the (unsigned version of) the base
+ type, in order to have wrap-around arithmetics for it. */
else
- fallback = true;
+ {
+ if (!TYPE_UNSIGNED (gnu_base_type))
+ {
+ gnu_base_type = gnat_unsigned_type (gnu_base_type);
+ gnu_first = convert (gnu_base_type, gnu_first);
+ gnu_last = convert (gnu_base_type, gnu_last);
+ gnu_one_node = convert (gnu_base_type, integer_one_node);
+ }
+ use_iv = true;
+ }
+
+ gnu_first
+ = build_binary_op (shift_code, gnu_base_type, gnu_first,
+ gnu_one_node);
+ LOOP_STMT_TOP_UPDATE_P (gnu_loop_stmt) = 1;
+ LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt) = 1;
}
else
{
else if (!can_equal_min_val_p (gnu_first, gnu_base_type, reverse)
&& !can_equal_min_val_p (gnu_last, gnu_base_type, reverse))
{
- gnu_first = build_binary_op (shift_code, gnu_base_type,
- gnu_first, gnu_one_node);
- gnu_last = build_binary_op (shift_code, gnu_base_type,
- gnu_last, gnu_one_node);
+ gnu_first
+ = build_binary_op (shift_code, gnu_base_type, gnu_first,
+ gnu_one_node);
+ gnu_last
+ = build_binary_op (shift_code, gnu_base_type, gnu_last,
+ gnu_one_node);
LOOP_STMT_TOP_UPDATE_P (gnu_loop_stmt) = 1;
}
/* Otherwise, use the fallback form. */
else
- fallback = true;
+ LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt) = 1;
}
- if (fallback)
- LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt) = 1;
-
/* If we use the BOTTOM_COND, we can turn the test into an inequality
test but we may have to add ENTRY_COND to protect the empty loop. */
if (LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt))
start_stmt_group ();
gnat_pushlevel ();
+ /* If we use the special induction variable, create it and set it to
+ its initial value. Morever, the regular iteration variable cannot
+ itself be initialized, lest the initial value wrapped around. */
+ if (use_iv)
+ {
+ gnu_loop_iv
+ = create_init_temporary ("I", gnu_first, &gnu_stmt, gnat_loop_var);
+ add_stmt (gnu_stmt);
+ gnu_first = NULL_TREE;
+ }
+ else
+ gnu_loop_iv = NULL_TREE;
+
/* Declare the iteration variable and set it to its initial value. */
gnu_loop_var = gnat_to_gnu_entity (gnat_loop_var, gnu_first, 1);
if (DECL_BY_REF_P (gnu_loop_var))
gnu_loop_var = convert (gnu_base_type, gnu_loop_var);
/* 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,
- gnu_last);
+ if (use_iv)
+ LOOP_STMT_COND (gnu_loop_stmt)
+ = build_binary_op (test_code, boolean_type_node, gnu_loop_iv,
+ gnu_last);
+ else
+ LOOP_STMT_COND (gnu_loop_stmt)
+ = build_binary_op (test_code, boolean_type_node, gnu_loop_var,
+ gnu_last);
/* Set either the top or bottom update statement and give it the source
location of the iteration for better coverage info. */
- LOOP_STMT_UPDATE (gnu_loop_stmt)
- = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_loop_var,
- build_binary_op (update_code, gnu_base_type,
- gnu_loop_var, gnu_one_node));
- set_expr_location_from_node (LOOP_STMT_UPDATE (gnu_loop_stmt),
- gnat_iter_scheme);
+ if (use_iv)
+ {
+ gnu_stmt
+ = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_loop_iv,
+ build_binary_op (update_code, gnu_base_type,
+ gnu_loop_iv, gnu_one_node));
+ set_expr_location_from_node (gnu_stmt, gnat_iter_scheme);
+ append_to_statement_list (gnu_stmt,
+ &LOOP_STMT_UPDATE (gnu_loop_stmt));
+ gnu_stmt
+ = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_loop_var,
+ gnu_loop_iv);
+ set_expr_location_from_node (gnu_stmt, gnat_iter_scheme);
+ append_to_statement_list (gnu_stmt,
+ &LOOP_STMT_UPDATE (gnu_loop_stmt));
+ }
+ else
+ {
+ gnu_stmt
+ = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_loop_var,
+ build_binary_op (update_code, gnu_base_type,
+ gnu_loop_var, gnu_one_node));
+ set_expr_location_from_node (gnu_stmt, gnat_iter_scheme);
+ LOOP_STMT_UPDATE (gnu_loop_stmt) = gnu_stmt;
+ }
}
/* If the loop was named, have the name point to this loop. In this case,
= build_stmt_group (Statements (gnat_node), true);
TREE_SIDE_EFFECTS (gnu_loop_stmt) = 1;
- /* If we declared a variable, then we are in a statement group for that
- declaration. Add the LOOP_STMT to it and make that the "loop". */
- if (gnu_loop_var)
+ /* If we have an iteration scheme, then we are in a statement group. Add
+ the LOOP_STMT to it, finish it and make it the "loop". */
+ if (Present (gnat_iter_scheme) && No (Condition (gnat_iter_scheme)))
{
add_stmt (gnu_loop_stmt);
gnat_poplevel ();
return;
establish_stmt
- = build_call_1_expr (vms_builtin_establish_handler_decl,
+ = build_call_n_expr (vms_builtin_establish_handler_decl, 1,
build_unary_op
(ADDR_EXPR, NULL_TREE,
gnat_vms_condition_handler_decl));
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));
+ const bool is_true_formal_parm
+ = gnu_formal && TREE_CODE (gnu_formal) == PARM_DECL;
/* In the Out or In Out case, we must suppress conversions that yield
an lvalue but can nevertheless cause the creation of a temporary,
because we need the real object in this case, either to pass its
We do it in the In case too, except for an unchecked conversion
because it alone can cause the actual to be misaligned and the
addressability test is applied to the real object. */
- bool suppress_type_conversion
+ const bool suppress_type_conversion
= ((Nkind (gnat_actual) == N_Unchecked_Type_Conversion
&& Ekind (gnat_formal) != E_In_Parameter)
|| (Nkind (gnat_actual) == N_Type_Conversion
/* If we are passing a non-addressable parameter by reference, pass the
address of a copy. In the Out or In Out case, set up to copy back
out after the call. */
- if (gnu_formal
+ if (is_true_formal_parm
&& (DECL_BY_REF_P (gnu_formal)
- || (TREE_CODE (gnu_formal) == PARM_DECL
- && (DECL_BY_COMPONENT_PTR_P (gnu_formal)
- || (DECL_BY_DESCRIPTOR_P (gnu_formal)))))
+ || DECL_BY_COMPONENT_PTR_P (gnu_formal)
+ || DECL_BY_DESCRIPTOR_P (gnu_formal))
&& (gnu_name_type = gnat_to_gnu_type (Etype (gnat_name)))
&& !addressable_p (gnu_name, gnu_name_type))
{
/* 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 parameter is passed by reference. */
- if (gnu_formal
- && TREE_CODE (gnu_formal) == PARM_DECL
- && DECL_BY_REF_P (gnu_formal))
+ if (is_true_formal_parm && DECL_BY_REF_P (gnu_formal))
{
if (Ekind (gnat_formal) != E_In_Parameter)
{
gnu_actual = build_unary_op (ADDR_EXPR, gnu_formal_type, gnu_actual);
}
- else if (gnu_formal
- && TREE_CODE (gnu_formal) == PARM_DECL
- && DECL_BY_COMPONENT_PTR_P (gnu_formal))
+ else if (is_true_formal_parm && DECL_BY_COMPONENT_PTR_P (gnu_formal))
{
gnu_formal_type = TREE_TYPE (gnu_formal);
gnu_actual = maybe_implicit_deref (gnu_actual);
but this is the most likely to work in all cases. */
gnu_actual = build_unary_op (ADDR_EXPR, gnu_formal_type, gnu_actual);
}
- else if (gnu_formal
- && TREE_CODE (gnu_formal) == PARM_DECL
- && DECL_BY_DESCRIPTOR_P (gnu_formal))
+ else if (is_true_formal_parm && DECL_BY_DESCRIPTOR_P (gnu_formal))
{
gnu_actual = convert (gnu_formal_type, gnu_actual);
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 (!is_true_formal_parm)
{
/* Make sure side-effects are evaluated before the call. */
if (TREE_SIDE_EFFECTS (gnu_name))
the setjmp buf known for any decls in this block. */
if (setjmp_longjmp)
{
- gnu_jmpsave_decl = create_var_decl (get_identifier ("JMPBUF_SAVE"),
- NULL_TREE, jmpbuf_ptr_type,
- build_call_0_expr (get_jmpbuf_decl),
- false, false, false, false,
- NULL, gnat_node);
+ gnu_jmpsave_decl
+ = create_var_decl (get_identifier ("JMPBUF_SAVE"), NULL_TREE,
+ jmpbuf_ptr_type,
+ build_call_n_expr (get_jmpbuf_decl, 0),
+ false, false, false, false, NULL, gnat_node);
DECL_ARTIFICIAL (gnu_jmpsave_decl) = 1;
/* The __builtin_setjmp receivers will immediately reinstall it. Now
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,
- NULL, gnat_node);
+ gnu_jmpbuf_decl
+ = create_var_decl (get_identifier ("JMP_BUF"), NULL_TREE,
+ jmpbuf_type,
+ NULL_TREE,
+ false, false, false, false, NULL, gnat_node);
DECL_ARTIFICIAL (gnu_jmpbuf_decl) = 1;
set_block_jmpbuf_decl (gnu_jmpbuf_decl);
/* When we exit this block, restore the saved value. */
- add_cleanup (build_call_1_expr (set_jmpbuf_decl, gnu_jmpsave_decl),
+ add_cleanup (build_call_n_expr (set_jmpbuf_decl, 1, gnu_jmpsave_decl),
End_Label (gnat_node));
}
to the binding level we made above. Note that add_cleanup is FIFO
so we must register this cleanup after the EH cleanup just above. */
if (at_end)
- add_cleanup (build_call_0_expr (gnat_to_gnu (At_End_Proc (gnat_node))),
+ add_cleanup (build_call_n_expr (gnat_to_gnu (At_End_Proc (gnat_node)), 0),
End_Label (gnat_node));
/* Now build the tree for the declarations and statements inside this block.
start_stmt_group ();
if (setjmp_longjmp)
- add_stmt (build_call_1_expr (set_jmpbuf_decl,
+ add_stmt (build_call_n_expr (set_jmpbuf_decl, 1,
build_unary_op (ADDR_EXPR, NULL_TREE,
gnu_jmpbuf_decl)));
VEC_safe_push (tree, gc, gnu_except_ptr_stack,
create_var_decl (get_identifier ("EXCEPT_PTR"), NULL_TREE,
build_pointer_type (except_type_node),
- build_call_0_expr (get_excptr_decl),
+ build_call_n_expr (get_excptr_decl, 0),
false, false, false, false,
NULL, gnat_node));
/* If none of the exception handlers did anything, re-raise but do not
defer abortion. */
- gnu_expr = build_call_1_expr (raise_nodefer_decl,
+ gnu_expr = build_call_n_expr (raise_nodefer_decl, 1,
VEC_last (tree, gnu_except_ptr_stack));
set_expr_location_from_node
(gnu_expr,
/* If the setjmp returns 1, we restore our incoming longjmp value and
then check the handlers. */
start_stmt_group ();
- add_stmt_with_node (build_call_1_expr (set_jmpbuf_decl,
+ add_stmt_with_node (build_call_n_expr (set_jmpbuf_decl, 1,
gnu_jmpsave_decl),
gnat_node);
add_stmt (gnu_handler);
/* This block is now "if (setjmp) ... <handlers> else <block>". */
gnu_result = build3 (COND_EXPR, void_type_node,
- (build_call_1_expr
- (setjmp_decl,
+ (build_call_n_expr
+ (setjmp_decl, 1,
build_unary_op (ADDR_EXPR, NULL_TREE,
gnu_jmpbuf_decl))),
gnu_handler, gnu_inner_block);
false, false, false, false,
NULL, gnat_node);
- add_stmt_with_node (build_call_1_expr (begin_handler_decl,
+ add_stmt_with_node (build_call_n_expr (begin_handler_decl, 1,
gnu_incoming_exc_ptr),
gnat_node);
/* ??? We don't seem to have an End_Label at hand to set the location. */
- add_cleanup (build_call_1_expr (end_handler_decl, gnu_incoming_exc_ptr),
+ add_cleanup (build_call_n_expr (end_handler_decl, 1, gnu_incoming_exc_ptr),
Empty);
add_stmt_list (Statements (gnat_node));
gnat_poplevel ();
add_stmt (build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_incoming_exc_ptr,
convert (ptr_type_node, integer_zero_node)));
- add_stmt (build_call_1_expr (reraise_zcx_decl, gnu_expr));
+ add_stmt (build_call_n_expr (reraise_zcx_decl, 1, gnu_expr));
gnat_poplevel ();
gnu_result = end_stmt_group ();
break;
{
const int reason = UI_To_Int (Reason (gnat_node));
const Node_Id cond = Condition (gnat_node);
- bool handled = false;
if (type_annotate_only)
{
if (Exception_Extra_Info
&& !No_Exception_Handlers_Set ()
&& !get_exception_label (kind)
- && TREE_CODE (gnu_result_type) == VOID_TYPE
+ && VOID_TYPE_P (gnu_result_type)
&& Present (cond))
- {
- if (reason == CE_Access_Check_Failed)
- {
- gnu_result = build_call_raise_column (reason, gnat_node);
- handled = true;
- }
- else if ((reason == CE_Index_Check_Failed
- || reason == CE_Range_Check_Failed
- || reason == CE_Invalid_Data)
- && Nkind (cond) == N_Op_Not
- && Nkind (Right_Opnd (cond)) == N_In
- && Nkind (Right_Opnd (Right_Opnd (cond))) == N_Range)
- {
- Node_Id op = Right_Opnd (cond); /* N_In node */
- Node_Id index = Left_Opnd (op);
- Node_Id type = Etype (index);
+ switch (reason)
+ {
+ case CE_Access_Check_Failed:
+ gnu_result = build_call_raise_column (reason, gnat_node);
+ break;
- if (Is_Type (type)
- && Known_Esize (type)
- && UI_To_Int (Esize (type)) <= 32)
- {
- Node_Id right_op = Right_Opnd (op);
+ case CE_Index_Check_Failed:
+ case CE_Range_Check_Failed:
+ case CE_Invalid_Data:
+ if (Nkind (cond) == N_Op_Not
+ && Nkind (Right_Opnd (cond)) == N_In
+ && Nkind (Right_Opnd (Right_Opnd (cond))) == N_Range)
+ {
+ Node_Id op = Right_Opnd (cond); /* N_In node */
+ Node_Id index = Left_Opnd (op);
+ Node_Id range = Right_Opnd (op);
+ Node_Id type = Etype (index);
+ if (Is_Type (type)
+ && Known_Esize (type)
+ && UI_To_Int (Esize (type)) <= 32)
gnu_result
- = build_call_raise_range
- (reason, gnat_node,
- gnat_to_gnu (index), /* index */
- gnat_to_gnu (Low_Bound (right_op)), /* first */
- gnat_to_gnu (High_Bound (right_op))); /* last */
- handled = true;
- }
- }
+ = build_call_raise_range (reason, gnat_node,
+ gnat_to_gnu (index),
+ gnat_to_gnu
+ (Low_Bound (range)),
+ gnat_to_gnu
+ (High_Bound (range)));
+ }
+ break;
+
+ default:
+ break;
}
- if (handled)
+ if (gnu_result == error_mark_node)
+ gnu_result = build_call_raise (reason, gnat_node, kind);
+
+ set_expr_location_from_node (gnu_result, 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 is one. */
+ if (VOID_TYPE_P (gnu_result_type))
{
- set_expr_location_from_node (gnu_result, gnat_node);
- gnu_result = build3 (COND_EXPR, void_type_node,
- gnat_to_gnu (cond),
- gnu_result, alloc_stmt_list ());
+ if (Present (cond))
+ gnu_result
+ = build3 (COND_EXPR, void_type_node, gnat_to_gnu (cond),
+ gnu_result, alloc_stmt_list ());
}
else
- {
- gnu_result = build_call_raise (reason, gnat_node, kind);
-
- /* If the type is VOID, this is a statement, so we need to generate
- the code for the call. Handle a Condition, if there is one. */
- if (TREE_CODE (gnu_result_type) == VOID_TYPE)
- {
- set_expr_location_from_node (gnu_result, gnat_node);
- if (Present (cond))
- gnu_result = build3 (COND_EXPR, void_type_node,
- gnat_to_gnu (cond),
- gnu_result, alloc_stmt_list ());
- }
- else
- gnu_result = build1 (NULL_EXPR, gnu_result_type, gnu_result);
- }
+ gnu_result = build1 (NULL_EXPR, gnu_result_type, gnu_result);
}
break;
return GS_UNHANDLED;
+ case VIEW_CONVERT_EXPR:
+ op = TREE_OPERAND (expr, 0);
+
+ /* If we are view-converting a CONSTRUCTOR or a call from an aggregate
+ type to a scalar one, explicitly create the local temporary. That's
+ required if the type is passed by reference. */
+ if ((TREE_CODE (op) == CONSTRUCTOR || TREE_CODE (op) == CALL_EXPR)
+ && AGGREGATE_TYPE_P (TREE_TYPE (op))
+ && !AGGREGATE_TYPE_P (TREE_TYPE (expr)))
+ {
+ tree mod, new_var = create_tmp_var_raw (TREE_TYPE (op), "C");
+ 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;
+ return GS_OK;
+ }
+
+ return GS_UNHANDLED;
+
case DECL_EXPR:
op = DECL_EXPR_DECL (expr);
{
tree int_64 = gnat_type_for_size (64, 0);
- return convert (gnu_type, build_call_2_expr (mulv64_decl,
+ return convert (gnu_type, build_call_n_expr (mulv64_decl, 2,
convert (int_64, lhs),
convert (int_64, rhs)));
}
}
}
\f
-/* 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. */
+/* GNAT_ENTITY is the type of the resulting constructor, GNAT_ASSOC is the
+ front of the Component_Associations of an N_Aggregate and GNU_TYPE is the
+ GCC type of the corresponding record type. Return the CONSTRUCTOR. */
static tree
assoc_to_constructor (Entity_Id gnat_entity, Node_Id gnat_assoc, tree gnu_type)
{
- tree gnu_list, gnu_result;
+ tree gnu_list = NULL_TREE, gnu_result;
/* We test for GNU_FIELD being empty in the case where a variant
was the last thing since we don't take things off GNAT_ASSOC in
that case. We check GNAT_ASSOC in case we have a variant, but it
has no fields. */
- for (gnu_list = NULL_TREE; Present (gnat_assoc);
- gnat_assoc = Next (gnat_assoc))
+ for (; Present (gnat_assoc); gnat_assoc = Next (gnat_assoc))
{
Node_Id gnat_field = First (Choices (gnat_assoc));
tree gnu_field = gnat_to_gnu_field_decl (Entity (gnat_field));
continue;
/* Also ignore discriminants of Unchecked_Unions. */
- else if (Is_Unchecked_Union (gnat_entity)
- && Ekind (Entity (gnat_field)) == E_Discriminant)
+ if (Is_Unchecked_Union (gnat_entity)
+ && Ekind (Entity (gnat_field)) == E_Discriminant)
continue;
/* Before assigning a value in an aggregate make sure range checks
gnu_result = extract_values (gnu_list, gnu_type);
#ifdef ENABLE_CHECKING
- {
- tree gnu_field;
-
- /* 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));
- }
+ /* Verify that every entry in GNU_LIST was used. */
+ for (; gnu_list; gnu_list = TREE_CHAIN (gnu_list))
+ gcc_assert (TREE_ADDRESSABLE (gnu_list));
#endif
return gnu_result;