diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-01-05 11:46:08 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-01-05 11:46:08 +0000 |
commit | d6f0c24648ff2f75aaa61552a5266089c3032178 (patch) | |
tree | a4affa22648b7f93d8a2072095e0862c373fc03b /gcc/fortran/trans-array.c | |
parent | 719b3a0366d1c59d33bee3525b1fa118e76eb6ab (diff) | |
download | gcc-d6f0c24648ff2f75aaa61552a5266089c3032178.tar.gz |
2012-01-05 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 182904 using svnmerge
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@182905 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran/trans-array.c')
-rw-r--r-- | gcc/fortran/trans-array.c | 59 |
1 files changed, 53 insertions, 6 deletions
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 50e1ee422f9..494721ee476 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -2422,10 +2422,21 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript, break; case GFC_SS_REFERENCE: - /* Scalar argument to elemental procedure. Evaluate this - now. */ + /* Scalar argument to elemental procedure. */ gfc_init_se (&se, NULL); - gfc_conv_expr (&se, expr); + if (ss_info->data.scalar.can_be_null_ref) + { + /* If the actual argument can be absent (in other words, it can + be a NULL reference), don't try to evaluate it; pass instead + the reference directly. */ + gfc_conv_expr_reference (&se, expr); + } + else + { + /* Otherwise, evaluate the argument outside the loop and pass + a reference to the value. */ + gfc_conv_expr (&se, expr); + } gfc_add_block_to_block (&outer_loop->pre, &se.pre); gfc_add_block_to_block (&outer_loop->post, &se.post); if (gfc_is_class_scalar_expr (expr)) @@ -8296,12 +8307,16 @@ gfc_reverse_ss (gfc_ss * ss) } -/* Walk the arguments of an elemental function. */ +/* Walk the arguments of an elemental function. + PROC_EXPR is used to check whether an argument is permitted to be absent. If + it is NULL, we don't do the check and the argument is assumed to be present. +*/ gfc_ss * gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, - gfc_ss_type type) + gfc_expr *proc_expr, gfc_ss_type type) { + gfc_formal_arglist *dummy_arg; int scalar; gfc_ss *head; gfc_ss *tail; @@ -8309,6 +8324,28 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, head = gfc_ss_terminator; tail = NULL; + + if (proc_expr) + { + gfc_ref *ref; + + /* Normal procedure case. */ + dummy_arg = proc_expr->symtree->n.sym->formal; + + /* Typebound procedure case. */ + for (ref = proc_expr->ref; ref; ref = ref->next) + { + if (ref->type == REF_COMPONENT + && ref->u.c.component->attr.proc_pointer + && ref->u.c.component->ts.interface) + dummy_arg = ref->u.c.component->ts.interface->formal; + else + dummy_arg = NULL; + } + } + else + dummy_arg = NULL; + scalar = 1; for (; arg; arg = arg->next) { @@ -8322,6 +8359,13 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, gcc_assert (type == GFC_SS_SCALAR || type == GFC_SS_REFERENCE); newss = gfc_get_scalar_ss (head, arg->expr); newss->info->type = type; + + if (dummy_arg != NULL + && dummy_arg->sym->attr.optional + && arg->expr->symtree + && arg->expr->symtree->n.sym->attr.optional + && arg->expr->ref == NULL) + newss->info->data.scalar.can_be_null_ref = true; } else scalar = 0; @@ -8333,6 +8377,9 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, while (tail->next != gfc_ss_terminator) tail = tail->next; } + + if (dummy_arg != NULL) + dummy_arg = dummy_arg->next; } if (scalar) @@ -8382,7 +8429,7 @@ gfc_walk_function_expr (gfc_ss * ss, gfc_expr * expr) by reference. */ if (sym->attr.elemental || (comp && comp->attr.elemental)) return gfc_walk_elemental_function_args (ss, expr->value.function.actual, - GFC_SS_REFERENCE); + expr, GFC_SS_REFERENCE); /* Scalar functions are OK as these are evaluated outside the scalarization loop. Pass back and let the caller deal with it. */ |