aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-expr.c
diff options
context:
space:
mode:
authorPaul Thomas <pault@gcc.gnu.org>2006-01-21 09:08:54 +0000
committerPaul Thomas <pault@gcc.gnu.org>2006-01-21 09:08:54 +0000
commit68ea355b5d9b51b994e0780d8392f7542262072f (patch)
treed96186ed49727fa545b68d7e5eaffe6789ccb236 /gcc/fortran/trans-expr.c
parent4e27a177f8a488fc1f9a3462672582715e164f0d (diff)
downloadgcc-68ea355b5d9b51b994e0780d8392f7542262072f.zip
gcc-68ea355b5d9b51b994e0780d8392f7542262072f.tar.gz
gcc-68ea355b5d9b51b994e0780d8392f7542262072f.tar.bz2
PR25024, PR20881, PR23308, PR25538 and PR25710 - Procedure references
2005-01-21 Paul Thomas <pault@gcc.gnu.org> PR fortran/25124 PR fortran/25625 * decl.c (get_proc_name): If there is an existing symbol in the encompassing namespace, call errors if it is a procedure of the same name or the kind field is set, indicating a type declaration. PR fortran/20881 PR fortran/23308 PR fortran/25538 PR fortran/25710 * decl.c (add_global_entry): New function to check for existing global symbol with this name and to create new one if none exists. (gfc_match_entry): Call add_global_entry before matching argument lists for subroutine and function entries. * gfortran.h: Prototype for existing function, global_used. * resolve.c (resolve_global_procedure): New function to check global symbols for procedures. (resolve_call, resolve_function): Calls to this new function for non-contained and non-module procedures. * match.c (match_common): Add check for existing global symbol, creat one if none exists and emit error if there is a clash. * parse.c (global_used): Remove static and use the gsymbol name rather than the new_block name, so that the function can be called from resolve.c. (parse_block_data, parse_module, add_global_procedure): Improve checks for existing gsymbols. Emit error if already defined or if references were to another type. Set defined flag. PR fortran/PR24276 * trans-expr.c (gfc_conv_aliased_arg): New function called by gfc_conv_function_call that coverts an expression for an aliased component reference to a derived type array into a temporary array of the same type as the component. The temporary is passed as an actual argument for the procedure call and is copied back to the derived type after the call. (is_aliased_array): New function that detects an array reference that is followed by a component reference. (gfc_conv_function_call): Detect an aliased actual argument with is_aliased_array and convert it to a temporary and back again using gfc_conv_aliased_arg. 2005-01-21 Paul Thomas <pault@gcc.gnu.org> PR fortran/25124 PR fortran/25625 * gfortran.dg/internal_references_1.f90: New test. PR fortran/20881 PR fortran/23308 PR fortran/25538 PR fortran/25710 * gfortran.dg/global_references_1.f90: New test. * gfortran.dg/g77/19990905-1.f: Restore the error that there is a clash between the common block name and the name of a subroutine reference. PR fortran/PR24276 * gfortran.dg/aliasing_dummy_1.f90: New test. From-SVN: r110063
Diffstat (limited to 'gcc/fortran/trans-expr.c')
-rw-r--r--gcc/fortran/trans-expr.c230
1 files changed, 229 insertions, 1 deletions
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 880994a..b30a121 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -1529,6 +1529,226 @@ gfc_apply_interface_mapping (gfc_interface_mapping * mapping,
gfc_free_expr (expr);
}
+/* Returns a reference to a temporary array into which a component of
+ an actual argument derived type array is copied and then returned
+ after the function call.
+ TODO Get rid of this kludge, when array descriptors are capable of
+ handling aliased arrays. */
+
+static void
+gfc_conv_aliased_arg (gfc_se * parmse, gfc_expr * expr, int g77)
+{
+ gfc_se lse;
+ gfc_se rse;
+ gfc_ss *lss;
+ gfc_ss *rss;
+ gfc_loopinfo loop;
+ gfc_loopinfo loop2;
+ gfc_ss_info *info;
+ tree offset;
+ tree tmp_index;
+ tree tmp;
+ tree base_type;
+ stmtblock_t body;
+ int n;
+
+ gcc_assert (expr->expr_type == EXPR_VARIABLE);
+
+ gfc_init_se (&lse, NULL);
+ gfc_init_se (&rse, NULL);
+
+ /* Walk the argument expression. */
+ rss = gfc_walk_expr (expr);
+
+ gcc_assert (rss != gfc_ss_terminator);
+
+ /* Initialize the scalarizer. */
+ gfc_init_loopinfo (&loop);
+ gfc_add_ss_to_loop (&loop, rss);
+
+ /* Calculate the bounds of the scalarization. */
+ gfc_conv_ss_startstride (&loop);
+
+ /* Build an ss for the temporary. */
+ base_type = gfc_typenode_for_spec (&expr->ts);
+ if (GFC_ARRAY_TYPE_P (base_type)
+ || GFC_DESCRIPTOR_TYPE_P (base_type))
+ base_type = gfc_get_element_type (base_type);
+
+ loop.temp_ss = gfc_get_ss ();;
+ loop.temp_ss->type = GFC_SS_TEMP;
+ loop.temp_ss->data.temp.type = base_type;
+
+ if (expr->ts.type == BT_CHARACTER)
+ loop.temp_ss->string_length = expr->ts.cl->backend_decl;
+
+ loop.temp_ss->data.temp.dimen = loop.dimen;
+ loop.temp_ss->next = gfc_ss_terminator;
+
+ /* Associate the SS with the loop. */
+ gfc_add_ss_to_loop (&loop, loop.temp_ss);
+
+ /* Setup the scalarizing loops. */
+ gfc_conv_loop_setup (&loop);
+
+ /* Pass the temporary descriptor back to the caller. */
+ info = &loop.temp_ss->data.info;
+ parmse->expr = info->descriptor;
+
+ /* Setup the gfc_se structures. */
+ gfc_copy_loopinfo_to_se (&lse, &loop);
+ gfc_copy_loopinfo_to_se (&rse, &loop);
+
+ rse.ss = rss;
+ lse.ss = loop.temp_ss;
+ gfc_mark_ss_chain_used (rss, 1);
+ gfc_mark_ss_chain_used (loop.temp_ss, 1);
+
+ /* Start the scalarized loop body. */
+ gfc_start_scalarized_body (&loop, &body);
+
+ /* Translate the expression. */
+ gfc_conv_expr (&rse, expr);
+
+ gfc_conv_tmp_array_ref (&lse);
+ gfc_advance_se_ss_chain (&lse);
+
+ tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts.type);
+ gfc_add_expr_to_block (&body, tmp);
+
+ gcc_assert (rse.ss == gfc_ss_terminator);
+
+ gfc_trans_scalarizing_loops (&loop, &body);
+
+ /* Add the post block after the second loop, so that any
+ freeing of allocated memory is done at the right time. */
+ gfc_add_block_to_block (&parmse->pre, &loop.pre);
+
+ /**********Copy the temporary back again.*********/
+
+ gfc_init_se (&lse, NULL);
+ gfc_init_se (&rse, NULL);
+
+ /* Walk the argument expression. */
+ lss = gfc_walk_expr (expr);
+ rse.ss = loop.temp_ss;
+ lse.ss = lss;
+
+ /* Initialize the scalarizer. */
+ gfc_init_loopinfo (&loop2);
+ gfc_add_ss_to_loop (&loop2, lss);
+
+ /* Calculate the bounds of the scalarization. */
+ gfc_conv_ss_startstride (&loop2);
+
+ /* Setup the scalarizing loops. */
+ gfc_conv_loop_setup (&loop2);
+
+ gfc_copy_loopinfo_to_se (&lse, &loop2);
+ gfc_copy_loopinfo_to_se (&rse, &loop2);
+
+ gfc_mark_ss_chain_used (lss, 1);
+ gfc_mark_ss_chain_used (loop.temp_ss, 1);
+
+ /* Declare the variable to hold the temporary offset and start the
+ scalarized loop body. */
+ offset = gfc_create_var (gfc_array_index_type, NULL);
+ gfc_start_scalarized_body (&loop2, &body);
+
+ /* Build the offsets for the temporary from the loop variables. The
+ temporary array has lbounds of zero and strides of one in all
+ dimensions, so this is very simple. The offset is only computed
+ outside the innermost loop, so the overall transfer could be
+ optimised further. */
+ info = &rse.ss->data.info;
+
+ tmp_index = gfc_index_zero_node;
+ for (n = info->dimen - 1; n > 0; n--)
+ {
+ tree tmp_str;
+ tmp = rse.loop->loopvar[n];
+ tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+ tmp, rse.loop->from[n]);
+ tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+ tmp, tmp_index);
+
+ tmp_str = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+ rse.loop->to[n-1], rse.loop->from[n-1]);
+ tmp_str = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+ tmp_str, gfc_index_one_node);
+
+ tmp_index = fold_build2 (MULT_EXPR, gfc_array_index_type,
+ tmp, tmp_str);
+ }
+
+ tmp_index = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+ tmp_index, rse.loop->from[0]);
+ gfc_add_modify_expr (&rse.loop->code[0], offset, tmp_index);
+
+ tmp_index = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+ rse.loop->loopvar[0], offset);
+
+ /* Now use the offset for the reference. */
+ tmp = build_fold_indirect_ref (info->data);
+ rse.expr = gfc_build_array_ref (tmp, tmp_index);
+
+ if (expr->ts.type == BT_CHARACTER)
+ rse.string_length = expr->ts.cl->backend_decl;
+
+ gfc_conv_expr (&lse, expr);
+
+ gcc_assert (lse.ss == gfc_ss_terminator);
+
+ tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts.type);
+ gfc_add_expr_to_block (&body, tmp);
+
+ /* Generate the copying loops. */
+ gfc_trans_scalarizing_loops (&loop2, &body);
+
+ /* Wrap the whole thing up by adding the second loop to the post-block
+ and following it by the post-block of the fist loop. In this way,
+ if the temporary needs freeing, it is done after use! */
+ gfc_add_block_to_block (&parmse->post, &loop2.pre);
+ gfc_add_block_to_block (&parmse->post, &loop2.post);
+
+ gfc_add_block_to_block (&parmse->post, &loop.post);
+
+ gfc_cleanup_loop (&loop);
+ gfc_cleanup_loop (&loop2);
+
+ /* Pass the string length to the argument expression. */
+ if (expr->ts.type == BT_CHARACTER)
+ parmse->string_length = expr->ts.cl->backend_decl;
+
+ /* We want either the address for the data or the address of the descriptor,
+ depending on the mode of passing array arguments. */
+ if (g77)
+ parmse->expr = gfc_conv_descriptor_data_get (parmse->expr);
+ else
+ parmse->expr = build_fold_addr_expr (parmse->expr);
+
+ return;
+}
+
+/* Is true if the last array reference is followed by a component reference. */
+
+static bool
+is_aliased_array (gfc_expr * e)
+{
+ gfc_ref * ref;
+ bool seen_array;
+
+ seen_array = false;
+ for (ref = e->ref; ref; ref = ref->next)
+ {
+ if (ref->type == REF_ARRAY)
+ seen_array = true;
+
+ if (ref->next == NULL && ref->type == REF_COMPONENT)
+ return seen_array;
+ }
+ return false;
+}
/* Generate code for a procedure call. Note can return se->post != NULL.
If se->direct_byref is set then se->expr contains the return parameter.
@@ -1655,7 +1875,15 @@ gfc_conv_function_call (gfc_se * se, gfc_symbol * sym,
&& !formal->sym->attr.pointer
&& formal->sym->as->type != AS_ASSUMED_SHAPE;
f = f || !sym->attr.always_explicit;
- gfc_conv_array_parameter (&parmse, arg->expr, argss, f);
+ if (arg->expr->expr_type == EXPR_VARIABLE
+ && is_aliased_array (arg->expr))
+ /* The actual argument is a component reference to an
+ array of derived types. In this case, the argument
+ is converted to a temporary, which is passed and then
+ written back after the procedure call. */
+ gfc_conv_aliased_arg (&parmse, arg->expr, f);
+ else
+ gfc_conv_array_parameter (&parmse, arg->expr, argss, f);
}
}