diff options
Diffstat (limited to 'gcc/fortran/resolve.c')
-rw-r--r-- | gcc/fortran/resolve.c | 209 |
1 files changed, 147 insertions, 62 deletions
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index c3aaf87c0c9..aee04eccd6c 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -910,6 +910,147 @@ resolve_actual_arglist (gfc_actual_arglist * arg) } +/* Do the checks of the actual argument list that are specific to elemental + procedures. If called with c == NULL, we have a function, otherwise if + expr == NULL, we have a subroutine. */ +static try +resolve_elemental_actual (gfc_expr *expr, gfc_code *c) +{ + gfc_actual_arglist *arg0; + gfc_actual_arglist *arg; + gfc_symbol *esym = NULL; + gfc_intrinsic_sym *isym = NULL; + gfc_expr *e = NULL; + gfc_intrinsic_arg *iformal = NULL; + gfc_formal_arglist *eformal = NULL; + bool formal_optional = false; + bool set_by_optional = false; + int i; + int rank = 0; + + /* Is this an elemental procedure? */ + if (expr && expr->value.function.actual != NULL) + { + if (expr->value.function.esym != NULL + && expr->value.function.esym->attr.elemental) + { + arg0 = expr->value.function.actual; + esym = expr->value.function.esym; + } + else if (expr->value.function.isym != NULL + && expr->value.function.isym->elemental) + { + arg0 = expr->value.function.actual; + isym = expr->value.function.isym; + } + else + return SUCCESS; + } + else if (c && c->ext.actual != NULL + && c->symtree->n.sym->attr.elemental) + { + arg0 = c->ext.actual; + esym = c->symtree->n.sym; + } + else + return SUCCESS; + + /* The rank of an elemental is the rank of its array argument(s). */ + for (arg = arg0; arg; arg = arg->next) + { + if (arg->expr != NULL && arg->expr->rank > 0) + { + rank = arg->expr->rank; + if (arg->expr->expr_type == EXPR_VARIABLE + && arg->expr->symtree->n.sym->attr.optional) + set_by_optional = true; + + /* Function specific; set the result rank and shape. */ + if (expr) + { + expr->rank = rank; + if (!expr->shape && arg->expr->shape) + { + expr->shape = gfc_get_shape (rank); + for (i = 0; i < rank; i++) + mpz_init_set (expr->shape[i], arg->expr->shape[i]); + } + } + break; + } + } + + /* If it is an array, it shall not be supplied as an actual argument + to an elemental procedure unless an array of the same rank is supplied + as an actual argument corresponding to a nonoptional dummy argument of + that elemental procedure(12.4.1.5). */ + formal_optional = false; + if (isym) + iformal = isym->formal; + else + eformal = esym->formal; + + for (arg = arg0; arg; arg = arg->next) + { + if (eformal) + { + if (eformal->sym && eformal->sym->attr.optional) + formal_optional = true; + eformal = eformal->next; + } + else if (isym && iformal) + { + if (iformal->optional) + formal_optional = true; + iformal = iformal->next; + } + else if (isym) + formal_optional = true; + + if (arg->expr != NULL + && arg->expr->expr_type == EXPR_VARIABLE + && arg->expr->symtree->n.sym->attr.optional + && formal_optional + && arg->expr->rank + && (set_by_optional || arg->expr->rank != rank)) + { + gfc_error ("'%s' at %L is an array and OPTIONAL; it cannot " + "therefore be an actual argument of an ELEMENTAL " + "procedure unless there is a non-optional argument " + "with the same rank (12.4.1.5)", + arg->expr->symtree->n.sym->name, &arg->expr->where); + return FAILURE; + } + } + + for (arg = arg0; arg; arg = arg->next) + { + if (arg->expr == NULL || arg->expr->rank == 0) + continue; + + /* Being elemental, the last upper bound of an assumed size array + argument must be present. */ + if (resolve_assumed_size_actual (arg->expr)) + return FAILURE; + + if (expr) + continue; + + /* Elemental subroutine array actual arguments must conform. */ + if (e != NULL) + { + if (gfc_check_conformance ("elemental subroutine", arg->expr, e) + == FAILURE) + return FAILURE; + } + else + e = arg->expr; + } + + return SUCCESS; +} + + /* Go through each actual argument in ACTUAL and see if it can be implemented as an inlined, non-copying intrinsic. FNSYM is the function being called, or NULL if not known. */ @@ -1237,7 +1378,6 @@ resolve_function (gfc_expr * expr) const char *name; try t; int temp; - int i; sym = NULL; if (expr->symtree) @@ -1313,38 +1453,9 @@ resolve_function (gfc_expr * expr) temp = need_full_assumed_size; need_full_assumed_size = 0; - if (expr->value.function.actual != NULL - && ((expr->value.function.esym != NULL - && expr->value.function.esym->attr.elemental) - || (expr->value.function.isym != NULL - && expr->value.function.isym->elemental))) - { - /* The rank of an elemental is the rank of its array argument(s). */ - for (arg = expr->value.function.actual; arg; arg = arg->next) - { - if (arg->expr != NULL && arg->expr->rank > 0) - { - expr->rank = arg->expr->rank; - if (!expr->shape && arg->expr->shape) - { - expr->shape = gfc_get_shape (expr->rank); - for (i = 0; i < expr->rank; i++) - mpz_init_set (expr->shape[i], arg->expr->shape[i]); - } - break; - } - } + if (resolve_elemental_actual (expr, NULL) == FAILURE) + return FAILURE; - /* Being elemental, the last upper bound of an assumed size array - argument must be present. */ - for (arg = expr->value.function.actual; arg; arg = arg->next) - { - if (arg->expr != NULL - && arg->expr->rank > 0 - && resolve_assumed_size_actual (arg->expr)) - return FAILURE; - } - } if (omp_workshare_flag && expr->value.function.esym && ! gfc_elemental (expr->value.function.esym)) @@ -1500,7 +1611,7 @@ resolve_generic_s (gfc_code * c) if (m == MATCH_ERROR) return FAILURE; - if (sym->ns->parent != NULL) + if (sym->ns->parent != NULL && !sym->attr.use_assoc) { gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); if (sym != NULL) @@ -1730,35 +1841,9 @@ resolve_call (gfc_code * c) gfc_internal_error ("resolve_subroutine(): bad function type"); } - /* Some checks of elemental subroutines. */ - if (c->ext.actual != NULL - && c->symtree->n.sym->attr.elemental) - { - gfc_actual_arglist * a; - gfc_expr * e; - e = NULL; - - for (a = c->ext.actual; a; a = a->next) - { - if (a->expr == NULL || a->expr->rank == 0) - continue; - - /* The last upper bound of an assumed size array argument must - be present. */ - if (resolve_assumed_size_actual (a->expr)) - return FAILURE; - - /* Array actual arguments must conform. */ - if (e != NULL) - { - if (gfc_check_conformance ("elemental subroutine", a->expr, e) - == FAILURE) - return FAILURE; - } - else - e = a->expr; - } - } + /* Some checks of elemental subroutine actual arguments. */ + if (resolve_elemental_actual (NULL, c) == FAILURE) + return FAILURE; if (t == SUCCESS) find_noncopying_intrinsics (c->resolved_sym, c->ext.actual); |