diff options
Diffstat (limited to 'gcc/fortran/resolve.c')
-rw-r--r-- | gcc/fortran/resolve.c | 4435 |
1 files changed, 4435 insertions, 0 deletions
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c new file mode 100644 index 00000000000..cec47165c02 --- /dev/null +++ b/gcc/fortran/resolve.c @@ -0,0 +1,4435 @@ +/* Perform type resolution on the various stuctures. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "gfortran.h" +#include "arith.h" /* For gfc_compare_expr(). */ +#include <assert.h> +#include <string.h> + +/* Stack to push the current if we descend into a block during + resolution. See resolve_branch() and resolve_code(). */ + +typedef struct code_stack +{ + struct gfc_code *head, *current; + struct code_stack *prev; +} +code_stack; + +static code_stack *cs_base = NULL; + + +/* Nonzero if we're inside a FORALL block */ + +static int forall_flag; + +/* Resolve types of formal argument lists. These have to be done early so that + the formal argument lists of module procedures can be copied to the + containing module before the individual procedures are resolved + individually. We also resolve argument lists of procedures in interface + blocks because they are self-contained scoping units. + + Since a dummy argument cannot be a non-dummy procedure, the only + resort left for untyped names are the IMPLICIT types. */ + +static void +resolve_formal_arglist (gfc_symbol * proc) +{ + gfc_formal_arglist *f; + gfc_symbol *sym; + int i; + + /* TODO: Procedures whose return character length parameter is not constant + or assumed must also have explicit interfaces. */ + if (proc->result != NULL) + sym = proc->result; + else + sym = proc; + + if (gfc_elemental (proc) + || sym->attr.pointer || sym->attr.allocatable + || (sym->as && sym->as->rank > 0)) + proc->attr.always_explicit = 1; + + for (f = proc->formal; f; f = f->next) + { + sym = f->sym; + + if (sym == NULL) + { + /* Alternate return placeholder. */ + if (gfc_elemental (proc)) + gfc_error ("Alternate return specifier in elemental subroutine " + "'%s' at %L is not allowed", proc->name, + &proc->declared_at); + if (proc->attr.function) + gfc_error ("Alternate return specifier in function " + "'%s' at %L is not allowed", proc->name, + &proc->declared_at); + continue; + } + + if (sym->attr.if_source != IFSRC_UNKNOWN) + resolve_formal_arglist (sym); + + if (sym->attr.subroutine || sym->attr.external || sym->attr.intrinsic) + { + if (gfc_pure (proc) && !gfc_pure (sym)) + { + gfc_error + ("Dummy procedure '%s' of PURE procedure at %L must also " + "be PURE", sym->name, &sym->declared_at); + continue; + } + + if (gfc_elemental (proc)) + { + gfc_error + ("Dummy procedure at %L not allowed in ELEMENTAL procedure", + &sym->declared_at); + continue; + } + + continue; + } + + if (sym->ts.type == BT_UNKNOWN) + { + if (!sym->attr.function || sym->result == sym) + gfc_set_default_type (sym, 1, sym->ns); + else + { + /* Set the type of the RESULT, then copy. */ + if (sym->result->ts.type == BT_UNKNOWN) + gfc_set_default_type (sym->result, 1, sym->result->ns); + + sym->ts = sym->result->ts; + if (sym->as == NULL) + sym->as = gfc_copy_array_spec (sym->result->as); + } + } + + gfc_resolve_array_spec (sym->as, 0); + + /* We can't tell if an array with dimension (:) is assumed or deferred + shape until we know if it has the pointer or allocatable attributes. + */ + if (sym->as && sym->as->rank > 0 && sym->as->type == AS_DEFERRED + && !(sym->attr.pointer || sym->attr.allocatable)) + { + sym->as->type = AS_ASSUMED_SHAPE; + for (i = 0; i < sym->as->rank; i++) + sym->as->lower[i] = gfc_int_expr (1); + } + + if ((sym->as && sym->as->rank > 0 && sym->as->type == AS_ASSUMED_SHAPE) + || sym->attr.pointer || sym->attr.allocatable || sym->attr.target + || sym->attr.optional) + proc->attr.always_explicit = 1; + + /* If the flavor is unknown at this point, it has to be a variable. + A procedure specification would have already set the type. */ + + if (sym->attr.flavor == FL_UNKNOWN) + gfc_add_flavor (&sym->attr, FL_VARIABLE, &sym->declared_at); + + if (gfc_pure (proc)) + { + if (proc->attr.function && !sym->attr.pointer + && sym->attr.flavor != FL_PROCEDURE + && sym->attr.intent != INTENT_IN) + + gfc_error ("Argument '%s' of pure function '%s' at %L must be " + "INTENT(IN)", sym->name, proc->name, + &sym->declared_at); + + if (proc->attr.subroutine && !sym->attr.pointer + && sym->attr.intent == INTENT_UNKNOWN) + + gfc_error + ("Argument '%s' of pure subroutine '%s' at %L must have " + "its INTENT specified", sym->name, proc->name, + &sym->declared_at); + } + + + if (gfc_elemental (proc)) + { + if (sym->as != NULL) + { + gfc_error + ("Argument '%s' of elemental procedure at %L must be scalar", + sym->name, &sym->declared_at); + continue; + } + + if (sym->attr.pointer) + { + gfc_error + ("Argument '%s' of elemental procedure at %L cannot have " + "the POINTER attribute", sym->name, &sym->declared_at); + continue; + } + } + + /* Each dummy shall be specified to be scalar. */ + if (proc->attr.proc == PROC_ST_FUNCTION) + { + if (sym->as != NULL) + { + gfc_error + ("Argument '%s' of statement function at %L must be scalar", + sym->name, &sym->declared_at); + continue; + } + + if (sym->ts.type == BT_CHARACTER) + { + gfc_charlen *cl = sym->ts.cl; + if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT) + { + gfc_error + ("Character-valued argument '%s' of statement function at " + "%L must has constant length", + sym->name, &sym->declared_at); + continue; + } + } + } + } +} + + +/* Work function called when searching for symbols that have argument lists + associated with them. */ + +static void +find_arglists (gfc_symbol * sym) +{ + + if (sym->attr.if_source == IFSRC_UNKNOWN || sym->ns != gfc_current_ns) + return; + + resolve_formal_arglist (sym); +} + + +/* Given a namespace, resolve all formal argument lists within the namespace. + */ + +static void +resolve_formal_arglists (gfc_namespace * ns) +{ + + if (ns == NULL) + return; + + gfc_traverse_ns (ns, find_arglists); +} + + +/* Resolve contained function types. Because contained functions can call one + another, they have to be worked out before any of the contained procedures + can be resolved. + + The good news is that if a function doesn't already have a type, the only + way it can get one is through an IMPLICIT type or a RESULT variable, because + by definition contained functions are contained namespace they're contained + in, not in a sibling or parent namespace. */ + +static void +resolve_contained_functions (gfc_namespace * ns) +{ + gfc_symbol *contained_sym, *sym_lower; + gfc_namespace *child; + try t; + + resolve_formal_arglists (ns); + + for (child = ns->contained; child; child = child->sibling) + { + sym_lower = child->proc_name; + + /* If this namespace is not a function, ignore it. */ + if (! sym_lower + || !( sym_lower->attr.function + || sym_lower->attr.flavor == FL_VARIABLE)) + continue; + + /* Find the contained symbol in the current namespace. */ + gfc_find_symbol (sym_lower->name, ns, 0, &contained_sym); + + if (contained_sym == NULL) + gfc_internal_error ("resolve_contained_functions(): Contained " + "function not found in parent namespace"); + + /* Try to find out of what type the function is. If there was an + explicit RESULT clause, try to get the type from it. If the + function is never defined, set it to the implicit type. If + even that fails, give up. */ + if (sym_lower->result != NULL) + sym_lower = sym_lower->result; + + if (sym_lower->ts.type == BT_UNKNOWN) + { + /* Assume we can find an implicit type. */ + t = SUCCESS; + + if (sym_lower->result == NULL) + t = gfc_set_default_type (sym_lower, 0, child); + else + { + if (sym_lower->result->ts.type == BT_UNKNOWN) + t = gfc_set_default_type (sym_lower->result, 0, NULL); + + sym_lower->ts = sym_lower->result->ts; + } + + if (t == FAILURE) + gfc_error ("Contained function '%s' at %L has no IMPLICIT type", + sym_lower->name, &sym_lower->declared_at); /* FIXME */ + } + + /* If the symbol in the parent of the contained namespace is not + the same as the one in contained namespace itself, copy over + the type information. */ + /* ??? Shouldn't we replace the symbol with the parent symbol instead? */ + if (contained_sym != sym_lower) + { + contained_sym->ts = sym_lower->ts; + contained_sym->as = gfc_copy_array_spec (sym_lower->as); + } + } +} + + +/* Resolve all of the elements of a structure constructor and make sure that + the types are correct. */ + +static try +resolve_structure_cons (gfc_expr * expr) +{ + gfc_constructor *cons; + gfc_component *comp; + try t; + + t = SUCCESS; + cons = expr->value.constructor; + /* A constructor may have references if it is the result of substituting a + parameter variable. In this case we just pull out the component we + want. */ + if (expr->ref) + comp = expr->ref->u.c.sym->components; + else + comp = expr->ts.derived->components; + + for (; comp; comp = comp->next, cons = cons->next) + { + if (! cons->expr) + { + t = FAILURE; + continue; + } + + if (gfc_resolve_expr (cons->expr) == FAILURE) + { + t = FAILURE; + continue; + } + + /* If we don't have the right type, try to convert it. */ + + if (!gfc_compare_types (&cons->expr->ts, &comp->ts) + && gfc_convert_type (cons->expr, &comp->ts, 1) == FAILURE) + t = FAILURE; + } + + return t; +} + + + +/****************** Expression name resolution ******************/ + +/* Returns 0 if a symbol was not declared with a type or + or attribute declaration statement, nonzero otherwise. */ + +static int +was_declared (gfc_symbol * sym) +{ + symbol_attribute a; + + a = sym->attr; + + if (!a.implicit_type && sym->ts.type != BT_UNKNOWN) + return 1; + + if (a.allocatable || a.dimension || a.external || a.intrinsic + || a.optional || a.pointer || a.save || a.target + || a.access != ACCESS_UNKNOWN || a.intent != INTENT_UNKNOWN) + return 1; + + return 0; +} + + +/* Determine if a symbol is generic or not. */ + +static int +generic_sym (gfc_symbol * sym) +{ + gfc_symbol *s; + + if (sym->attr.generic || + (sym->attr.intrinsic && gfc_generic_intrinsic (sym->name))) + return 1; + + if (was_declared (sym) || sym->ns->parent == NULL) + return 0; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &s); + + return (s == NULL) ? 0 : generic_sym (s); +} + + +/* Determine if a symbol is specific or not. */ + +static int +specific_sym (gfc_symbol * sym) +{ + gfc_symbol *s; + + if (sym->attr.if_source == IFSRC_IFBODY + || sym->attr.proc == PROC_MODULE + || sym->attr.proc == PROC_INTERNAL + || sym->attr.proc == PROC_ST_FUNCTION + || (sym->attr.intrinsic && + gfc_specific_intrinsic (sym->name)) + || sym->attr.external) + return 1; + + if (was_declared (sym) || sym->ns->parent == NULL) + return 0; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &s); + + return (s == NULL) ? 0 : specific_sym (s); +} + + +/* Figure out if the procedure is specific, generic or unknown. */ + +typedef enum +{ PTYPE_GENERIC = 1, PTYPE_SPECIFIC, PTYPE_UNKNOWN } +proc_type; + +static proc_type +procedure_kind (gfc_symbol * sym) +{ + + if (generic_sym (sym)) + return PTYPE_GENERIC; + + if (specific_sym (sym)) + return PTYPE_SPECIFIC; + + return PTYPE_UNKNOWN; +} + + +/* Resolve an actual argument list. Most of the time, this is just + resolving the expressions in the list. + The exception is that we sometimes have to decide whether arguments + that look like procedure arguments are really simple variable + references. */ + +static try +resolve_actual_arglist (gfc_actual_arglist * arg) +{ + gfc_symbol *sym; + gfc_symtree *parent_st; + gfc_expr *e; + + for (; arg; arg = arg->next) + { + + e = arg->expr; + if (e == NULL) + { + /* Check the label is a valid branching target. */ + if (arg->label) + { + if (arg->label->defined == ST_LABEL_UNKNOWN) + { + gfc_error ("Label %d referenced at %L is never defined", + arg->label->value, &arg->label->where); + return FAILURE; + } + } + continue; + } + + if (e->ts.type != BT_PROCEDURE) + { + if (gfc_resolve_expr (e) != SUCCESS) + return FAILURE; + continue; + } + + /* See if the expression node should really be a variable + reference. */ + + sym = e->symtree->n.sym; + + if (sym->attr.flavor == FL_PROCEDURE + || sym->attr.intrinsic + || sym->attr.external) + { + + /* If the symbol is the function that names the current (or + parent) scope, then we really have a variable reference. */ + + if (sym->attr.function && sym->result == sym + && (sym->ns->proc_name == sym + || (sym->ns->parent != NULL + && sym->ns->parent->proc_name == sym))) + goto got_variable; + + continue; + } + + /* See if the name is a module procedure in a parent unit. */ + + if (was_declared (sym) || sym->ns->parent == NULL) + goto got_variable; + + if (gfc_find_sym_tree (sym->name, sym->ns->parent, 1, &parent_st)) + { + gfc_error ("Symbol '%s' at %L is ambiguous", sym->name, &e->where); + return FAILURE; + } + + if (parent_st == NULL) + goto got_variable; + + sym = parent_st->n.sym; + e->symtree = parent_st; /* Point to the right thing. */ + + if (sym->attr.flavor == FL_PROCEDURE + || sym->attr.intrinsic + || sym->attr.external) + { + continue; + } + + got_variable: + e->expr_type = EXPR_VARIABLE; + e->ts = sym->ts; + if (sym->as != NULL) + { + e->rank = sym->as->rank; + e->ref = gfc_get_ref (); + e->ref->type = REF_ARRAY; + e->ref->u.ar.type = AR_FULL; + e->ref->u.ar.as = sym->as; + } + } + + return SUCCESS; +} + + +/************* Function resolution *************/ + +/* Resolve a function call known to be generic. + Section 14.1.2.4.1. */ + +static match +resolve_generic_f0 (gfc_expr * expr, gfc_symbol * sym) +{ + gfc_symbol *s; + + if (sym->attr.generic) + { + s = + gfc_search_interface (sym->generic, 0, &expr->value.function.actual); + if (s != NULL) + { + expr->value.function.name = s->name; + expr->value.function.esym = s; + expr->ts = s->ts; + if (s->as != NULL) + expr->rank = s->as->rank; + return MATCH_YES; + } + + /* TODO: Need to search for elemental references in generic interface */ + } + + if (sym->attr.intrinsic) + return gfc_intrinsic_func_interface (expr, 0); + + return MATCH_NO; +} + + +static try +resolve_generic_f (gfc_expr * expr) +{ + gfc_symbol *sym; + match m; + + sym = expr->symtree->n.sym; + + for (;;) + { + m = resolve_generic_f0 (expr, sym); + if (m == MATCH_YES) + return SUCCESS; + else if (m == MATCH_ERROR) + return FAILURE; + +generic: + if (sym->ns->parent == NULL) + break; + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + + if (sym == NULL) + break; + if (!generic_sym (sym)) + goto generic; + } + + /* Last ditch attempt. */ + + if (!gfc_generic_intrinsic (expr->symtree->n.sym->name)) + { + gfc_error ("Generic function '%s' at %L is not an intrinsic function", + expr->symtree->n.sym->name, &expr->where); + return FAILURE; + } + + m = gfc_intrinsic_func_interface (expr, 0); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_NO) + gfc_error + ("Generic function '%s' at %L is not consistent with a specific " + "intrinsic interface", expr->symtree->n.sym->name, &expr->where); + + return FAILURE; +} + + +/* Resolve a function call known to be specific. */ + +static match +resolve_specific_f0 (gfc_symbol * sym, gfc_expr * expr) +{ + match m; + + if (sym->attr.external || sym->attr.if_source == IFSRC_IFBODY) + { + if (sym->attr.dummy) + { + sym->attr.proc = PROC_DUMMY; + goto found; + } + + sym->attr.proc = PROC_EXTERNAL; + goto found; + } + + if (sym->attr.proc == PROC_MODULE + || sym->attr.proc == PROC_ST_FUNCTION + || sym->attr.proc == PROC_INTERNAL) + goto found; + + if (sym->attr.intrinsic) + { + m = gfc_intrinsic_func_interface (expr, 1); + if (m == MATCH_YES) + return MATCH_YES; + if (m == MATCH_NO) + gfc_error + ("Function '%s' at %L is INTRINSIC but is not compatible with " + "an intrinsic", sym->name, &expr->where); + + return MATCH_ERROR; + } + + return MATCH_NO; + +found: + gfc_procedure_use (sym, &expr->value.function.actual, &expr->where); + + expr->ts = sym->ts; + expr->value.function.name = sym->name; + expr->value.function.esym = sym; + if (sym->as != NULL) + expr->rank = sym->as->rank; + + return MATCH_YES; +} + + +static try +resolve_specific_f (gfc_expr * expr) +{ + gfc_symbol *sym; + match m; + + sym = expr->symtree->n.sym; + + for (;;) + { + m = resolve_specific_f0 (sym, expr); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + + if (sym->ns->parent == NULL) + break; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + + if (sym == NULL) + break; + } + + gfc_error ("Unable to resolve the specific function '%s' at %L", + expr->symtree->n.sym->name, &expr->where); + + return SUCCESS; +} + + +/* Resolve a procedure call not known to be generic nor specific. */ + +static try +resolve_unknown_f (gfc_expr * expr) +{ + gfc_symbol *sym; + gfc_typespec *ts; + + sym = expr->symtree->n.sym; + + if (sym->attr.dummy) + { + sym->attr.proc = PROC_DUMMY; + expr->value.function.name = sym->name; + goto set_type; + } + + /* See if we have an intrinsic function reference. */ + + if (gfc_intrinsic_name (sym->name, 0)) + { + if (gfc_intrinsic_func_interface (expr, 1) == MATCH_YES) + return SUCCESS; + return FAILURE; + } + + /* The reference is to an external name. */ + + sym->attr.proc = PROC_EXTERNAL; + expr->value.function.name = sym->name; + expr->value.function.esym = expr->symtree->n.sym; + + if (sym->as != NULL) + expr->rank = sym->as->rank; + + /* Type of the expression is either the type of the symbol or the + default type of the symbol. */ + +set_type: + gfc_procedure_use (sym, &expr->value.function.actual, &expr->where); + + if (sym->ts.type != BT_UNKNOWN) + expr->ts = sym->ts; + else + { + ts = gfc_get_default_type (sym, sym->ns); + + if (ts->type == BT_UNKNOWN) + { + gfc_error ("Function '%s' at %L has no implicit type", + sym->name, &expr->where); + return FAILURE; + } + else + expr->ts = *ts; + } + + return SUCCESS; +} + + +/* Figure out if if a function reference is pure or not. Also sets the name + of the function for a potential error message. Returns nonzero if the + function is PURE, zero if not. */ + +static int +pure_function (gfc_expr * e, char **name) +{ + int pure; + + if (e->value.function.esym) + { + pure = gfc_pure (e->value.function.esym); + *name = e->value.function.esym->name; + } + else if (e->value.function.isym) + { + pure = e->value.function.isym->pure + || e->value.function.isym->elemental; + *name = e->value.function.isym->name; + } + else + { + /* Implicit functions are not pure. */ + pure = 0; + *name = e->value.function.name; + } + + return pure; +} + + +/* Resolve a function call, which means resolving the arguments, then figuring + out which entity the name refers to. */ +/* TODO: Check procedure arguments so that an INTENT(IN) isn't passed + to INTENT(OUT) or INTENT(INOUT). */ + +static try +resolve_function (gfc_expr * expr) +{ + gfc_actual_arglist *arg; + char *name; + try t; + + if (resolve_actual_arglist (expr->value.function.actual) == FAILURE) + return FAILURE; + +/* See if function is already resolved. */ + + if (expr->value.function.name != NULL) + { + if (expr->ts.type == BT_UNKNOWN) + expr->ts = expr->symtree->n.sym->ts; + t = SUCCESS; + } + else + { + /* Apply the rules of section 14.1.2. */ + + switch (procedure_kind (expr->symtree->n.sym)) + { + case PTYPE_GENERIC: + t = resolve_generic_f (expr); + break; + + case PTYPE_SPECIFIC: + t = resolve_specific_f (expr); + break; + + case PTYPE_UNKNOWN: + t = resolve_unknown_f (expr); + break; + + default: + gfc_internal_error ("resolve_function(): bad function type"); + } + } + + /* If the expression is still a function (it might have simplified), + then we check to see if we are calling an elemental function. */ + + if (expr->expr_type != EXPR_FUNCTION) + return t; + + 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; + break; + } + } + } + + if (!pure_function (expr, &name)) + { + if (forall_flag) + { + gfc_error + ("Function reference to '%s' at %L is inside a FORALL block", + name, &expr->where); + t = FAILURE; + } + else if (gfc_pure (NULL)) + { + gfc_error ("Function reference to '%s' at %L is to a non-PURE " + "procedure within a PURE procedure", name, &expr->where); + t = FAILURE; + } + } + + return t; +} + + +/************* Subroutine resolution *************/ + +static void +pure_subroutine (gfc_code * c, gfc_symbol * sym) +{ + + if (gfc_pure (sym)) + return; + + if (forall_flag) + gfc_error ("Subroutine call to '%s' in FORALL block at %L is not PURE", + sym->name, &c->loc); + else if (gfc_pure (NULL)) + gfc_error ("Subroutine call to '%s' at %L is not PURE", sym->name, + &c->loc); +} + + +static match +resolve_generic_s0 (gfc_code * c, gfc_symbol * sym) +{ + gfc_symbol *s; + + if (sym->attr.generic) + { + s = gfc_search_interface (sym->generic, 1, &c->ext.actual); + if (s != NULL) + { + c->resolved_sym = s; + pure_subroutine (c, s); + return MATCH_YES; + } + + /* TODO: Need to search for elemental references in generic interface. */ + } + + if (sym->attr.intrinsic) + return gfc_intrinsic_sub_interface (c, 0); + + return MATCH_NO; +} + + +static try +resolve_generic_s (gfc_code * c) +{ + gfc_symbol *sym; + match m; + + sym = c->symtree->n.sym; + + m = resolve_generic_s0 (c, sym); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + + if (sym->ns->parent != NULL) + { + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + if (sym != NULL) + { + m = resolve_generic_s0 (c, sym); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + } + } + + /* Last ditch attempt. */ + + if (!gfc_generic_intrinsic (sym->name)) + { + gfc_error + ("Generic subroutine '%s' at %L is not an intrinsic subroutine", + sym->name, &c->loc); + return FAILURE; + } + + m = gfc_intrinsic_sub_interface (c, 0); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_NO) + gfc_error ("Generic subroutine '%s' at %L is not consistent with an " + "intrinsic subroutine interface", sym->name, &c->loc); + + return FAILURE; +} + + +/* Resolve a subroutine call known to be specific. */ + +static match +resolve_specific_s0 (gfc_code * c, gfc_symbol * sym) +{ + match m; + + if (sym->attr.external || sym->attr.if_source == IFSRC_IFBODY) + { + if (sym->attr.dummy) + { + sym->attr.proc = PROC_DUMMY; + goto found; + } + + sym->attr.proc = PROC_EXTERNAL; + goto found; + } + + if (sym->attr.proc == PROC_MODULE || sym->attr.proc == PROC_INTERNAL) + goto found; + + if (sym->attr.intrinsic) + { + m = gfc_intrinsic_sub_interface (c, 1); + if (m == MATCH_YES) + return MATCH_YES; + if (m == MATCH_NO) + gfc_error ("Subroutine '%s' at %L is INTRINSIC but is not compatible " + "with an intrinsic", sym->name, &c->loc); + + return MATCH_ERROR; + } + + return MATCH_NO; + +found: + gfc_procedure_use (sym, &c->ext.actual, &c->loc); + + c->resolved_sym = sym; + pure_subroutine (c, sym); + + return MATCH_YES; +} + + +static try +resolve_specific_s (gfc_code * c) +{ + gfc_symbol *sym; + match m; + + sym = c->symtree->n.sym; + + m = resolve_specific_s0 (c, sym); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + + if (sym != NULL) + { + m = resolve_specific_s0 (c, sym); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + } + + gfc_error ("Unable to resolve the specific subroutine '%s' at %L", + sym->name, &c->loc); + + return FAILURE; +} + + +/* Resolve a subroutine call not known to be generic nor specific. */ + +static try +resolve_unknown_s (gfc_code * c) +{ + gfc_symbol *sym; + + sym = c->symtree->n.sym; + + if (sym->attr.dummy) + { + sym->attr.proc = PROC_DUMMY; + goto found; + } + + /* See if we have an intrinsic function reference. */ + + if (gfc_intrinsic_name (sym->name, 1)) + { + if (gfc_intrinsic_sub_interface (c, 1) == MATCH_YES) + return SUCCESS; + return FAILURE; + } + + /* The reference is to an external name. */ + +found: + gfc_procedure_use (sym, &c->ext.actual, &c->loc); + + c->resolved_sym = sym; + + pure_subroutine (c, sym); + + return SUCCESS; +} + + +/* Resolve a subroutine call. Although it was tempting to use the same code + for functions, subroutines and functions are stored differently and this + makes things awkward. */ + +static try +resolve_call (gfc_code * c) +{ + try t; + + if (resolve_actual_arglist (c->ext.actual) == FAILURE) + return FAILURE; + + if (c->resolved_sym != NULL) + return SUCCESS; + + switch (procedure_kind (c->symtree->n.sym)) + { + case PTYPE_GENERIC: + t = resolve_generic_s (c); + break; + + case PTYPE_SPECIFIC: + t = resolve_specific_s (c); + break; + + case PTYPE_UNKNOWN: + t = resolve_unknown_s (c); + break; + + default: + gfc_internal_error ("resolve_subroutine(): bad function type"); + } + + return t; +} + + +/* Resolve an operator expression node. This can involve replacing the + operation with a user defined function call. */ + +static try +resolve_operator (gfc_expr * e) +{ + gfc_expr *op1, *op2; + char msg[200]; + try t; + + /* Resolve all subnodes-- give them types. */ + + switch (e->operator) + { + default: + if (gfc_resolve_expr (e->op2) == FAILURE) + return FAILURE; + + /* Fall through... */ + + case INTRINSIC_NOT: + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + if (gfc_resolve_expr (e->op1) == FAILURE) + return FAILURE; + break; + } + + /* Typecheck the new node. */ + + op1 = e->op1; + op2 = e->op2; + + switch (e->operator) + { + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + if (op1->ts.type == BT_INTEGER + || op1->ts.type == BT_REAL + || op1->ts.type == BT_COMPLEX) + { + e->ts = op1->ts; + break; + } + + sprintf (msg, "Operand of unary numeric operator '%s' at %%L is %s", + gfc_op2string (e->operator), gfc_typename (&e->ts)); + goto bad_op; + + case INTRINSIC_PLUS: + case INTRINSIC_MINUS: + case INTRINSIC_TIMES: + case INTRINSIC_DIVIDE: + case INTRINSIC_POWER: + if (gfc_numeric_ts (&op1->ts) && gfc_numeric_ts (&op2->ts)) + { + gfc_type_convert_binary (e); + break; + } + + sprintf (msg, + "Operands of binary numeric operator '%s' at %%L are %s/%s", + gfc_op2string (e->operator), gfc_typename (&op1->ts), + gfc_typename (&op2->ts)); + goto bad_op; + + case INTRINSIC_CONCAT: + if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER) + { + e->ts.type = BT_CHARACTER; + e->ts.kind = op1->ts.kind; + break; + } + + sprintf (msg, + "Operands of string concatenation operator at %%L are %s/%s", + gfc_typename (&op1->ts), gfc_typename (&op2->ts)); + goto bad_op; + + case INTRINSIC_AND: + case INTRINSIC_OR: + case INTRINSIC_EQV: + case INTRINSIC_NEQV: + if (op1->ts.type == BT_LOGICAL && op2->ts.type == BT_LOGICAL) + { + e->ts.type = BT_LOGICAL; + e->ts.kind = gfc_kind_max (op1, op2); + if (op1->ts.kind < e->ts.kind) + gfc_convert_type (op1, &e->ts, 2); + else if (op2->ts.kind < e->ts.kind) + gfc_convert_type (op2, &e->ts, 2); + break; + } + + sprintf (msg, "Operands of logical operator '%s' at %%L are %s/%s", + gfc_op2string (e->operator), gfc_typename (&op1->ts), + gfc_typename (&op2->ts)); + + goto bad_op; + + case INTRINSIC_NOT: + if (op1->ts.type == BT_LOGICAL) + { + e->ts.type = BT_LOGICAL; + e->ts.kind = op1->ts.kind; + break; + } + + sprintf (msg, "Operand of .NOT. operator at %%L is %s", + gfc_typename (&op1->ts)); + goto bad_op; + + case INTRINSIC_GT: + case INTRINSIC_GE: + case INTRINSIC_LT: + case INTRINSIC_LE: + if (op1->ts.type == BT_COMPLEX || op2->ts.type == BT_COMPLEX) + { + strcpy (msg, "COMPLEX quantities cannot be compared at %L"); + goto bad_op; + } + + /* Fall through... */ + + case INTRINSIC_EQ: + case INTRINSIC_NE: + if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER) + { + e->ts.type = BT_LOGICAL; + e->ts.kind = gfc_default_logical_kind (); + break; + } + + if (gfc_numeric_ts (&op1->ts) && gfc_numeric_ts (&op2->ts)) + { + gfc_type_convert_binary (e); + + e->ts.type = BT_LOGICAL; + e->ts.kind = gfc_default_logical_kind (); + break; + } + + sprintf (msg, "Operands of comparison operator '%s' at %%L are %s/%s", + gfc_op2string (e->operator), gfc_typename (&op1->ts), + gfc_typename (&op2->ts)); + + goto bad_op; + + case INTRINSIC_USER: + if (op2 == NULL) + sprintf (msg, "Operand of user operator '%s' at %%L is %s", + e->uop->ns->proc_name->name, gfc_typename (&op1->ts)); + else + sprintf (msg, "Operands of user operator '%s' at %%L are %s/%s", + e->uop->ns->proc_name->name, gfc_typename (&op1->ts), + gfc_typename (&op2->ts)); + + goto bad_op; + + default: + gfc_internal_error ("resolve_operator(): Bad intrinsic"); + } + + /* Deal with arrayness of an operand through an operator. */ + + t = SUCCESS; + + switch (e->operator) + { + case INTRINSIC_PLUS: + case INTRINSIC_MINUS: + case INTRINSIC_TIMES: + case INTRINSIC_DIVIDE: + case INTRINSIC_POWER: + case INTRINSIC_CONCAT: + case INTRINSIC_AND: + case INTRINSIC_OR: + case INTRINSIC_EQV: + case INTRINSIC_NEQV: + case INTRINSIC_EQ: + case INTRINSIC_NE: + case INTRINSIC_GT: + case INTRINSIC_GE: + case INTRINSIC_LT: + case INTRINSIC_LE: + + if (op1->rank == 0 && op2->rank == 0) + e->rank = 0; + + if (op1->rank == 0 && op2->rank != 0) + { + e->rank = op2->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op2->shape, op2->rank); + } + + if (op1->rank != 0 && op2->rank == 0) + { + e->rank = op1->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op1->shape, op1->rank); + } + + if (op1->rank != 0 && op2->rank != 0) + { + if (op1->rank == op2->rank) + { + e->rank = op1->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op1->shape, op1->rank); + + } + else + { + gfc_error ("Inconsistent ranks for operator at %L and %L", + &op1->where, &op2->where); + t = FAILURE; + + /* Allow higher level expressions to work. */ + e->rank = 0; + } + } + + break; + + case INTRINSIC_NOT: + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + e->rank = op1->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op1->shape, op1->rank); + + /* Simply copy arrayness attribute */ + break; + + default: + break; + } + + /* Attempt to simplify the expression. */ + if (t == SUCCESS) + t = gfc_simplify_expr (e, 0); + return t; + +bad_op: + if (gfc_extend_expr (e) == SUCCESS) + return SUCCESS; + + gfc_error (msg, &e->where); + return FAILURE; +} + + +/************** Array resolution subroutines **************/ + + +typedef enum +{ CMP_LT, CMP_EQ, CMP_GT, CMP_UNKNOWN } +comparison; + +/* Compare two integer expressions. */ + +static comparison +compare_bound (gfc_expr * a, gfc_expr * b) +{ + int i; + + if (a == NULL || a->expr_type != EXPR_CONSTANT + || b == NULL || b->expr_type != EXPR_CONSTANT) + return CMP_UNKNOWN; + + if (a->ts.type != BT_INTEGER || b->ts.type != BT_INTEGER) + gfc_internal_error ("compare_bound(): Bad expression"); + + i = mpz_cmp (a->value.integer, b->value.integer); + + if (i < 0) + return CMP_LT; + if (i > 0) + return CMP_GT; + return CMP_EQ; +} + + +/* Compare an integer expression with an integer. */ + +static comparison +compare_bound_int (gfc_expr * a, int b) +{ + int i; + + if (a == NULL || a->expr_type != EXPR_CONSTANT) + return CMP_UNKNOWN; + + if (a->ts.type != BT_INTEGER) + gfc_internal_error ("compare_bound_int(): Bad expression"); + + i = mpz_cmp_si (a->value.integer, b); + + if (i < 0) + return CMP_LT; + if (i > 0) + return CMP_GT; + return CMP_EQ; +} + + +/* Compare a single dimension of an array reference to the array + specification. */ + +static try +check_dimension (int i, gfc_array_ref * ar, gfc_array_spec * as) +{ + +/* Given start, end and stride values, calculate the minimum and + maximum referenced indexes. */ + + switch (ar->type) + { + case AR_FULL: + break; + + case AR_ELEMENT: + if (compare_bound (ar->start[i], as->lower[i]) == CMP_LT) + goto bound; + if (compare_bound (ar->start[i], as->upper[i]) == CMP_GT) + goto bound; + + break; + + case AR_SECTION: + if (compare_bound_int (ar->stride[i], 0) == CMP_EQ) + { + gfc_error ("Illegal stride of zero at %L", &ar->c_where[i]); + return FAILURE; + } + + if (compare_bound (ar->start[i], as->lower[i]) == CMP_LT) + goto bound; + if (compare_bound (ar->start[i], as->upper[i]) == CMP_GT) + goto bound; + + /* TODO: Possibly, we could warn about end[i] being out-of-bound although + it is legal (see 6.2.2.3.1). */ + + break; + + default: + gfc_internal_error ("check_dimension(): Bad array reference"); + } + + return SUCCESS; + +bound: + gfc_warning ("Array reference at %L is out of bounds", &ar->c_where[i]); + return SUCCESS; +} + + +/* Compare an array reference with an array specification. */ + +static try +compare_spec_to_ref (gfc_array_ref * ar) +{ + gfc_array_spec *as; + int i; + + as = ar->as; + i = as->rank - 1; + /* TODO: Full array sections are only allowed as actual parameters. */ + if (as->type == AS_ASSUMED_SIZE + && (/*ar->type == AR_FULL + ||*/ (ar->type == AR_SECTION + && ar->dimen_type[i] == DIMEN_RANGE && ar->end[i] == NULL))) + { + gfc_error ("Rightmost upper bound of assumed size array section" + " not specified at %L", &ar->where); + return FAILURE; + } + + if (ar->type == AR_FULL) + return SUCCESS; + + if (as->rank != ar->dimen) + { + gfc_error ("Rank mismatch in array reference at %L (%d/%d)", + &ar->where, ar->dimen, as->rank); + return FAILURE; + } + + for (i = 0; i < as->rank; i++) + if (check_dimension (i, ar, as) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Resolve one part of an array index. */ + +try +gfc_resolve_index (gfc_expr * index, int check_scalar) +{ + gfc_typespec ts; + + if (index == NULL) + return SUCCESS; + + if (gfc_resolve_expr (index) == FAILURE) + return FAILURE; + + if (index->ts.type != BT_INTEGER) + { + gfc_error ("Array index at %L must be of INTEGER type", &index->where); + return FAILURE; + } + + if (check_scalar && index->rank != 0) + { + gfc_error ("Array index at %L must be scalar", &index->where); + return FAILURE; + } + + if (index->ts.kind != gfc_index_integer_kind) + { + ts.type = BT_INTEGER; + ts.kind = gfc_index_integer_kind; + + gfc_convert_type_warn (index, &ts, 2, 0); + } + + return SUCCESS; +} + + +/* Given an expression that contains array references, update those array + references to point to the right array specifications. While this is + filled in during matching, this information is difficult to save and load + in a module, so we take care of it here. + + The idea here is that the original array reference comes from the + base symbol. We traverse the list of reference structures, setting + the stored reference to references. Component references can + provide an additional array specification. */ + +static void +find_array_spec (gfc_expr * e) +{ + gfc_array_spec *as; + gfc_component *c; + gfc_ref *ref; + + as = e->symtree->n.sym->as; + c = e->symtree->n.sym->components; + + for (ref = e->ref; ref; ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + if (as == NULL) + gfc_internal_error ("find_array_spec(): Missing spec"); + + ref->u.ar.as = as; + as = NULL; + break; + + case REF_COMPONENT: + for (; c; c = c->next) + if (c == ref->u.c.component) + break; + + if (c == NULL) + gfc_internal_error ("find_array_spec(): Component not found"); + + if (c->dimension) + { + if (as != NULL) + gfc_internal_error ("find_array_spec(): unused as(1)"); + as = c->as; + } + + c = c->ts.derived->components; + break; + + case REF_SUBSTRING: + break; + } + + if (as != NULL) + gfc_internal_error ("find_array_spec(): unused as(2)"); +} + + +/* Resolve an array reference. */ + +static try +resolve_array_ref (gfc_array_ref * ar) +{ + int i, check_scalar; + + for (i = 0; i < ar->dimen; i++) + { + check_scalar = ar->dimen_type[i] == DIMEN_RANGE; + + if (gfc_resolve_index (ar->start[i], check_scalar) == FAILURE) + return FAILURE; + if (gfc_resolve_index (ar->end[i], check_scalar) == FAILURE) + return FAILURE; + if (gfc_resolve_index (ar->stride[i], check_scalar) == FAILURE) + return FAILURE; + + if (ar->dimen_type[i] == DIMEN_UNKNOWN) + switch (ar->start[i]->rank) + { + case 0: + ar->dimen_type[i] = DIMEN_ELEMENT; + break; + + case 1: + ar->dimen_type[i] = DIMEN_VECTOR; + break; + + default: + gfc_error ("Array index at %L is an array of rank %d", + &ar->c_where[i], ar->start[i]->rank); + return FAILURE; + } + } + + /* If the reference type is unknown, figure out what kind it is. */ + + if (ar->type == AR_UNKNOWN) + { + ar->type = AR_ELEMENT; + for (i = 0; i < ar->dimen; i++) + if (ar->dimen_type[i] == DIMEN_RANGE + || ar->dimen_type[i] == DIMEN_VECTOR) + { + ar->type = AR_SECTION; + break; + } + } + + if (compare_spec_to_ref (ar) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +static try +resolve_substring (gfc_ref * ref) +{ + + if (ref->u.ss.start != NULL) + { + if (gfc_resolve_expr (ref->u.ss.start) == FAILURE) + return FAILURE; + + if (ref->u.ss.start->ts.type != BT_INTEGER) + { + gfc_error ("Substring start index at %L must be of type INTEGER", + &ref->u.ss.start->where); + return FAILURE; + } + + if (ref->u.ss.start->rank != 0) + { + gfc_error ("Substring start index at %L must be scalar", + &ref->u.ss.start->where); + return FAILURE; + } + + if (compare_bound_int (ref->u.ss.start, 1) == CMP_LT) + { + gfc_error ("Substring start index at %L is less than one", + &ref->u.ss.start->where); + return FAILURE; + } + } + + if (ref->u.ss.end != NULL) + { + if (gfc_resolve_expr (ref->u.ss.end) == FAILURE) + return FAILURE; + + if (ref->u.ss.end->ts.type != BT_INTEGER) + { + gfc_error ("Substring end index at %L must be of type INTEGER", + &ref->u.ss.end->where); + return FAILURE; + } + + if (ref->u.ss.end->rank != 0) + { + gfc_error ("Substring end index at %L must be scalar", + &ref->u.ss.end->where); + return FAILURE; + } + + if (ref->u.ss.length != NULL + && compare_bound (ref->u.ss.end, ref->u.ss.length->length) == CMP_GT) + { + gfc_error ("Substring end index at %L is out of bounds", + &ref->u.ss.start->where); + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Resolve subtype references. */ + +static try +resolve_ref (gfc_expr * expr) +{ + int current_part_dimension, n_components, seen_part_dimension; + gfc_ref *ref; + + for (ref = expr->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY && ref->u.ar.as == NULL) + { + find_array_spec (expr); + break; + } + + for (ref = expr->ref; ref; ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + if (resolve_array_ref (&ref->u.ar) == FAILURE) + return FAILURE; + break; + + case REF_COMPONENT: + break; + + case REF_SUBSTRING: + resolve_substring (ref); + break; + } + + /* Check constraints on part references. */ + + current_part_dimension = 0; + seen_part_dimension = 0; + n_components = 0; + + for (ref = expr->ref; ref; ref = ref->next) + { + switch (ref->type) + { + case REF_ARRAY: + switch (ref->u.ar.type) + { + case AR_FULL: + case AR_SECTION: + current_part_dimension = 1; + break; + + case AR_ELEMENT: + current_part_dimension = 0; + break; + + case AR_UNKNOWN: + gfc_internal_error ("resolve_ref(): Bad array reference"); + } + + break; + + case REF_COMPONENT: + if ((current_part_dimension || seen_part_dimension) + && ref->u.c.component->pointer) + { + gfc_error + ("Component to the right of a part reference with nonzero " + "rank must not have the POINTER attribute at %L", + &expr->where); + return FAILURE; + } + + n_components++; + break; + + case REF_SUBSTRING: + break; + } + + if (((ref->type == REF_COMPONENT && n_components > 1) + || ref->next == NULL) + && current_part_dimension + && seen_part_dimension) + { + + gfc_error ("Two or more part references with nonzero rank must " + "not be specified at %L", &expr->where); + return FAILURE; + } + + if (ref->type == REF_COMPONENT) + { + if (current_part_dimension) + seen_part_dimension = 1; + + /* reset to make sure */ + current_part_dimension = 0; + } + } + + return SUCCESS; +} + + +/* Given an expression, determine its shape. This is easier than it sounds. + Leaves the shape array NULL if it is not possible to determine the shape. */ + +static void +expression_shape (gfc_expr * e) +{ + mpz_t array[GFC_MAX_DIMENSIONS]; + int i; + + if (e->rank == 0 || e->shape != NULL) + return; + + for (i = 0; i < e->rank; i++) + if (gfc_array_dimen_size (e, i, &array[i]) == FAILURE) + goto fail; + + e->shape = gfc_get_shape (e->rank); + + memcpy (e->shape, array, e->rank * sizeof (mpz_t)); + + return; + +fail: + for (i--; i >= 0; i--) + mpz_clear (array[i]); +} + + +/* Given a variable expression node, compute the rank of the expression by + examining the base symbol and any reference structures it may have. */ + +static void +expression_rank (gfc_expr * e) +{ + gfc_ref *ref; + int i, rank; + + if (e->ref == NULL) + { + if (e->expr_type == EXPR_ARRAY) + goto done; + /* Constructors can have a rank different from one via RESHAPE(). */ + + if (e->symtree == NULL) + { + e->rank = 0; + goto done; + } + + e->rank = (e->symtree->n.sym->as == NULL) + ? 0 : e->symtree->n.sym->as->rank; + goto done; + } + + rank = 0; + + for (ref = e->ref; ref; ref = ref->next) + { + if (ref->type != REF_ARRAY) + continue; + + if (ref->u.ar.type == AR_FULL) + { + rank = ref->u.ar.as->rank; + break; + } + + if (ref->u.ar.type == AR_SECTION) + { + /* Figure out the rank of the section. */ + if (rank != 0) + gfc_internal_error ("expression_rank(): Two array specs"); + + for (i = 0; i < ref->u.ar.dimen; i++) + if (ref->u.ar.dimen_type[i] == DIMEN_RANGE + || ref->u.ar.dimen_type[i] == DIMEN_VECTOR) + rank++; + + break; + } + } + + e->rank = rank; + +done: + expression_shape (e); +} + + +/* Resolve a variable expression. */ + +static try +resolve_variable (gfc_expr * e) +{ + gfc_symbol *sym; + + if (e->ref && resolve_ref (e) == FAILURE) + return FAILURE; + + sym = e->symtree->n.sym; + if (sym->attr.flavor == FL_PROCEDURE && !sym->attr.function) + { + e->ts.type = BT_PROCEDURE; + return SUCCESS; + } + + if (sym->ts.type != BT_UNKNOWN) + gfc_variable_attr (e, &e->ts); + else + { + /* Must be a simple variable reference. */ + if (gfc_set_default_type (sym, 1, NULL) == FAILURE) + return FAILURE; + e->ts = sym->ts; + } + + return SUCCESS; +} + + +/* Resolve an expression. That is, make sure that types of operands agree + with their operators, intrinsic operators are converted to function calls + for overloaded types and unresolved function references are resolved. */ + +try +gfc_resolve_expr (gfc_expr * e) +{ + try t; + + if (e == NULL) + return SUCCESS; + + switch (e->expr_type) + { + case EXPR_OP: + t = resolve_operator (e); + break; + + case EXPR_FUNCTION: + t = resolve_function (e); + break; + + case EXPR_VARIABLE: + t = resolve_variable (e); + if (t == SUCCESS) + expression_rank (e); + break; + + case EXPR_SUBSTRING: + t = resolve_ref (e); + break; + + case EXPR_CONSTANT: + case EXPR_NULL: + t = SUCCESS; + break; + + case EXPR_ARRAY: + t = FAILURE; + if (resolve_ref (e) == FAILURE) + break; + + t = gfc_resolve_array_constructor (e); + /* Also try to expand a constructor. */ + if (t == SUCCESS) + { + expression_rank (e); + gfc_expand_constructor (e); + } + + break; + + case EXPR_STRUCTURE: + t = resolve_ref (e); + if (t == FAILURE) + break; + + t = resolve_structure_cons (e); + if (t == FAILURE) + break; + + t = gfc_simplify_expr (e, 0); + break; + + default: + gfc_internal_error ("gfc_resolve_expr(): Bad expression type"); + } + + return t; +} + + +/* Resolve the expressions in an iterator structure and require that they all + be of integer type. */ + +try +gfc_resolve_iterator (gfc_iterator * iter) +{ + + if (gfc_resolve_expr (iter->var) == FAILURE) + return FAILURE; + + if (iter->var->ts.type != BT_INTEGER || iter->var->rank != 0) + { + gfc_error ("Loop variable at %L must be a scalar INTEGER", + &iter->var->where); + return FAILURE; + } + + if (gfc_pure (NULL) && gfc_impure_variable (iter->var->symtree->n.sym)) + { + gfc_error ("Cannot assign to loop variable in PURE procedure at %L", + &iter->var->where); + return FAILURE; + } + + if (gfc_resolve_expr (iter->start) == FAILURE) + return FAILURE; + + if (iter->start->ts.type != BT_INTEGER || iter->start->rank != 0) + { + gfc_error ("Start expression in DO loop at %L must be a scalar INTEGER", + &iter->start->where); + return FAILURE; + } + + if (gfc_resolve_expr (iter->end) == FAILURE) + return FAILURE; + + if (iter->end->ts.type != BT_INTEGER || iter->end->rank != 0) + { + gfc_error ("End expression in DO loop at %L must be a scalar INTEGER", + &iter->end->where); + return FAILURE; + } + + if (gfc_resolve_expr (iter->step) == FAILURE) + return FAILURE; + + if (iter->step->ts.type != BT_INTEGER || iter->step->rank != 0) + { + gfc_error ("Step expression in DO loop at %L must be a scalar INTEGER", + &iter->step->where); + return FAILURE; + } + + if (iter->step->expr_type == EXPR_CONSTANT + && mpz_cmp_ui (iter->step->value.integer, 0) == 0) + { + gfc_error ("Step expression in DO loop at %L cannot be zero", + &iter->step->where); + return FAILURE; + } + + return SUCCESS; +} + + +/* Resolve a list of FORALL iterators. */ + +static void +resolve_forall_iterators (gfc_forall_iterator * iter) +{ + + while (iter) + { + if (gfc_resolve_expr (iter->var) == SUCCESS + && iter->var->ts.type != BT_INTEGER) + gfc_error ("FORALL Iteration variable at %L must be INTEGER", + &iter->var->where); + + if (gfc_resolve_expr (iter->start) == SUCCESS + && iter->start->ts.type != BT_INTEGER) + gfc_error ("FORALL start expression at %L must be INTEGER", + &iter->start->where); + if (iter->var->ts.kind != iter->start->ts.kind) + gfc_convert_type (iter->start, &iter->var->ts, 2); + + if (gfc_resolve_expr (iter->end) == SUCCESS + && iter->end->ts.type != BT_INTEGER) + gfc_error ("FORALL end expression at %L must be INTEGER", + &iter->end->where); + if (iter->var->ts.kind != iter->end->ts.kind) + gfc_convert_type (iter->end, &iter->var->ts, 2); + + if (gfc_resolve_expr (iter->stride) == SUCCESS + && iter->stride->ts.type != BT_INTEGER) + gfc_error ("FORALL Stride expression at %L must be INTEGER", + &iter->stride->where); + if (iter->var->ts.kind != iter->stride->ts.kind) + gfc_convert_type (iter->stride, &iter->var->ts, 2); + + iter = iter->next; + } +} + + +/* Given a pointer to a symbol that is a derived type, see if any components + have the POINTER attribute. The search is recursive if necessary. + Returns zero if no pointer components are found, nonzero otherwise. */ + +static int +derived_pointer (gfc_symbol * sym) +{ + gfc_component *c; + + for (c = sym->components; c; c = c->next) + { + if (c->pointer) + return 1; + + if (c->ts.type == BT_DERIVED && derived_pointer (c->ts.derived)) + return 1; + } + + return 0; +} + + +/* Resolve the argument of a deallocate expression. The expression must be + a pointer or a full array. */ + +static try +resolve_deallocate_expr (gfc_expr * e) +{ + symbol_attribute attr; + int allocatable; + gfc_ref *ref; + + if (gfc_resolve_expr (e) == FAILURE) + return FAILURE; + + attr = gfc_expr_attr (e); + if (attr.pointer) + return SUCCESS; + + if (e->expr_type != EXPR_VARIABLE) + goto bad; + + allocatable = e->symtree->n.sym->attr.allocatable; + for (ref = e->ref; ref; ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + if (ref->u.ar.type != AR_FULL) + allocatable = 0; + break; + + case REF_COMPONENT: + allocatable = (ref->u.c.component->as != NULL + && ref->u.c.component->as->type == AS_DEFERRED); + break; + + case REF_SUBSTRING: + allocatable = 0; + break; + } + + if (allocatable == 0) + { + bad: + gfc_error ("Expression in DEALLOCATE statement at %L must be " + "ALLOCATABLE or a POINTER", &e->where); + } + + return SUCCESS; +} + + +/* Resolve the expression in an ALLOCATE statement, doing the additional + checks to see whether the expression is OK or not. The expression must + have a trailing array reference that gives the size of the array. */ + +static try +resolve_allocate_expr (gfc_expr * e) +{ + int i, pointer, allocatable, dimension; + symbol_attribute attr; + gfc_ref *ref, *ref2; + gfc_array_ref *ar; + + if (gfc_resolve_expr (e) == FAILURE) + return FAILURE; + + /* Make sure the expression is allocatable or a pointer. If it is + pointer, the next-to-last reference must be a pointer. */ + + ref2 = NULL; + + if (e->expr_type != EXPR_VARIABLE) + { + allocatable = 0; + + attr = gfc_expr_attr (e); + pointer = attr.pointer; + dimension = attr.dimension; + + } + else + { + allocatable = e->symtree->n.sym->attr.allocatable; + pointer = e->symtree->n.sym->attr.pointer; + dimension = e->symtree->n.sym->attr.dimension; + + for (ref = e->ref; ref; ref2 = ref, ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + if (ref->next != NULL) + pointer = 0; + break; + + case REF_COMPONENT: + allocatable = (ref->u.c.component->as != NULL + && ref->u.c.component->as->type == AS_DEFERRED); + + pointer = ref->u.c.component->pointer; + dimension = ref->u.c.component->dimension; + break; + + case REF_SUBSTRING: + allocatable = 0; + pointer = 0; + break; + } + } + + if (allocatable == 0 && pointer == 0) + { + gfc_error ("Expression in ALLOCATE statement at %L must be " + "ALLOCATABLE or a POINTER", &e->where); + return FAILURE; + } + + if (pointer && dimension == 0) + return SUCCESS; + + /* Make sure the next-to-last reference node is an array specification. */ + + if (ref2 == NULL || ref2->type != REF_ARRAY || ref2->u.ar.type == AR_FULL) + { + gfc_error ("Array specification required in ALLOCATE statement " + "at %L", &e->where); + return FAILURE; + } + + if (ref2->u.ar.type == AR_ELEMENT) + return SUCCESS; + + /* Make sure that the array section reference makes sense in the + context of an ALLOCATE specification. */ + + ar = &ref2->u.ar; + + for (i = 0; i < ar->dimen; i++) + switch (ar->dimen_type[i]) + { + case DIMEN_ELEMENT: + break; + + case DIMEN_RANGE: + if (ar->start[i] != NULL + && ar->end[i] != NULL + && ar->stride[i] == NULL) + break; + + /* Fall Through... */ + + case DIMEN_UNKNOWN: + case DIMEN_VECTOR: + gfc_error ("Bad array specification in ALLOCATE statement at %L", + &e->where); + return FAILURE; + } + + return SUCCESS; +} + + +/************ SELECT CASE resolution subroutines ************/ + +/* Callback function for our mergesort variant. Determines interval + overlaps for CASEs. Return <0 if op1 < op2, 0 for overlap, >0 for + op1 > op2. Assumes we're not dealing with the default case. */ + +static int +compare_cases (const void * _op1, const void * _op2) +{ + const gfc_case *op1, *op2; + + op1 = (const gfc_case *) _op1; + op2 = (const gfc_case *) _op2; + + if (op1->low == NULL) /* op1 = (:N) */ + { + if (op2->low == NULL) /* op2 = (:M), so overlap. */ + return 0; + + else if (op2->high == NULL) /* op2 = (M:) */ + { + if (gfc_compare_expr (op1->high, op2->low) < 0) + return -1; /* N < M */ + else + return 0; + } + + else /* op2 = (L:M) */ + { + if (gfc_compare_expr (op1->high, op2->low) < 0) + return -1; /* N < L */ + else + return 0; + } + } + + else if (op1->high == NULL) /* op1 = (N:) */ + { + if (op2->low == NULL) /* op2 = (:M) */ + { + if (gfc_compare_expr (op1->low, op2->high) > 0) + return 1; /* N > M */ + else + return 0; + } + + else if (op2->high == NULL) /* op2 = (M:), so overlap. */ + return 0; + + else /* op2 = (L:M) */ + { + if (gfc_compare_expr (op1->low, op2->high) > 0) + return 1; /* N > M */ + else + return 0; + } + } + + else /* op1 = (N:P) */ + { + if (op2->low == NULL) /* op2 = (:M) */ + { + if (gfc_compare_expr (op1->low, op2->high) > 0) + return 1; /* N > M */ + else + return 0; + } + + else if (op2->high == NULL) /* op2 = (M:) */ + { + if (gfc_compare_expr (op1->high, op2->low) < 0) + return -1; /* P < M */ + else + return 0; + } + + else /* op2 = (L:M) */ + { + if (gfc_compare_expr (op1->high, op2->low) < 0) + return -1; /* P < L */ + + if (gfc_compare_expr (op1->low, op2->high) > 0) + return 1; /* N > M */ + + return 0; + } + } +} + + +/* Merge-sort a double linked case list, detecting overlap in the + process. LIST is the head of the double linked case list before it + is sorted. Returns the head of the sorted list if we don't see any + overlap, or NULL otherwise. */ + +static gfc_case * +check_case_overlap (gfc_case * list) +{ + gfc_case *p, *q, *e, *tail; + int insize, nmerges, psize, qsize, cmp, overlap_seen; + + /* If the passed list was empty, return immediately. */ + if (!list) + return NULL; + + overlap_seen = 0; + insize = 1; + + /* Loop unconditionally. The only exit from this loop is a return + statement, when we've finished sorting the case list. */ + for (;;) + { + p = list; + list = NULL; + tail = NULL; + + /* Count the number of merges we do in this pass. */ + nmerges = 0; + + /* Loop while there exists a merge to be done. */ + while (p) + { + int i; + + /* Count this merge. */ + nmerges++; + + /* Cut the list in two pieces by steppin INSIZE places + forward in the list, starting from P. */ + psize = 0; + q = p; + for (i = 0; i < insize; i++) + { + psize++; + q = q->right; + if (!q) + break; + } + qsize = insize; + + /* Now we have two lists. Merge them! */ + while (psize > 0 || (qsize > 0 && q != NULL)) + { + + /* See from which the next case to merge comes from. */ + if (psize == 0) + { + /* P is empty so the next case must come from Q. */ + e = q; + q = q->right; + qsize--; + } + else if (qsize == 0 || q == NULL) + { + /* Q is empty. */ + e = p; + p = p->right; + psize--; + } + else + { + cmp = compare_cases (p, q); + if (cmp < 0) + { + /* The whole case range for P is less than the + one for Q. */ + e = p; + p = p->right; + psize--; + } + else if (cmp > 0) + { + /* The whole case range for Q is greater than + the case range for P. */ + e = q; + q = q->right; + qsize--; + } + else + { + /* The cases overlap, or they are the same + element in the list. Either way, we must + issue an error and get the next case from P. */ + /* FIXME: Sort P and Q by line number. */ + gfc_error ("CASE label at %L overlaps with CASE " + "label at %L", &p->where, &q->where); + overlap_seen = 1; + e = p; + p = p->right; + psize--; + } + } + + /* Add the next element to the merged list. */ + if (tail) + tail->right = e; + else + list = e; + e->left = tail; + tail = e; + } + + /* P has now stepped INSIZE places along, and so has Q. So + they're the same. */ + p = q; + } + tail->right = NULL; + + /* If we have done only one merge or none at all, we've + finished sorting the cases. */ + if (nmerges <= 1) + { + if (!overlap_seen) + return list; + else + return NULL; + } + + /* Otherwise repeat, merging lists twice the size. */ + insize *= 2; + } +} + + +/* Check to see if an expression is suitable for use in a CASE + statement. Makes sure that all case expressions are scalar + constants of the same type/kind. Return FAILURE if anything + is wrong. */ + +static try +validate_case_label_expr (gfc_expr * e, gfc_expr * case_expr) +{ + gfc_typespec case_ts = case_expr->ts; + + if (e == NULL) return SUCCESS; + + if (e->expr_type != EXPR_CONSTANT) + { + gfc_error ("Expression in CASE statement at %L must be a constant", + &e->where); + return FAILURE; + } + + if (e->ts.type != case_ts.type) + { + gfc_error ("Expression in CASE statement at %L must be of type %s", + &e->where, gfc_basic_typename (case_ts.type)); + return FAILURE; + } + + if (e->ts.kind != case_ts.kind) + { + gfc_error("Expression in CASE statement at %L must be kind %d", + &e->where, case_ts.kind); + return FAILURE; + } + + if (e->rank != 0) + { + gfc_error ("Expression in CASE statement at %L must be scalar", + &e->where); + return FAILURE; + } + + return SUCCESS; +} + + +/* Given a completely parsed select statement, we: + + - Validate all expressions and code within the SELECT. + - Make sure that the selection expression is not of the wrong type. + - Make sure that no case ranges overlap. + - Eliminate unreachable cases and unreachable code resulting from + removing case labels. + + The standard does allow unreachable cases, e.g. CASE (5:3). But + they are a hassle for code generation, and to prevent that, we just + cut them out here. This is not necessary for overlapping cases + because they are illegal and we never even try to generate code. + + We have the additional caveat that a SELECT construct could have + been a computed GOTO in the source code. Furtunately we can fairly + easily work around that here: The case_expr for a "real" SELECT CASE + is in code->expr1, but for a computed GOTO it is in code->expr2. All + we have to do is make sure that the case_expr is a scalar integer + expression. */ + +static void +resolve_select (gfc_code * code) +{ + gfc_code *body; + gfc_expr *case_expr; + gfc_case *cp, *default_case, *tail, *head; + int seen_unreachable; + int ncases; + bt type; + try t; + + if (code->expr == NULL) + { + /* This was actually a computed GOTO statement. */ + case_expr = code->expr2; + if (case_expr->ts.type != BT_INTEGER + || case_expr->rank != 0) + gfc_error ("Selection expression in computed GOTO statement " + "at %L must be a scalar integer expression", + &case_expr->where); + + /* Further checking is not necessary because this SELECT was built + by the compiler, so it should always be OK. Just move the + case_expr from expr2 to expr so that we can handle computed + GOTOs as normal SELECTs from here on. */ + code->expr = code->expr2; + code->expr2 = NULL; + return; + } + + case_expr = code->expr; + + type = case_expr->ts.type; + if (type != BT_LOGICAL && type != BT_INTEGER && type != BT_CHARACTER) + { + gfc_error ("Argument of SELECT statement at %L cannot be %s", + &case_expr->where, gfc_typename (&case_expr->ts)); + + /* Punt. Going on here just produce more garbage error messages. */ + return; + } + + if (case_expr->rank != 0) + { + gfc_error ("Argument of SELECT statement at %L must be a scalar " + "expression", &case_expr->where); + + /* Punt. */ + return; + } + + /* Assume there is no DEFAULT case. */ + default_case = NULL; + head = tail = NULL; + ncases = 0; + + for (body = code->block; body; body = body->block) + { + /* Assume the CASE list is OK, and all CASE labels can be matched. */ + t = SUCCESS; + seen_unreachable = 0; + + /* Walk the case label list, making sure that all case labels + are legal. */ + for (cp = body->ext.case_list; cp; cp = cp->next) + { + /* Count the number of cases in the whole construct. */ + ncases++; + + /* Intercept the DEFAULT case. */ + if (cp->low == NULL && cp->high == NULL) + { + if (default_case != NULL) + { + gfc_error ("The DEFAULT CASE at %L cannot be followed " + "by a second DEFAULT CASE at %L", + &default_case->where, &cp->where); + t = FAILURE; + break; + } + else + { + default_case = cp; + continue; + } + } + + /* Deal with single value cases and case ranges. Errors are + issued from the validation function. */ + if(validate_case_label_expr (cp->low, case_expr) != SUCCESS + || validate_case_label_expr (cp->high, case_expr) != SUCCESS) + { + t = FAILURE; + break; + } + + if (type == BT_LOGICAL + && ((cp->low == NULL || cp->high == NULL) + || cp->low != cp->high)) + { + gfc_error + ("Logical range in CASE statement at %L is not allowed", + &cp->low->where); + t = FAILURE; + break; + } + + if (cp->low != NULL && cp->high != NULL + && cp->low != cp->high + && gfc_compare_expr (cp->low, cp->high) > 0) + { + if (gfc_option.warn_surprising) + gfc_warning ("Range specification at %L can never " + "be matched", &cp->where); + + cp->unreachable = 1; + seen_unreachable = 1; + } + else + { + /* If the case range can be matched, it can also overlap with + other cases. To make sure it does not, we put it in a + double linked list here. We sort that with a merge sort + later on to detect any overlapping cases. */ + if (!head) + { + head = tail = cp; + head->right = head->left = NULL; + } + else + { + tail->right = cp; + tail->right->left = tail; + tail = tail->right; + tail->right = NULL; + } + } + } + + /* It there was a failure in the previous case label, give up + for this case label list. Continue with the next block. */ + if (t == FAILURE) + continue; + + /* See if any case labels that are unreachable have been seen. + If so, we eliminate them. This is a bit of a kludge because + the case lists for a single case statement (label) is a + single forward linked lists. */ + if (seen_unreachable) + { + /* Advance until the first case in the list is reachable. */ + while (body->ext.case_list != NULL + && body->ext.case_list->unreachable) + { + gfc_case *n = body->ext.case_list; + body->ext.case_list = body->ext.case_list->next; + n->next = NULL; + gfc_free_case_list (n); + } + + /* Strip all other unreachable cases. */ + if (body->ext.case_list) + { + for (cp = body->ext.case_list; cp->next; cp = cp->next) + { + if (cp->next->unreachable) + { + gfc_case *n = cp->next; + cp->next = cp->next->next; + n->next = NULL; + gfc_free_case_list (n); + } + } + } + } + } + + /* See if there were overlapping cases. If the check returns NULL, + there was overlap. In that case we don't do anything. If head + is non-NULL, we prepend the DEFAULT case. The sorted list can + then used during code generation for SELECT CASE constructs with + a case expression of a CHARACTER type. */ + if (head) + { + head = check_case_overlap (head); + + /* Prepend the default_case if it is there. */ + if (head != NULL && default_case) + { + default_case->left = NULL; + default_case->right = head; + head->left = default_case; + } + } + + /* Eliminate dead blocks that may be the result if we've seen + unreachable case labels for a block. */ + for (body = code; body && body->block; body = body->block) + { + if (body->block->ext.case_list == NULL) + { + /* Cut the unreachable block from the code chain. */ + gfc_code *c = body->block; + body->block = c->block; + + /* Kill the dead block, but not the blocks below it. */ + c->block = NULL; + gfc_free_statements (c); + } + } + + /* More than two cases is legal but insane for logical selects. + Issue a warning for it. */ + if (gfc_option.warn_surprising && type == BT_LOGICAL + && ncases > 2) + gfc_warning ("Logical SELECT CASE block at %L has more that two cases", + &code->loc); +} + + +/*********** Toplevel code resolution subroutines ***********/ + +/* Given a branch to a label and a namespace, if the branch is conforming. + The code node described where the branch is located. */ + +static void +resolve_branch (gfc_st_label * label, gfc_code * code) +{ + gfc_code *block, *found; + code_stack *stack; + gfc_st_label *lp; + + if (label == NULL) + return; + lp = label; + + /* Step one: is this a valid branching target? */ + + if (lp->defined == ST_LABEL_UNKNOWN) + { + gfc_error ("Label %d referenced at %L is never defined", lp->value, + &lp->where); + return; + } + + if (lp->defined != ST_LABEL_TARGET) + { + gfc_error ("Statement at %L is not a valid branch target statement " + "for the branch statement at %L", &lp->where, &code->loc); + return; + } + + /* Step two: make sure this branch is not a branch to itself ;-) */ + + if (code->here == label) + { + gfc_warning ("Branch at %L causes an infinite loop", &code->loc); + return; + } + + /* Step three: Try to find the label in the parse tree. To do this, + we traverse the tree block-by-block: first the block that + contains this GOTO, then the block that it is nested in, etc. We + can ignore other blocks because branching into another block is + not allowed. */ + + found = NULL; + + for (stack = cs_base; stack; stack = stack->prev) + { + for (block = stack->head; block; block = block->next) + { + if (block->here == label) + { + found = block; + break; + } + } + + if (found) + break; + } + + if (found == NULL) + { + /* still nothing, so illegal. */ + gfc_error_now ("Label at %L is not in the same block as the " + "GOTO statement at %L", &lp->where, &code->loc); + return; + } + + /* Step four: Make sure that the branching target is legal if + the statement is an END {SELECT,DO,IF}. */ + + if (found->op == EXEC_NOP) + { + for (stack = cs_base; stack; stack = stack->prev) + if (stack->current->next == found) + break; + + if (stack == NULL) + gfc_notify_std (GFC_STD_F95_DEL, + "Obsolete: GOTO at %L jumps to END of construct at %L", + &code->loc, &found->loc); + } +} + + +/* Check whether EXPR1 has the same shape as EXPR2. */ + +static try +resolve_where_shape (gfc_expr *expr1, gfc_expr *expr2) +{ + mpz_t shape[GFC_MAX_DIMENSIONS]; + mpz_t shape2[GFC_MAX_DIMENSIONS]; + try result = FAILURE; + int i; + + /* Compare the rank. */ + if (expr1->rank != expr2->rank) + return result; + + /* Compare the size of each dimension. */ + for (i=0; i<expr1->rank; i++) + { + if (gfc_array_dimen_size (expr1, i, &shape[i]) == FAILURE) + goto ignore; + + if (gfc_array_dimen_size (expr2, i, &shape2[i]) == FAILURE) + goto ignore; + + if (mpz_cmp (shape[i], shape2[i])) + goto over; + } + + /* When either of the two expression is an assumed size array, we + ignore the comparison of dimension sizes. */ +ignore: + result = SUCCESS; + +over: + for (i--; i>=0; i--) + { + mpz_clear (shape[i]); + mpz_clear (shape2[i]); + } + return result; +} + + +/* Check whether a WHERE assignment target or a WHERE mask expression + has the same shape as the outmost WHERE mask expression. */ + +static void +resolve_where (gfc_code *code, gfc_expr *mask) +{ + gfc_code *cblock; + gfc_code *cnext; + gfc_expr *e = NULL; + + cblock = code->block; + + /* Store the first WHERE mask-expr of the WHERE statement or construct. + In case of nested WHERE, only the outmost one is stored. */ + if (mask == NULL) /* outmost WHERE */ + e = cblock->expr; + else /* inner WHERE */ + e = mask; + + while (cblock) + { + if (cblock->expr) + { + /* Check if the mask-expr has a consistent shape with the + outmost WHERE mask-expr. */ + if (resolve_where_shape (cblock->expr, e) == FAILURE) + gfc_error ("WHERE mask at %L has inconsistent shape", + &cblock->expr->where); + } + + /* the assignment statement of a WHERE statement, or the first + statement in where-body-construct of a WHERE construct */ + cnext = cblock->next; + while (cnext) + { + switch (cnext->op) + { + /* WHERE assignment statement */ + case EXEC_ASSIGN: + + /* Check shape consistent for WHERE assignment target. */ + if (e && resolve_where_shape (cnext->expr, e) == FAILURE) + gfc_error ("WHERE assignment target at %L has " + "inconsistent shape", &cnext->expr->where); + break; + + /* WHERE or WHERE construct is part of a where-body-construct */ + case EXEC_WHERE: + resolve_where (cnext, e); + break; + + default: + gfc_error ("Unsupported statement inside WHERE at %L", + &cnext->loc); + } + /* the next statement within the same where-body-construct */ + cnext = cnext->next; + } + /* the next masked-elsewhere-stmt, elsewhere-stmt, or end-where-stmt */ + cblock = cblock->block; + } +} + + +/* Check whether the FORALL index appears in the expression or not. */ + +static try +gfc_find_forall_index (gfc_expr *expr, gfc_symbol *symbol) +{ + gfc_array_ref ar; + gfc_ref *tmp; + gfc_actual_arglist *args; + int i; + + switch (expr->expr_type) + { + case EXPR_VARIABLE: + assert (expr->symtree->n.sym); + + /* A scalar assignment */ + if (!expr->ref) + { + if (expr->symtree->n.sym == symbol) + return SUCCESS; + else + return FAILURE; + } + + /* the expr is array ref, substring or struct component. */ + tmp = expr->ref; + while (tmp != NULL) + { + switch (tmp->type) + { + case REF_ARRAY: + /* Check if the symbol appears in the array subscript. */ + ar = tmp->u.ar; + for (i = 0; i < GFC_MAX_DIMENSIONS; i++) + { + if (ar.start[i]) + if (gfc_find_forall_index (ar.start[i], symbol) == SUCCESS) + return SUCCESS; + + if (ar.end[i]) + if (gfc_find_forall_index (ar.end[i], symbol) == SUCCESS) + return SUCCESS; + + if (ar.stride[i]) + if (gfc_find_forall_index (ar.stride[i], symbol) == SUCCESS) + return SUCCESS; + } /* end for */ + break; + + case REF_SUBSTRING: + if (expr->symtree->n.sym == symbol) + return SUCCESS; + tmp = expr->ref; + /* Check if the symbol appears in the substring section. */ + if (gfc_find_forall_index (tmp->u.ss.start, symbol) == SUCCESS) + return SUCCESS; + if (gfc_find_forall_index (tmp->u.ss.end, symbol) == SUCCESS) + return SUCCESS; + break; + + case REF_COMPONENT: + break; + + default: + gfc_error("expresion reference type error at %L", &expr->where); + } + tmp = tmp->next; + } + break; + + /* If the expression is a function call, then check if the symbol + appears in the actual arglist of the function. */ + case EXPR_FUNCTION: + for (args = expr->value.function.actual; args; args = args->next) + { + if (gfc_find_forall_index(args->expr,symbol) == SUCCESS) + return SUCCESS; + } + break; + + /* It seems not to happen. */ + case EXPR_SUBSTRING: + if (expr->ref) + { + tmp = expr->ref; + assert(expr->ref->type == REF_SUBSTRING); + if (gfc_find_forall_index (tmp->u.ss.start, symbol) == SUCCESS) + return SUCCESS; + if (gfc_find_forall_index (tmp->u.ss.end, symbol) == SUCCESS) + return SUCCESS; + } + break; + + /* It seems not to happen. */ + case EXPR_STRUCTURE: + case EXPR_ARRAY: + gfc_error ("Unsupported statement while finding forall index in " + "expression"); + break; + default: + break; + } + + /* Find the FORALL index in the first operand. */ + if (expr->op1) + { + if (gfc_find_forall_index (expr->op1, symbol) == SUCCESS) + return SUCCESS; + } + + /* Find the FORALL index in the second operand. */ + if (expr->op2) + { + if (gfc_find_forall_index (expr->op2, symbol) == SUCCESS) + return SUCCESS; + } + return FAILURE; +} + + +/* Resolve assignment in FORALL construct. + NVAR is the number of FORALL index variables, and VAR_EXPR records the + FORALL index variables. */ + +static void +gfc_resolve_assign_in_forall (gfc_code *code, int nvar, gfc_expr **var_expr) +{ + int n; + + for (n = 0; n < nvar; n++) + { + gfc_symbol *forall_index; + + forall_index = var_expr[n]->symtree->n.sym; + + /* Check whether the assignment target is one of the FORALL index + variable. */ + if ((code->expr->expr_type == EXPR_VARIABLE) + && (code->expr->symtree->n.sym == forall_index)) + gfc_error ("Assignment to a FORALL index variable at %L", + &code->expr->where); + else + { + /* If one of the FORALL index variables doesn't appear in the + assignment target, then there will be a many-to-one + assignment. */ + if (gfc_find_forall_index (code->expr, forall_index) == FAILURE) + gfc_error ("The FORALL with index '%s' cause more than one " + "assignment to this object at %L", + var_expr[n]->symtree->name, &code->expr->where); + } + } +} + + +/* Resolve WHERE statement in FORALL construct. */ + +static void +gfc_resolve_where_code_in_forall (gfc_code *code, int nvar, gfc_expr **var_expr){ + gfc_code *cblock; + gfc_code *cnext; + + cblock = code->block; + while (cblock) + { + /* the assignment statement of a WHERE statement, or the first + statement in where-body-construct of a WHERE construct */ + cnext = cblock->next; + while (cnext) + { + switch (cnext->op) + { + /* WHERE assignment statement */ + case EXEC_ASSIGN: + gfc_resolve_assign_in_forall (cnext, nvar, var_expr); + break; + + /* WHERE or WHERE construct is part of a where-body-construct */ + case EXEC_WHERE: + gfc_resolve_where_code_in_forall (cnext, nvar, var_expr); + break; + + default: + gfc_error ("Unsupported statement inside WHERE at %L", + &cnext->loc); + } + /* the next statement within the same where-body-construct */ + cnext = cnext->next; + } + /* the next masked-elsewhere-stmt, elsewhere-stmt, or end-where-stmt */ + cblock = cblock->block; + } +} + + +/* Traverse the FORALL body to check whether the following errors exist: + 1. For assignment, check if a many-to-one assignment happens. + 2. For WHERE statement, check the WHERE body to see if there is any + many-to-one assignment. */ + +static void +gfc_resolve_forall_body (gfc_code *code, int nvar, gfc_expr **var_expr) +{ + gfc_code *c; + + c = code->block->next; + while (c) + { + switch (c->op) + { + case EXEC_ASSIGN: + case EXEC_POINTER_ASSIGN: + gfc_resolve_assign_in_forall (c, nvar, var_expr); + break; + + /* Because the resolve_blocks() will handle the nested FORALL, + there is no need to handle it here. */ + case EXEC_FORALL: + break; + case EXEC_WHERE: + gfc_resolve_where_code_in_forall(c, nvar, var_expr); + break; + default: + break; + } + /* The next statement in the FORALL body. */ + c = c->next; + } +} + + +/* Given a FORALL construct, first resolve the FORALL iterator, then call + gfc_resolve_forall_body to resolve the FORALL body. */ + +static void resolve_blocks (gfc_code *, gfc_namespace *); + +static void +gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save) +{ + static gfc_expr **var_expr; + static int total_var = 0; + static int nvar = 0; + gfc_forall_iterator *fa; + gfc_symbol *forall_index; + gfc_code *next; + int i; + + /* Start to resolve a FORALL construct */ + if (forall_save == 0) + { + /* Count the total number of FORALL index in the nested FORALL + construct in order to allocate the VAR_EXPR with proper size. */ + next = code; + while ((next != NULL) && (next->op == EXEC_FORALL)) + { + for (fa = next->ext.forall_iterator; fa; fa = fa->next) + total_var ++; + next = next->block->next; + } + + /* allocate VAR_EXPR with NUMBER_OF_FORALL_INDEX elements. */ + var_expr = (gfc_expr **) gfc_getmem (total_var * sizeof (gfc_expr *)); + } + + /* The information about FORALL iterator, including FORALL index start, end + and stride. The FORALL index can not appear in start, end or stride. */ + for (fa = code->ext.forall_iterator; fa; fa = fa->next) + { + /* Check if any outer FORALL index name is the same as the current + one. */ + for (i = 0; i < nvar; i++) + { + if (fa->var->symtree->n.sym == var_expr[i]->symtree->n.sym) + { + gfc_error ("An outer FORALL construct already has an index " + "with this name %L", &fa->var->where); + } + } + + /* Record the current FORALL index. */ + var_expr[nvar] = gfc_copy_expr (fa->var); + + forall_index = fa->var->symtree->n.sym; + + /* Check if the FORALL index appears in start, end or stride. */ + if (gfc_find_forall_index (fa->start, forall_index) == SUCCESS) + gfc_error ("A FORALL index must not appear in a limit or stride " + "expression in the same FORALL at %L", &fa->start->where); + if (gfc_find_forall_index (fa->end, forall_index) == SUCCESS) + gfc_error ("A FORALL index must not appear in a limit or stride " + "expression in the same FORALL at %L", &fa->end->where); + if (gfc_find_forall_index (fa->stride, forall_index) == SUCCESS) + gfc_error ("A FORALL index must not appear in a limit or stride " + "expression in the same FORALL at %L", &fa->stride->where); + nvar++; + } + + /* Resolve the FORALL body. */ + gfc_resolve_forall_body (code, nvar, var_expr); + + /* May call gfc_resolve_forall to resolve the inner FORALL loop. */ + resolve_blocks (code->block, ns); + + /* Free VAR_EXPR after the whole FORALL construct resolved. */ + for (i = 0; i < total_var; i++) + gfc_free_expr (var_expr[i]); + + /* Reset the counters. */ + total_var = 0; + nvar = 0; +} + + +/* Resolve lists of blocks found in IF, SELECT CASE, WHERE, FORALL ,GOTO and + DO code nodes. */ + +static void resolve_code (gfc_code *, gfc_namespace *); + +static void +resolve_blocks (gfc_code * b, gfc_namespace * ns) +{ + try t; + + for (; b; b = b->block) + { + t = gfc_resolve_expr (b->expr); + if (gfc_resolve_expr (b->expr2) == FAILURE) + t = FAILURE; + + switch (b->op) + { + case EXEC_IF: + if (t == SUCCESS && b->expr != NULL + && (b->expr->ts.type != BT_LOGICAL || b->expr->rank != 0)) + gfc_error + ("ELSE IF clause at %L requires a scalar LOGICAL expression", + &b->expr->where); + break; + + case EXEC_WHERE: + if (t == SUCCESS + && b->expr != NULL + && (b->expr->ts.type != BT_LOGICAL + || b->expr->rank == 0)) + gfc_error + ("WHERE/ELSEWHERE clause at %L requires a LOGICAL array", + &b->expr->where); + break; + + case EXEC_GOTO: + resolve_branch (b->label, b); + break; + + case EXEC_SELECT: + case EXEC_FORALL: + case EXEC_DO: + case EXEC_DO_WHILE: + break; + + default: + gfc_internal_error ("resolve_block(): Bad block type"); + } + + resolve_code (b->next, ns); + } +} + + +/* Given a block of code, recursively resolve everything pointed to by this + code block. */ + +static void +resolve_code (gfc_code * code, gfc_namespace * ns) +{ + int forall_save = 0; + code_stack frame; + gfc_alloc *a; + try t; + + frame.prev = cs_base; + frame.head = code; + cs_base = &frame; + + for (; code; code = code->next) + { + frame.current = code; + + if (code->op == EXEC_FORALL) + { + forall_save = forall_flag; + forall_flag = 1; + gfc_resolve_forall (code, ns, forall_save); + } + else + resolve_blocks (code->block, ns); + + if (code->op == EXEC_FORALL) + forall_flag = forall_save; + + t = gfc_resolve_expr (code->expr); + if (gfc_resolve_expr (code->expr2) == FAILURE) + t = FAILURE; + + switch (code->op) + { + case EXEC_NOP: + case EXEC_CYCLE: + case EXEC_IOLENGTH: + case EXEC_PAUSE: + case EXEC_STOP: + case EXEC_EXIT: + case EXEC_CONTINUE: + case EXEC_DT_END: + case EXEC_TRANSFER: + break; + + case EXEC_WHERE: + resolve_where (code, NULL); + break; + + case EXEC_GOTO: + if (code->expr != NULL && code->expr->ts.type != BT_INTEGER) + gfc_error ("ASSIGNED GOTO statement at %L requires an INTEGER " + "variable", &code->expr->where); + else + resolve_branch (code->label, code); + break; + + case EXEC_RETURN: + if (code->expr != NULL && code->expr->ts.type != BT_INTEGER) + gfc_error ("Alternate RETURN statement at %L requires an INTEGER " + "return specifier", &code->expr->where); + break; + + case EXEC_ASSIGN: + if (t == FAILURE) + break; + + if (gfc_extend_assign (code, ns) == SUCCESS) + goto call; + + if (gfc_pure (NULL)) + { + if (gfc_impure_variable (code->expr->symtree->n.sym)) + { + gfc_error + ("Cannot assign to variable '%s' in PURE procedure at %L", + code->expr->symtree->n.sym->name, &code->expr->where); + break; + } + + if (code->expr2->ts.type == BT_DERIVED + && derived_pointer (code->expr2->ts.derived)) + { + gfc_error + ("Right side of assignment at %L is a derived type " + "containing a POINTER in a PURE procedure", + &code->expr2->where); + break; + } + } + + gfc_check_assign (code->expr, code->expr2, 1); + break; + + case EXEC_LABEL_ASSIGN: + if (code->label->defined == ST_LABEL_UNKNOWN) + gfc_error ("Label %d referenced at %L is never defined", + code->label->value, &code->label->where); + if (t == SUCCESS && code->expr->ts.type != BT_INTEGER) + gfc_error ("ASSIGN statement at %L requires an INTEGER " + "variable", &code->expr->where); + break; + + case EXEC_POINTER_ASSIGN: + if (t == FAILURE) + break; + + gfc_check_pointer_assign (code->expr, code->expr2); + break; + + case EXEC_ARITHMETIC_IF: + if (t == SUCCESS + && code->expr->ts.type != BT_INTEGER + && code->expr->ts.type != BT_REAL) + gfc_error ("Arithmetic IF statement at %L requires a numeric " + "expression", &code->expr->where); + + resolve_branch (code->label, code); + resolve_branch (code->label2, code); + resolve_branch (code->label3, code); + break; + + case EXEC_IF: + if (t == SUCCESS && code->expr != NULL + && (code->expr->ts.type != BT_LOGICAL + || code->expr->rank != 0)) + gfc_error ("IF clause at %L requires a scalar LOGICAL expression", + &code->expr->where); + break; + + case EXEC_CALL: + call: + resolve_call (code); + break; + + case EXEC_SELECT: + /* Select is complicated. Also, a SELECT construct could be + a transformed computed GOTO. */ + resolve_select (code); + break; + + case EXEC_DO: + if (code->ext.iterator != NULL) + gfc_resolve_iterator (code->ext.iterator); + break; + + case EXEC_DO_WHILE: + if (code->expr == NULL) + gfc_internal_error ("resolve_code(): No expression on DO WHILE"); + if (t == SUCCESS + && (code->expr->rank != 0 + || code->expr->ts.type != BT_LOGICAL)) + gfc_error ("Exit condition of DO WHILE loop at %L must be " + "a scalar LOGICAL expression", &code->expr->where); + break; + + case EXEC_ALLOCATE: + if (t == SUCCESS && code->expr != NULL + && code->expr->ts.type != BT_INTEGER) + gfc_error ("STAT tag in ALLOCATE statement at %L must be " + "of type INTEGER", &code->expr->where); + + for (a = code->ext.alloc_list; a; a = a->next) + resolve_allocate_expr (a->expr); + + break; + + case EXEC_DEALLOCATE: + if (t == SUCCESS && code->expr != NULL + && code->expr->ts.type != BT_INTEGER) + gfc_error + ("STAT tag in DEALLOCATE statement at %L must be of type " + "INTEGER", &code->expr->where); + + for (a = code->ext.alloc_list; a; a = a->next) + resolve_deallocate_expr (a->expr); + + break; + + case EXEC_OPEN: + if (gfc_resolve_open (code->ext.open) == FAILURE) + break; + + resolve_branch (code->ext.open->err, code); + break; + + case EXEC_CLOSE: + if (gfc_resolve_close (code->ext.close) == FAILURE) + break; + + resolve_branch (code->ext.close->err, code); + break; + + case EXEC_BACKSPACE: + case EXEC_ENDFILE: + case EXEC_REWIND: + if (gfc_resolve_filepos (code->ext.filepos) == FAILURE) + break; + + resolve_branch (code->ext.filepos->err, code); + break; + + case EXEC_INQUIRE: + if (gfc_resolve_inquire (code->ext.inquire) == FAILURE) + break; + + resolve_branch (code->ext.inquire->err, code); + break; + + case EXEC_READ: + case EXEC_WRITE: + if (gfc_resolve_dt (code->ext.dt) == FAILURE) + break; + + resolve_branch (code->ext.dt->err, code); + resolve_branch (code->ext.dt->end, code); + resolve_branch (code->ext.dt->eor, code); + break; + + case EXEC_FORALL: + resolve_forall_iterators (code->ext.forall_iterator); + + if (code->expr != NULL && code->expr->ts.type != BT_LOGICAL) + gfc_error + ("FORALL mask clause at %L requires a LOGICAL expression", + &code->expr->where); + break; + + default: + gfc_internal_error ("resolve_code(): Bad statement code"); + } + } + + cs_base = frame.prev; +} + + +/* Resolve initial values and make sure they are compatible with + the variable. */ + +static void +resolve_values (gfc_symbol * sym) +{ + + if (sym->value == NULL) + return; + + if (gfc_resolve_expr (sym->value) == FAILURE) + return; + + gfc_check_assign_symbol (sym, sym->value); +} + + +/* Do anything necessary to resolve a symbol. Right now, we just + assume that an otherwise unknown symbol is a variable. This sort + of thing commonly happens for symbols in module. */ + +static void +resolve_symbol (gfc_symbol * sym) +{ + /* Zero if we are checking a formal namespace. */ + static int formal_ns_flag = 1; + int formal_ns_save, check_constant, mp_flag; + + if (sym->attr.flavor == FL_UNKNOWN) + { + if (sym->attr.external == 0 && sym->attr.intrinsic == 0) + sym->attr.flavor = FL_VARIABLE; + else + { + sym->attr.flavor = FL_PROCEDURE; + if (sym->attr.dimension) + sym->attr.function = 1; + } + } + + /* Symbols that are module procedures with results (functions) have + the types and array specification copied for type checking in + procedures that call them, as well as for saving to a module + file. These symbols can't stand the scrutiny that their results + can. */ + mp_flag = (sym->result != NULL && sym->result != sym); + + /* Assign default type to symbols that need one and don't have one. */ + if (sym->ts.type == BT_UNKNOWN) + { + if (sym->attr.flavor == FL_VARIABLE || sym->attr.flavor == FL_PARAMETER) + gfc_set_default_type (sym, 0, NULL); + + if (sym->attr.flavor == FL_PROCEDURE && sym->attr.function) + { + if (!mp_flag) + gfc_set_default_type (sym, 0, NULL); + else + { + /* Result may be in another namespace. */ + resolve_symbol (sym->result); + + sym->ts = sym->result->ts; + sym->as = gfc_copy_array_spec (sym->result->as); + } + } + } + + if (sym->as != NULL + && (sym->as->type == AS_ASSUMED_SIZE + || sym->as->type == AS_ASSUMED_SHAPE) + && sym->attr.dummy == 0) + { + gfc_error("Assumed %s array at %L must be a dummy argument", + sym->as->type == AS_ASSUMED_SIZE ? "size" : "shape", + &sym->declared_at); + return; + } + + /* Make sure that character string variables with assumed length are + dummy argument. */ + + if (sym->attr.flavor == FL_VARIABLE && !sym->attr.result + && sym->ts.type == BT_CHARACTER + && sym->ts.cl->length == NULL && sym->attr.dummy == 0) + { + gfc_error ("Entity with assumed character length at %L must be a " + "dummy argument or a PARAMETER", &sym->declared_at); + return; + } + + /* Make sure a parameter that has been implicitly typed still + matches the implicit type, since PARAMETER statements can precede + IMPLICIT statements. */ + + if (sym->attr.flavor == FL_PARAMETER + && sym->attr.implicit_type + && !gfc_compare_types (&sym->ts, gfc_get_default_type (sym, sym->ns))) + gfc_error ("Implicitly typed PARAMETER '%s' at %L doesn't match a " + "later IMPLICIT type", sym->name, &sym->declared_at); + + /* Make sure the types of derived parameters are consistent. This + type checking is deferred until resolution because the type may + refer to a derived type from the host. */ + + if (sym->attr.flavor == FL_PARAMETER + && sym->ts.type == BT_DERIVED + && !gfc_compare_types (&sym->ts, &sym->value->ts)) + gfc_error ("Incompatible derived type in PARAMETER at %L", + &sym->value->where); + + /* Make sure symbols with known intent or optional are really dummy + variable. Because of ENTRY statement, this has to be deferred + until resolution time. */ + + if (! sym->attr.dummy + && (sym->attr.optional + || sym->attr.intent != INTENT_UNKNOWN)) + { + gfc_error ("Symbol at %L is not a DUMMY variable", &sym->declared_at); + return; + } + + if (sym->attr.proc == PROC_ST_FUNCTION) + { + if (sym->ts.type == BT_CHARACTER) + { + gfc_charlen *cl = sym->ts.cl; + if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT) + { + gfc_error ("Character-valued statement function '%s' at %L must " + "have constant length", sym->name, &sym->declared_at); + return; + } + } + } + + /* Constraints on deferred shape variable. */ + if (sym->attr.flavor == FL_VARIABLE + || (sym->attr.flavor == FL_PROCEDURE + && sym->attr.function)) + { + if (sym->as == NULL || sym->as->type != AS_DEFERRED) + { + if (sym->attr.allocatable) + { + if (sym->attr.dimension) + gfc_error ("Allocatable array at %L must have a deferred shape", + &sym->declared_at); + else + gfc_error ("Object at %L may not be ALLOCATABLE", + &sym->declared_at); + return; + } + + if (sym->attr.pointer && sym->attr.dimension) + { + gfc_error ("Pointer to array at %L must have a deferred shape", + &sym->declared_at); + return; + } + + } + else + { + if (!mp_flag && !sym->attr.allocatable + && !sym->attr.pointer && !sym->attr.dummy) + { + gfc_error ("Array at %L cannot have a deferred shape", + &sym->declared_at); + return; + } + } + } + + /* Make sure that intrinsic exist */ + if (sym->attr.intrinsic + && ! gfc_intrinsic_name(sym->name, 0) + && ! gfc_intrinsic_name(sym->name, 1)) + gfc_error("Intrinsic at %L does not exist", &sym->declared_at); + + /* Resolve array specifier. Check as well some constraints + on COMMON blocks. */ + + check_constant = sym->attr.in_common && !sym->attr.pointer; + gfc_resolve_array_spec (sym->as, check_constant); + + /* Resolve formal namespaces. */ + + if (formal_ns_flag && sym != NULL && sym->formal_ns != NULL) + { + formal_ns_save = formal_ns_flag; + formal_ns_flag = 0; + gfc_resolve (sym->formal_ns); + formal_ns_flag = formal_ns_save; + } +} + + + +/************* Resolve DATA statements *************/ + +static struct +{ + gfc_data_value *vnode; + int left; +} +values; + + +/* Advance the values structure to point to the next value in the data list. */ + +static try +next_data_value (void) +{ + + while (values.left == 0) + { + if (values.vnode->next == NULL) + return FAILURE; + + values.vnode = values.vnode->next; + values.left = values.vnode->repeat; + } + + values.left--; + return SUCCESS; +} + + +static try +check_data_variable (gfc_data_variable * var, locus * where) +{ + gfc_expr *e; + mpz_t size; + mpz_t offset; + try t; + int mark = 0; + int i; + mpz_t section_index[GFC_MAX_DIMENSIONS]; + gfc_ref *ref; + gfc_array_ref *ar; + + if (gfc_resolve_expr (var->expr) == FAILURE) + return FAILURE; + + ar = NULL; + mpz_init_set_si (offset, 0); + e = var->expr; + + if (e->expr_type != EXPR_VARIABLE) + gfc_internal_error ("check_data_variable(): Bad expression"); + + if (e->rank == 0) + mpz_init_set_ui (size, 1); + else + { + ref = e->ref; + + /* Find the array section reference. */ + for (ref = e->ref; ref; ref = ref->next) + { + if (ref->type != REF_ARRAY) + continue; + if (ref->u.ar.type == AR_ELEMENT) + continue; + break; + } + assert (ref); + + /* Set marks asscording to the reference pattern. */ + switch (ref->u.ar.type) + { + case AR_FULL: + mark = 1; + break; + + case AR_SECTION: + ar = &ref->u.ar; + /* Get the start position of array section. */ + gfc_get_section_index (ar, section_index, &offset); + mark = 2; + break; + + default: + abort(); + } + + if (gfc_array_size (e, &size) == FAILURE) + { + gfc_error ("Nonconstant array section at %L in DATA statement", + &e->where); + mpz_clear (offset); + return FAILURE; + } + } + + t = SUCCESS; + + while (mpz_cmp_ui (size, 0) > 0) + { + if (next_data_value () == FAILURE) + { + gfc_error ("DATA statement at %L has more variables than values", + where); + t = FAILURE; + break; + } + + t = gfc_check_assign (var->expr, values.vnode->expr, 0); + if (t == FAILURE) + break; + + /* Assign initial value to symbol. */ + gfc_assign_data_value (var->expr, values.vnode->expr, offset); + + if (mark == 1) + mpz_add_ui (offset, offset, 1); + + /* Modify the array section indexes and recalculate the offset for + next element. */ + else if (mark == 2) + gfc_advance_section (section_index, ar, &offset); + + mpz_sub_ui (size, size, 1); + } + if (mark == 2) + { + for (i = 0; i < ar->dimen; i++) + mpz_clear (section_index[i]); + } + + mpz_clear (size); + mpz_clear (offset); + + return t; +} + + +static try traverse_data_var (gfc_data_variable *, locus *); + +/* Iterate over a list of elements in a DATA statement. */ + +static try +traverse_data_list (gfc_data_variable * var, locus * where) +{ + mpz_t trip; + iterator_stack frame; + gfc_expr *e; + + mpz_init (frame.value); + + mpz_init_set (trip, var->iter.end->value.integer); + mpz_sub (trip, trip, var->iter.start->value.integer); + mpz_add (trip, trip, var->iter.step->value.integer); + + mpz_div (trip, trip, var->iter.step->value.integer); + + mpz_set (frame.value, var->iter.start->value.integer); + + frame.prev = iter_stack; + frame.variable = var->iter.var->symtree; + iter_stack = &frame; + + while (mpz_cmp_ui (trip, 0) > 0) + { + if (traverse_data_var (var->list, where) == FAILURE) + { + mpz_clear (trip); + return FAILURE; + } + + e = gfc_copy_expr (var->expr); + if (gfc_simplify_expr (e, 1) == FAILURE) + { + gfc_free_expr (e); + return FAILURE; + } + + mpz_add (frame.value, frame.value, var->iter.step->value.integer); + + mpz_sub_ui (trip, trip, 1); + } + + mpz_clear (trip); + mpz_clear (frame.value); + + iter_stack = frame.prev; + return SUCCESS; +} + + +/* Type resolve variables in the variable list of a DATA statement. */ + +static try +traverse_data_var (gfc_data_variable * var, locus * where) +{ + try t; + + for (; var; var = var->next) + { + if (var->expr == NULL) + t = traverse_data_list (var, where); + else + t = check_data_variable (var, where); + + if (t == FAILURE) + return FAILURE; + } + + return SUCCESS; +} + + +/* Resolve the expressions and iterators associated with a data statement. + This is separate from the assignment checking because data lists should + only be resolved once. */ + +static try +resolve_data_variables (gfc_data_variable * d) +{ + + for (; d; d = d->next) + { + if (d->list == NULL) + { + if (gfc_resolve_expr (d->expr) == FAILURE) + return FAILURE; + } + else + { + if (gfc_resolve_iterator (&d->iter) == FAILURE) + return FAILURE; + + if (d->iter.start->expr_type != EXPR_CONSTANT + || d->iter.end->expr_type != EXPR_CONSTANT + || d->iter.step->expr_type != EXPR_CONSTANT) + gfc_internal_error ("resolve_data_variables(): Bad iterator"); + + if (resolve_data_variables (d->list) == FAILURE) + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Resolve a single DATA statement. We implement this by storing a pointer to + the value list into static variables, and then recursively traversing the + variables list, expanding iterators and such. */ + +static void +resolve_data (gfc_data * d) +{ + + if (resolve_data_variables (d->var) == FAILURE) + return; + + values.vnode = d->value; + values.left = (d->value == NULL) ? 0 : d->value->repeat; + + if (traverse_data_var (d->var, &d->where) == FAILURE) + return; + + /* At this point, we better not have any values left. */ + + if (next_data_value () == SUCCESS) + gfc_error ("DATA statement at %L has more values than variables", + &d->where); +} + + +/* Determines if a variable is not 'pure', ie not assignable within a pure + procedure. Returns zero if assignment is OK, nonzero if there is a problem. + */ + +int +gfc_impure_variable (gfc_symbol * sym) +{ + + if (sym->attr.use_assoc || sym->attr.in_common) + return 1; + + if (sym->ns != gfc_current_ns) + return !sym->attr.function; + + /* TODO: Check storage association through EQUIVALENCE statements */ + + return 0; +} + + +/* Test whether a symbol is pure or not. For a NULL pointer, checks the + symbol of the current procedure. */ + +int +gfc_pure (gfc_symbol * sym) +{ + symbol_attribute attr; + + if (sym == NULL) + sym = gfc_current_ns->proc_name; + if (sym == NULL) + return 0; + + attr = sym->attr; + + return attr.flavor == FL_PROCEDURE && (attr.pure || attr.elemental); +} + + +/* Test whether the current procedure is elemental or not. */ + +int +gfc_elemental (gfc_symbol * sym) +{ + symbol_attribute attr; + + if (sym == NULL) + sym = gfc_current_ns->proc_name; + if (sym == NULL) + return 0; + attr = sym->attr; + + return attr.flavor == FL_PROCEDURE && attr.elemental; +} + + +/* Warn about unused labels. */ + +static void +warn_unused_label (gfc_namespace * ns) +{ + gfc_st_label *l; + + l = ns->st_labels; + if (l == NULL) + return; + + while (l->next) + l = l->next; + + for (; l; l = l->prev) + { + if (l->defined == ST_LABEL_UNKNOWN) + continue; + + switch (l->referenced) + { + case ST_LABEL_UNKNOWN: + gfc_warning ("Label %d at %L defined but not used", l->value, + &l->where); + break; + + case ST_LABEL_BAD_TARGET: + gfc_warning ("Label %d at %L defined but cannot be used", l->value, + &l->where); + break; + + default: + break; + } + } +} + + +/* Resolve derived type EQUIVALENCE object. */ + +static try +resolve_equivalence_derived (gfc_symbol *derived, gfc_symbol *sym, gfc_expr *e) +{ + gfc_symbol *d; + gfc_component *c = derived->components; + + if (!derived) + return SUCCESS; + + /* Shall not be an object of nonsequence derived type. */ + if (!derived->attr.sequence) + { + gfc_error ("Derived type variable '%s' at %L must have SEQUENCE " + "attribute to be an EQUIVALENCE object", sym->name, &e->where); + return FAILURE; + } + + for (; c ; c = c->next) + { + d = c->ts.derived; + if (d && (resolve_equivalence_derived (c->ts.derived, sym, e) == FAILURE)) + return FAILURE; + + /* Shall not be an object of sequence derived type containing a pointer + in the structure. */ + if (c->pointer) + { + gfc_error ("Derived type variable '%s' at %L has pointer componet(s) " + "cannot be an EQUIVALENCE object", sym->name, &e->where); + return FAILURE; + } + } + return SUCCESS; +} + + +/* Resolve equivalence object. + An EQUIVALENCE object shall not be a dummy argument, a pointer, an + allocatable array, an object of nonsequence derived type, an object of + sequence derived type containing a pointer at any level of component + selection, an automatic object, a function name, an entry name, a result + name, a named constant, a structure component, or a subobject of any of + the preceding objects. */ + +static void +resolve_equivalence (gfc_equiv *eq) +{ + gfc_symbol *sym; + gfc_symbol *derived; + gfc_expr *e; + gfc_ref *r; + + for (; eq; eq = eq->eq) + { + e = eq->expr; + if (gfc_resolve_expr (e) == FAILURE) + continue; + + sym = e->symtree->n.sym; + + /* Shall not be a dummy argument. */ + if (sym->attr.dummy) + { + gfc_error ("Dummy argument '%s' at %L cannot be an EQUIVALENCE " + "object", sym->name, &e->where); + continue; + } + + /* Shall not be an allocatable array. */ + if (sym->attr.allocatable) + { + gfc_error ("Allocatable array '%s' at %L cannot be an EQUIVALENCE " + "object", sym->name, &e->where); + continue; + } + + /* Shall not be a pointer. */ + if (sym->attr.pointer) + { + gfc_error ("Pointer '%s' at %L cannot be an EQUIVALENCE object", + sym->name, &e->where); + continue; + } + + /* Shall not be a function name, ... */ + if (sym->attr.function || sym->attr.result || sym->attr.entry + || sym->attr.subroutine) + { + gfc_error ("Entity '%s' at %L cannot be an EQUIVALENCE object", + sym->name, &e->where); + continue; + } + + /* Shall not be a named constant. */ + if (e->expr_type == EXPR_CONSTANT) + { + gfc_error ("Named constant '%s' at %L cannot be an EQUIVALENCE " + "object", sym->name, &e->where); + continue; + } + + derived = e->ts.derived; + if (derived && resolve_equivalence_derived (derived, sym, e) == FAILURE) + continue; + + if (!e->ref) + continue; + + /* Shall not be an automatic array. */ + if (e->ref->type == REF_ARRAY + && gfc_resolve_array_spec (e->ref->u.ar.as, 1) == FAILURE) + { + gfc_error ("Array '%s' at %L with non-constant bounds cannot be " + "an EQUIVALENCE object", sym->name, &e->where); + continue; + } + + /* Shall not be a structure component. */ + r = e->ref; + while (r) + { + if (r->type == REF_COMPONENT) + { + gfc_error ("Structure component '%s' at %L cannot be an " + "EQUIVALENCE object", + r->u.c.component->name, &e->where); + break; + } + r = r->next; + } + } +} + + +/* This function is called after a complete program unit has been compiled. + Its purpose is to examine all of the expressions associated with a program + unit, assign types to all intermediate expressions, make sure that all + assignments are to compatible types and figure out which names refer to + which functions or subroutines. */ + +void +gfc_resolve (gfc_namespace * ns) +{ + gfc_namespace *old_ns, *n; + gfc_charlen *cl; + gfc_data *d; + gfc_equiv *eq; + + old_ns = gfc_current_ns; + gfc_current_ns = ns; + + resolve_contained_functions (ns); + + gfc_traverse_ns (ns, resolve_symbol); + + for (n = ns->contained; n; n = n->sibling) + { + if (gfc_pure (ns->proc_name) && !gfc_pure (n->proc_name)) + gfc_error ("Contained procedure '%s' at %L of a PURE procedure must " + "also be PURE", n->proc_name->name, + &n->proc_name->declared_at); + + gfc_resolve (n); + } + + forall_flag = 0; + gfc_check_interfaces (ns); + + for (cl = ns->cl_list; cl; cl = cl->next) + { + if (cl->length == NULL || gfc_resolve_expr (cl->length) == FAILURE) + continue; + + if (cl->length->ts.type != BT_INTEGER) + gfc_error + ("Character length specification at %L must be of type INTEGER", + &cl->length->where); + } + + gfc_traverse_ns (ns, resolve_values); + + if (ns->save_all) + gfc_save_all (ns); + + iter_stack = NULL; + for (d = ns->data; d; d = d->next) + resolve_data (d); + + iter_stack = NULL; + gfc_traverse_ns (ns, gfc_formalize_init_value); + + for (eq = ns->equiv; eq; eq = eq->next) + resolve_equivalence (eq); + + cs_base = NULL; + resolve_code (ns->code, ns); + + /* Warn about unused labels. */ + if (gfc_option.warn_unused_labels) + warn_unused_label (ns); + + gfc_current_ns = old_ns; +} + |